Make single definition of `defaultRolePrefix` and `rolePrefix`

Previous to this commit, role prefix had to be set in every class
causing repetition. Now, bean `GrantedAuthorityDefaults` can be used to
define the role prefix in a single point.

Fixes gh-3701
This commit is contained in:
Eddú Meléndez 2016-06-21 16:55:16 +10:00 committed by Rob Winch
parent 2e6656e9d3
commit eabeaf35d6
13 changed files with 362 additions and 29 deletions

View File

@ -15,11 +15,15 @@
*/
package org.springframework.security.config.annotation.authentication.configurers.ldap;
import java.io.IOException;
import java.net.ServerSocket;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder;
@ -43,9 +47,6 @@ import org.springframework.security.ldap.userdetails.PersonContextMapper;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.util.Assert;
import java.io.IOException;
import java.net.ServerSocket;
/**
* Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}.
*
@ -60,7 +61,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private String groupRoleAttribute = "cn";
private String groupSearchBase = "";
private String groupSearchFilter = "(uniqueMember={0})";
private String rolePrefix = "ROLE_";
private GrantedAuthorityDefaults rolePrefix = new GrantedAuthorityDefaults("ROLE_");
private String userSearchBase = ""; // only for search
private String userSearchFilter = null;// "uid={0}"; // only for search
private String[] userDnPatterns;
@ -128,7 +129,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
contextSource, groupSearchBase);
defaultAuthoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
defaultAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
defaultAuthoritiesPopulator.setRolePrefix(rolePrefix);
defaultAuthoritiesPopulator.setRolePrefix(this.rolePrefix.getRolePrefix());
this.ldapAuthoritiesPopulator = defaultAuthoritiesPopulator;
return defaultAuthoritiesPopulator;
@ -161,7 +162,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
}
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
simpleAuthorityMapper.setPrefix(rolePrefix);
simpleAuthorityMapper.setPrefix(this.rolePrefix.getRolePrefix());
simpleAuthorityMapper.afterPropertiesSet();
this.authoritiesMapper = simpleAuthorityMapper;
return simpleAuthorityMapper;
@ -356,7 +357,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* @see SimpleAuthorityMapper#setPrefix(String)
*/
public LdapAuthenticationProviderConfigurer<B> rolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
this.rolePrefix = new GrantedAuthorityDefaults(rolePrefix);
return this;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -49,6 +49,7 @@ import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.intercept.AfterInvocationManager;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.RunAsManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource;
@ -63,6 +64,8 @@ import org.springframework.security.access.vote.RoleVoter;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
@ -74,6 +77,7 @@ import org.springframework.util.Assert;
* {@link EnableGlobalMethodSecurity} annotation on the subclass.
*
* @author Rob Winch
* @author Eddú Meléndez
* @since 3.2
* @see EnableGlobalMethodSecurity
*/
@ -130,6 +134,14 @@ public class GlobalMethodSecurityConfiguration
.setSecurityMetadataSource(methodSecurityMetadataSource());
RunAsManager runAsManager = runAsManager();
if (runAsManager != null) {
if (runAsManager instanceof RunAsManagerImpl) {
GrantedAuthorityDefaults grantedAuthorityDefaults =
getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
((RunAsManagerImpl) runAsManager).setRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
}
}
methodSecurityInterceptor.setRunAsManager(runAsManager);
}
@ -168,6 +180,13 @@ public class GlobalMethodSecurityConfiguration
if (trustResolver != null) {
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
}
GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(
GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
this.defaultMethodExpressionHandler.setDefaultRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
}
}
private <T> T getSingleBeanOrNull(Class<T> type) {
@ -355,6 +374,12 @@ public class GlobalMethodSecurityConfiguration
sources.add(new SecuredAnnotationSecurityMetadataSource());
}
if (jsr250Enabled()) {
GrantedAuthorityDefaults grantedAuthorityDefaults =
getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
this.jsr250MethodSecurityMetadataSource.setDefaultRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
}
sources.add(jsr250MethodSecurityMetadataSource);
}
return new DelegatingMethodSecurityMetadataSource(sources);

