Angel Gonzalez Pena
Angel Gonzalez Pena

Reputation: 145

How to allow any other role in Spring Security?

How you would do an expression to permit access to all roles unless one, without declaring them all in spring-security.xml?

We have four roles: private, user1, user2 and user3. private is the only role that can execute certain services. The other are allowed only to user1, user2 and user3.

<http pattern="/priv/**">
    <intercept-url pattern="/**" access="hasRole('private')"/>
    <http-basic/>
</http>

<http pattern="/pub/**">
    <intercept-url pattern="/**" access="!hasRole('private')"/>
    <http-basic/>
</http>

I know that with this, the problem would be solved, but in the case of an user having private and user2 for example, this user should can execute the /priv/ and the /pub/ operation. How could the xml be configured? If the user has two roles (private and one more of the others), both operations would be allowed.

Upvotes: 1

Views: 247

Answers (2)

Ralph
Ralph

Reputation: 120831

You can implement an extension of WebSecurityExpressionRoot with a method boolean hasAnyRoleExcept(String... ignoredRoles)


sketch (written without IDE support):

import org.springframework.security.core.authority.AuthorityUtils;

public class MyWebSecurityExpressionRoot extends WebSecurityExpressionRoot {

   public MyWebSecurityExpressionRoot(final Authentication a, final FilterInvocation fi) {
      super(a, fi);
   }

   public boolean hasAnyRoleExcept(String... ignoredRoles) {
        //see SecurityExpressionRoot.hasAnyRole
        Set<String> roles = 
            AuthorityUtils.authorityListToSet(
               getAuthentication().getAuthorities());

        //find a not ignored role
        for (String role : roles) {
            if (!ignoredRoles.contains(role)) {
                return true;
            }
        }

        return false;
   }
}

To register it:

public class MyWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler {

    //Attention: override setTrustResolver too.
    private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

    @Override
    protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
        MyWebSecurityExpressionRoot root = new MyWebSecurityExpressionRoot(authentication, fi);
        root.setPermissionEvaluator(getPermissionEvaluator());
        root.setTrustResolver(trustResolver);
        root.setRoleHierarchy(getRoleHierarchy());
        return root;
    }
}
<security:http use-expressions="true" ...>
    ...

    <security:expression-handler ref="myWebSecurityExpressionHandler"/>

    <security:intercept-url pattern="/**" access="hasAnyRoleExcept('private')"/>
</security:http>

<bean id="myWebSecurityExpressionHandler" class="MyWebSecurityExpressionHandler"/>

Upvotes: 0

Marcus Hert da Coregio
Marcus Hert da Coregio

Reputation: 6308

You can make use of RoleHierarchy to simplify your security configuration.

<bean id="roleVoter" 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_PRIVATE > ROLE_USER
            ROLE_USER > ROLE_USER1 > ROLE_USER2 > ROLE_USER3
        </value>
    </property>
</bean>

And then in your http configuration:

<http pattern="/priv/**">
            <intercept-url pattern="/**" access="hasRole('PRIVATE')"/>
            <http-basic/>
 </http>

<http pattern="/pub/**">
            <intercept-url pattern="/**" access="hasRole('USER')"/>
            <http-basic/>
 </http>

This way your ROLE_USER will "embed" all other ROLE_USERX rules, and ROLE_PRIVATE will embed all from ROLE_USER.

You should also refer to the Spring Security Reference.

Upvotes: 0

Related Questions