Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle special case of xssProtection #625

Merged
merged 11 commits into from
Nov 15, 2024
2 changes: 2 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,9 @@ dependencies {
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework:spring-webmvc:5.3.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-core:5.5.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-config:5.5.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-config:5.8.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-web:5.5.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-web:5.8.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-ldap:5.5.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-oauth2-client:5.5.+")
"testWithSpringBoot_2_4RuntimeOnly"("org.springframework.security:spring-security-oauth2-resource-server:5.5.+")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,9 @@ public class ConvertToSecurityDslVisitor<P> extends JavaIsoVisitor<P> {

public static final String FQN_CUSTOMIZER = "org.springframework.security.config.Customizer";

private static final JavaType.FullyQualified CUSTOMIZER_SHALLOW_TYPE =
(JavaType.ShallowClass) JavaType.buildType(FQN_CUSTOMIZER);
private static final MethodMatcher XSS_PROTECTION_ENABLED = new MethodMatcher("org.springframework.security.config.annotation.web.configurers.HeadersConfigurer.XXssConfig xssProtectionEnabled(boolean)");

private static final JavaType.FullyQualified CUSTOMIZER_SHALLOW_TYPE = JavaType.ShallowClass.build(FQN_CUSTOMIZER);

private final String securityFqn;

Expand All @@ -65,12 +66,12 @@ public ConvertToSecurityDslVisitor(String securityFqn, Collection<String> conver
}

public ConvertToSecurityDslVisitor(String securityFqn, Collection<String> convertableMethods,
Map<String, String> argReplacements) {
Map<String, String> argReplacements) {
this(securityFqn, convertableMethods, argReplacements, new HashMap<>());
}

public ConvertToSecurityDslVisitor(String securityFqn, Collection<String> convertableMethods,
Map<String, String> argReplacements, Map<String, String> methodRenames) {
Map<String, String> argReplacements, Map<String, String> methodRenames) {
this.securityFqn = securityFqn;
this.convertableMethods = convertableMethods;
this.argReplacements = argReplacements;
Expand Down Expand Up @@ -127,6 +128,15 @@ private static String generateParamNameFromMethodName(String n) {
private J.Lambda createLambdaParam(String paramName, JavaType paramType, List<J.MethodInvocation> chain) {
J.Identifier param = createIdentifier(paramName, paramType);
J.MethodInvocation body = unfoldMethodInvocationChain(createIdentifier(paramName, paramType), chain);
// Special case for xssProtectionEnabled method
if (XSS_PROTECTION_ENABLED.matches(body)) {
if (J.Literal.isLiteralValue(body.getArguments().get(0), false)) {
body = body.withName(body.getName().withSimpleName("disable")).withArguments(null);
} else {
// Enabled by default; but returning `null` will cause issues, so we use `and()` as a placeholder
body = body.withName(body.getName().withSimpleName("and")).withArguments(null);
timtebeek marked this conversation as resolved.
Show resolved Hide resolved
}
}
return new J.Lambda(Tree.randomId(), Space.EMPTY, Markers.EMPTY,
new J.Lambda.Parameters(Tree.randomId(), Space.EMPTY, Markers.EMPTY, false, Collections.singletonList(new JRightPadded<>(param, Space.EMPTY, Markers.EMPTY))),
Space.build(" ", Collections.emptyList()),
Expand Down Expand Up @@ -161,17 +171,17 @@ private boolean isApplicableMethod(J.MethodInvocation m) {
if (type != null) {
JavaType.FullyQualified declaringType = type.getDeclaringType();
return securityFqn.equals(declaringType.getFullyQualifiedName()) &&
(type.getParameterTypes().isEmpty() || hasHandleableArg(m)) &&
convertableMethods.contains(m.getSimpleName());
(type.getParameterTypes().isEmpty() || hasHandleableArg(m)) &&
convertableMethods.contains(m.getSimpleName());
}
return false;
}

private boolean hasHandleableArg(J.MethodInvocation m) {
return argReplacements.containsKey(m.getSimpleName()) &&
m.getMethodType() != null &&
m.getMethodType().getParameterTypes().size() == 1 &&
!TypeUtils.isAssignableTo(FQN_CUSTOMIZER, m.getMethodType().getParameterTypes().get(0));
m.getMethodType() != null &&
m.getMethodType().getParameterTypes().size() == 1 &&
!TypeUtils.isAssignableTo(FQN_CUSTOMIZER, m.getMethodType().getParameterTypes().get(0));
}

private Optional<JavaType.Method> createDesiredReplacement(J.MethodInvocation m) {
Expand Down Expand Up @@ -268,8 +278,8 @@ private List<J.MethodInvocation> computeAndMarkChain() {

private boolean isAndMethod(J.MethodInvocation method) {
return "and".equals(method.getSimpleName()) &&
(method.getArguments().isEmpty() || method.getArguments().get(0) instanceof J.Empty) &&
TypeUtils.isAssignableTo(securityFqn, method.getType());
(method.getArguments().isEmpty() || method.getArguments().get(0) instanceof J.Empty) &&
TypeUtils.isAssignableTo(securityFqn, method.getType());
}

private boolean isDisableMethod(J.MethodInvocation method) {
Expand Down
Loading