View File

@ -17,7 +17,8 @@ package org.springframework.security.config.annotation.method.configuration
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl
import org.springframework.security.config.GrantedAuthorityDefaults;
import java.lang.reflect.Proxy;
@ -496,4 +497,27 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
return new RoleHierarchyImpl(hierarchy:"ROLE_USER > ROLE_ADMIN")
}
}
def "GrantedAuthorityDefaults autowires"() {
when:
loadConfig(CustomGrantedAuthorityConfig)
def preAdviceVoter = context.getBean(MethodInterceptor).accessDecisionManager.decisionVoters.find { it instanceof PreInvocationAuthorizationAdviceVoter}
then:
preAdviceVoter.preAdvice.expressionHandler.defaultRolePrefix == "ROLE:"
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
static class CustomGrantedAuthorityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
}
@Bean
public GrantedAuthorityDefaults ga() {
return new GrantedAuthorityDefaults("ROLE:")
}
}
}

View File

@ -15,7 +15,9 @@
*/
package org.springframework.security.config.annotation.method.configuration
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor
import org.springframework.security.config.GrantedAuthorityDefaults
import static org.assertj.core.api.Assertions.assertThat
import static org.junit.Assert.fail
@ -146,6 +148,39 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
public static class Jsr250Config extends BaseMethodConfig {
}
def "enable jsr250 with custom role prefix"() {
when:
context = new AnnotationConfigApplicationContext(Jsr250WithCustomRolePrefixConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then: "@Secured and @PreAuthorize are ignored"
service.secured() == null
service.preAuthorize() == null
when: "@DenyAll method invoked"
service.jsr250()
then: "access is denied"
thrown(AccessDeniedException)
when: "@PermitAll method invoked"
String jsr250PermitAll = service.jsr250PermitAll()
then: "access is allowed"
jsr250PermitAll == null
when:
Jsr250MethodSecurityMetadataSource jsr250MethodSecurity = context.getBean(Jsr250MethodSecurityMetadataSource)
then:
jsr250MethodSecurity.defaultRolePrefix == "ROLE:"
}
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Configuration
public static class Jsr250WithCustomRolePrefixConfig extends BaseMethodConfig {
@Bean
public GrantedAuthorityDefaults ga() {
return new GrantedAuthorityDefaults("ROLE:")
}
}
// --- metadata-source-ref ---
def "custom MethodSecurityMetadataSource can be used with higher priority than other sources"() {
@ -320,7 +355,7 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomRunAsManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService)
then:
service.runAs().authorities.find { it.authority == "ROLE_RUN_AS_SUPER"}
service.runAs().authorities.find { it.authority == "ROLE:RUN_AS_SUPER"}
}
@EnableGlobalMethodSecurity(securedEnabled = true)
@ -331,6 +366,11 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
runAsManager.setKey("some key")
return runAsManager
}
@Bean
public GrantedAuthorityDefaults ga() {
return new GrantedAuthorityDefaults("ROLE:")
}
}
// --- secured-annotation ---

View File

