diff --git a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll index 658983f2437b..c1ef873b1fa7 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-016/SpringBootActuators.qll @@ -22,8 +22,7 @@ class TypeAuthorizedUrl extends Class { } /** - * The class - * `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. + * The class `org.springframework.security.config.annotation.web.AbstractRequestMatcherRegistry`. */ class TypeAbstractRequestMatcherRegistry extends Class { TypeAbstractRequestMatcherRegistry() { @@ -34,38 +33,44 @@ class TypeAbstractRequestMatcherRegistry extends Class { } /** - * The class - * `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest.EndpointRequestMatcher`. + * The class `org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest`. */ -class TypeEndpointRequestMatcher extends Class { - TypeEndpointRequestMatcher() { +class TypeEndpointRequest extends Class { + TypeEndpointRequest() { this .hasQualifiedName("org.springframework.boot.actuate.autoconfigure.security.servlet", - "EndpointRequest$EndpointRequestMatcher") + "EndpointRequest") + } +} + +/** A call to `EndpointRequest.toAnyEndpoint` method. */ +class ToAnyEndpointCall extends MethodAccess { + ToAnyEndpointCall() { + getMethod().hasName("toAnyEndpoint") and + getMethod().getDeclaringType() instanceof TypeEndpointRequest } } /** - * A call to `HttpSecurity.requestMatcher` method with argument of type - * `EndpointRequestMatcher`. + * A call to `HttpSecurity.requestMatcher` method with argument `RequestMatcher.toAnyEndpoint()`. */ class RequestMatcherCall extends MethodAccess { RequestMatcherCall() { getMethod().hasName("requestMatcher") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).getType() instanceof TypeEndpointRequestMatcher + getArgument(0) instanceof ToAnyEndpointCall } } /** - * A call to `HttpSecurity.requestMatchers` method with lambda argument resolving to - * `EndpointRequestMatcher` type. + * A call to `HttpSecurity.requestMatchers` method with lambda argument + * `RequestMatcher.toAnyEndpoint()`. */ class RequestMatchersCall extends MethodAccess { RequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeHttpSecurity and - getArgument(0).(LambdaExpr).getExprBody().getType() instanceof TypeEndpointRequestMatcher + getArgument(0).(LambdaExpr).getExprBody() instanceof ToAnyEndpointCall } } @@ -92,9 +97,6 @@ class PermitAllCall extends MethodAccess { or // .requestMatchers(matcher -> EndpointRequest).authorizeRequests([...]).[...] authorizeRequestsCall.getQualifier() instanceof RequestMatchersCall - or - // http.authorizeRequests([...]).[...] - authorizeRequestsCall.getQualifier() instanceof VarAccess | // [...].authorizeRequests(r -> r.anyRequest().permitAll()) or // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) @@ -117,6 +119,22 @@ class PermitAllCall extends MethodAccess { this.getQualifier() = anyRequestCall ) ) + or + exists(AuthorizeRequestsCall authorizeRequestsCall | + // http.authorizeRequests([...]).[...] + authorizeRequestsCall.getQualifier() instanceof VarAccess + | + // [...].authorizeRequests(r -> r.requestMatchers(EndpointRequest).permitAll()) + authorizeRequestsCall.getArgument(0).(LambdaExpr).getExprBody() = this and + this.getQualifier() instanceof RegistryRequestMatchersCall + or + // [...].authorizeRequests().requestMatchers(EndpointRequest).permitAll() or + authorizeRequestsCall.getNumArgument() = 0 and + exists(RegistryRequestMatchersCall registryRequestMatchersCall | + registryRequestMatchersCall.getQualifier() = authorizeRequestsCall and + this.getQualifier() = registryRequestMatchersCall + ) + ) } } @@ -129,13 +147,13 @@ class AnyRequestCall extends MethodAccess { } /** - * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument of type - * `EndpointRequestMatcher`. + * A call to `AbstractRequestMatcherRegistry.requestMatchers` method with an argument + * `RequestMatcher.toAnyEndpoint()`. */ class RegistryRequestMatchersCall extends MethodAccess { RegistryRequestMatchersCall() { getMethod().hasName("requestMatchers") and getMethod().getDeclaringType() instanceof TypeAbstractRequestMatcherRegistry and - getAnArgument().getType() instanceof TypeEndpointRequestMatcher + getAnArgument() instanceof ToAnyEndpointCall } } diff --git a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java index b554a7bac7e1..da59919fbe6c 100644 --- a/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java +++ b/java/ql/test/experimental/query-tests/security/CWE-016/SpringBootActuators.java @@ -37,4 +37,68 @@ protected void configureOk1(HttpSecurity http) throws Exception { protected void configureOk2(HttpSecurity http) throws Exception { http.requestMatchers().requestMatchers(EndpointRequest.toAnyEndpoint()); } + + protected void configureOk3(HttpSecurity http) throws Exception { + http.authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOk4(HttpSecurity http) throws Exception { + http.authorizeRequests(authz -> authz.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests(requests -> requests.anyRequest().permitAll()); + } + + protected void configureOkSafeEndpoints2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health")).authorizeRequests().requestMatchers(EndpointRequest.to("health")).permitAll(); + } + + protected void configureOkSafeEndpoints3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkSafeEndpoints5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.to("health", "info")).permitAll(); + } + + protected void configureOkSafeEndpoints6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.to("health", "info")).permitAll()); + } + + protected void configureOkSafeEndpoints7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.to("health", "info")).authorizeRequests().anyRequest().permitAll(); + } + + protected void configureOkNoPermitAll1(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests(requests -> requests.anyRequest()); + } + + protected void configureOkNoPermitAll2(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll3(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll4(HttpSecurity http) throws Exception { + http.requestMatcher(EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } + + protected void configureOkNoPermitAll5(HttpSecurity http) throws Exception { + http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()); + } + + protected void configureOkNoPermitAll6(HttpSecurity http) throws Exception { + http.authorizeRequests(requests -> requests.requestMatchers(EndpointRequest.toAnyEndpoint())); + } + + protected void configureOkNoPermitAll7(HttpSecurity http) throws Exception { + http.requestMatchers(matcher -> EndpointRequest.toAnyEndpoint()).authorizeRequests().anyRequest(); + } } diff --git a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java index 5b94a086e8f4..e7dd0fd7673b 100644 --- a/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java +++ b/java/ql/test/experimental/stubs/springframework-5.2.3/org/springframework/boot/actuate/autoconfigure/security/servlet/EndpointRequest.java @@ -7,6 +7,10 @@ public final class EndpointRequest { public static EndpointRequestMatcher toAnyEndpoint() { return null; } + + public static EndpointRequestMatcher to(String... endpoints) { + return null; + } public static final class EndpointRequestMatcher extends AbstractRequestMatcher {}