3

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.

Lee Chee Kiam
  • 11,450
  • 10
  • 65
  • 87

3 Answers3

8

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)

jgraglia
  • 591
  • 6
  • 4
3

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>
Jim Richards
  • 708
  • 1
  • 7
  • 19
2

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>
Ralph
  • 118,862
  • 56
  • 287
  • 383
  • I see, by default an AffirmativeBased implementation is used for with a RoleVoter and an AuthenticatedVoter. http://static.springsource.org/spring-security/site/docs/3.0.x/reference/appendix-namespace.html – Lee Chee Kiam Oct 19 '11 at 12:55