Skip to content

Commit 35868d6

Browse files
Support for auto handling of SQL Injection in Mule closes #146
Co-authored-by: sanagaraj-pivotal <[email protected]>
1 parent 0a61b22 commit 35868d6

File tree

11 files changed

+303
-37
lines changed

11 files changed

+303
-37
lines changed

applications/spring-shell/src/test/java/org/springframework/sbm/BootifySimpleMuleAppIntegrationTest.java

+13-9
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,6 @@ public static void afterAll() {
8080
}
8181
}
8282

83-
@Test
84-
@Tag("integration")
85-
@DisabledIfSystemProperty(named= "os.arch", matches = "aarch64", disabledReason = "imbcom/mq image not supported with Apple Silicon")
86-
void t1_testWebsphereMqMigration() throws JMSException, InterruptedException {
87-
checkWmqIntegration(rabbitMqContainer.getNetwork());
88-
}
89-
9083
@Test
9184
@Tag("integration")
9285
public void t0_springIntegrationWorks() throws IOException, TimeoutException, InterruptedException {
@@ -109,10 +102,15 @@ public void t0_springIntegrationWorks() throws IOException, TimeoutException, I
109102
checkSendHttpMessage(container.getContainer().getMappedPort(9081));
110103
checkInboundGatewayHttpMessage(container.getContainer().getMappedPort(9081));
111104
checkRabbitMqIntegration(ampqChannel);
105+
checkDbIntegration(container.getContainer().getMappedPort(9081));
112106
}
113107

114-
115-
108+
@Test
109+
@Tag("integration")
110+
@DisabledIfSystemProperty(named= "os.arch", matches = "aarch64", disabledReason = "imbcom/mq image not supported with Apple Silicon")
111+
void t1_testWebsphereMqMigration() throws JMSException, InterruptedException {
112+
checkWmqIntegration(rabbitMqContainer.getNetwork());
113+
}
116114

117115
private void checkRabbitMqIntegration(Channel amqpChannel)
118116
throws IOException, InterruptedException {
@@ -157,6 +155,12 @@ private void checkWmqIntegration(Network rabbitMqNetwork) throws InterruptedExce
157155
assertThat(latchResult).isTrue();
158156
}
159157

