Just want to describe my solution to this problem, which may be useful to someone. I feel this may not be optimal, so still open to any suggestions on cleaner implementation.
Assuming I need to secure the following actions:
- activity:edit
- activity:view
And I also need to make sure that permissions are not system wide, but depends on my role in particular department. What I did is explicitly added 'department-dependant' permission for user in my Realm. Example (see hierarchy in the post):
- DEP_A:activity:view
- DEP_C:activity:view
- DEP_C:activity:edit
Each time I want to check if action against some activity is allowed or not, I'm creating a list of permissions to check. Example:
Activity A belongs to Department D, I want to 'view' it. Permissions to check will be:
- DEP_D:activity:view
- DEP_C:activity:view
- DEP_B:activity:view
If I'm Admin in department C, I would have 'DEP_C:activity:view' permission and hence the check will be passed. Thats allows to implement rights inheritance in company structure hierarchy.
Here is the code snipplet from my service class responsible for permission checks:
@Override
public void checkIfOperationPermitted( SecurityOperation operation,
Object object )
{
final Subject currentUser = SecurityUtils.getSubject();
if(currentUser.isPermitted(
SecurityOperation.SYSTEM_ADMIN.getPermissionString()) ||
currentUser.hasRole( "admin" ))
{
// no need to check anything else,
// admin is system wide role.
return;
}
if(object instanceof Activity)
{
// Activity permissions fully depends on organization and
// product hierarchies. PermissionResolver is just a class
// which generates list of permission strings based on
// department activity is belonging to.
Activity a = (Activity) object;
List<String> permissionsToCheck =
permissionResolver.resolveHierarchicalPermissions(operation, a);
boolean permitted = false;
for(String permission: permissionsToCheck)
{
if(currentUser.isPermitted( permission ))
{
permitted = true;
break;
}
}
if(!permitted)
{
throw new UnauthorizedException( "Access denied" );
}
}
else
{
// Check for system wide permissions
currentUser.checkPermission( operation.getPermissionString() );
}
}
Another way I was thinking about is add all such permissions for user in my Realm, but declined this since company hierarchy can in general contain N tiers - which greatly increases duplication in permissions list for particular user (memory usage).