Summary
Updated spring security to version 5.2.2-RELEASE (starting point 5.1.5-RELEASE) and the build started failing with the same code.
After updating
Actual Behavior
Build breaks
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is java.lang.IllegalStateException: Can't configure antMatchers after anyRequest
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185)
at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651)
... 21 common frames omitted
Caused by: java.lang.IllegalStateException: Can't configure antMatchers after anyRequest
Expected Behavior
Build to pass
14:39:58.995 [main] INFO o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-8080"]
14:39:59.008 [main] INFO o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
14:39:59.010 [main] INFO c.draughtmaster.core.CoreApplication - Started CoreApplication in 39.016 seconds (JVM running for 39.403)
<===========--> 87% EXECUTING [1m 11s]
Version
springBootVersion = '2.2.2.RELEASE' org.springframework.security:spring-security-config:5.2.2.RELEASE
Comment From: jzheaux
Thanks for checking on this @ManueljgnFerreira. This change was intentional to notify against improper configurations.
I'm going to close this as working as designed, but please feel free to reopen it if you have a use case where you need to call antMatchers after calling anyRequest.
Recall that the authorizeRequests stack is read like a sequence of if statements, so placing an antMatchers after an anyRequest call means that it won't take affect.
Comment From: manuel-g-ferreira
@jzheaux Thanks for the quick reply, but it seems that something not right.
I had basic authentication configure for endpoints after an anyMatcher and it was not ignored. Here goes an example of the code:
http.cors().and().csrf().disable().authorizeRequests()
// Endpoints without Authentication
.antMatchers(HttpMethod.POST,ApiConfiguration.VERSION + "/xxx/yyy").permitAll()
-> .anyRequest().authenticated()
.and()
// Default filters
.addFilter(jwtAuthenticationFilter)
.addFilter(jwtAuthorizationFilter)
.headers()
.contentSecurityPolicy(DEFAULT_SRC_SELF)
.and()
.httpStrictTransportSecurity()
.includeSubDomains(true)
.maxAgeInSeconds(HSTS_MAX_AGE_IN_SECONDS)
.preload(true);
// Basic Auth endpoints
http.cors().and().csrf().disable().authorizeRequests()
// Swagger endpoints
.antMatchers(HttpMethod.GET, "/swagger-ui.html").authenticated()
.antMatchers(HttpMethod.GET, "/v2/api-docs").authenticated()
.antMatchers(HttpMethod.GET, "/configuration/ui").authenticated()
.antMatchers(HttpMethod.GET, "/configuration/security").authenticated()
.antMatchers(HttpMethod.GET, "/webjars/**").authenticated()
.and()
.httpBasic()
.and()
.headers()
.contentSecurityPolicy(DEFAULT_SRC_SELF)
.and()
.httpStrictTransportSecurity()
.includeSubDomains(true)
.maxAgeInSeconds(HSTS_MAX_AGE_IN_SECONDS)
.preload(true);
Comment From: jzheaux
Okay, thanks for the code snippet, that gives me some perspective.
For some additional background, this check was added intentionally to error on invalid configurations. Because authorizeRequests matcher calls are called in order, no matchers configured after anyRequest take effect, creating potential security vulnerabilities.
The spot that is the problem in your code is likely the first .antMatchers call in the second block:
// Basic Auth endpoints
http.cors().and().csrf().disable().authorizeRequests()
// Swagger endpoints
.antMatchers(HttpMethod.GET, "/swagger-ui.html").authenticated() <-- here
because it was called after the anyRequests that you called a few lines earlier (in the first block).
Since it appears what you want to do is change your authentication based on endpoint, I'd recommend that you have two separate instances of WebSecurityConfigurerAdapter:
@Configuration
@Order(99)
public class SwaggerSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
http
.requestMatchers()
// Swagger endpoints
.antMatchers(HttpMethod.GET, "/swagger-ui.html")
.antMatchers(HttpMethod.GET, "/v2/api-docs")
.antMatchers(HttpMethod.GET, "/configuration/ui")
.antMatchers(HttpMethod.GET, "/configuration/security")
.antMatchers(HttpMethod.GET, "/webjars/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
// ... your remaining swagger configuration
}
}
@Configuration
// @Order(100) <-- this is the default order value
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) {
http
.authorizeRequests()
// Endpoints without Authentication
.antMatchers(HttpMethod.POST, ApiConfiguration.VERSION + "/xxx/yyy").permitAll()
.anyRequest().authenticated()
.and()
// ... your remaining default configuration
}
}
Comment From: ivanmarkov13
@jzheaux I understand the intention behind this restriction, but what if I want to setup ResourceServerConfigurer for my tests. Here is the code.
ResourceServerConfigurer in source code: `@Profile("!unsecured") @Component public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager;
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and().cors();
}
}`
and I want to create ResourceServerConfigurer for test purposes: `@TestConfiguration public class TestResourceServerConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
super.configure(resources);
resources
.stateless(false);
}
}`
Here I get the error "Caused by: java.lang.IllegalStateException: Can't configure anyRequest after itself" because ".anyRequest()).authenticated();" is called twice - once in every of the ResourceServerConfigurer instances. What is the best approach here?
Comment From: jzheaux
@ivanmarkov13, this is probably best answered via a StackOverflow question. We try and keep GitHub tickets focused on features and bugs.
If you feel like its a bug, since this relates to the separate spring-security-oauth project, would you please file a ticket in that project to get the bug fixed?