diff --git a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerConfiguration.java b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerConfiguration.java index b606047af..df48ff7a3 100644 --- a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerConfiguration.java +++ b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/config/annotation/web/configuration/AuthorizationServerConfiguration.java @@ -20,8 +20,12 @@ import javax.annotation.PostConstruct; +import org.springframework.aop.TargetSource; +import org.springframework.aop.framework.Advised; +import org.springframework.aop.target.AbstractBeanFactoryBasedTargetSource; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; @@ -57,6 +61,7 @@ import org.springframework.security.oauth2.provider.token.ConsumerTokenServices; import org.springframework.security.oauth2.provider.token.InMemoryTokenStore; import org.springframework.security.oauth2.provider.token.TokenStore; +import org.springframework.stereotype.Component; /** * @author Rob Winch @@ -283,4 +288,38 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) t } + /** + * If the user inadvertently autowires one of the lazy beans and then injects it back into the configurer they are + * going to create a proxy with a cyclic target. This processor ensures that at least there won't be a + * StackOverflowError (although the IllegalStateException comes too late to fail fast on startup). See + * https://jira.spring.io/browse/SPR-11684 + * + * @author Dave Syer + * + */ + @Component + protected static class CyclicProxyDetector implements BeanPostProcessor { + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { + if (bean instanceof Advised) { + Advised advised = (Advised) bean; + TargetSource targetSource = advised.getTargetSource(); + if (targetSource != null && targetSource instanceof AbstractBeanFactoryBasedTargetSource) { + AbstractBeanFactoryBasedTargetSource source = (AbstractBeanFactoryBasedTargetSource) targetSource; + if (beanName.equals(source.getTargetBeanName())) { + throw new IllegalStateException("Cyclic proxy references itself as target: " + beanName); + } + } + } + return bean; + } + + } + } diff --git a/spring-security-oauth2/src/test/java/org/springframework/security/oauth2/config/annotation/AuthorizationServerConfigurationTests.java b/spring-security-oauth2/src/test/java/org/springframework/security/oauth2/config/annotation/AuthorizationServerConfigurationTests.java index a5cede0a4..0b6f2c560 100644 --- a/spring-security-oauth2/src/test/java/org/springframework/security/oauth2/config/annotation/AuthorizationServerConfigurationTests.java +++ b/spring-security-oauth2/src/test/java/org/springframework/security/oauth2/config/annotation/AuthorizationServerConfigurationTests.java @@ -77,6 +77,7 @@ public class AuthorizationServerConfigurationTests { public static List parameters() { return Arrays.asList( // @formatter:off new Object[] { BeanCreationException.class, new Class[] { AuthorizationServerUnconfigured.class } }, + new Object[] { BeanCreationException.class, new Class[] { AuthorizationServerCycle.class } }, new Object[] { null, new Class[] { AuthorizationServerVanilla.class } }, new Object[] { null, new Class[] { AuthorizationServerDisableApproval.class } }, new Object[] { null, new Class[] { AuthorizationServerExtras.class } }, @@ -155,6 +156,34 @@ public void run() { } } + @Configuration + @EnableWebMvcSecurity + @EnableAuthorizationServer + protected static class AuthorizationServerCycle extends AuthorizationServerConfigurerAdapter implements Runnable { + @Autowired + private AuthorizationServerTokenServices tokenServices; + + @Override + public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { + oauthServer.tokenServices(tokenServices); // Bang! (Cyclic proxy) + } + + @Override + public void configure(ClientDetailsServiceConfigurer clients) throws Exception { + // @formatter:off + clients.inMemory() + .withClient("my-trusted-client") + .authorizedGrantTypes("password"); + // @formatter:on + } + + @Override + public void run() { + tokenServices.createAccessToken(null); + } + + } + @Configuration @EnableWebMvcSecurity @EnableAuthorizationServer @@ -169,10 +198,7 @@ public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // @formatter:off clients.inMemory() .withClient("my-trusted-client") - .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") - .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") - .scopes("read", "write", "trust") - .accessTokenValiditySeconds(60); + .authorizedGrantTypes("password"); // @formatter:on } @@ -250,10 +276,7 @@ public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // @formatter:off clients.jdbc(dataSource()) .withClient("my-trusted-client") - .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") - .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") - .scopes("read", "write", "trust") - .accessTokenValiditySeconds(60); + .authorizedGrantTypes("password"); // @formatter:on } @@ -304,10 +327,7 @@ public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // @formatter:off clients.inMemory() .withClient("my-trusted-client") - .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") - .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") - .scopes("read", "write", "trust") - .accessTokenValiditySeconds(60); + .authorizedGrantTypes("password"); // @formatter:on } @@ -333,10 +353,7 @@ public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // @formatter:off clients.inMemory() .withClient("my-trusted-client") - .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") - .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") - .scopes("read", "write", "trust") - .accessTokenValiditySeconds(60); + .authorizedGrantTypes("password"); // @formatter:on }