Overview

Clear Entitlement leverages the Extensible Access Control Markup Language (XACML) architecture as its foundation, extending it with developer-friendly APIs to provide powerful access control capabilities.
The high-level architectural diagram below illustrates the key components and interactions within the Clear Entitlement system.



Clear Entitlement supports only Permit and Deny decisions and applies the 'Deny-overrides' combining algorithm. In other words, if any decision evaluates to Deny, or if no decision evaluates to Permit, then the overall result is Deny. Conversely, if all decisions evaluate to Permit, the overall result is Permit.


As a further resource, you may find valuable insights on Extensible Access Control Markup Language (XACML) and Next Generation Access Control (NGAC).

Policy Guide

Policy Record

An application can have multiple versions of policies, but only one version is deployed and active at any given time.
An application's policy typically consists of multiple policy records, each containing seven parts



- Type
Permit or Deny.
Clear Entitlement evaluates "Deny" policies first; if a decision can be reached, it won't process "Permit" policies.

- Resource
The target of the policy, e.g., domesticPayment—think of this as the resource in a RESTful API.
For convenience, multiple resources can be added to a single record; each line represents a different resource.

Clear Entitlement supports two types of resources: path pattern match and exact match. When a resource string starts with "/", it is a path pattern:
? matches one character
* matches zero or more characters within a path segment
** matches zero or more path segments until the end of the path
{spring} matches a path segment and captures it as a variable named "spring"
{spring:[a-z]+} matches the regexp [a-z]+ against a path segment and captures it a path variable named "spring"
{*spring} matches zero or more path segments until the end of the path and captures it as a variable named "spring"
For example, "/user/{uid}" matches any string starting with "/user/", and the remaining part is matched to {uid}. To reference the value in the condition, use "resource.uid" in this case. For more details, please check the Spring document

When the resource string doesn't start with "/", it is an exact match.
Also, for exact match resources, they form trees, with the delimiter being "/". For example, if we define two resources as "payment/domesticPayment" and "payment/internationalPayment", the resource tree is structured as follows:

              payment -> domesticPayment
                     |
                      -> internationalPayment
                    
The policies defined for ancestor nodes in the tree apply to all descendant nodes. In the above example, the policies with resource="payment" will be evaluated if the request is for "payment/domesticPayment" or "payment/internationalPayment"

- Action
The action on the resource, such as create, read, update, delete, etc., akin to the method in REST.
For convenience, multiple actions can be added to a single record, with each line representing a different action.


- Subject
Can consist of users, groups, or roles, or a combination of them.
For convenience, multiple subjects can be added to a single record, with each line representing a different subject.

For users, use the subject format user/{username}, for example, user/johnf, or user/jonhf@clearentitlement.com if email is used as the username.
For groups, use the subject format group/{group name}, for example, group/sales.
For application roles, use the subject format appRole/{role name}, for example, appRole/paymentChecker.
or global roles, use the subject format role/{role name}, for example, role/admin.

There are three special subjects: everyUser, everyGroup, and everyRole.
"everyUser" can be used if the policy applies to every user.
"everyGroup" matches only if the current user belongs to at least one group. Additionally, if there are group attributes in the condition, those attributes are specific to the current group being evaluated. If no decision can be reached based on the current group, the evaluation continues with the next group.
"everyRole" matches only if the current user has at least one role. Similarly, if there are role or role membership attributes in the condition, those attributes pertain to the current role being evaluated. If no decision can be reached based on the current role, the evaluation continues with the next role.


- Condition
Specifies the condition for the access APIs, providing the complete criteria for granting access. Refer to the grammar section for details on how to write the condition.

- Functional Condition
Refers to the condition for functional access, distinct from the full access check. For instance, when verifying permission for making a payment, the full condition may entail checking account details, amounts, etc. However, to decide whether to display a "payment" menu item, only the role may need to be verified.

- Obligation:
This is the instruction/data returned from the API for the client to act on. Clear Entitlement uses this for data redaction/filtering.

