Spring 3.x configuration for multiple login pages - spring

I'm using Spring 3.1 for authentication purpose.
My requirement:
Two different login pages. One for Customer and other for Employee.
Each after successful authentication, will be forwarded to respective successful URL.
My spring security configuration:
<sec:http pattern="/resources/**" security="none" />
<sec:http auto-config="true">
<sec:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<sec:intercept-url pattern="/customer/**" access="ROLE_CUSTOMER" />
<sec:intercept-url pattern="/employee/**" access="ROLE_EMPLOYEE" />
</sec:http>
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<sec:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/**"
filters="authenticationProcessingFilterForCustomer,authenticationProcessingFilterForEmployee" />
</sec:filter-chain-map>
</bean>
<bean id="authenticationProcessingFilterForCustomer"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForCustomer" />
<property name="filterProcessesUrl" value="/j_spring_security_check_for_customer" />
<property name="authenticationSuccessHandler" ref="customerSuccessHandler" />
<property name="authenticationFailureHandler" ref="customerFailureHandler" />
</bean>
<bean id="customerSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/customer/index.html" />
</bean>
<bean id="customerFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/customer.html?login_error=1" />
</bean>
<bean id="authenticationManagerForCustomer"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref bean="customCustomerAuthenticationProvider" />
</list>
</property>
</bean>
<bean id="customCustomerAuthenticationProvider" class="com.edu.CustomerCustomAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.edu.CustomerUserDetailsService" />
</property>
</bean>
<bean id="authenticationProcessingFilterForEmployee"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManagerForEmployee" />
<property name="filterProcessesUrl" value="/j_spring_security_check_for_employee" />
<property name="authenticationSuccessHandler" ref="employeeSuccessHandler" />
<property name="authenticationFailureHandler" ref="employeeFailureHandler" />
</bean>
<bean id="employeeSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/employee/index.html" />
</bean>
<bean id="employeeFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/employee.html?login_error=1" />
</bean>
<bean id="authenticationManagerForEmployee"
class="org.springframework.security.authentication.ProviderManager">
<property name="providers">
<list>
<ref bean="customEmployeeAuthenticationProvider" />
</list>
</property>
</bean>
<bean id="customEmployeeAuthenticationProvider" class="com.edu.EmployeeCustomAuthenticationProvider">
<property name="userDetailsService">
<bean class="com.edu.EmployeeUserDetailsService" />
</property>
</bean>
<sec:authentication-manager alias="authenticationManager">
<sec:authentication-provider ref="customCustomerAuthenticationProvider" />
<sec:authentication-provider ref="customEmployeeAuthenticationProvider" />
</sec:authentication-manager>
Both CustomAuthenticationProvider have implemented Support method as follows:
public boolean supports(Class<? extends Object> authentication) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
After launching application, while trying to authenticate, the message displayed in login pages are:
Your login attempt was not successful, try again.
Reason: No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken
I'm using Spring 3.1. Any help appreciated.
Thank You

I have done similar things in grails, what you need is:
extend UsernamePasswordAuthenticationToken, create two sub-class for employee and customer, say EmployeeUsernamePasswordAuthenticationToken and CustomerUsernamePasswordAuthenticationToken
extend UsernamePasswordAuthenticationFilter, to create different instance of EmployeeUsernamePasswordAuthenticationToken or CustomerUsernamePasswordAuthenticationToken based on current auth request
extend AuthenticationProvider for employee and custoner, create two class say EmployeeAuthenticationProvider and CustomerAuthenticationProvider, overwrite each class' supports method to support its target UsernamePasswordAuthenticationToken
you only need one authenticationManager, register both provide into it
only need one AuthenticationSuccessHandler, you can decide which url want to go in it
I also create a my own instance of AuthenticationEntryPoint to support multi entrypoint

Beginning from Spring 3.1 you have as many configuration as you want :
https://jira.springsource.org/browse/SEC-1171

You should point the authenticationManager ref in 'authenticationProcessingFilterForCustomer' and 'authenticationProcessingFilterForEmployee' beans to correct bean i.e. 'authenticationManager' which has providers. No need to define 'authenticationManagerForCustomer' and 'authenticationManagerForEmployee' beans.

Related

Spring Security having two authentication layers

In our application, we are required to have two layers of authentication,Database and LDAP, i.e,
Once User logins with username and password, Database validation is done only to check if username exists in database using custom authentication privider.
If username exists in the database then second layer of LDAP has to be invoked to check if password matches.If password matches with that in LDAP then user should be authenticated.If username doesn't exist in the database, the LDAP layer shouldn't be invoked and user shouldn't be authenticated.
I have implemented the first layer of authentication i.e Database validation for username.
However I am not able to figure out how I can have second layer i.e LDAP for password check.
It would be great if someone helps me on this.
Below is the code in security xml file:
<security:http auto-config="false" use-expressions="true"
entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:custom-filter ref="customAuthenticationFilter"
position="FORM_LOGIN_FILTER" />
<security:custom-filter ref="concurrencyFilter" position="CONCURRENT_SESSION_FILTER" />
<security:access-denied-handler
error-page="/accessDenied" />
<security:logout delete-cookies="JSESSIONID" logout-success-url="/logout" />
<security:session-management session-authentication-strategy-ref="sas" />
<security:headers >
<security:cache-control />
<security:hsts/>
</security:headers>
</security:http>
<security:global-method-security
pre-post-annotations="enabled" />
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="customAuthenticationProvider" />
</security:authentication-manager>
<bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/">
</property>
</bean>
<bean id="customAuthenticationFilter"
class="com.honeywell.wfm.util.CustomAuthenticationFilter">
<property name="usernameParameter" value="username"></property>
<property name="passwordParameter" value="password"></property>
<property name="authenticationManager" ref="authenticationManager"/>
<property name="authenticationFailureHandler" ref="failureHandler"/>
<property name="authenticationSuccessHandler" ref="successHandler"/>
<property name="sessionAuthenticationStrategy" ref="sas" />
</bean>
<bean id="successHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<property name="defaultTargetUrl" value="/dashboard"/>
</bean>
<bean id="failureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<property name="defaultFailureUrl" value="/failTologin"/>
</bean>
<bean id="concurrencyFilter"
class="org.springframework.security.web.session.ConcurrentSessionFilter">
<property name="sessionRegistry" ref="sessionRegistry" />
<property name="expiredUrl" value="/logout" />
</bean>
<bean id="sas"
class="org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
<constructor-arg>
<list>
<bean
class="org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
<property name="maximumSessions" value="1" />
<property name="exceptionIfMaximumExceeded" value="false" />
</bean>
<bean
class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
</bean>
<bean
class="org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
<constructor-arg ref="sessionRegistry" />
</bean>
</list>
</constructor-arg>
</bean>
<bean id="sessionRegistry"
class="org.springframework.security.core.session.SessionRegistryImpl" />
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter">
<property name="rolePrefix" value="" />
</bean>
<bean id="customAuthenticationProvider"
class="com.honeywell.wfm.service.impl.CustomAuthenticationProvider"></bean>
CustomAuthenticationProvider.java
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String employeeNumber = authentication.getName();
String password = (String) authentication.getCredentials();
UserDTO userDTO = loginComponent.loadUserByUsername(employeeNumber);
if (userDTO.getEmployeeNo() == null) {
logger.error("Authentication failure for "+employeeNumber);
throw new BadCredentialsException("Invalid Employee Number");
}
logger.info("Successfully Authenticated " +userDTO.getUserName());
userDTO.setPassword(password);
return new UsernamePasswordAuthenticationToken(userDTO, password, userDTO.getAuthorities());
}

TAM Webseal + spring pre-authentication

Has anybody done spring pre-authentication with TAM Web-seal?
Can you please share the configuration details?
If webseal forward the request with the username in iv-user header, then it is relative simple to configure spring-security:
<security:http auto-config="false" use-expressions="true" entry-point-ref="authenticationEntryPoint" access-decision-manager-ref="httpAccessDecisionManager">
<security:custom-filter ref="webSealPreAuthFilter" position="PRE_AUTH_FILTER"/>
...
</security:http>
<bean id="webSealPreAuthFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="principalRequestHeader" value="iv-user"/>
<!-- exceptionIfHeaderMissing AND checkForPrincipalChanges needs to be enable to check that each request needs a "iv-user" header -->
<property name="checkForPrincipalChanges" value="true"/>
<property name="exceptionIfHeaderMissing" value="true"/>
</bean>
<alias name="authenticationManager" alias="org.springframework.security.authenticationManager"/>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<property name="authenticationEventPublisher">
<bean class="org.springframework.security.authentication.DefaultAuthenticationEventPublisher"/>
</property>
<constructor-arg name="providers">
<list>
<ref local="preAuthenticatedAuthenticationProvider"/>
</list>
</constructor-arg>
</bean>
<bean id="preAuthenticatedAuthenticationProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/>
You need an userDetailsService but this is highly dependend on how your application works.

Spring Security and custom Remember me filter: logout issue

I need to define a custom RememberMeAuthenticationFilter so that I can override the onSuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, Authentication authResult) method to put some custom logic.
I've configured the XML in order to use my custom filter:
<security:http disable-url-rewriting="true" request-matcher-ref="excludeUrlRequestMatcher" entry-point-ref="authenticationEntryPoint">
<security:custom-filter position="FORM_LOGIN_FILTER" ref="usernamePasswordAuthenticationFilter"/>
<security:custom-filter position="REMEMBER_ME_FILTER" ref="extRememberMeProcessingFilter"/>
<security:anonymous username="anonymous" granted-authority="ROLE_ANONYMOUS"/>
<security:session-management session-authentication-strategy-ref="fixation" />
<!-- Intercepts url HERE: removed for brevity -->
<!--<security:form-login: using custom filter -->
<!--login-page="/login"-->
<!--authentication-failure-handler-ref="loginAuthenticationFailureHandler"-->
<!--authentication-success-handler-ref="loginGuidAuthenticationSuccessHandler"/>-->
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler"/>
<security:port-mappings>
<security:port-mapping http="#{configurationService.configuration.getProperty('tomcat.http.port')}"
https="#{configurationService.configuration.getProperty('tomcat.ssl.port')}"/>
<security:port-mapping http="80" https="443"/>
<!--security:port-mapping http="#{configurationService.configuration.getProperty('proxy.http.port')}"
https="#{configurationService.configuration.getProperty('proxy.ssl.port')}" /-->
</security:port-mappings>
<security:request-cache ref="httpSessionRequestCache"/>
<security:access-denied-handler ref="b2bAccessDeniedHandler"/>
<!-- RememberMe: using custom filter -->
<!--<security:remember-me key="comtestrememberme" services-ref="rememberMeServices"/>-->
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="myAuthenticationProvider"/>
<security:authentication-provider ref="rememberMeAuthenticationProvider"/>
</security:authentication-manager>
<bean id="myAuthenticationProvider"
class="com.test.security.MyAuthenticationProvider">
<property name="bruteForceAttackCounter" ref="bruteForceAttackCounter"/>
<property name="customerService" ref="customerService"/>
<aop:scoped-proxy/>
</bean>
<bean id="rememberMeServices"
class="com.test.security.MyRememberMeServices">
<property name="key" value="comtestrememberme"/>
<property name="cookieName" value="myRememberMe"/>
<property name="alwaysRemember" value="false"/>
<property name="customerService" ref="customerService"/>
<property name="useSecureCookie" value="false"/>
<aop:scoped-proxy/>
</bean>
<bean id="rememberMeAuthenticationProvider"
class="org.springframework.security.authentication.RememberMeAuthenticationProvider">
<property name="key" value="comtestrememberme"/>
<aop:scoped-proxy/>
</bean>
<bean id="usernamePasswordAuthenticationFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="filterProcessesUrl" value="/j_spring_security_check"/>
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationSuccessHandler" ref="loginGuidAuthenticationSuccessHandler"/>
<property name="authenticationFailureHandler" ref="loginAuthenticationFailureHandler"/>
</bean>
<bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<property name="loginFormUrl" value="/login"/>
</bean>
<bean id="extRememberMeProcessingFilter" class="com.test.security.filters.ExtRememberMeAuthenticationFilter">
<property name="rememberMeServices" ref="rememberMeServices"/>
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
The remember me cookie is getting created and my custom filter is being used, but the problem is that the logout never happens.
When I click on the logout button it looks like I'm going through the authentication process again and the customer is logged in again.
If I revert back to the standard Spring Filters everything is working fine.
Have I missed something in the configuration?
What may be happening here is - your logout is working fine but you haven't deleted myRememberMe cookie on logout. So, when your session is getting invalidated on logout, remember me services is creating a new session by using myRememberMe cookie.
Solution: You can modify your configuration by adding delete-cookies attribute in your <security:logout> tag.
<security:logout logout-url="/logout" success-handler-ref="logoutSuccessHandler" delete-cookies="JSESSIONID,myRememberMe" />

How can I use intercept-method using its filters, not namespace?

I'm trying to add some intercept-method in my application (using spring security) without namespaces.
So here is what I did:
First, I added a filter to filter-chain-map named "methodSecurityInterceptor" as you can see:
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/css/**" filters="none" />
<sec:filter-chain pattern="/images/**" filters="none" />
<sec:filter-chain pattern="/login.jsp*" filters="none" />
<sec:filter-chain pattern="/**"
filters="
ConcurrentSessionFilter,
securityContextPersistenceFilter,
sessionManagementFilter,
authenticationProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor,
methodSecurityInterceptor,
logoutFilter" />
</security:filter-chain-map>
</bean>
Then I introduced its bean like this:
<bean id="methodSecurityInterceptor"
class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="securityMetadataSource" ref="MyMethodMetdataSource">
</property>
</bean>
<bean id="MyMethodMetdataSource" class="com.datx.dao.MyMethodMetdataSource">
</bean>
And I have my MyMethodMetadataSource implemented like this:
public class MyMethodMetdataSource extends AbstractMethodSecurityMetadataSource{
#Override
public Collection<ConfigAttribute> getAttributes(Method arg0, Class<?> arg1) {
String url = arg0.getName();
List<ConfigAttribute> attributes = new ArrayList<ConfigAttribute>();
attributes = getAttributesByURL2(url); //Here is my function which
//returns corresponding roles
return attributes;
}
#Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
// TODO Auto-generated method stub
return null;
}
Apparently I am not allowed to use methodSecurityInterceptor as it's not a filter!
So what should I do?
I've read this but I have no idea how to use it with one of Spring AOP's proxying mechanisms!
So... Any idea?
The example I gave you before, is pretty much as simple as you can make it without using the namespace <global-method-security> element.
Use Spring's AOP namespace with a pointcut matching the method(s) you want to protect:
<aop:config>
<aop:pointcut id='targetMethods' expression='execution(* org.springframework.security.TargetObject.*(..))'/>
<aop:advisor advice-ref='securityInterceptor' pointcut-ref='targetMethods' />
</aop:config>
and declare the security interceptor as a bean:
<bean id='target' class='org.springframework.security.TargetObject'/>
<bean id='securityInterceptor' class='org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor' autowire='byType' >
<property name='securityMetadataSource' ref="yourSecurityMetadataSource"/>
</bean>
External calls to that bean will then be routed through the security interceptor before the method is invoked.
I'd suggest you checkout the source and try running the test in a debugger to get a feel for how it works if you haven't use AOP before.
Luckily I found the answer to this question.
One cannot use filters for intercept-method. So I suggest using proxies instead.
So here is the solution:
Change back the filter chain to its normal:
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<sec:filter-chain pattern="/css/**" filters="none" />
<sec:filter-chain pattern="/images/**" filters="none" />
<sec:filter-chain pattern="/login.jsp*" filters="none" />
<sec:filter-chain pattern="/**"
filters="
ConcurrentSessionFilter,
securityContextPersistenceFilter,
sessionManagementFilter,
authenticationProcessingFilter,
exceptionTranslationFilter,
filterSecurityInterceptor,
logoutFilter" />
</security:filter-chain-map>
See what I did there? I removed the methodSecurityInterceptor.
Then add a proxy:
<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="interceptorNames">
<list>
<value>methodSecurityInterceptor</value> <!-- Responsible for checking roles and accesspaths -->
</list>
</property>
<property name="beanNames">
<list>
<value>Manager2</value> <!--The Class that I want to protect its methods -->
</list>
</property>
</bean>
Of course we have to add these beans to application context too:
<bean id="methodSecurityInterceptor"
class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager" />
<property name="accessDecisionManager" ref="accessDecisionManager" />
<property name="securityMetadataSource" ref="MyMethodMetdataSource">
</property>
</bean>
<bean id="MyMethodMetdataSource" class="com.datx.dao.MyMethodMetdataSource">
</bean>
Here we go :)
Now every method in Manager2.java will be checked for every method call.

AccessDeniedException if using RoleHierarchyImpl

I am using role hierarchy in Spring Security.
<beans:bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<beans:constructor-arg ref="roleHierarchy" />
</beans:bean>
<beans:bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<beans:property name="hierarchy">
<beans:value>
ROLE_USER > ROLE_GUEST
</beans:value>
</beans:property>
</beans:bean>
I am securing methods using protect-pointcut
<global-method-security secured-annotations="enabled" pre-post-annotations="enabled">
<protect-pointcut expression="execution(* my.package.*(..))"
access="ROLE_GUEST"/>
</global-method-security>
However, I got AccessDeniedException if I login with user that has authority ROLE_USER. I have no issue if I specified protect-pointcut with access="ROLE_GUEST,ROLE_USER".
Am I missing some steps? FYI, I am using Spring 3.0.5.
Thanks.
Don't forget to add a WebExpressionVoter to be able to also use expressions in http element:
<sec:http use-expressions="true" access-decision-manager-ref="accessDecisionManager">
<sec:intercept-url pattern="/index.html" access="hasRole('ROLE_AUTHENTICATED')" />
<sec:intercept-url pattern="/admin" access="hasRole('ROLE_SUPERVISOR')" />
...
So I end up with an accessDecisionManager containing a role hierarchy voter and a WebExpressionVoter, both using the same roleHierarchyImpl bean.
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<ref bean="roleHierarchyVoter" />
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler">
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
<property name="roleHierarchy" ref="roleHierarchy"/>
</bean>
</property>
</bean>
<bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>
</list>
</property>
</bean>
<bean id="roleHierarchyVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_SUPERVISOR > ROLE_XX
ROLE_XX > ROLE_AUTHENTICATED
ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED
</value>
</property>
</bean>
(spring sec 3.1)
The nested beans are slightly wrong in jgraglia example above, and you don't need <ref bean="roleHierarchyVoter" /> because the hierarchy is handled in WebExpressionVoter. I'm doing this in Spring Security 4.0.0, but the code looks the same except you don't need use-expressions="true" because it's on by default.
I usually try and nest my beans as much as possible, so my code has no ref="" values unless required.
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<constructor-arg>
<bean class="org.springframework.security.web.access.expression.WebExpressionVoter">
<property name="expressionHandler" ref="webExpressionHandler" />
</bean>
</constructor-arg>
</bean>
<bean id="webExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler">
<property name="roleHierarchy" ref="roleHierarchy"/>
</bean>
<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_USER
ROLE_USER > ROLE_ANONYMOUS
</value>
</property>
</bean>
Have a look at bug report SEC-1163 and the comment below.
If you want basic support for role hierarchies, then use a RoleHierarchyVoter, instead of a RoleVoter.
So you need somethink like:
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<list>
<ref bean="roleHierarchyVoter" />
<ref bean="authenticatedVoter" />
<ref bean="preAdviceVoter" />
<ref bean="mediaItemReadVoter" />
<ref bean="mediaItemWriteVoter" />
</list>
</property>
</bean>
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy"/>
</bean>

Resources