Skip to content

Commit 8be323f

Browse files
authored
SQL Injection visitor utility (#383)
Utility to help implement sql injection codemods' visit method
1 parent cf47632 commit 8be323f

File tree

3 files changed

+160
-70
lines changed

3 files changed

+160
-70
lines changed
Lines changed: 8 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
package io.codemodder.codemods;
22

33
import com.github.javaparser.ast.CompilationUnit;
4-
import com.github.javaparser.ast.expr.MethodCallExpr;
54
import io.codemodder.*;
5+
import io.codemodder.codemods.util.JavaParserSQLInjectionRemediatorStrategy;
66
import io.codemodder.codetf.DetectorRule;
7-
import io.codemodder.codetf.FixedFinding;
8-
import io.codemodder.codetf.UnfixedFinding;
97
import io.codemodder.javaparser.JavaParserChanger;
108
import io.codemodder.providers.defectdojo.DefectDojoScan;
119
import io.codemodder.providers.defectdojo.Finding;
1210
import io.codemodder.providers.defectdojo.RuleFindings;
13-
import java.util.ArrayList;
1411
import java.util.List;
1512
import java.util.Objects;
1613
import javax.inject.Inject;
@@ -52,73 +49,14 @@ public DetectorRule detectorRule() {
5249
@Override
5350
public CodemodFileScanningResult visit(
5451
final CodemodInvocationContext context, final CompilationUnit cu) {
55-
56-
List<MethodCallExpr> allMethodCalls = cu.findAll(MethodCallExpr.class);
57-
5852
List<Finding> findingsForThisPath = findings.getForPath(context.path());
59-
if (findingsForThisPath.isEmpty()) {
60-
return CodemodFileScanningResult.none();
61-
}
62-
63-
List<UnfixedFinding> unfixedFindings = new ArrayList<>();
64-
65-
List<CodemodChange> changes = new ArrayList<>();
66-
for (Finding finding : findingsForThisPath) {
67-
String id = String.valueOf(finding.getId());
68-
Integer line = finding.getLine();
69-
if (line == null) {
70-
UnfixedFinding unfixableFinding =
71-
new UnfixedFinding(
72-
id, detectorRule(), context.path().toString(), null, "No line number provided");
73-
unfixedFindings.add(unfixableFinding);
74-
continue;
75-
}
76-
77-
List<MethodCallExpr> supportedSqlMethodCallsOnThatLine =
78-
allMethodCalls.stream()
79-
.filter(methodCallExpr -> methodCallExpr.getRange().get().begin.line == line)
80-
.filter(SQLParameterizer::isSupportedJdbcMethodCall)
81-
.toList();
82-
83-
if (supportedSqlMethodCallsOnThatLine.isEmpty()) {
84-
UnfixedFinding unfixableFinding =
85-
new UnfixedFinding(
86-
id,
87-
detectorRule(),
88-
context.path().toString(),
89-
line,
90-
"No supported SQL methods found on the given line");
91-
unfixedFindings.add(unfixableFinding);
92-
continue;
93-
}
94-
95-
if (supportedSqlMethodCallsOnThatLine.size() > 1) {
96-
UnfixedFinding unfixableFinding =
97-
new UnfixedFinding(
98-
id,
99-
detectorRule(),
100-
context.path().toString(),
101-
line,
102-
"Multiple supported SQL methods found on the given line");
103-
unfixedFindings.add(unfixableFinding);
104-
continue;
105-
}
106-
107-
MethodCallExpr methodCallExpr = supportedSqlMethodCallsOnThatLine.get(0);
108-
if (SQLParameterizerWithCleanup.checkAndFix(methodCallExpr)) {
109-
changes.add(CodemodChange.from(line, new FixedFinding(id, detectorRule())));
110-
} else {
111-
UnfixedFinding unfixableFinding =
112-
new UnfixedFinding(
113-
id,
114-
detectorRule(),
115-
context.path().toString(),
116-
line,
117-
"State changing effects possible or unrecognized code shape");
118-
unfixedFindings.add(unfixableFinding);
119-
}
120-
}
12153

122-
return CodemodFileScanningResult.from(changes, unfixedFindings);
54+
return JavaParserSQLInjectionRemediatorStrategy.DEFAULT.visit(
55+
context,
56+
cu,
57+
findingsForThisPath,
58+
detectorRule(),
59+
finding -> String.valueOf(finding.getId()),
60+
Finding::getLine);
12361
}
12462
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package io.codemodder.codemods.util;
2+
3+
import com.github.javaparser.ast.CompilationUnit;
4+
import com.github.javaparser.ast.expr.MethodCallExpr;
5+
import io.codemodder.CodemodChange;
6+
import io.codemodder.CodemodFileScanningResult;
7+
import io.codemodder.CodemodInvocationContext;
8+
import io.codemodder.codemods.SQLParameterizer;
9+
import io.codemodder.codemods.SQLParameterizerWithCleanup;
10+
import io.codemodder.codetf.DetectorRule;
11+
import io.codemodder.codetf.FixedFinding;
12+
import io.codemodder.codetf.UnfixedFinding;
13+
import java.util.ArrayList;
14+
import java.util.Collection;
15+
import java.util.List;
16+
import java.util.function.Function;
17+
18+
/**
19+
* Default implementation of the JavaParserSQLInjectionRemediatorStrategy interface. This class
20+
* provides the logic to visit a CompilationUnit and process findings for potential SQL injections.
21+
*/
22+
final class DefaultJavaParserSQLInjectionRemediatorStrategy
23+
implements JavaParserSQLInjectionRemediatorStrategy {
24+
25+
/**
26+
* Visits the provided CompilationUnit and processes findings for potential SQL injections.
27+
*
28+
* @param context the context of the codemod invocation
29+
* @param cu the compilation unit to be scanned
30+
* @param pathFindings a collection of findings to be processed
31+
* @param detectorRule the rule used to detect potential issues
32+
* @param findingIdExtractor a function to extract the ID from a finding
33+
* @param findingLineExtractor a function to extract the line number from a finding
34+
* @param <T> the type of the findings
35+
* @return a result object containing the changes and unfixed findings
36+
*/
37+
public <T> CodemodFileScanningResult visit(
38+
final CodemodInvocationContext context,
39+
final CompilationUnit cu,
40+
final Collection<T> pathFindings,
41+
final DetectorRule detectorRule,
42+
final Function<T, String> findingIdExtractor,
43+
final Function<T, Integer> findingLineExtractor) {
44+
45+
final List<MethodCallExpr> allMethodCalls = cu.findAll(MethodCallExpr.class);
46+
47+
if (pathFindings.isEmpty()) {
48+
return CodemodFileScanningResult.none();
49+
}
50+
51+
final List<UnfixedFinding> unfixedFindings = new ArrayList<>();
52+
final List<CodemodChange> changes = new ArrayList<>();
53+
54+
for (T finding : pathFindings) {
55+
final String id = findingIdExtractor.apply(finding);
56+
final Integer line = findingLineExtractor.apply(finding);
57+
58+
if (line == null) {
59+
final UnfixedFinding unfixableFinding =
60+
new UnfixedFinding(
61+
id, detectorRule, context.path().toString(), null, "No line number provided");
62+
unfixedFindings.add(unfixableFinding);
63+
continue;
64+
}
65+
66+
final List<MethodCallExpr> supportedSqlMethodCallsOnThatLine =
67+
allMethodCalls.stream()
68+
.filter(methodCallExpr -> methodCallExpr.getRange().get().begin.line == line)
69+
.filter(SQLParameterizer::isSupportedJdbcMethodCall)
70+
.toList();
71+
72+
if (supportedSqlMethodCallsOnThatLine.isEmpty()) {
73+
final UnfixedFinding unfixableFinding =
74+
new UnfixedFinding(
75+
id,
76+
detectorRule,
77+
context.path().toString(),
78+
line,
79+
"No supported SQL methods found on the given line");
80+
unfixedFindings.add(unfixableFinding);
81+
continue;
82+
}
83+
84+
if (supportedSqlMethodCallsOnThatLine.size() > 1) {
85+
final UnfixedFinding unfixableFinding =
86+
new UnfixedFinding(
87+
id,
88+
detectorRule,
89+
context.path().toString(),
90+
line,
91+
"Multiple supported SQL methods found on the given line");
92+
unfixedFindings.add(unfixableFinding);
93+
continue;
94+
}
95+
96+
final MethodCallExpr methodCallExpr = supportedSqlMethodCallsOnThatLine.get(0);
97+
if (SQLParameterizerWithCleanup.checkAndFix(methodCallExpr)) {
98+
changes.add(CodemodChange.from(line, new FixedFinding(id, detectorRule)));
99+
} else {
100+
final UnfixedFinding unfixableFinding =
101+
new UnfixedFinding(
102+
id,
103+
detectorRule,
104+
context.path().toString(),
105+
line,
106+
"State changing effects possible or unrecognized code shape");
107+
unfixedFindings.add(unfixableFinding);
108+
}
109+
}
110+
111+
return CodemodFileScanningResult.from(changes, unfixedFindings);
112+
}
113+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.codemodder.codemods.util;
2+
3+
import com.github.javaparser.ast.CompilationUnit;
4+
import io.codemodder.CodemodFileScanningResult;
5+
import io.codemodder.CodemodInvocationContext;
6+
import io.codemodder.codetf.DetectorRule;
7+
import java.util.Collection;
8+
import java.util.function.Function;
9+
10+
/**
11+
* Strategy interface for remediating SQL injection vulnerabilities using JavaParser.
12+
* Implementations of this interface define the method to visit a CompilationUnit and process
13+
* findings for potential SQL injections.
14+
*/
15+
public interface JavaParserSQLInjectionRemediatorStrategy {
16+
17+
/**
18+
* Visits the provided CompilationUnit and processes findings for potential SQL injections.
19+
*
20+
* @param context the context of the codemod invocation
21+
* @param cu the compilation unit to be scanned
22+
* @param pathFindings a collection of findings to be processed
23+
* @param detectorRule the rule used to detect potential issues
24+
* @param findingIdExtractor a function to extract the ID from a finding
25+
* @param findingLineExtractor a function to extract the line number from a finding
26+
* @param <T> the type of the findings
27+
* @return a result object containing the changes and unfixed findings
28+
*/
29+
<T> CodemodFileScanningResult visit(
30+
final CodemodInvocationContext context,
31+
final CompilationUnit cu,
32+
final Collection<T> pathFindings,
33+
final DetectorRule detectorRule,
34+
final Function<T, String> findingIdExtractor,
35+
final Function<T, Integer> findingLineExtractor);
36+
37+
JavaParserSQLInjectionRemediatorStrategy DEFAULT =
38+
new DefaultJavaParserSQLInjectionRemediatorStrategy();
39+
}

0 commit comments

Comments
 (0)