@ -0,0 +1,38 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config;
/**
* @author Eddú Meléndez
* @since 4.2.0
*/
public class GrantedAuthorityDefaults {
private String rolePrefix = "ROLE_";
public GrantedAuthorityDefaults(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
public String getRolePrefix() {
return this.rolePrefix;
}
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
}

View File

@ -16,6 +16,10 @@
package org.springframework.security.ldap.userdetails;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.SpringSecurityLdapTemplate;
@ -97,7 +101,7 @@ import java.util.Set;
* @author Luke Taylor
* @author Filip Hanik
*/
public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {
public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator, ApplicationContextAware {
// ~ Static fields/initializers
// =====================================================================================
@ -140,7 +144,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
/**
* The role prefix that will be prepended to each role name
*/
private String rolePrefix = "ROLE_";
private GrantedAuthorityDefaults rolePrefix = new GrantedAuthorityDefaults("ROLE_");
/**
* Should we convert the role name to uppercase
*/
@ -250,7 +254,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
role = role.toUpperCase();
}
authorities.add(new SimpleGrantedAuthority(rolePrefix + role));
authorities.add(new SimpleGrantedAuthority(rolePrefix.getRolePrefix() + role));
}
return authorities;
@ -297,7 +301,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
*/
public void setRolePrefix(String rolePrefix) {
Assert.notNull(rolePrefix, "rolePrefix must not be null");
this.rolePrefix = rolePrefix;
this.rolePrefix = new GrantedAuthorityDefaults(rolePrefix);
}
/**
@ -360,7 +364,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
* @see #setRolePrefix(String)
*/
protected final String getRolePrefix() {
return rolePrefix;
return this.rolePrefix.getRolePrefix();
}
/**
@ -391,4 +395,14 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
private SearchControls getSearchControls() {
return searchControls;
}
@Override
public void setApplicationContext(ApplicationContext context) throws
BeansException {
String[] beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
if (beanNames.length == 1) {
this.rolePrefix = context.getBean(beanNames[0], GrantedAuthorityDefaults.class);
}
}
}

View File

@ -20,8 +20,13 @@ import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
@ -34,14 +39,15 @@ import org.springframework.util.Assert;
* object.
*
* @author Luke Taylor
* @author Eddú Meléndez
*/
public class LdapUserDetailsMapper implements UserDetailsContextMapper {
public class LdapUserDetailsMapper implements UserDetailsContextMapper, ApplicationContextAware {
// ~ Instance fields
// ================================================================================================
private final Log logger = LogFactory.getLog(LdapUserDetailsMapper.class);
private String passwordAttributeName = "userPassword";
private String rolePrefix = "ROLE_";
private GrantedAuthorityDefaults rolePrefix = new GrantedAuthorityDefaults("ROLE_");
private String[] roleAttributes = null;
private boolean convertToUpperCase = true;
@ -146,7 +152,7 @@ public class LdapUserDetailsMapper implements UserDetailsContextMapper {
if (convertToUpperCase) {
role = ((String) role).toUpperCase();
}
return new SimpleGrantedAuthority(rolePrefix + role);
return new SimpleGrantedAuthority(this.rolePrefix.getRolePrefix() + role);
}
return null;
}
@ -188,6 +194,16 @@ public class LdapUserDetailsMapper implements UserDetailsContextMapper {
* @param rolePrefix the prefix (defaults to "ROLE_").
*/
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
this.rolePrefix = new GrantedAuthorityDefaults(rolePrefix);
}
@Override
public void setApplicationContext(ApplicationContext context) throws
BeansException {
String[] beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
if (beanNames.length == 1) {
this.rolePrefix = context.getBean(beanNames[0], GrantedAuthorityDefaults.class);
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 2002-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.ldap.userdetails;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.ContextSource;
import org.springframework.security.config.GrantedAuthorityDefaults;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* @author Eddú Meléndez
*/
public class DefaultLdapAuthoritiesPopulatorTests {
@Test
public void testDefaultRolePrefix() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(LdapAuthoritiesPopulatorConfiguration.class);
context.refresh();
DefaultLdapAuthoritiesPopulator ldapPopulator = context.getBean(DefaultLdapAuthoritiesPopulator.class);
assertThat(ldapPopulator.getRolePrefix()).isEqualTo("ROL_");
}
@Configuration
static class LdapAuthoritiesPopulatorConfiguration {
@Bean
public GrantedAuthorityDefaults authorityDefaults() {
return new GrantedAuthorityDefaults("ROL_");
}
@Bean
public DefaultLdapAuthoritiesPopulator ldapAuthoritiesPopulator() {
ContextSource contextSource = mock(ContextSource.class);
return new DefaultLdapAuthoritiesPopulator(contextSource, "ou=groups");
}
}
}

View File

@ -21,9 +21,14 @@ import javax.naming.directory.BasicAttributes;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -94,4 +99,32 @@ public class LdapUserDetailsMapperTests {
assertThat(user.getPassword()).isEqualTo("mypassword");
}
@Test
public void testDefaultRolePrefix() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(LdapUserDetailsMapperConfiguration.class);
context.refresh();
LdapUserDetailsMapper ldapUserDetailsMapper = context.getBean(LdapUserDetailsMapper.class);
GrantedAuthorityDefaults rolePrefix = (GrantedAuthorityDefaults) ReflectionTestUtils.getField(ldapUserDetailsMapper, "rolePrefix");
assertThat(rolePrefix.getRolePrefix()).isEqualTo("ROL_");
}
@Configuration
static class LdapUserDetailsMapperConfiguration {
@Bean
public GrantedAuthorityDefaults authorityDefaults() {
return new GrantedAuthorityDefaults("ROL_");
}
@Bean
public LdapUserDetailsMapper ldapUserDetailsMapper() {
return new LdapUserDetailsMapper();
}
}
}

View File

@ -15,11 +15,14 @@
*/
package org.springframework.security.web.access.expression;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation;
import org.springframework.util.Assert;
@ -27,6 +30,7 @@ import org.springframework.util.Assert;
/**
*
* @author Luke Taylor
* @author Eddú Meléndez
* @since 3.0
*/
public class DefaultWebSecurityExpressionHandler extends
@ -34,7 +38,7 @@ public class DefaultWebSecurityExpressionHandler extends
SecurityExpressionHandler<FilterInvocation> {
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private String defaultRolePrefix = "ROLE_";
private GrantedAuthorityDefaults defaultRolePrefix = new GrantedAuthorityDefaults("ROLE_");
@Override
protected SecurityExpressionOperations createSecurityExpressionRoot(
@ -43,7 +47,7 @@ public class DefaultWebSecurityExpressionHandler extends
root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(trustResolver);
root.setRoleHierarchy(getRoleHierarchy());
root.setDefaultRolePrefix(defaultRolePrefix);
root.setDefaultRolePrefix(this.defaultRolePrefix.getRolePrefix());
return root;
}
@ -74,6 +78,16 @@ public class DefaultWebSecurityExpressionHandler extends
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
*/
public void setDefaultRolePrefix(String defaultRolePrefix) {
this.defaultRolePrefix = defaultRolePrefix;
this.defaultRolePrefix = new GrantedAuthorityDefaults(defaultRolePrefix);
}
@Override
public void setApplicationContext(ApplicationContext context) {
super.setApplicationContext(context);
String[] beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
if (beanNames.length == 1) {
this.defaultRolePrefix = context.getBean(beanNames[0], GrantedAuthorityDefaults.class);
}
}
}

View File

@ -27,9 +27,13 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
@ -71,12 +75,13 @@ import org.springframework.web.filter.GenericFilterBean;
* @author Ben Alex
* @author Luke Taylor
* @author Rob Winch
* @author Eddú Meléndez
*/
public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean implements ApplicationContextAware {
// ~ Instance fields
// ================================================================================================
private String rolePrefix = "ROLE_";
private GrantedAuthorityDefaults rolePrefix = new GrantedAuthorityDefaults("ROLE_");
private HttpServletRequestFactory requestFactory;
@ -93,7 +98,7 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
public void setRolePrefix(String rolePrefix) {
Assert.notNull(rolePrefix, "Role prefix must not be null");
this.rolePrefix = rolePrefix;
this.rolePrefix = new GrantedAuthorityDefaults(rolePrefix);
updateFactory();
}
@ -177,8 +182,9 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
}
private void updateFactory() {
this.requestFactory = isServlet3() ? createServlet3Factory(this.rolePrefix)
: new HttpServlet25RequestFactory(this.trustResolver, this.rolePrefix);
String rolePrefix = this.rolePrefix.getRolePrefix();
this.requestFactory = isServlet3() ? createServlet3Factory(rolePrefix)
: new HttpServlet25RequestFactory(this.trustResolver, rolePrefix);
}
/**
@ -210,4 +216,14 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
private boolean isServlet3() {
return ClassUtils.hasMethod(ServletRequest.class, "startAsync");
}
@Override
public void setApplicationContext(ApplicationContext context) throws
BeansException {
String[] beanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
if (beanNames.length == 1) {
this.rolePrefix = context.getBean(beanNames[0], GrantedAuthorityDefaults.class);
}
}
}

View File

@ -33,6 +33,7 @@ import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
@ -62,7 +63,7 @@ public class DefaultWebSecurityExpressionHandlerTests {
}
@Test
public void expressionPropertiesAreResolvedAgainsAppContextBeans() throws Exception {
public void expressionPropertiesAreResolvedAgainstAppContextBeans() throws Exception {
StaticApplicationContext appContext = new StaticApplicationContext();
RootBeanDefinition bean = new RootBeanDefinition(SecurityConfig.class);
bean.getConstructorArgumentValues().addGenericArgumentValue("ROLE_A");
@ -95,4 +96,22 @@ public class DefaultWebSecurityExpressionHandlerTests {
verify(trustResolver).isAnonymous(authentication);
}
@Test
public void testDefaultRolePrefix() {
StaticApplicationContext appContext = new StaticApplicationContext();
RootBeanDefinition bean = new RootBeanDefinition(GrantedAuthorityDefaults.class);
bean.getConstructorArgumentValues().addGenericArgumentValue("ROL_");
appContext.registerBeanDefinition("authorityDefaults", bean);
handler.setApplicationContext(appContext);
EvaluationContext ctx = handler.createEvaluationContext(
mock(Authentication.class), mock(FilterInvocation.class));
ExpressionParser parser = handler.getExpressionParser();
assertThat(parser.parseExpression("@authorityDefaults.getRolePrefix() == 'ROL_'").getValue(
ctx, Boolean.class)).isTrue();
assertThat(parser.parseExpression("@authorityDefaults.rolePrefix == 'ROL_'").getValue(ctx,
Boolean.class)).isTrue();
}
}

View File

@ -36,6 +36,9 @@ import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.internal.WhiteboxImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
@ -43,11 +46,13 @@ import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.concurrent.DelegatingSecurityContextRunnable;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat;
@ -67,6 +72,7 @@ import static org.powermock.api.mockito.PowerMockito.when;
*
* @author Ben Alex
* @author Rob Winch
* @author Eddú Meléndez
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest(ClassUtils.class)
@ -195,7 +201,7 @@ public class SecurityContextHolderAwareRequestFilterTests {
// SEC-2296
@Test
public void loginWithExstingUser() throws Exception {
public void loginWithExistingUser() throws Exception {
TestingAuthenticationToken expectedAuth = new TestingAuthenticationToken("user",
"password", "ROLE_USER");
when(this.authenticationManager
@ -415,4 +421,31 @@ public class SecurityContextHolderAwareRequestFilterTests {
return this.requestCaptor.getValue();
}
@Test
public void testDefaultRolePrefix() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(FilterConfiguration.class);
context.refresh();
SecurityContextHolderAwareRequestFilter filter = context.getBean(SecurityContextHolderAwareRequestFilter.class);
GrantedAuthorityDefaults authorityDefaults = (GrantedAuthorityDefaults) ReflectionTestUtils.getField(filter, "rolePrefix");
assertThat(authorityDefaults.getRolePrefix()).isEqualTo("ROL_");
}
@Configuration
static class FilterConfiguration {
@Bean
public GrantedAuthorityDefaults authorityDefaults() {
return new GrantedAuthorityDefaults("ROL_");
}
@Bean
public SecurityContextHolderAwareRequestFilter requestFilter() {
return new SecurityContextHolderAwareRequestFilter();
}
}
}