Spring Security customization (Part 1 – Customizing UserDetails or extending GrantedAuthority)

This is the first part of what I hope will become a multipart series of small posts showing practical examples around Spring Security customization. The requirements for these customizations are not imaginary and all came from the field. . .
Assume you have the following requirement. You have a list of roles where each role contains list of business functions applicable to this role (see below):
ROLE_ADMIN
BF_QUOTE_CREATE
BF_POLICY_CREATE
BF_POLICY_DELETE
ROLE_AGENT
BF_QUOTE_CREATE
BF_POLICY_CREATE
ROLE_USER
BF_QUOTE_CREATE
The trick is to be able to make authorization decisions based on either.
For example:
User who has a role ROLE_ADMIN should be given access to any resource protected by this role.
<p><a href="http://www.google.com">Google</a>
</sec:authorize>
or
public void foo()
. . .
}
The same user should be given access to any resource protected by the corresponding business function.
<p><a href="http://www.google.com">Google</a>
</sec:authorize>
or
public void foo()
. . .
}
There are actually several ways for handling this requirement. One of them would be to create a RoleHierarchy and use RoleHierarchyVoter to traverse hierarchy of roles. The downside of this approach is that in the current implementation of Spring Security 2.0.4, taglibs (security: authorize . . . ) do not go through AccessDecisionManager to make a decision, thus no Voters are playing any role while making decisions about protecting HTML elements. However given the amazing flexibility and customization power of Spring Security, accomplishing this requirement is still quite simple.
One of the biggest benefits of Spring Security is customizations around how Principal (UserDetails object) is created. When UserDetails object is created it is populated with the list of GrantedAuthorities. This list is later inspected to match against GrantedAuthority protecting a resource.
One of the customization we can do is to customize the list of GrantedAuthorities during the creation of UserDetails object.
In the supplied example there are two property files (for simplification I am using property files, however you can easily modify it to use DB or LDAP).
One file users.properties maps user to roles
while the other one role-to-bf.properties maps roles to the list of business functions
Our goal is to create a UserDetails object which contains a list of GrantedAuthorities representing both roles and business functions.
For example: for the user oleg the list of GrantedAuthorities should be:
So all we need is define a custom implementation of UserDetailsService where by using both property files (could be DB or LDAP in real life) we will create custom list of GrantedAuthorities and then inject them into the final UserDetails object. This is quite simple and we can reuse the existing implementation of GrantedAuthority interface such as GrantedAuthorityImpl. However, we also want to make sure that we can trace (for debugging or any other purpose) the parent GrantedAuthority for each GrantedAuthority that represents a business function.
In order to accomplish both of these goals we will extend GrantedAuthorityImpl by defining a BusinessFunctionGrantedAuthority class which simply contains a list of all parent GrantedAuthority objects which define such business function.
private List<GrantedAuthority> parentAuthorities;
. . .
}
Then we will create a custom implementation of UserDetailsService and implement loadUserByName(..) method where we will perform the following:
1. Create UserAttribute object based on contents of users.properties file. UserAttribute will contain the list of GrantedAuthorities representing roles.
2. Iterate through the list of role-GratedAuthorities and for each role-GrantedAuthority create a BusinessFunctionGrantedAuthority and add it to the overall list of already created GrantedAuthorities
2.1 Add parent GrantedAuthority to each BusinessFunctionGrantedAuthority
3. Create final UserDetails object which contains the full list of GrantedAuthorities.
Then define your AuthenticationProvider in you Spring Security configuration:
NOTE: we are injecting AuthenticationProvider with custom UserDetailsService implemented by ComplexAuthorityUserDetailsService class.(see sample code for more details)
Secure your resources, deploy and access application: http://localhost:8080/spring-security-sample-grantedAuthority/index.jsp
After Logging on you should see the list of GrantedAuthorities being displayed along with other properties of the Principal:
You can clearly see that GrantedAuthority representing business function also shows the list of parent GratedAuthorities defining such business function.
Inspect index.jsp and observe how security:authorize tag is using both roles and business functions to protect HTML elements
That is all. You can clearly see how with few minor customizations you can easily extend and customize the structure of the Principal and apply declarative protection based on custom GrantedAuthorities without polluting your business code with custom security code.
Sample code could be downloaded here: spring-security-sample-grantedauthority
Similar Posts
- Spring Security customization (Part 2 – Adjusting secured session in real time)
- dm Server 2.0.0.M5
- Behind the Spring Security Namespace
- What's New in Spring Security 2?
- Spring Security 3.0.0.M1 Released













