Issue Details (XML | Word | Printable)

Key: SEC-232
Type: Improvement Improvement
Status: Closed Closed
Resolution: Fixed
Priority: Major Major
Assignee: Luke Taylor
Reporter: Michael Mayr
Votes: 6
Watchers: 9
Operations

If you were logged in you would be able to see more operations.
Spring Security

Support hierarchical roles

Created: 19/Mar/06 05:10 PM   Updated: 19/Sep/07 05:13 PM
Component/s: Core
Affects Version/s: 1.0.0 RC1
Fix Version/s: 2.0.0 M1

Time Tracking:
Not Specified

File Attachments: 1. Zip Archive HierarchicalRoles-RELEASECANDIDATE1.zip (12 kB)
2. Zip Archive HierarchicalRoles-RELEASECANDIDATE2.zip (12 kB)
3. File HierarchicalRoles.odt (24 kB)
4. PDF File HierarchicalRoles.pdf (90 kB)
5. Zip Archive mm.zip (3 kB)
6. Zip Archive reworked.zip (5 kB)
7. Java Source File RoleGraphImpl.java (9 kB)

Environment: Windows XP, Tomcat 5.0.28, JSDK 1.4.2


 Description  « Hide
It would be great if Acegi would support hierarchical role models (e. g. like the SAP R/3 role model). This would make the access rule definitions more elegant and more powerful.

Consider the following example using Acegi's standard RoleVoter (background: every user that is logged in should be able to log out):

/logout.html=ROLE_ADMIN,ROLE_A,ROLE_B,ROLE_AUTHENTICATED

With HierarchicalRoleVoter this can now be shortened to:

/logout.html=ROLE_AUTHENTICATED

I'm attaching a prototype for supporting hierarchical roles (File: mm.zip) that contains a class for the easy definition of hierarchical role models and a cooperating class HierarchicalRoleVoter which can be used as drop-in replacement for Acegi's RoleVoter.

It would be configured like this:

<bean id="roleHierarchy" class="mm.roles.RoleHierarchy" >
<property name="rolePrefix">
<value>ROLE_</value>
</property>
<property name="roles">
<value>
ROLE_UNAUTHENTICATED
ROLE_AUTHENTICATED
ROLE_A
ROLE_B
ROLE_ADMIN
</value>
</property>
<property name="hierarchy">
<value>
ROLE_A > ROLE_B
ROLE_B > ROLE_AUTHENTICATED
ROLE_ADMIN > ROLE_AUTHENTICATED
ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED
</value>
</property>
</bean>

<bean id="roleVoter" class="mm.roles.HierarchicalRoleVoter" >
<property name="roleHierarchy">
<ref bean="roleHierarchy"/>
</property>
</bean>

Hint: Read the ">" character in the hierarchy definition as "includes".

Since Acegi's authz JSP taglib currently doesn't support hierarchical roles, you would need to write something like this:

<%@ page import="org.acegisecurity.Authentication" %>
<%@ page import="org.acegisecurity.context.SecurityContextHolder" %>
<%@ page import="org.springframework.web.context.support.WebApplicationContextUtils" %>
<%@ page import="mm.roles.RoleHierarchy" %>
 
<% RoleHierarchy roleHierarchy = (RoleHierarchy) WebApplicationContextUtils.getWebApplicationContext(getServletContext()).getBean("roleHierarchy"); %>
<% Authentication auth = SecurityContextHolder.getContext().getAuthentication(); %>

       <% if (roleHierarchy.userHasRole(auth, "ROLE_A")) {%>
You have ROLE_A!
<% } %>

 All   Comments   Work Log   Change History   FishEye   Builds      Sort Order: Ascending order - Click to sort in descending order
Michael Mayr added a comment - 19/Mar/06 05:13 PM
A prototype for supporting hierarchical role models

Michael Mayr added a comment - 30/Mar/06 03:30 PM
Hi all,

I'm currently reworking my implementation: The idea behind the new version is to wrap UserDetailsService and UserDetails so that UserDetails.getAuthorities() returns all reachable granted authorities by taking into concern the RoleHierarchy. The HierarchicalRoleVoter will be dropped. You will be able to use Acegi's standard RoleVoter and you will be able to use Acegi's Authz Taglib as they are now. So this alternative will offer the maximum of backwards compatibility. Stay tuned! More news to come soon...

Michael Mayr added a comment - 09/Apr/06 09:56 AM
As promised I reworked my prototype for maximum backward compatibility. It wraps around existing UserDetails and UserDetailsService. You use Acegi's standard RoleVoter and Acegi's standard taglib as you would normally.

It is configured like this:

<bean id="roleHierarchy" class="mm.hierarchicalroles.RoleHierarchyImpl" >
<property name="rolePrefix">
<value>ROLE_</value>
</property>
<property name="roles">
<value>
ROLE_UNAUTHENTICATED
ROLE_AUTHENTICATED
ROLE_A
ROLE_B
ROLE_ADMIN
</value>
</property>
<property name="hierarchy">
<value>
ROLE_A > ROLE_B
ROLE_B > ROLE_AUTHENTICATED
ROLE_ADMIN > ROLE_AUTHENTICATED
ROLE_AUTHENTICATED > ROLE_UNAUTHENTICATED
</value>
</property>
</bean>

<bean id="userDetailsServiceWrapper" class="mm.hierarchicalroles.UserDetailsServiceWrapper" >
<property name="roleHierarchy">
<ref bean="roleHierarchy"/>
</property>
<property name="userDetailsService">
<ref bean="userDetailsService"/>
</property>
</bean>

I would like to hear what you think.

Michael Mayr added a comment - 09/Apr/06 09:58 AM
The reworked prototype with maximum backward compatibility

