hguser
hguser

Reputation: 36028

how to control the user authentication using spring mvc

I am using spring mvc3 to build a user-manager system.

This system conain the following models:

Department
User

And the Departments have the hierarchic structure,for example:

Dep1
  SubDep1
  SubDep2
    Sub_sub_dep1
    xxxx

One can add/update/delete departments/users if he is authenciationed,but he can only do these operation within his department and the sub-departmens.

For example,there are three departments(with there users):

Dep01(user1:{id:1}}
  Dep0101(user2:{id:2}
  Dep0102(user3:{id:3}
    Dep010201(user4:{id:4}

So user1 can do the /add/upate/delete all the users(user1,user2,user3,user4)

While user3 can only do the operation for user(user3,user4).

I can control that the user3 can not see the user1 and user2 in the department/list page.

But how about if he enter the url like this:

department/update/1

This has to be avoided since the user1(whose id is 1) does not belong to Dep0102 or Dep010201.

How to controll this?

Upvotes: 1

Views: 775

Answers (1)

jcurtin
jcurtin

Reputation: 364

One option is to create a custom Spring Security PermissionEvaluator and implement your custom checks in the hasPermission(Authentication authentication, Object targetDomainObject, Object permission) method.

The signature of the method to protect ends up looking like this:

@PreAuthorize("hasRole('ROLE_USER') and hasPermission(#_dept, 'deptAndSubs')")
public String methodToProtect(String _dept)throws Exception    {
        <custom code>;
    }

The first argument to the hasPermission expression is the department that the user wants to modify and the second is the permission. For us the deptAndSubs permission indicates that the user can execute the method only if the department being modified is equal to the users assigned department or any of the sub departments of that department (other permissions are 'deptOnly' and 'subsOnly').

In our application we have a custom Spring Security UserDetails object that includes the user department code so we can get the logged in user's department directly from the Authentication object that Spring passes into the method. Here's what the custom evaluator finally ends up looking like:

    public class CustomPermissionEvaluator implements PermissionEvaluator {
           @Override
           public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
            AppUser appUser = (AppUser)authentication.getPrincipal();
            if(permission instanceof String){
                if("deptAndSubs".equals(permission)){
                    return isTargetDeptInUserDeptTree((String)targetDomainObject, appUser.getDeptCode());
                }else if(.... other permission checks){}
            }
            return false;
        }

The method isTargetDeptInUserDeptTree is custom code to extract the user's department tree and verify that the target department is in it.

Finally you have to set up your xml configuration:

<global-method-security pre-post-annotations="enabled" >
    <expression-handler ref="expressionHandler"/>
</global-method-security>

<beans:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
    <beans:property name="permissionEvaluator" ref="customPermissionEvaluator"/>
</beans:bean>

<beans:bean id="customPermissionEvaluator" class="....CustomPermissionEvaluator"/>

Good luck!

Upvotes: 3

Related Questions