Skip to content

Commit

Permalink
New Sonar JNDI Injection Codemod (#453)
Browse files Browse the repository at this point in the history
\close #work
  • Loading branch information
andrecsilva authored Oct 2, 2024
1 parent 6fc81f2 commit 93d1c90
Show file tree
Hide file tree
Showing 12 changed files with 1,858 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public static List<Class<? extends CodeChanger>> asList() {
SemgrepOverlyPermissiveFilePermissionsCodemod.class,
SimplifyRestControllerAnnotationsCodemod.class,
SubstituteReplaceAllCodemod.class,
SonarJNDIInjectionCodemod.class,
SonarRemoveUnthrowableExceptionCodemod.class,
SonarXXECodemod.class,
SonarSQLInjectionCodemod.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package io.codemodder.codemods;

import com.github.javaparser.ast.CompilationUnit;
import io.codemodder.*;
import io.codemodder.codetf.DetectorRule;
import io.codemodder.providers.sonar.ProvidedSonarScan;
import io.codemodder.providers.sonar.RuleIssue;
import io.codemodder.providers.sonar.SonarRemediatingJavaParserChanger;
import io.codemodder.remediation.GenericRemediationMetadata;
import io.codemodder.remediation.jndiinjection.JNDIInjectionRemediator;
import io.codemodder.sonar.model.Issue;
import io.codemodder.sonar.model.SonarFinding;
import java.util.List;
import java.util.Objects;
import javax.inject.Inject;

/** This codemod knows how to fix JNDI vulnerabilities found by sonar. */
@Codemod(
id = "sonar:java/jndi-injection-s2078",
reviewGuidance = ReviewGuidance.MERGE_AFTER_CURSORY_REVIEW,
executionPriority = CodemodExecutionPriority.HIGH,
importance = Importance.HIGH)
public final class SonarJNDIInjectionCodemod extends SonarRemediatingJavaParserChanger {

private final JNDIInjectionRemediator remediator;
private final RuleIssue issues;

@Inject
public SonarJNDIInjectionCodemod(
@ProvidedSonarScan(ruleId = "javasecurity:S2078") final RuleIssue issues) {
super(GenericRemediationMetadata.JNDI.reporter(), issues);
this.issues = Objects.requireNonNull(issues);
this.remediator = JNDIInjectionRemediator.DEFAULT;
}

@Override
public DetectorRule detectorRule() {
return new DetectorRule(
"javasecurity:S2078",
"LDAP queries should not be vulnerable to injection attacks",
"https://rules.sonarsource.com/java/RSPEC-2078/");
}

@Override
public CodemodFileScanningResult visit(
final CodemodInvocationContext context, final CompilationUnit cu) {
List<Issue> issuesForFile = issues.getResultsByPath(context.path());
return remediator.remediateAll(
cu,
context.path().toString(),
detectorRule(),
issuesForFile,
SonarFinding::getKey,
i -> i.getTextRange() != null ? i.getTextRange().getStartLine() : i.getLine(),
i -> i.getTextRange() != null ? i.getTextRange().getEndLine() : null,
i -> i.getTextRange() != null ? i.getTextRange().getStartOffset() : null);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.codemodder.codemods;

import io.codemodder.DependencyGAV;
import io.codemodder.testutils.CodemodTestMixin;
import io.codemodder.testutils.Metadata;
import org.junit.jupiter.api.Nested;

final class SonarJNDIInjectionCodemodTest {

@Nested
@Metadata(
codemodType = SonarJNDIInjectionCodemod.class,
testResourceDir = "sonar-jndi-injection-s2078/normal",
renameTestFile = "src/main/java/com/mycompany/app/jndi/JNDIVuln.java",
expectingFixesAtLines = {15},
dependencies = DependencyGAV.JAVA_SECURITY_TOOLKIT_GAV)
final class ExpectedSinkInLocationTest implements CodemodTestMixin {}

@Nested
@Metadata(
codemodType = SonarJNDIInjectionCodemod.class,
testResourceDir = "sonar-jndi-injection-s2078/misleading-location",
renameTestFile = "src/main/java/com/mycompany/app/jndi/FindResource.java",
expectingFixesAtLines = {18},
dependencies = DependencyGAV.JAVA_SECURITY_TOOLKIT_GAV)
final class MisleadingSinkInLocationTest implements CodemodTestMixin {}

/** Just confirms that when there are no changes for a given file, nothing errors. */
@Nested
@Metadata(
codemodType = SonarJNDIInjectionCodemod.class,
testResourceDir = "sonar-jndi-injection-s2078/unrelated-file",
renameTestFile = "src/main/java/com/acme/jndi/UnrelatedFile.java",
dependencies = {})
final class UnrelatedFileTest implements CodemodTestMixin {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.acme.jndi;

import io.github.pixee.security.JNDI;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/** JNDI resource finder. */
public final class FindResource {

private FindResource() { }

public static String findResource(final String resource) throws NamingException {
return lookupResource(resource);
}

private static String lookupResource(final String resource) throws NamingException {
Context ctx = new InitialContext();
return String.valueOf(JNDI.limitedContext(ctx).lookup(resource));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.acme.jndi;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;

/** JNDI resource finder. */
public final class FindResource {

private FindResource() { }

public static String findResource(final String resource) throws NamingException {
return lookupResource(resource);
}

private static String lookupResource(final String resource) throws NamingException {
Context ctx = new InitialContext();
return String.valueOf(ctx.lookup(resource));
}
}
Loading

0 comments on commit 93d1c90

Please sign in to comment.