瀏覽代碼

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
Eddú Meléndez 9 年之前
父節點
當前提交
eabeaf35d6
共有 13 個文件被更改,包括 362 次插入29 次删除
  1. 8 7
      config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java
  2. 26 1
      config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java
  3. 25 1
      config/src/test/groovy/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.groovy
  4. 41 1
      config/src/test/groovy/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.groovy
  5. 38 0
      core/src/main/java/org/springframework/security/config/GrantedAuthorityDefaults.java
  6. 19 5
      ldap/src/main/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulator.java
  7. 20 4
      ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsMapper.java
  8. 60 0
      ldap/src/test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java
  9. 33 0
      ldap/src/test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsMapperTests.java
  10. 17 3
      web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java
  11. 21 5
      web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java
  12. 20 1
      web/src/test/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandlerTests.java
  13. 34 1
      web/src/test/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilterTests.java

+ 8 - 7
config/src/main/java/org/springframework/security/config/annotation/authentication/configurers/ldap/LdapAuthenticationProviderConfigurer.java

@@ -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;
 	}
 

+ 26 - 1
config/src/main/java/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.java

@@ -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);

+ 25 - 1
config/src/test/groovy/org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfigurationTests.groovy

@@ -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:")
+		}
+	}
 }

+ 41 - 1
config/src/test/groovy/org/springframework/security/config/annotation/method/configuration/NamespaceGlobalMethodSecurityTests.groovy

@@ -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 ---

+ 38 - 0
core/src/main/java/org/springframework/security/config/GrantedAuthorityDefaults.java

@@ -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;
+	}
+
+}

+ 19 - 5
ldap/src/main/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulator.java

@@ -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);
+		}
+	}
+
 }

+ 20 - 4
ldap/src/main/java/org/springframework/security/ldap/userdetails/LdapUserDetailsMapper.java

@@ -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);
+		}
+	}
+
 }

+ 60 - 0
ldap/src/test/java/org/springframework/security/ldap/userdetails/DefaultLdapAuthoritiesPopulatorTests.java

@@ -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");
+		}
+
+	}
+
+}

+ 33 - 0
ldap/src/test/java/org/springframework/security/ldap/userdetails/LdapUserDetailsMapperTests.java

@@ -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();
+		}
+
+	}
+
 }

+ 17 - 3
web/src/main/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandler.java

@@ -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);
+		}
+	}
+
 }

+ 21 - 5
web/src/main/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilter.java

@@ -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);
+		}
+	}
+
 }

+ 20 - 1
web/src/test/java/org/springframework/security/web/access/expression/DefaultWebSecurityExpressionHandlerTests.java

@@ -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();
+	}
+
 }

+ 34 - 1
web/src/test/java/org/springframework/security/web/servletapi/SecurityContextHolderAwareRequestFilterTests.java

@@ -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();
+		}
+
+	}
+
 }