Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to change Spring Security roles by context?

I want to know if its possible to set roles based on a selected category. In our app there are categories which contain articles. Now we have a role hierarchy like this: ROLE_ADMIN > ROLE_EDITOR > ROLE_USER. The problem is that a user might have different roles based on the currently selected category:

user1 - cat1 - ROLE_USER

user1 - cat2 - ROLE_EDITOR

The categories are not static. New ones can be added and older deleted. Is it possible to achieve this using Spring Security?

like image 507
Stefan Avatar asked Nov 28 '13 15:11

Stefan


2 Answers

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:

  1. you customize Spring Security by implement your own Access Decision Manager (see here for details) or
  2. 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.

like image 161
David Brossard Avatar answered Oct 22 '22 04:10

David Brossard


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
}
like image 28
Rodrigo Villalba Zayas Avatar answered Oct 22 '22 04:10

Rodrigo Villalba Zayas