Reputation: 36028
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
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