Obligations are in the format of name=value, and multiple obligations can be set up in one policy record, one line each.
The value of the obligation can be any format agreed upon between the client and policy, such as string, JSON, XML, etc. To reference attributes (the same attribute in the condition), use ${attribute.name}$, for example:
accounts=$roleAtts.accountAndLimit.account$
restrictions=$roleAtts.accountAndLimit$
Note: roleAtts is a built-in attribute that refers to the membership attribute for the current role.
Sample response:
                {
                  "granted": true,
                  "filterObject": {
                       "restrictions": [
                            [
                                 {
                                      "account": "8744336085399580",
                                      "maxAmount": 1200
                                 },
                                 {
                                      "account": "70048841700216300",
                                      "maxAmount": 2000
                                 },
                                 {
                                      "account": "12494980148173100",
                                      "maxAmount": 1000
                                 },
                                 {
                                      "account": "3690859741294280",
                                      "maxAmount": 1500
                                 }
                            ]
                       ],
                       "accounts": [
                            [
                                 "3690859741294280",
                                 "12494980148173100",
                                 "8744336085399580",
                                 "70048841700216300"
                            ]
                       ]
                  }
             }
             

Attribute Based Access Control (ABAC)

Clear Entitlement offers ABAC support for various data entities, and each has a built-in attribute retriever to fetch (and cache) the values.

User attribute: To reference user attributes, use user.{attributeName} Group attribute: group.{attributeName}
Role attribute: role.{attributeName}
Entitlement attribute: entitlement.{attributeName}
User-role membership attribute: roleAtts.{attributeName}
Group-role membership attribute: roleAtts.{attributeName}

Sample conditions:
"user.department in ('sales', 'IT')"
"ifAny(roleAtts.accountAndLimit, 'payload.account=.amount and payload.amount<=.amount')"

Note: "ifAny" is a built-in function to iterate through multi-value attributes, in this case, roleAtts.accountAndLimit, and see if any value can satisfy the condition.

Other built-in attributes:
username: the username.
resource: the resource in the request.
action: the action in the request.
resource.{attributeName}: the resource section when the resource is in path pattern resource.
context.{attributeName}: the object passed from the request's context.
userId: the user ID of the subject. Note, not the username.
orgId: the org ID, for multi-tenant deployments.
roleId: the role ID of the current subject if the subject is a role.
groupId: the group ID of the current subject if the subject is a group.
Customers can build their attribute retriever to fetch any value from an external data source. For details, check the developer's guide.

Functions

Clear Entitlement provides built-in functions that can be used in conditions:

now(): Returns the current date and time.
countMatchedValue(attributes, regex): Returns the number of items in attributes (a multi-value string list) that match the regex.
ifAny(attributes, condition): Checks if any item in attributes (a multi-value object list) evaluates to true based on the condition. Use .{attributeName} to reference the attributes of the current item in the iteration.
ifAll(attributes, condition): Checks if all items in attributes (a multi-value object list) evaluate to true based on the condition. Use .{attributeName} to reference the attributes of the current item in the iteration.
toJson(string): Converts a string to a JSON object.

Customers can build their own functions; for details, check the developer's guide.

Condition Grammar

Clear Entitlement's condition grammar is straightforward, making it easy for anyone familiar with programming to write conditions.
In essence, the condition consists of one or more condition units connected by "and", "or", or "not" operators.
Operator precedence follows the order: not > and > or. To alter precedence, use parentheses ().
Each condition unit takes the form "operand" or "operand1 operator operand2", where the operand can be a literal, attribute, or function.

If the condition unit is a single "operand", its result must be a boolean type.

- Operators

=: equal.
!=: not equal.
≪: less than.
<=: less than or equal.
>: greater than.
>=: greater than or equal.
in: checks if a single value is in a list of values.
not_in: checks if a value is not in a list of values.
start_with: checks if a string starts with another string.
not_start_with: checks if a string doesn't start with another string.
contain: checks if a string contains another string.
not_contain: checks if a string doesn't contain another string.
match: checks if a string matches a regular expression.
not_match: checks if a string doesn't match a regular expression.