Jochen Szostek says:
Added on January 2nd, 2009 at 7:39 pmThanks for the interesting article!
Will try to implement spring security in my webapp next week so might be quite useful.
Greets,
Jochen
Oleg Zhurakousky (blog author) says:
Added on January 2nd, 2009 at 7:57 pmGlad to hear that
Oleg
Senthil says:
Added on January 7th, 2009 at 12:30 amNice article
But it would have been great if u would explained the basic flow of Spring security… instead directly going to UserDetailsService.
Might be start with SecurityContextHolder -> SecurityContext -> Authentication -> AuthenticationManager -> Provider -> Service & then UserDetails
Thanks,
Senthil
Oleg Zhurakousky (blog author) says:
Added on January 8th, 2009 at 1:22 amAlthough this post assumed that reader has some basic understanding of Spring Security, I hear your point
I'll try to find some time to do it. . .
Do you have any specific problem you are experiencing?
Senthil says:
Added on January 8th, 2009 at 12:02 pmThanks. No, as of now… I don't have any problem. It would be really good for others if it starts from scratch.
-Senthil
PR says:
Added on February 5th, 2009 at 11:02 amHello,
Thanks for the article. Would appreciate if you could provide an example with LDAP. We are in the process of implementing a solution for our application.
Thanks
Bousselham Salmi says:
Added on April 16th, 2009 at 8:38 amHi,
Thanks for both articles. Would appreciate if you provide an example using database tables instead properties files.
Thanks!
john says:
Added on May 4th, 2009 at 6:44 pmCould you please help me with with configuring my IDE so that I can use 2.5 MVC framework and Security. I'm using NetBnz 6.5. I have the 2.5 framework, but it doesn't have the security .jars included. I downloaded the security .zip file, but I don't know what to do with it. Can I even use NetBnz to implement my apps? I would really appreciate it if you could help me out. Maybe I need to use a different IDE? Thank you very much.
Anand says:
Added on June 4th, 2009 at 9:29 amWhy I'm not able to do following
Anand says:
Added on June 4th, 2009 at 9:30 amintercept-url pattern="/index.htm*" access="ROLE_ADMIN" /
Vishal says:
Added on July 14th, 2009 at 8:53 amI have little different scenario.
– In my the case password stored in DB is in encrypted form.
– I have implemented 'UserDetailsService' so I need to give the implementation of loadUserByUsername(String username) method. But in this method, we get only the username that user has entered on login page. How can I get the password?
If somehow I get the password then I will encrypt the password and pass it to User (org.springframework.security.userdetails.User) Object.
gio2375 says:
Added on July 17th, 2009 at 10:16 amGreat article Thanks very much. You saved me a lot of time.
I've to do a little modify to make it working… Spring in security tags take account of only strings that start with "ROLE" and then our Businness functions that starts with "BF" are ignored.
To avoid this I've set rolePrefix to "".
That's the code:
Giovanni
Felix says:
Added on September 16th, 2009 at 4:31 ami hope you can help me with my problem or point me to where i can. im new to implementing spring and spring security
our security requirement goes like this. once a user logs into the application we will do a check to see if he has more than 1 role. if the user has more than 1 role we will show a page of the roles that the user has and ask the user to select the role that he wanted for that session.
i already created a subclass of the userdetails object and when the user selected the role i will modify the user object setAuthorities.
when doing this:
User user = (User) authentication.getPrincipal();
GrantedAuthority[] grarray=user.getAuthorities();
it is returning the updated Authorities but when doing this on the JSP page:
the "remove role" role not selected is still being seen which im expecthing should not since it is not in the userdetails anymore…
i hope you could help me. thanks a lot in advance.
Venu says:
Added on March 9th, 2010 at 2:56 amCan any one explain about "SwitchUser feature of Spring Security" in Spring3.0.x ?
Can you suggest me any online tutorials about "SwitchUser feature of Spring Security" in Spring3.0.x ?
Thanks In Advance
Thanks && Regards
Venu.K