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; 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.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.encoding.PasswordEncoder; import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder; 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.ObjectPostProcessor;
import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
import org.springframework.security.config.annotation.authentication.ProviderManagerBuilder; 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.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import java.io.IOException;
import java.net.ServerSocket;
/** /**
* Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}. * Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}.
* *
@ -60,7 +61,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private String groupRoleAttribute = "cn"; private String groupRoleAttribute = "cn";
private String groupSearchBase = ""; private String groupSearchBase = "";
private String groupSearchFilter = "(uniqueMember={0})"; private String groupSearchFilter = "(uniqueMember={0})";
private String rolePrefix = "ROLE_"; private GrantedAuthorityDefaults rolePrefix = new GrantedAuthorityDefaults("ROLE_");
private String userSearchBase = ""; // only for search private String userSearchBase = ""; // only for search
private String userSearchFilter = null;// "uid={0}"; // only for search private String userSearchFilter = null;// "uid={0}"; // only for search
private String[] userDnPatterns; private String[] userDnPatterns;
@ -128,7 +129,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
contextSource, groupSearchBase); contextSource, groupSearchBase);
defaultAuthoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute); defaultAuthoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
defaultAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter); defaultAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
defaultAuthoritiesPopulator.setRolePrefix(rolePrefix); defaultAuthoritiesPopulator.setRolePrefix(this.rolePrefix.getRolePrefix());
this.ldapAuthoritiesPopulator = defaultAuthoritiesPopulator; this.ldapAuthoritiesPopulator = defaultAuthoritiesPopulator;
return defaultAuthoritiesPopulator; return defaultAuthoritiesPopulator;
@ -161,7 +162,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
} }
SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper(); SimpleAuthorityMapper simpleAuthorityMapper = new SimpleAuthorityMapper();
simpleAuthorityMapper.setPrefix(rolePrefix); simpleAuthorityMapper.setPrefix(this.rolePrefix.getRolePrefix());
simpleAuthorityMapper.afterPropertiesSet(); simpleAuthorityMapper.afterPropertiesSet();
this.authoritiesMapper = simpleAuthorityMapper; this.authoritiesMapper = simpleAuthorityMapper;
return simpleAuthorityMapper; return simpleAuthorityMapper;
@ -356,7 +357,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* @see SimpleAuthorityMapper#setPrefix(String) * @see SimpleAuthorityMapper#setPrefix(String)
*/ */
public LdapAuthenticationProviderConfigurer<B> rolePrefix(String rolePrefix) { public LdapAuthenticationProviderConfigurer<B> rolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix; this.rolePrefix = new GrantedAuthorityDefaults(rolePrefix);
return this; 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.AfterInvocationManager;
import org.springframework.security.access.intercept.AfterInvocationProviderManager; import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.RunAsManager; 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.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor; import org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor;
import org.springframework.security.access.method.DelegatingMethodSecurityMetadataSource; 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.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher; 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.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
@ -74,6 +77,7 @@ import org.springframework.util.Assert;
* {@link EnableGlobalMethodSecurity} annotation on the subclass. * {@link EnableGlobalMethodSecurity} annotation on the subclass.
* *
* @author Rob Winch * @author Rob Winch
* @author Eddú Meléndez
* @since 3.2 * @since 3.2
* @see EnableGlobalMethodSecurity * @see EnableGlobalMethodSecurity
*/ */
@ -130,6 +134,14 @@ public class GlobalMethodSecurityConfiguration
.setSecurityMetadataSource(methodSecurityMetadataSource()); .setSecurityMetadataSource(methodSecurityMetadataSource());
RunAsManager runAsManager = runAsManager(); RunAsManager runAsManager = runAsManager();
if (runAsManager != null) { if (runAsManager != null) {
if (runAsManager instanceof RunAsManagerImpl) {
GrantedAuthorityDefaults grantedAuthorityDefaults =
getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
((RunAsManagerImpl) runAsManager).setRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
}
}
methodSecurityInterceptor.setRunAsManager(runAsManager); methodSecurityInterceptor.setRunAsManager(runAsManager);
} }
@ -168,6 +180,13 @@ public class GlobalMethodSecurityConfiguration
if (trustResolver != null) { if (trustResolver != null) {
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver); this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
} }
GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(
GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
this.defaultMethodExpressionHandler.setDefaultRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
}
} }
private <T> T getSingleBeanOrNull(Class<T> type) { private <T> T getSingleBeanOrNull(Class<T> type) {
@ -355,6 +374,12 @@ public class GlobalMethodSecurityConfiguration
sources.add(new SecuredAnnotationSecurityMetadataSource()); sources.add(new SecuredAnnotationSecurityMetadataSource());
} }
if (jsr250Enabled()) { if (jsr250Enabled()) {
GrantedAuthorityDefaults grantedAuthorityDefaults =
getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
this.jsr250MethodSecurityMetadataSource.setDefaultRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
}
sources.add(jsr250MethodSecurityMetadataSource); sources.add(jsr250MethodSecurityMetadataSource);
} }
return new DelegatingMethodSecurityMetadataSource(sources); 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.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; import java.lang.reflect.Proxy;
@ -496,4 +497,27 @@ public class GlobalMethodSecurityConfigurationTests extends BaseSpringSpec {
return new RoleHierarchyImpl(hierarchy:"ROLE_USER > ROLE_ADMIN") 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 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.access.intercept.aspectj.AspectJMethodSecurityInterceptor
import org.springframework.security.config.GrantedAuthorityDefaults
import static org.assertj.core.api.Assertions.assertThat import static org.assertj.core.api.Assertions.assertThat
import static org.junit.Assert.fail import static org.junit.Assert.fail
@ -146,6 +148,39 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
public static class Jsr250Config extends BaseMethodConfig { 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 --- // --- metadata-source-ref ---
def "custom MethodSecurityMetadataSource can be used with higher priority than other sources"() { 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) context = new AnnotationConfigApplicationContext(BaseMethodConfig,CustomRunAsManagerConfig)
MethodSecurityService service = context.getBean(MethodSecurityService) MethodSecurityService service = context.getBean(MethodSecurityService)
then: then:
service.runAs().authorities.find { it.authority == "ROLE_RUN_AS_SUPER"} service.runAs().authorities.find { it.authority == "ROLE:RUN_AS_SUPER"}
} }
@EnableGlobalMethodSecurity(securedEnabled = true) @EnableGlobalMethodSecurity(securedEnabled = true)
@ -331,6 +366,11 @@ public class NamespaceGlobalMethodSecurityTests extends BaseSpringSpec {
runAsManager.setKey("some key") runAsManager.setKey("some key")
return runAsManager return runAsManager
} }
@Bean
public GrantedAuthorityDefaults ga() {
return new GrantedAuthorityDefaults("ROLE:")
}
} }
// --- secured-annotation --- // --- 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; 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.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.SpringSecurityLdapTemplate; import org.springframework.security.ldap.SpringSecurityLdapTemplate;
@ -97,7 +101,7 @@ import java.util.Set;
* @author Luke Taylor * @author Luke Taylor
* @author Filip Hanik * @author Filip Hanik
*/ */
public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator { public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator, ApplicationContextAware {
// ~ Static fields/initializers // ~ Static fields/initializers
// ===================================================================================== // =====================================================================================
@ -140,7 +144,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
/** /**
* The role prefix that will be prepended to each role name * 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 * Should we convert the role name to uppercase
*/ */
@ -250,7 +254,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
role = role.toUpperCase(); role = role.toUpperCase();
} }
authorities.add(new SimpleGrantedAuthority(rolePrefix + role)); authorities.add(new SimpleGrantedAuthority(rolePrefix.getRolePrefix() + role));
} }
return authorities; return authorities;
@ -297,7 +301,7 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
*/ */
public void setRolePrefix(String rolePrefix) { public void setRolePrefix(String rolePrefix) {
Assert.notNull(rolePrefix, "rolePrefix must not be null"); 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) * @see #setRolePrefix(String)
*/ */
protected final String getRolePrefix() { protected final String getRolePrefix() {
return rolePrefix; return this.rolePrefix.getRolePrefix();
} }
/** /**
@ -391,4 +395,14 @@ public class DefaultLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator
private SearchControls getSearchControls() { private SearchControls getSearchControls() {
return searchControls; 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.Log;
import org.apache.commons.logging.LogFactory; 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.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations; import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
@ -34,14 +39,15 @@ import org.springframework.util.Assert;
* object. * object.
* *
* @author Luke Taylor * @author Luke Taylor
* @author Eddú Meléndez
*/ */
public class LdapUserDetailsMapper implements UserDetailsContextMapper { public class LdapUserDetailsMapper implements UserDetailsContextMapper, ApplicationContextAware {
// ~ Instance fields // ~ Instance fields
// ================================================================================================ // ================================================================================================
private final Log logger = LogFactory.getLog(LdapUserDetailsMapper.class); private final Log logger = LogFactory.getLog(LdapUserDetailsMapper.class);
private String passwordAttributeName = "userPassword"; private String passwordAttributeName = "userPassword";
private String rolePrefix = "ROLE_"; private GrantedAuthorityDefaults rolePrefix = new GrantedAuthorityDefaults("ROLE_");
private String[] roleAttributes = null; private String[] roleAttributes = null;
private boolean convertToUpperCase = true; private boolean convertToUpperCase = true;
@ -146,7 +152,7 @@ public class LdapUserDetailsMapper implements UserDetailsContextMapper {
if (convertToUpperCase) { if (convertToUpperCase) {
role = ((String) role).toUpperCase(); role = ((String) role).toUpperCase();
} }
return new SimpleGrantedAuthority(rolePrefix + role); return new SimpleGrantedAuthority(this.rolePrefix.getRolePrefix() + role);
} }
return null; return null;
} }
@ -188,6 +194,16 @@ public class LdapUserDetailsMapper implements UserDetailsContextMapper {
* @param rolePrefix the prefix (defaults to "ROLE_"). * @param rolePrefix the prefix (defaults to "ROLE_").
*/ */
public void setRolePrefix(String rolePrefix) { 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.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.DirContextAdapter;
import org.springframework.ldap.core.DistinguishedName; import org.springframework.ldap.core.DistinguishedName;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -94,4 +99,32 @@ public class LdapUserDetailsMapperTests {
assertThat(user.getPassword()).isEqualTo("mypassword"); 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; 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.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionHandler; import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.access.expression.SecurityExpressionOperations; import org.springframework.security.access.expression.SecurityExpressionOperations;
import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.FilterInvocation;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -27,6 +30,7 @@ import org.springframework.util.Assert;
/** /**
* *
* @author Luke Taylor * @author Luke Taylor
* @author Eddú Meléndez
* @since 3.0 * @since 3.0
*/ */
public class DefaultWebSecurityExpressionHandler extends public class DefaultWebSecurityExpressionHandler extends
@ -34,7 +38,7 @@ public class DefaultWebSecurityExpressionHandler extends
SecurityExpressionHandler<FilterInvocation> { SecurityExpressionHandler<FilterInvocation> {
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private String defaultRolePrefix = "ROLE_"; private GrantedAuthorityDefaults defaultRolePrefix = new GrantedAuthorityDefaults("ROLE_");
@Override @Override
protected SecurityExpressionOperations createSecurityExpressionRoot( protected SecurityExpressionOperations createSecurityExpressionRoot(
@ -43,7 +47,7 @@ public class DefaultWebSecurityExpressionHandler extends
root.setPermissionEvaluator(getPermissionEvaluator()); root.setPermissionEvaluator(getPermissionEvaluator());
root.setTrustResolver(trustResolver); root.setTrustResolver(trustResolver);
root.setRoleHierarchy(getRoleHierarchy()); root.setRoleHierarchy(getRoleHierarchy());
root.setDefaultRolePrefix(defaultRolePrefix); root.setDefaultRolePrefix(this.defaultRolePrefix.getRolePrefix());
return root; return root;
} }
@ -74,6 +78,16 @@ public class DefaultWebSecurityExpressionHandler extends
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_". * @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
*/ */
public void setDefaultRolePrefix(String defaultRolePrefix) { 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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; 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.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl; 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.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
@ -71,12 +75,13 @@ import org.springframework.web.filter.GenericFilterBean;
* @author Ben Alex * @author Ben Alex
* @author Luke Taylor * @author Luke Taylor
* @author Rob Winch * @author Rob Winch
* @author Eddú Meléndez
*/ */
public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean { public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean implements ApplicationContextAware {
// ~ Instance fields // ~ Instance fields
// ================================================================================================ // ================================================================================================
private String rolePrefix = "ROLE_"; private GrantedAuthorityDefaults rolePrefix = new GrantedAuthorityDefaults("ROLE_");
private HttpServletRequestFactory requestFactory; private HttpServletRequestFactory requestFactory;
@ -93,7 +98,7 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
public void setRolePrefix(String rolePrefix) { public void setRolePrefix(String rolePrefix) {
Assert.notNull(rolePrefix, "Role prefix must not be null"); Assert.notNull(rolePrefix, "Role prefix must not be null");
this.rolePrefix = rolePrefix; this.rolePrefix = new GrantedAuthorityDefaults(rolePrefix);
updateFactory(); updateFactory();
} }
@ -177,8 +182,9 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
} }
private void updateFactory() { private void updateFactory() {
this.requestFactory = isServlet3() ? createServlet3Factory(this.rolePrefix) String rolePrefix = this.rolePrefix.getRolePrefix();
: new HttpServlet25RequestFactory(this.trustResolver, this.rolePrefix); this.requestFactory = isServlet3() ? createServlet3Factory(rolePrefix)
: new HttpServlet25RequestFactory(this.trustResolver, rolePrefix);
} }
/** /**
@ -210,4 +216,14 @@ public class SecurityContextHolderAwareRequestFilter extends GenericFilterBean {
private boolean isServlet3() { private boolean isServlet3() {
return ClassUtils.hasMethod(ServletRequest.class, "startAsync"); 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.expression.ExpressionParser;
import org.springframework.security.access.SecurityConfig; import org.springframework.security.access.SecurityConfig;
import org.springframework.security.authentication.AuthenticationTrustResolver; import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation; import org.springframework.security.web.FilterInvocation;
@ -62,7 +63,7 @@ public class DefaultWebSecurityExpressionHandlerTests {
} }
@Test @Test
public void expressionPropertiesAreResolvedAgainsAppContextBeans() throws Exception { public void expressionPropertiesAreResolvedAgainstAppContextBeans() throws Exception {
StaticApplicationContext appContext = new StaticApplicationContext(); StaticApplicationContext appContext = new StaticApplicationContext();
RootBeanDefinition bean = new RootBeanDefinition(SecurityConfig.class); RootBeanDefinition bean = new RootBeanDefinition(SecurityConfig.class);
bean.getConstructorArgumentValues().addGenericArgumentValue("ROLE_A"); bean.getConstructorArgumentValues().addGenericArgumentValue("ROLE_A");
@ -95,4 +96,22 @@ public class DefaultWebSecurityExpressionHandlerTests {
verify(trustResolver).isAnonymous(authentication); 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.modules.junit4.PowerMockRunner;
import org.powermock.reflect.internal.WhiteboxImpl; 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.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager; 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.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.concurrent.DelegatingSecurityContextRunnable; import org.springframework.security.concurrent.DelegatingSecurityContextRunnable;
import org.springframework.security.config.GrantedAuthorityDefaults;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.logout.LogoutHandler; import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -67,6 +72,7 @@ import static org.powermock.api.mockito.PowerMockito.when;
* *
* @author Ben Alex * @author Ben Alex
* @author Rob Winch * @author Rob Winch
* @author Eddú Meléndez
*/ */
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PrepareForTest(ClassUtils.class) @PrepareForTest(ClassUtils.class)
@ -195,7 +201,7 @@ public class SecurityContextHolderAwareRequestFilterTests {
// SEC-2296 // SEC-2296
@Test @Test
public void loginWithExstingUser() throws Exception { public void loginWithExistingUser() throws Exception {
TestingAuthenticationToken expectedAuth = new TestingAuthenticationToken("user", TestingAuthenticationToken expectedAuth = new TestingAuthenticationToken("user",
"password", "ROLE_USER"); "password", "ROLE_USER");
when(this.authenticationManager when(this.authenticationManager
@ -415,4 +421,31 @@ public class SecurityContextHolderAwareRequestFilterTests {
return this.requestCaptor.getValue(); 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();
}
}
} }