- Literal

Number: Can be an integer or decimal, such as 100 or 9.5.
String: Enclosed in either single or double quotes, for example, "abc", 'abc', "John's account", or '"some quoted value"'.
Boolean: Represented as true or false, without quotes.
NULL: Indicates a non-existent value, represented as null, without quotes.
ANY: Indicates any value, represented as any, without quotes.
Date: Represented in the format mm/dd/yyyy or mm/dd/yyyy hh:mm:ss, such as 03/20/2024 or 03/20/2024 05:03:20.
Time: Represented in the format hh:mm:ss, for example, 05:03:20.

- Attribute

Attribute names can include letters, numbers, "_", "$", ".", and "[]". They cannot start with a number.
"." is used as a delimiter to indicate a child attribute when the attribute name is a constant. If the attribute name is a variable, use [].

Examples:
userId
user.department
.account
org[orgId].primaryContactEmail

Plugins


Clear Entitlement offers a variety of built-in attribute retrievers, and customers can also add their own by integrating Java code into the Java class path.

                  public class YourAttributeRetriever extends AttributeRetrieverBase implements AttributeRetriever {
                       public Object execute(String name, EvaluationContext evaluationContext) {
                          ...
                          return value.
                       }
                  } 

In the above code snippet, "name" represents the attribute name, and "evaluationContext" provides all the contextual data required. This context can also be utilized for caching data within the scope of a single evaluation.
For instance, if the attribute retriever queries a database and retrieves multiple attributes, it can cache them in the context. When other attributes are referenced, the retriever can first check the cache in the context. If there's no match, it can then query the database.

The configuration for adding these retrievers is done in the app.cfg file:
condition.attributeRetriever.*.{you attribute name}={Full class name with package}
The asterisk (*) in the configuration implies it's for all applications. Replace it with the specific application name for app-scoped attribute retrievers.


Similarly, Clear Entitlement provides numerous built-in functions. However, if these functions don't meet the requirements, customers can create custom functions by integrating Java code into the Java class path.

                  public class YourFunction implements ConditionFunction {
    
                    public Object execute(String fname, Object[] args, EvaluationContext evaluationContext) {
                        ...
                        return value;
                    }

In the above code, "fname" represents the function name, "args" are the function arguments, and "evaluationContext" provides all the required contextual data.
If an argument is an attribute, it's evaluated to its value before the function is invoked.

The configuration for adding custom functions is also done in the app.cfg file:
condition.conditionFunction.*.{your function name}={Full class name with package}
Similar to attribute retrievers, the asterisk (*) implies it's for all applications. Replace it with the specific application name for app-scoped functions.

Policy Management


Policy Management Workflow

Clear Entitlement's policy management workflow comprises three states: policy creation, policy approval, and policy deployment.

The lifecycle of a policy version includes "DRAFT", "PENDING APPROVAL", "APPROVED"/"REJECTED", and "DEPLOYED"/"UNDEPLOYED".




To create a policy, navigate to "Application" -> "Manage Access Policy" and select the application if it hasn't been chosen previously.
Once the application is selected, users with policy creation permission will see the "New Version" and "Upload Policy" buttons.

After the policies are created, the policy modeler can either save them as drafts or submit them for approval.




The policy reviewer can either approve or reject the policies.




Once the policy is approved, the policy deployer can deploy the policy.
When a new version of the policy is deployed, the previous version changes to "UNDEPLOYED".





Policy Management Permissions

The resource for policy is "/Applications/{appId}/Policies"
The actions are: "read", "create", "update", "delete", "approve", and "deploy".
Out of the box, Clear Entitlement provides three application roles to support the workflow: PolicyMaker, PolicyChecker, and PolicyDeployer. (no SoD by default)
These roles also support fine-grained entitlements by specifying which applications are authorized to manage policy when assign the user to the role.




To retrieve the application ID, navigate to "Application" -> "Manage Applications" -> view an application. The application ID can be found in the address bar, for example:
.../application/b472f8b3-7696-4975-8136-46720ccbabd4