This question is more about design patterns, dependency injection, than Spring. Security itself, I expect people without special Spring Security knowledge to understand this question.
In Introduction to Spring Security 3 / 3.1 , to check if the current user is allowed to perform an action on the target, Mike Wiesner implements a PermissionEvaluator . This bean is connected to the security configuration and is called in the method annotation before the action on the target continues.
The goal is to check whether the user is allowed or not to take any action for a particular object. It shows the following code (without explicit checks, for brevity, I suppose):
public class MyPermissionEvaluator implements PermissionEvaluator { @Override public boolean hasPermission(Authentication auth, Object target, Object perm) { if (target instanceof MyRequest) { //first class of target object... MyRequest req = (MyRequest) target; if (perm.equals("cancel")) { //action we wish to perform on the object return auth.getName().equals(req.getEmployee()); } else if (perm.equals("list")) { //another action return !hr.getEmployee().equals("rod") || auth.getName.equals("rod"); } } else if (target instanceof ...) { //second class of target object... ... } throw new UnsupportedOperationException("hasPermission not supported"); } }
He mentions that this implementation method is only suitable for small applications, but in practice it should be divided into several methods or classes. That was exactly what I was thinking:
- in a multi-module application, several modules may not know about each other
- we must apply the Open-Close principle (when adding a new module)
My question is: how would you solve the problem?
My job would be to have a global permissions evaluator and one permissions evaluator for each class of the target.
public interface TargetPermissionEvaluator extends PermissionEvaluator { Class getTargetClass(); //so we know for which target class we can use it } public class MyGlobalPermissionEvaluator implements PermissionEvaluator { @Autowired private List<TargetPermissionEvaluator> evaluators; @Override public boolean hasPermission(Authentication auth, Object target, Object perm) { for (MyEvaluator evaluator : evaluators) { if (target instanceof evaluator.getTargetClass()) { return evaluator.hasPermission(auth, target, perm); } } throw new UnsupportedOperationException("hasPermission not supported"); } }
The list of evaluators will be defined in the Spring XML configuration. What do you think? Is this a good way or do you have any ideas? Am I missing another suitable design template?