Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Hierarchical Roles in Spring Security

I am trying to implement Hierarchical roles in Spring security and added the following configuration in my xml files as per spring source documentation.

<bean id="roleHierarchy" class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
    <property name="hierarchy">
        <value>
            ROLE_ADMIN > ROLE_PRO
            ROLE_PRO > ROLE_PREMIUM
            ROLE_PREMIUM > ROLE_BASIC
            ROLE_BASIC > ROLE_ANONYMOUS
        </value>
    </property>
</bean>

 <bean id="roleVoter"
        class="org.springframework.security.access.vote.RoleHierarchyVoter">
         <constructor-arg ref="roleHierarchy"/>
</bean>

I have tried with above lines but I am getting Access Denial while ROLE_ADMIN trying to access the url assigned to ROLE_BASIC. Do I need to add anything more than this. I found nothing other than those lines in Spring site. Also, If you know of any good implementation of Hierarchical roles, please do mention them.

like image 245
Jeevan Mysore Avatar asked Mar 24 '14 13:03

Jeevan Mysore


2 Answers

I think you need to register the roleVoter at the accessDecisionManager. @See this answer for an example.


But to be honest, I doubt the Spring Hierarchical Voter concept, because you need to add a special hierarchical voter everywhere. I personally prefer an other way: I have implemented an custom JdbcDaoImpl that overrides the addCustomAuthorities and add "normal" Roles to the "existing" once.

/**
 * Extension of {@link JdbcDaoImpl} User Detail Provider, so that is uses the
 * {@link PrivilegesService} to extend the provided Authorities.
 *
 */
public class JdbcDaoPrivilegesImpl extends JdbcDaoImpl {

    private PrivilegesService privilegesService;

    public JdbcDaoPrivilegesImpl(final PrivilegesService privilegesService) {        
        this.privilegesService = privilegesService;
    }

    @Override
    protected void addCustomAuthorities(String username, List<GrantedAuthority> authorities) {
        super.addCustomAuthorities(username, authorities);         

        List<GrantedAuthority> privileges = new ArrayList<GrantedAuthority>();
        for (GrantedAuthority role : authorities) {
            privileges.addAll(privilegesService.getPrivilegesForRole(role));
        }
        authorities.addAll(privileges);    
    }
}


public interface PrivilegesService {

     Collection<? extends GrantedAuthority> getPrivilegesForRole(GrantedAuthority role);
}


public class PropertyPrivilegesServiceImpl implements PrivilegesService {

    /**
     * Property bases mapping of roles to privileges.
     * Every role is one line, the privileges are comma separated.
     */
    private Properties roleToPrivileges;

    public PropertyPrivilegesServiceImpl(Properties roleToPrivileges) {
        if (roleToPrivileges == null) {
            throw new IllegalArgumentException("roleToPrivileges must not be null");
        }
        this.roleToPrivileges = roleToPrivileges;
    }

    @Override
    public Collection<? extends GrantedAuthority> getPrivilegesForRole(GrantedAuthority role) {
        if (roleToPrivileges == null) {
            throw new IllegalArgumentException("role must not be null");
        }

        String authority = role.getAuthority();
        if(authority != null) {
            String commaSeparatedPrivileges = roleToPrivileges.getProperty(role.getAuthority());
            if (commaSeparatedPrivileges != null) {
                List<GrantedAuthority> privileges = new ArrayList<GrantedAuthority>();
                for(String privilegeName : StringUtils.commaDelimitedListToSet(commaSeparatedPrivileges)) {
                    privileges.add(new GrantedAuthorityImpl(privilegeName.trim()));
                }                
                return privileges;
            } else {
                return Collections.emptyList();
            }
        } else {
            return Collections.emptyList();
        }
    }
}

Example config

  <bean id="myUserDetailsService" class="JdbcDaoForUpdatableUsernames">
    <constructor-arg ref="propertyPrivilegesService"/>
    <property name="dataSource" ref="dataSource"/>
    <property name="usersByUsernameQuery" value="SELECT login,encryptedPassword,loginEnabled FROM user WHERE login = ?"/>
    <property name="enableAuthorities" value="true"/>
    <property name="authoritiesByUsernameQuery" value="SELECT u.login, r.securityRoles FROM user u, user2security_roles r WHERE u.login= ? AND u.id = r. User_fk;"/>
</bean>

 <bean id="propertyPrivilegesService" class="PropertyPrivilegesServiceImpl">
    <constructor-arg>
        <props>
            <prop key="ROLE_ADMIN">
                ROLE_PREMIUM,
                ROLE_BASIC
            </prop>
            <prop key="ROLE_PREMIUM">
                RROLE_BASIC
            </prop>
        </props>
    </constructor-arg>
</bean>
like image 84
Ralph Avatar answered Sep 20 '22 08:09

Ralph


Try by adding this to spring-security.xml:

<http auto-config="true" use-expressions="true" access-decision-manager-ref="accessDecisionManager">


<beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
    <beans:constructor-arg>
        <beans:list>
            <beans:ref bean="roleVoter" />
        </beans:list>
    </beans:constructor-arg>
</beans:bean>
like image 22
zygimantus Avatar answered Sep 21 '22 08:09

zygimantus