ABAC Policy Language

Protect resources in a Java micro-service by policies

Bala Dutt
3 min readAug 11, 2021

Subject access to resources in a web application is controlled by reasoning over data, which include attributes of subject, resource, the action being performed and the environment in which it is performed. For example, if subject is manager of team, then subject may have access to all resources that individuals in team have. And this could apply transitively to manager of managers. A doctor may only access records of their patients in a hospital and no more. Similarly, some resources like bank account for transferring money may need strong authentication of subject compared to seeing other employee’s name or contact details in a company.

Each access decision needs to be made by executing a policy. This is called as Attribute-based access control (ABAC), also interchangeably known as policy-based access control. It defines an access control paradigm whereby access rights are granted to subjects through the use of policies which reason over attributes fetched from many sources. The policies can use any type of attributes (subject attributes, resource attributes, environment attributes etc.). Read more here — https://en.wikipedia.org/wiki/Attribute-based_access_control.

Embedding APL

ABAC Policy Language (APL) is a lightweight, performant language for writing authorization policies. It runs on JVM and can be embedded in your java based micro-service. You may embed this in your maven project easily by using,

<dependency>
<groupId>com.intuit.apl</groupId>
<artifactId>apl-core</artifactId>
<version>0.23</version>
</dependency>

You may check the source code and find more details at https://github.com/intuit/identity-authz-apl.

Authoring a policy

You may now author rules in a policy and externalise the policy from the business logic code.

rule: Doctor Patient Access
description: Allow doctor to access patient details
when:
- containsAnyIgnoreCase({"doctor"}, sub["role"])
- res["id"] == "PatientRecord"
- action["id"] == "read" || action["id"] == "update"
- res["doctorOfThePatient"] == sub["id"]
- env["skuOfTheProduct"] == "PLUS"
then:
- decision=permit

The rules are written as a set of conditions, which when all of them are true result in rule being fired. On firing the “then” section of rule is executed causing actions like decision being permitted.

Performance

These access decisions have to be made on every access. It is very important for these decisions to be made very quickly as they would add overhead to request execution time. Below are few of the features that help the language achieve this.

The policies are parsed and cached in data structures. The data structures ensure that a condition is at max evaluated only once even when the condition is present many times in many rules. This reduces number of conditions to be evaluated to only unique ones.

The execution also short circuits the process as it gets a decision. As soon as a rule fires giving a decision the process stops and returns back decision.

The engine is smart enough to monitor and learn the order of evaluation of conditions and rules to get decision fast. The engine collects data continuously and at configurable intervals reconfigures itself with a predicted best order of evaluation.

Other features

The language is designed for security/authorization. Unlike general purpose languages it is restrictive to only work on data provided to it. Yet, it is flexible to write complex conditions and actions. It is also fault tolerant and will run reliably in the event of any input giving a decision on every invocation.

References

--

--