|
Important
|
Work in progress
TODO:
|
This project is a simple implementation of an authorization mechanism. It can be named an Attribute Based Authorization Control (ABAC) or simply a Policy Rule Based Authorization.
This is not a fancy enterprise level, distributed and centralised authorisation mechanism. It is a simple-to-use framework as it should be any other.
The story is that while I was looking for an authorization implementation, I’ve found RBAC (Role Based Authorization Control). That was somewhere on 2009/2010. At that time, RBAC was already a standard (NIST RBAC).
At that time, Spring Security was a mess. An implementation of Access Control Lists (ACL) following no standards.
If I mentioned ACLs, the rbac standard follows the capability lists approach of implementing the Lampson’s access control matrix. RBAC comes with multiple optional levels of functionality (RBAC0 to RBAC3).
In the years that followed, I’ve implemented the RBAC model on multiple project. I’ve implemented only RBAC0, but with the addition of "dynamic evaluation of permissions". That means that in order to avoid the role "explosion", the permissions are evaluated at runtime based on user’s and resource attributes.
We cannot create a role for each combination of user and resource attributes. For example a access rule can be: "User can READ patient’s records if it is a doctor, the patient have an appointment to the doctor and can only access records related to the medicine branch that the doctor is part of. But this only during the working hours of the doctor." This can be done, of course, only if we evaluate the rule at runtime based of the attributes of the doctor, of the user and of the medical records.
Here I need to mention to be aware what represents security concerns and what is business flow.
However, after some implementation of RBAC0 + "Dynamic Permissions", I’ve realised that there is no real need for roles. And if we name these permissions "Policy Rules", there is a simple implementation of what it supposed to be ABAC. I’ve once implemented a Domain Specific Language for such Policy Rules, but is just simpler to implement them in Java.
I’ve found very disappointing that NIST ABAC (Attribute-Based Access Control) is very complicated (ine the book Attribute-Based Access Control from Amazon. I guess that the reason to be so complicated it is to be able to answer to the two questions:
-
On what resources user X has access?
-
What users can access resource Y?
Well, this framework cannot answer to neither one. RBAC can answer to the first question (and not the second).
To keep things simple and to contradict Nassim Taleb who wrote on Antifragile that "Technothinkers love precision at the expense of applicability", there are no negative permissions or better said: policy rules cannot explicitly deny access. This is in concordance with NIST RBAC. The poly rule can permit something or just withold his vote. And also there are no roles. Because I didn’t find any real use of roles when using attribute-based authorization.
-
user - user that performs an action
-
permission - a protected resource and an action to be conducted on that resource
-
protected resource - an object that is the subject of a user’s action.
-
action - action to be conducted against a protected resource (READ/WRITE etc.).
-
-
subject - computer process acting on behalf of a user
-
policy rule - a piece of code that permit or not the permission that the user is trying to obtain.
To better understand the framework here is an example. Let’s take the previous one:
"User can READ patient’s records if it is a doctor, the patient have an appointment to the doctor and can only access records related to the medicine branch that the doctor is part of. But this only during the working hours of the doctor."
The implementations used in the code are from protego-basic.
Init the framework:
PolicyRulesProvider policyRulesProvider = new BasicPolicyRuleProvider();
PolicyEvaluator.registerProviders(policyRulesProvider);Store the authenticated user:
private static final ScopedValue<User> AUTHENTICATED_USER = ScopedValue.newInstance();
...
User authenticatedUser = authenticate(credentials);
ScopedValue.where(AUTHENTICATED_USER, authenticatedUser).run(() -> service.processRequest(pacientRecord));Test the access:
AllowSameBranchPermission allowSameBranchPermission = new AllowSameBranchPermission(READ, somePacientRecord);
PolicyEvaluator.evaluatePermission(allowSameBranchPermission);The permission:
public class AllowSameBranchPermission<CrudAction, PacientRecord> extends Permission {
public AllowSameBranchPermission(PacientRecord protectedResource, CrudAction action) {
super(protectedResource, action);
}
}And the policy rule:
public class AllowSameBranchPolicyRule implements PolicyRule {
@Override
public boolean hasPermission(Permission permission) {
if (!(permission instanceof AllowSameBranchPermission)) {
return false;
}
//the doctor is the subject
User authenticatedUser = AUTHENTICATED_USER.get();
if (!authenticatedUser.isDoctor()) {
return false;
}
// only read is allowed
if (permission.getAction() != CrudAction.READ) {
return false;
}
// has an appointment today
if (!permission.getProtectedResource().getOwner().hasAppointemnt(authenticatedUser, LocalDate.now())) {
return false;
}
//the medical record belongs to the same medicine branch
if (authenticatedUser.asDoctor().getSpeciality() != permission.getProtectedResource().getSpeciality()) {
return false;
}
//the doctor is at work
if (!authenticatedUser.getTodaysWorkingHoursInterval().includes(Instant.now())) {
return false;
}
return true;
}
}|
Important
|
Vulnerability aspects
I can identify two:
|
This project is licensed under the MIT License - see the License.adoc file for details.