How to change Spring Security roles by context?
From your description, it sounds like the RBAC model that Spring Security gives you is not enough. You have 2 options available to you. Either:
- you customize Spring Security by implement your own Access Decision Manager (see here for details) or
- you move to attribute-based access control (aka ABAC as explained by NIST here). The way to use ABAC in Spring is to use a Java implementation of XACML, the eXtensible Access Control Markup Language. XACML gives you an externalized, policy and attribute-based authorization framework. This means you can define policies such as a user with the role=manager can do action=view in the category=foo. You can have as many rules as you like and combine / factor them accordingly.
There are several open-source and vendor implementations of XACML for Java:
- SunXACML
- HerasAF
- IBM
- Axiomatics (disclaimer: the vendor I work for)
If you want more information on XACML, I would recommend you check out its wikipedia page as well as our YouTube channel that has vendor-neutral tutorials.
XACML might turn out to be too much for your use case but it is still worth considering.
I think I'm little late here but this is what worked for me:
When a new category is selected, you can set a new Authentication object with new roles in your session(The previous authentication object gets invalidated). Something like this:
@RequestMapping(value = "/cat1")String cat1(HttpServletRequest request) { reloadRolesForAuthenticatedUser("cat1") ....}private void reloadRolesForAuthenticatedUser(String cat) { Authentication auth = SecurityContextHolder.getContext().getAuthentication() List<String> newRoles = getRoles(auth.getPrincipal().getUsername(), cat) List<GrantedAuthority> authorities = getAuthorities(newRoles) Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(),auth.getCredentials(),authorities) SecurityContextHolder.getContext().setAuthentication(newAuth)}private List<GrantedAuthority> getAuthorities(List<String> roles) { List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>() if (!roles.isEmpty()) { for (String r : roles) { auths.add(new SimpleGrantedAuthority(r)) } } return auths}
I don't know how your "categories" work, but you can set a "ROLE" to UserDetails
object.
The UserDetails
object has Collection<? extends GrantedAuthority> getAuthorities();
method and "ROLE" is value of GrantedAuthority.getAuthority()
.
So you can set multiple "ROLE"s to single session.
And You can control your UserDetails
object by implement UserDetailsService
.