This should work:
@SpringBootApplication
@EnableResourceServer
public class SampleSecureOAuth2ResourceApplication extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/**");
}
public static void main(String[] args) {
SpringApplication.run(SampleSecureOAuth2ResourceApplication.class, args);
}
}
but with application.properties:
security.oauth2.resource.id=service
security.oauth2.resource.tokenInfoUri=http://localhost:8080/oauth/check_token
you get this:
Caused by: java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer@603fb93a to already built object
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:194)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.apply(AbstractConfiguredSecurityBuilder.java:129)
at org.springframework.security.config.annotation.web.builders.HttpSecurity.getOrApply(HttpSecurity.java:1187)
at org.springframework.security.config.annotation.web.builders.HttpSecurity.authorizeRequests(HttpSecurity.java:592)
at org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer.configure(ResourceServerSecurityConfigurer.java:199)
at org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer.configure(ResourceServerSecurityConfigurer.java:1)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.configure(AbstractConfiguredSecurityBuilder.java:378)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:328)
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:41)
at org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild(WebSecurity.java:289)
at org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild(WebSecurity.java:74)
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.doBuild(AbstractConfiguredSecurityBuilder.java:332)
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:41)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:105)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f51585e6.CGLIB$springSecurityFilterChain$3(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f51585e6$$FastClassBySpringCGLIB$$7cac89cc.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$f51585e6.springSecurityFilterChain(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 39 more
The application.psoperties are missing client credentials, so it should fail at some point, but not with this confusing error.
Changing the application.properties slightly you get a different problem:
security.oauth2.client.client-id=foo
security.oauth2.client.client-secret=bar
security.oauth2.resource.id=service
security.oauth2.resource.tokenInfoUri=http://localhost:8080/oauth/check_token
or
security.oauth2.resource.id=service
security.oauth2.resource.userInfoUri=http://localhost:8080/user
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'viewControllerHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: The resources may not be accessed if they are not currently started
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 18 more
Caused by: java.lang.IllegalStateException: The resources may not be accessed if they are not currently started
at org.apache.catalina.webresources.StandardRoot.validate(StandardRoot.java:245)
at org.apache.catalina.webresources.StandardRoot.getResource(StandardRoot.java:212)
at org.apache.catalina.webresources.StandardRoot.getResource(StandardRoot.java:206)
Update: it's the same problem in both cases. In the second example the failure (same one as first example) has happened in a different thread and the servlet container has failed to start so the exception bubbles up differently.
The problem appears in Spring Security OAuth's ResourceServerSecurityConfigurer which is trying to add an additional SecurityConfigurer in the configure phase. This is not permitted because the contract is:
SecurityConfigurer.init methods are invokedSecurityConfigurer.configure methods are invokedHowever, in this instance http.authorizeRequests() is trying to add another SecurityConfigurer in the ResourceServerSecurityConfigurer.configure method. This breaks the contract since the newly added SecurityConfigurer needs its init method invoked, but we have already invoked at least one configure method.
Likely the reason this has gone unnoticed is if someone has already configured the 'http.authorizeRequests()then the error is not present (since theSecurityConfigurer` is not being added but modified). For example, the following fixes the error:
@SpringBootApplication
@EnableResourceServer
public class SampleSecureOAuth2ResourceApplication extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
// Add below
.authorizeRequests()
.anyRequest().authenticated();
}
public static void main(String[] args) {
SpringApplication.run(SampleSecureOAuth2ResourceApplication.class, args);
}
}
Ultimately, Spring Security OAuth should be using the init method to invoke http.authorizeRequests is going to be added.
So the sample is fixed (spring-boot-sample-secure-oauth2-resource) by explicitly authorizing all requests as per the snippet Rob gave. I don't pretend to understand why that worked yet, but it seems reasonable that most people will want to do that. And the problem is in spring-security-oauth2 anyway, so I'll mark this as "On Hold" in case anyone wants to track the Boot side of it.
Closing since Spring Boot 2.0 provides OAuth support via Spring Security
Most helpful comment
The problem appears in Spring Security OAuth's
ResourceServerSecurityConfigurerwhich is trying to add an additionalSecurityConfigurerin the configure phase. This is not permitted because the contract is:SecurityConfigurer.initmethods are invokedSecurityConfigurer.configuremethods are invokedHowever, in this instance
http.authorizeRequests()is trying to add anotherSecurityConfigurerin theResourceServerSecurityConfigurer.configuremethod. This breaks the contract since the newly addedSecurityConfigurerneeds itsinitmethod invoked, but we have already invoked at least oneconfiguremethod.Likely the reason this has gone unnoticed is if someone has already configured the 'http.authorizeRequests()
then the error is not present (since theSecurityConfigurer` is not being added but modified). For example, the following fixes the error:Ultimately, Spring Security OAuth should be using the init method to invoke
http.authorizeRequestsis going to be added.