158+
private void checkDbIntegration(int port) {
159+
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:" + port + "/db", String.class);
160+
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
161+
assertThat(responseEntity.getBody()).contains("{\"ID\":1,\"USERNAME\":\"TestUser\",\"PASSWORD\":\"secret\"");
162+
}
163+
160164
private void checkInboundGatewayHttpMessage(int port) {
161165
ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://localhost:" + port + "/helloworld", String.class);
162166
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<mule xmlns:db="http://www.mulesoft.org/schema/mule/db"
2+
xmlns:http="http://www.mulesoft.org/schema/mule/http"
3+
xmlns="http://www.mulesoft.org/schema/mule/core"
4+
xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xsi:schemaLocation="
7+
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
8+
http://www.mulesoft.org/schema/mule/db http://www.mulesoft.org/schema/mule/db/current/mule-db.xsd
9+
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
10+
<flow name="get:/db:helloword-config">
11+
<db:insert config-ref="Oracle_Configuration" doc:name="Database">
12+
<db:parameterized-query>
13+
<![CDATA[INSERT INTO USERS (username, password) VALUES ('TestUser', 'secret')]]></db:parameterized-query>
14+
</db:insert>
15+
<db:select config-ref="Oracle_Configuration" doc:name="Database">
16+
<db:dynamic-query>
17+
<![CDATA[select * from users where username='TestUser' and password='secret']]></db:dynamic-query>
18+
</db:select>
19+
</flow>
20+
</mule>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
DROP TABLE IF EXISTS USERS;
2+
3+
CREATE TABLE USERS (
4+
id INT AUTO_INCREMENT PRIMARY KEY,
5+
username VARCHAR(250) NOT NULL,
6+
password VARCHAR(250) NOT NULL
7+
);

components/sbm-recipes-mule-to-boot/src/main/java/org/springframework/sbm/mule/actions/javadsl/translators/db/DBCommons.java

+70
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,78 @@
1515
*/
1616
package org.springframework.sbm.mule.actions.javadsl.translators.db;
1717

18+
19+
import lombok.AllArgsConstructor;
20+
import lombok.Data;
21+
import lombok.NoArgsConstructor;
22+
import org.mulesoft.schema.mule.db.AdvancedDbMessageProcessorType;
23+
24+
import java.util.ArrayList;
25+
import java.util.List;
26+
import java.util.regex.Matcher;
27+
import java.util.regex.Pattern;
28+
import java.util.stream.Collectors;
29+
30+
@Data
31+
@AllArgsConstructor
32+
@NoArgsConstructor
33+
class QueryWithParameters {
34+
private String query = "";
35+
private List<String> muleExpressions = new ArrayList<>();
36+
}
37+
38+
@Data
39+
@AllArgsConstructor
40+
@NoArgsConstructor
41+
class QueryFunctionParameter {
42+
private String query = "";
43+
private String arguments = "";
44+
}
45+
1846
public class DBCommons {
1947
public static String escapeDoubleQuotes(String str) {
2048
return str.replace("\"", "\\\"");
2149
}
50+
51+
private static final String regexPattern = "#\\[(.+?)]";
52+
private static final Pattern pattern = Pattern.compile(regexPattern);
53+
54+
public static QueryWithParameters parseQueryParameter(String input) {
55+
56+
if (input == null) {
57+
return new QueryWithParameters();
58+
}
59+
60+
Matcher m = pattern.matcher(input);
61+
62+
List<String> muleExpressions = new ArrayList<>();
63+
64+
while (m.find()) {
65+
muleExpressions.add(m.group(1));
66+
}
67+
68+
return new QueryWithParameters(input
69+
.replaceAll(regexPattern, "?")
70+
.replace("'?'", "?")
71+
, muleExpressions);
72+
}
73+
74+
public static QueryFunctionParameter extractQueryAndParameters(AdvancedDbMessageProcessorType component) {
75+
76+
String query = component.getDynamicQuery() == null ? component.getParameterizedQuery()
77+
: component.getDynamicQuery();
78+
QueryWithParameters queryWithParameters = DBCommons.parseQueryParameter(query);
79+
String argumentTemplate = " p.getFirst(\"%s\") /* TODO: Translate #[%s] to java expression*/";
80+
String arguments = queryWithParameters
81+
.getMuleExpressions()
82+
.stream()
83+
.map(muleExpression -> String.format(argumentTemplate, muleExpression, muleExpression))
84+
.collect(Collectors.joining(",\n"));
85+
86+
if (!arguments.isEmpty()) {
87+
arguments = ",\n" + arguments + "\n";
88+
}
89+
90+
return new QueryFunctionParameter(queryWithParameters.getQuery(), arguments);
91+
}
2292
}

components/sbm-recipes-mule-to-boot/src/main/java/org/springframework/sbm/mule/actions/javadsl/translators/db/InsertTranslator.java

+13-5
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,29 @@ public DslSnippet translate(int id,
4040
MuleConfigurations muleConfigurations,
4141
String flowName,
4242
Map<Class, MuleComponentToSpringIntegrationDslTranslator> translatorsMap) {
43+
44+
QueryFunctionParameter queryAndParameters = DBCommons.extractQueryAndParameters(component);
45+
46+
String translation =
47+
" .<LinkedMultiValueMap<String, String>>handle((p, h) -> {\n" +
48+
" jdbcTemplate.update(\"" + DBCommons.escapeDoubleQuotes(queryAndParameters.getQuery()) + "\"" +
49+
queryAndParameters.getArguments() +
50+
");\n" +
51+
" return p;\n" +
52+
" })";
4353
return DslSnippet.builder()
4454
.renderedSnippet(
4555
" // TODO: payload type might not be always LinkedMultiValueMap please change it to appropriate type \n" +
4656
" // TODO: mule expression language is not converted to java, do it manually. example: #[payload] etc \n" +
47-
" .<LinkedMultiValueMap<String, String>>handle((p, h) -> {\n" +
48-
" jdbcTemplate.execute(\"" + DBCommons.escapeDoubleQuotes(component.getParameterizedQuery()) + "\");\n" +
49-
" return p;\n" +
50-
" })")
57+
translation)
5158
.requiredImports(Set.of(
5259
"org.springframework.util.LinkedMultiValueMap",
5360
"org.springframework.jdbc.core.JdbcTemplate"
5461
))
5562
.requiredDependencies(Set.of(
5663
"org.springframework.boot:spring-boot-starter-jdbc:2.5.5",
57-
"org.springframework.integration:spring-integration-jdbc:5.5.4"
64+
"org.springframework.integration:spring-integration-jdbc:5.5.4",
65+
"com.h2database:h2:2.1.214"
5866
))
5967
.beans(Set.of(new Bean("jdbcTemplate", "org.springframework.jdbc.core.JdbcTemplate")))
6068
.build();

components/sbm-recipes-mule-to-boot/src/main/java/org/springframework/sbm/mule/actions/javadsl/translators/db/SelectTranslator.java

+12-10
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@
2323
import org.springframework.stereotype.Component;
2424

2525
import javax.xml.namespace.QName;
26+
import java.util.List;
2627
import java.util.Map;
2728
import java.util.Set;
2829

29-
import static org.springframework.sbm.mule.actions.javadsl.translators.db.DBCommons.escapeDoubleQuotes;
30-
3130
@Component
3231
public class SelectTranslator implements MuleComponentToSpringIntegrationDslTranslator<SelectMessageProcessorType> {
3332

@@ -43,18 +42,21 @@ public DslSnippet translate(int id, SelectMessageProcessorType component,
4342
String flowName,
4443
Map<Class, MuleComponentToSpringIntegrationDslTranslator> translatorsMap) {
4544

46-
String query = component.getDynamicQuery() == null ? component.getParameterizedQuery()
47-
: component.getDynamicQuery();
45+
QueryFunctionParameter queryAndParameters = DBCommons.extractQueryAndParameters(component);
4846

47+
String translation = ".<LinkedMultiValueMap<String, String>>handle((p, h) ->\n" +
48+
" jdbcTemplate.queryForList(\n" +
49+
" \"" + DBCommons.escapeDoubleQuotes(queryAndParameters.getQuery()) + "\"" +
50+
queryAndParameters.getArguments() + "))";
4951
return DslSnippet.builder()
50-
.renderedSnippet(
51-
" // TODO: substitute expression language with appropriate java code \n" +
52-
" // TODO: use appropriate translation for pagination for more information visit: https://bit.ly/3xlqByv \n" +
53-
" .handle((p, h) -> jdbcTemplate.queryForList(\"" +
54-
escapeDoubleQuotes(query) + "\"))")
52+
.renderedSnippet("// TODO: substitute expression language with appropriate java code \n" +
53+
"// TODO: The datatype might not be LinkedMultiValueMap please substitute the right type for payload\n" +
54+
translation
55+
)
5556
.requiredDependencies(Set.of(
5657
"org.springframework.boot:spring-boot-starter-jdbc:2.5.5",
57-
"org.springframework.integration:spring-integration-jdbc:5.5.4"
58+
"org.springframework.integration:spring-integration-jdbc:5.5.4",
59+
"com.h2database:h2:2.1.214"
5860
))
5961
.beans(
6062
Set.of(

components/sbm-recipes-mule-to-boot/src/test/java/org/springframework/sbm/mule/actions/MuleToJavaDSLChoiceTest.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,13 @@ public void otherwiseStatementShouldDoImportsBeansAndDependencies() {
369369
" // TODO: payload type might not be always LinkedMultiValueMap please change it to appropriate type \n" +
370370
" // TODO: mule expression language is not converted to java, do it manually. example: #[payload] etc \n" +
371371
" .<LinkedMultiValueMap<String, String>>handle((p, h) -> {\n" +
372-
" jdbcTemplate.execute(\"INSERT INTO ${ORA_SCHEMA}.CHANGE_REQUEST_DETAILS (CHANGE_REQUEST_ID, CR_ATTRIBUTE_ID, SECONDARY_ATTRIBUTE, OLD_VALUE, NEW_VALUE) VALUES (#[flowVars.changeRequestId], #[payload.crAttributeId], #[payload.secondaryAttribute], #[payload.oldValue], #[payload.newValue])\");\n" +
372+
" jdbcTemplate.update(\"INSERT INTO ${ORA_SCHEMA}.CHANGE_REQUEST_DETAILS (CHANGE_REQUEST_ID, CR_ATTRIBUTE_ID, SECONDARY_ATTRIBUTE, OLD_VALUE, NEW_VALUE) VALUES (?, ?, ?, ?, ?)\",\n" +
373+
" p.getFirst(\"flowVars.changeRequestId\") /* TODO: Translate #[flowVars.changeRequestId] to java expression*/,\n" +
374+
" p.getFirst(\"payload.crAttributeId\") /* TODO: Translate #[payload.crAttributeId] to java expression*/,\n" +
375+
" p.getFirst(\"payload.secondaryAttribute\") /* TODO: Translate #[payload.secondaryAttribute] to java expression*/,\n" +
376+
" p.getFirst(\"payload.oldValue\") /* TODO: Translate #[payload.oldValue] to java expression*/,\n" +
377+
" p.getFirst(\"payload.newValue\") /* TODO: Translate #[payload.newValue] to java expression*/\n" +
378+
" );\n" +
373379
" return p;\n" +
374380
" }))\n" +
375381
" )\n" +

components/sbm-recipes-mule-to-boot/src/test/java/org/springframework/sbm/mule/actions/db/MuleToJavaDSLDBInsertTest.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ public void dbInsert() {
6565
" // TODO: payload type might not be always LinkedMultiValueMap please change it to appropriate type \n" +
6666
" // TODO: mule expression language is not converted to java, do it manually. example: #[payload] etc \n" +
6767
" .<LinkedMultiValueMap<String, String>>handle((p, h) -> {\n" +
68-
" jdbcTemplate.execute(\"INSERT INTO STUDENTS (NAME, AGE, CITY) VALUES (#[payload.name], #[payload.age], #[payload.city])\");\n" +
68+
" jdbcTemplate.update(\"INSERT INTO STUDENTS (NAME, AGE, CITY) VALUES (?, ?, ?)\",\n" +
69+
" p.getFirst(\"payload.name\") /* TODO: Translate #[payload.name] to java expression*/,\n" +
70+
" p.getFirst(\"payload.age\") /* TODO: Translate #[payload.age] to java expression*/,\n" +
71+
" p.getFirst(\"payload.city\") /* TODO: Translate #[payload.city] to java expression*/\n" +
72+
" );\n" +
6973
" return p;\n" +
7074
" })\n" +
7175
" .get();\n" +

0 commit comments

Comments
 (0)