diff --git a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java index 6e1c7a0e67..f02a0686c0 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthorizationFilterParser.java @@ -49,6 +49,8 @@ class AuthorizationFilterParser implements BeanDefinitionParser { private static final String ATT_USE_EXPRESSIONS = "use-expressions"; + private static final String ATT_ACCESS_DECISION_MANAGER_REF = "access-decision-manager-ref"; + private static final String ATT_HTTP_METHOD = "method"; private static final String ATT_PATTERN = "pattern"; @@ -59,6 +61,12 @@ class AuthorizationFilterParser implements BeanDefinitionParser { private String authorizationManagerRef; + private final BeanMetadataElement securityContextHolderStrategy; + + AuthorizationFilterParser(BeanMetadataElement securityContextHolderStrategy) { + this.securityContextHolderStrategy = securityContextHolderStrategy; + } + @Override public BeanDefinition parse(Element element, ParserContext parserContext) { if (!isUseExpressions(element)) { @@ -66,10 +74,16 @@ class AuthorizationFilterParser implements BeanDefinitionParser { element); return null; } + if (StringUtils.hasText(element.getAttribute(ATT_ACCESS_DECISION_MANAGER_REF))) { + parserContext.getReaderContext().error( + "AuthorizationManager cannot be used in conjunction with `access-decision-manager-ref`", element); + return null; + } this.authorizationManagerRef = createAuthorizationManager(element, parserContext); BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.rootBeanDefinition(AuthorizationFilter.class); filterBuilder.getRawBeanDefinition().setSource(parserContext.extractSource(element)); BeanDefinition filter = filterBuilder.addConstructorArgReference(this.authorizationManagerRef) + .addPropertyValue("securityContextHolderStrategy", this.securityContextHolderStrategy) .getBeanDefinition(); String id = element.getAttribute(AbstractBeanDefinitionParser.ID_ATTRIBUTE); if (StringUtils.hasText(id)) { @@ -171,7 +185,9 @@ class AuthorizationFilterParser implements BeanDefinitionParser { @Override public DefaultHttpSecurityExpressionHandler getBean() { - this.handler.setDefaultRolePrefix(this.rolePrefix); + if (this.rolePrefix != null) { + this.handler.setDefaultRolePrefix(this.rolePrefix); + } return this.handler; } diff --git a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java index 1f642ea1ea..db27d23cc1 100644 --- a/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/HttpConfigurationBuilder.java @@ -729,7 +729,7 @@ class HttpConfigurationBuilder { } private void createAuthorizationFilter() { - AuthorizationFilterParser authorizationFilterParser = new AuthorizationFilterParser(); + AuthorizationFilterParser authorizationFilterParser = new AuthorizationFilterParser(this.holderStrategyRef); BeanDefinition fsiBean = authorizationFilterParser.parse(this.httpElt, this.pc); String fsiId = this.pc.getReaderContext().generateBeanName(fsiBean); this.pc.registerBeanComponent(new BeanComponentDefinition(fsiBean, fsiId)); diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java index 1c35b669a2..37c6c94acd 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/oauth2/server/resource/OAuth2ResourceServerConfigurerTests.java @@ -1356,11 +1356,10 @@ public class OAuth2ResourceServerConfigurerTests { } @Test - public void getWhenCustomAuthenticationConverterThenConverts() throws Exception { + public void getWhenCustomAuthenticationConverterThenUsed() throws Exception { this.spring.register(RestOperationsConfig.class, OpaqueTokenAuthenticationConverterConfig.class, BasicController.class).autowire(); - OpaqueTokenAuthenticationConverter authenticationConverter = this.spring.getContext() - .getBean(OpaqueTokenAuthenticationConverter.class); + OpaqueTokenAuthenticationConverter authenticationConverter = bean(OpaqueTokenAuthenticationConverter.class); given(authenticationConverter.convert(anyString(), any(OAuth2AuthenticatedPrincipal.class))) .willReturn(new TestingAuthenticationToken("jdoe", null, Collections.emptyList())); mockRestOperations(json("Active")); @@ -1369,6 +1368,7 @@ public class OAuth2ResourceServerConfigurerTests { .andExpect(status().isOk()) .andExpect(content().string("jdoe")); // @formatter:on + verify(authenticationConverter).convert(any(), any()); } private static void registerMockBean(GenericApplicationContext context, String name, Class clazz) { diff --git a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java index 8705229c58..ef900c98ef 100644 --- a/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java +++ b/config/src/test/java/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests.java @@ -23,7 +23,6 @@ import java.security.interfaces.RSAPublicKey; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; -import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -67,16 +66,14 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AuthenticationManagerResolver; import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.JwtBeanDefinitionParser; import org.springframework.security.config.http.OAuth2ResourceServerBeanDefinitionParser.OpaqueTokenBeanDefinitionParser; import org.springframework.security.config.test.SpringTestContext; import org.springframework.security.config.test.SpringTestContextExtension; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.oauth2.core.OAuth2AuthenticatedPrincipal; +import org.springframework.security.core.context.SecurityContextHolderStrategy; import org.springframework.security.oauth2.core.OAuth2Error; import org.springframework.security.oauth2.core.OAuth2TokenValidator; import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; @@ -654,13 +651,13 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueTokenAndAuthenticationConverter")) .autowire(); mockRestOperations(json("Active")); + OpaqueTokenAuthenticationConverter converter = bean(OpaqueTokenAuthenticationConverter.class); + given(converter.convert(any(), any())).willReturn(new TestingAuthenticationToken("user", "pass", "app")); // @formatter:off this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token")) .andExpect(status().isNotFound()); - - this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalidToken")) - .andExpect(status().isUnauthorized()); // @formatter:on + verify(converter).convert(any(), any()); } @Test @@ -1097,39 +1094,4 @@ public class OAuth2ResourceServerBeanDefinitionParserTests { } - public static class TestAuthentication extends AbstractAuthenticationToken { - - private final String introspectedToken; - - public TestAuthentication(String introspectedToken, Collection authorities) { - super(authorities); - this.introspectedToken = introspectedToken; - } - - @Override - public Object getCredentials() { - return this.introspectedToken; - } - - @Override - public Object getPrincipal() { - return this.introspectedToken; - } - - @Override - public boolean isAuthenticated() { - return "token".equals(this.introspectedToken); - } - - } - - public static class TestOpaqueTokenAuthenticationConverter implements OpaqueTokenAuthenticationConverter { - - @Override - public Authentication convert(String introspectedToken, OAuth2AuthenticatedPrincipal authenticatedPrincipal) { - return new TestAuthentication(introspectedToken, Collections.emptyList()); - } - - } - } diff --git a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml index 5a22b05c8a..8df4949985 100644 --- a/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml +++ b/config/src/test/resources/org/springframework/security/config/http/OAuth2ResourceServerBeanDefinitionParserTests-OpaqueTokenAndAuthenticationConverter.xml @@ -22,7 +22,8 @@ http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> + class="org.mockito.Mockito" factory-method="mock"> + diff --git a/web/src/main/java/org/springframework/security/web/access/expression/DefaultHttpSecurityExpressionHandler.java b/web/src/main/java/org/springframework/security/web/access/expression/DefaultHttpSecurityExpressionHandler.java index a75c0d2959..7a3b74c630 100644 --- a/web/src/main/java/org/springframework/security/web/access/expression/DefaultHttpSecurityExpressionHandler.java +++ b/web/src/main/java/org/springframework/security/web/access/expression/DefaultHttpSecurityExpressionHandler.java @@ -90,7 +90,7 @@ public class DefaultHttpSecurityExpressionHandler extends AbstractSecurityExpres * "ROLE_". */ public void setDefaultRolePrefix(String defaultRolePrefix) { - Assert.hasText(defaultRolePrefix, "defaultRolePrefix cannot be empty"); + Assert.notNull(defaultRolePrefix, "defaultRolePrefix cannot be null"); this.defaultRolePrefix = defaultRolePrefix; }