Ben Alex added a comment - 24/Apr/06 07:45 AM
Looks an interesting new feature. I'll hold it until 1.0.1 because we're trying to reduce scope as far as possible so we can release 1.0.0 final. If I get time, I'll add it to 1.0.0.

Michael Mayr added a comment - 16/Jul/07 07:22 AM
Short Announcement that may be of interest for Acegi release 2.0: I will upload a production-quality implementation of hierarchical roles for Acegi including JavaDocs and JUnit tests by the end of this week. In addition to that I already implemented some other improvements like less required configuration and automatic detection of cycles in the definition of the role hierarchy. I will also write a short paragraph for the Acegi Reference Guide about hierarchical roles.

Michael Mayr added a comment - 22/Jul/07 06:48 PM
I have still some work to do on this issue. I expect it to be done in a few days.

Michael Mayr added a comment - 03/Sep/07 07:01 AM
As promised, here is the "release candidate" of my hierarchical role contribution:

Code improvements are:
- reviewed and improved code
- less required configuration
- automatic detection of cycles in the role hierarchy definition
- unit tests for everything
- updated JavaDocs
See the attached HierarchicalRoles-RELEASECANDIDATE1.zip for an archive of all the code including tests.

I also wrote a paragraph about hierarchical roles for the Acegi Reference Guide. See the attached HierarchicalRoles.pdf for the PDF version or the attached HierarchicalRoles.odt for the OpenOffice 2.x version.

I am interested to hear from you what you think about it.

P. S.: Sorry, that it took longer than expected but recently my job required A LOT of attention so that I didn't find time to finish that easily (I am sure you know this problem, too).

Jay Bertrand added a comment - 17/Sep/07 06:16 AM
Great job, works fine "as-is" for me :-) BTW, here's the RC-compatible definition for beans:

  <bean id="roleHierarchy" class="org.acegisecurity.userdetails.hierarchicalroles.RoleHierarchyImpl" >
    <property name="hierarchy">
      <value>
        ROLE_ADMIN > ROLE_USER
        ROLE_USER > ROLE_GUEST
        ROLE_GUEST > IS_AUTHENTICATED_FULLY
      </value>
    </property>
  </bean>

  <bean id="daoUserDetailsServiceWrapper" class="org.acegisecurity.userdetails.hierarchicalroles.UserDetailsServiceWrapper" >
    <property name="roleHierarchy" ref="roleHierarchy" />
    <property name="userDetailsService">
      <ref local="daoUserDetailsService"/>
    </property>
  </bean>

The new beans can be used with:

  <bean id="daoUserDetailsService" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
    <property name="userMap">
      <value>
        root=secret,ROLE_ADMIN
        guest=secret,ROLE_GUEST
      </value>
    </property>
  </bean>
  
  <bean id="daoAuthenticationProvider" class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    <property name="userDetailsService"><ref local="daoUserDetailsServiceWrapper"/></property>
  </bean>

Jay Bertrand added a comment - 17/Sep/07 08:39 AM
Well, I provide another implementation of RoleHierarchy that works with an acyclic graph. This means you can define roles with multiple inheritance such as (A > B, A > C, B > D, C > D). This can be used to group some roles together. However, be careful to graph definition that can lead to (very) complicated rules: USE WITH CARE.

Example of use: suppose you have a webapp with two modules, A and B, protected by ROLE_A and ROLE_B, both inheriting the ROLE_AUTHED role. You can now define a ROLE_ADMIN that inherits both ROLE_A and ROLE_B, and thus ROLE_AUTHED.

Access rules can be reduces to:

<bean id="filterInvocationInterceptor" class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
 <property name="objectDefinitionSource">
  <value>
   /logout.html=ROLE_AUTHED
   /module_a/*.html=ROLE_A
   /module_b/*.html=ROLE_B
   /admin/*.html=ROLE_ADMIN
 </value>
 ...
 </property>
</bean>

Hope this will help.
Regards.

Jay Bertrand added a comment - 17/Sep/07 08:39 AM
Acyclic graph implementation of RoleHierarchy.

Luke Taylor added a comment - 17/Sep/07 05:36 PM
Thanks! I've added your code to the main source tree. It looks like a nice contribution. I've made some changes to convert it to use JDK 1.4 regexes since we have dropped the ORO dependency for the 2.0 release. You might want to review those (the tests still seem to pass OK).

Michael Mayr added a comment - 19/Sep/07 04:17 PM
@Jay: Thanks for finding a bug in the cycle detection of RoleHierarchyImpl. Under some circumstances the code incorrectly detected a cycle where there was none like in your (perfectly fine) example (A > B, A > C, B > D, C > D). The rest of the code was ok. In the spirit of true Test Driven Programming I added tests for your example in RoleHierachyImplTests and then fixed the bug. The fix is straight forward and very small, it only involved fixing an if-condition. See my new attachment HierarchicalRoles-RELEASECANDIDATE2.zip for the fix and the added tests. Thanks for your help.

@Luke: Awesome, thanks for committing my code on trunk :-) Could you also commit my fix for RoleHierarchyImpl and the two additional tests (testComplexRoleHierarchy() and testNoCyclesInRoleHierarchy()) in RoleHierarchyImplTests, please? To simplify your diff I wrote the fix against your JDK 1.4 regexes trunk version. See my new attachment HierarchicalRoles-RELEASECANDIDATE2.zip for the fix in RoleHierarchyImpl and the added tests in RoleHierarchyImplTests (I did not touch the other files). Thanks in advance.

Cheers,
Michael

Luke Taylor added a comment - 19/Sep/07 05:13 PM
Ok. That's great. I've committed the latest changes (rev 2136). I'll close this issue now and people can raise more specific issues against the code as and if required.