Policy-based Authorization in ForgeRock
Posted August 5, 2021 by Jatinder Singh ‐ 10 min read
Centralizing and decoupling authorization using Policy-based Access Control (PBAC) in ForgeRock AM

Introduction
As published in the Gartner Hype Cycle for Identity and Access Management 2020 report, Externalized Authorization Management (EAM) is on the rise. Covid-19 has increased the visibility of the IAM landscape, and with that, organizations need to establish more robust authorization practices to prevent breaches and improve compliance and security. This blog post will show you how we can use the ForgeRock Access Manager (AM) Policy Authorization to centralize and decouple authorization. The demo includes step-by-step instructions on how to implement this within AM to protect REST resources. In addition, our GitHub repository provides the companion source code to help you implement this topic in your lab environment.
A quick summary of what we will uncover:
What is Policy-based Authorization?
A Policy-based Authorization, also known by the name Attribute-based Access Control (ABAC) or Policy-based Access Control (PBAC), is an access control model that establishes who (authenticated identity) can access what (resources) and under what circumstances (conditions). While this way of externalizing authorization is getting much traction in the last few years, it is not new. The policy-based design extends from the eXtensible Access Control Markup Language (XACML), which has been around since 2003, with the draft officially standardized by the OASIS Standard in 2013.
The ForgeRock AM achieves policy-based authorization using a policy document that the policy administrator defines. In a nutshell, the policy document is a criteria set by its administrator that the requester must meet to access a protected resource. The official standard of XACML has many different constructs, but we will primarily discuss the top-level constructs to focus on AM’s interpretation of XACML.
A brief overview of Policy Architecture
As discussed in the XACML standard, the architecture of a Policy-based design requires the following components:
- Policy Decision Point( PDP);
- Policy Enforcement Point (PEP);
- Policy Information Point (PIP);
- Policy Administration Point (PAP).
While the above components can exist in isolation and be independent services, AM encapsulates all of them as a cohesive unit in a single application. Due to this encapsulation, the diagram below doesn’t reveal the interaction between PDP, PIP, and PAP.

What are Policy, Policy Set, and Resource Type constructs?
In the XACML standard to manage the authorization policies, a component called PAP is defined, allowing the administration of new and existing policies. Within PAP, policy construction happens using the constructs Policy
, Policy Set
, and Resource Type
. With these constructs, a policy administrator can create a concrete policy. AM provides access to these constructs through REST endpoints /resourcestypes
, /applications
, and /policies
. In addition, the GUI equivalent is available through the Authorization
menu in the AM console.
- Resource Type - A resource type enables an administrator to specify a template for the kind of resources AM should protect. For example, URL-based resources, IoT devices, or the doors of an airport.
- Policy Set - A policy set allows an administrator to provide a container to group policies based on templates (resource types) included in a policy set. For example, grouping policies for URL-based endpoint (e.g.
/v1/pets
). - Policy - A policy defines resources, actions, subject conditions, environmental conditions, and response attributes, allowing AM to determine whether to grant or deny access. A Policy is what consumes a given template within its
Policy Set
to satisfy concrete authorization requirements. So, for example, a Policy based on a URL-based template, we can state allow Managers to GET access to the/v1/pets
endpoint. Similarly, a second policy can allow Employees to GET access to/v1/pets
endpoint within regular business hours of 9-5.

Policy Authorization in Action (Demo)
One of the first steps in the authorization landscape is to talk to the business stakeholders to define authorization requirements. Since I am the everything for this post, we will set the following authorization business requirements:
- Requirement #1 - Allow Employees
GET
action to/v1/pets
endpoint. - Requirement #2 - Allow Managers whose last name starts with “Mc”,
POST
,PUT
andDELETE
actions to/v1/pets
endpoint.
While the above requirements are simple enough, implementing them, we will learn how access models, including RBAC and ABAC, can be defined using the ForgeRock AM Policy authorization.
My ForgeRock stack for this post includes:
- AM
v7.1.0
; - DS
v7.1.0
.
Note The complete Postman collection, including the companion source code, is available under the GitHub section.
Set-up Policy Infrastructure
Since our requirement is to protect URL-based endpoints, AM’s default configuration comes with a URL-based Resource Type
that we will use. Therefore, in Step 1 of the demo, we will set up our policy infrastructure to evaluate policies on the protected resources later.
Step 1 - Login as Policy Administrator
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/authenticate' \
--header 'Accept-API-Version: resource=2.1' \
--header 'X-OpenAM-Username: amadmin' \
--header 'X-OpenAM-Password: changeit'
Response:
{
"tokenId": "U_IXfUMyuosjyolpQ2IC7XfUjxQ.*AAJTSQACMDIAAlNLABwvY3BuMjFKSWZUMzhPNGRIRnc1czRBRFhUUjA9AAR0eXBlAANDVFMAAlMxAAIwMQ..*",
"successUrl": "/openam/console",
"realm": "/"
}
Step 2 - Create Policy Set to hold policies
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/realms/pbac/applications/?_action=create' \
--header 'Content-Type: application/json' \
--header 'Accept-API-Version: resource=2.1' \
--header 'Cookie: amlbcookie=01; iPlanetDirectoryPro=PRrXH0XU7ABss3Y0Fw45HGUXxDY.*AAJTSQACMDIAAlNLABxCc3NyYWpXb1prU0wwejJsSUl2ckhuRmRBQlE9AAR0eXBlAANDVFMAAlMxAAIwMQ..*' \
--data-raw '{
"name":"PetsPolicySet",
"resourceTypeUuids":[
"76656a38-5f8e-401b-83aa-4ccb74ce88d2"
],
"realm":"/pbac",
"conditions":[
"AND",
"Script",
"OR",
"NOT",
"AMIdentityMembership",
"AuthLevel",
"AuthScheme",
"AuthenticateToRealm",
"AuthenticateToService",
"IPv4",
"IPv6",
"LDAPFilter",
"LEAuthLevel",
"OAuth2Scope",
"ResourceEnvIP",
"Session",
"SessionProperty",
"SimpleTime"
],
"applicationType":"iPlanetAMWebAgentService",
"description":"Policy AuthZ Demo",
"resourceComparator":"com.sun.identity.entitlement.URLResourceName",
"subjects":[
"AND",
"OR",
"NOT",
"AuthenticatedUsers",
"Identity",
"JwtClaim"
],
"entitlementCombiner":"DenyOverride",
"saveIndex":null,
"searchIndex":null,
"attributeNames":[
]
}'
Response:
{
"_id": "PetsPolicySet",
"_rev": "1628529590564",
"name": "PetsPolicySet",
"displayName": null,
"resourceTypeUuids": [
"76656a38-5f8e-401b-83aa-4ccb74ce88d2"
],
"description": "Policy AuthZ Demo",
"attributeNames": [],
"creationDate": 1628529590564,
"createdBy": "id=amadmin,ou=user,dc=sqoopdata,dc=local",
"conditions": [
"AND",
"Script",
"OR",
"NOT",
"AMIdentityMembership",
"AuthLevel",
"AuthScheme",
"AuthenticateToRealm",
"AuthenticateToService",
"IPv4",
"IPv6",
"LDAPFilter",
"LEAuthLevel",
"OAuth2Scope",
"ResourceEnvIP",
"Session",
"SessionProperty",
"SimpleTime"
],
"resourceComparator": "com.sun.identity.entitlement.URLResourceName",
"lastModifiedDate": 1628529590564,
"lastModifiedBy": "id=amadmin,ou=user,dc=sqoopdata,dc=local",
"subjects": [
"AND",
"OR",
"NOT",
"AuthenticatedUsers",
"Identity",
"JwtClaim"
],
"saveIndex": null,
"searchIndex": null,
"entitlementCombiner": "DenyOverride",
"editable": true,
"applicationType": "iPlanetAMWebAgentService"
}
Step 3 - Create Employee Policy
With the Resource Type
and Policy Set
in place, let’s create a Policy to implement Requirement 1. The policy request below is an ALLOW policy that will ALLOW users access to /v1/pets
who belong to an Employee role. In addition, the policy uses an LDAP Filter environmental condition that constructs a standard LDAPv3 filter to define role relationships. So there you go, we have a basic RBAC in action using Policy-based authorization.
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/realms/pbac/policies?_action=create' \
--header 'Content-Type: application/json' \
--header 'Accept-API-Version: resource=1.0' \
--header 'Cookie: amlbcookie=01; iPlanetDirectoryPro=PRrXH0XU7ABss3Y0Fw45HGUXxDY.*AAJTSQACMDIAAlNLABxCc3NyYWpXb1prU0wwejJsSUl2ckhuRmRBQlE9AAR0eXBlAANDVFMAAlMxAAIwMQ..*' \
--data-raw '{
"name": "EmployeePetsPolicy",
"active": true,
"description": "Defines Pets Policies for Employees",
"applicationName": "PetsPolicySet",
"actionValues": {
"GET": true
},
"resources": [
"*://*:*/*/v1/pets/*"
],
"subject": {
"type": "AuthenticatedUsers"
},
"condition": {
"type": "LDAPFilter",
"ldapFilter": "(&(objectclass=inetorgperson)(ismemberof=cn=Employee,ou=groups,dc=sqoopdata,dc=local))"
},
"resourceTypeUuid": "76656a38-5f8e-401b-83aa-4ccb74ce88d2"
}'
Response:
{
"_id": "EmployeePetsPolicy",
"_rev": "1628535741884",
"name": "EmployeePetsPolicy",
"active": true,
"description": "Defines Pets Policies for Employees",
"resources": [
"*://*:*/*/v1/pets/*"
],
"applicationName": "PetsPolicySet",
"actionValues": {
"GET": true
},
"subject": {
"type": "AuthenticatedUsers"
},
"condition": {
"type": "LDAPFilter",
"ldapFilter": "(&(objectclass=inetorgperson)(ismemberof=cn=Employee,ou=groups,dc=sqoopdata,dc=local))"
},
"lastModifiedBy": "id=amadmin,ou=user,dc=sqoopdata,dc=local",
"lastModifiedDate": "2021-08-09T19:02:21.884Z",
"createdBy": "id=amadmin,ou=user,dc=sqoopdata,dc=local",
"creationDate": "2021-08-09T19:02:21.884Z"
}
Step 4 - Create Manager Policy
Creating a manager policy is very similar to the employee policy, with the difference being a modified LDAP Filter environment condition. So, the below is an ALLOW policy that will ALLOW authenticated identities access to POST
, DELETE
, and PUT
actions on the /v1/pets
endpoint. The identity must belong to a Manager role, and its sn
attribute must start with the letters “mc”. Using an attribute to determine access, we have successfully implemented the ABAC model.
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/realms/pbac/policies?_action=create' \
--header 'Content-Type: application/json' \
--header 'Accept-API-Version: resource=1.0' \
--header 'Cookie: amlbcookie=01; iPlanetDirectoryPro=PRrXH0XU7ABss3Y0Fw45HGUXxDY.*AAJTSQACMDIAAlNLABxCc3NyYWpXb1prU0wwejJsSUl2ckhuRmRBQlE9AAR0eXBlAANDVFMAAlMxAAIwMQ..*' \
--data-raw '{
"name": "ManagerPetsPolicy",
"active": true,
"description": "Defines Pets Policies for Managers",
"applicationName": "PetsPolicySet",
"actionValues": {
"DELETE": true,
"POST": true,
"PUT": true
},
"resources": [
"*://*:*/*/v1/pets/*"
],
"subject": {
"type": "AuthenticatedUsers"
},
"condition": {
"type": "LDAPFilter",
"ldapFilter": "(&(objectclass=inetorgperson)(sn=mc*)(ismemberof=cn=Manager,ou=groups,dc=sqoopdata,dc=local))"
},
"resourceTypeUuid": "76656a38-5f8e-401b-83aa-4ccb74ce88d2"
}'
Response:
{
"_id": "ManagerPetsPolicy",
"_rev": "1628536957837",
"name": "ManagerPetsPolicy",
"active": true,
"description": "Defines Pets Policies for Managers",
"resources": [
"*://*:*/*/v1/pets/*"
],
"applicationName": "PetsPolicySet",
"actionValues": {
"DELETE": true,
"POST": true,
"PUT": true
},
"subject": {
"type": "AuthenticatedUsers"
},
"condition": {
"type": "LDAPFilter",
"ldapFilter": "(&(objectclass=inetorgperson)(sn=mc*)(ismemberof=cn=Manager,ou=groups,dc=sqoopdata,dc=local))"
},
"lastModifiedBy": "id=amadmin,ou=user,dc=sqoopdata,dc=local",
"lastModifiedDate": "2021-08-09T19:22:37.837Z",
"createdBy": "id=amadmin,ou=user,dc=sqoopdata,dc=local",
"creationDate": "2021-08-09T19:22:37.837Z"
}
Evaluate Policies
We will test our policies against the following user vs. role matrix. As prerequisite steps, we have already obtained SSO tokens for all the below three users.
Full Name | User | Role |
---|---|---|
John Doe | jdoe | Employee |
Denny McDonald | dmcdonald | Manager |
Alice Charlie | alice | Manager |
Ron Saunders | rsaunders | Analyst |
Test Policy Evaluation for Requirement #1
Test Case - Check Ron Saunders access to /v1/pets
endpoint.
Expected Result - Since Ron Sauders is an Analyst, the server will NOT MATCH ANY POLICY.
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/realms/pbac/policies?_action=evaluate' \
--header 'Content-Type: application/json' \
--header 'Accept-API-Version: resource=2.1' \
--header 'Cookie: amlbcookie=01; iPlanetDirectoryPro=PRrXH0XU7ABss3Y0Fw45HGUXxDY.*AAJTSQACMDIAAlNLABxCc3NyYWpXb1prU0wwejJsSUl2ckhuRmRBQlE9AAR0eXBlAANDVFMAAlMxAAIwMQ..*' \
--data-raw '{
"resources": [
"https://pets.clinic.com:443/app/v1/pets/all"
],
"application": "PetsPolicySet",
"subject": {
"ssoToken": "zdq-Ahw436shRW70fYw0rBhydNQ.*AAJTSQACMDIAAlNLABwreS9HKzFoQnNyVjRvdUc0S1JFa3JSVEV3SlE9AAR0eXBlAANDVFMAAlMxAAIwMQ..*"
}
}'
Response:
[
{
"resource": "https://pets.clinic.com:443/app/v1/pets/all",
"actions": {},
"attributes": {},
"advices": {},
"ttl": 9223372036854775807
}
]
Test Case - Check John Doe’s access to /v1/pets
endpoint.
Expected Result - Since John Doe is an Employee, the server must MATCH POLICY and return ACTIONS ALLOWED.
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/realms/pbac/policies?_action=evaluate' \
--header 'Content-Type: application/json' \
--header 'Accept-API-Version: resource=2.1' \
--header 'Cookie: amlbcookie=01; iPlanetDirectoryPro=fcuTuCtv4pD6hyb7ksZosGF02lk.*AAJTSQACMDIAAlNLABxFYlljMGE5S1F4SFI0dkFxZitiWXoydVBkUzg9AAR0eXBlAANDVFMAAlMxAAIwMQ..*' \
--data-raw '{
"resources": [
"https://pets.clinic.com:443/app/v1/pets/all"
],
"application": "PetsPolicySet",
"subject": {
"ssoToken": "_u4wdGguigg3HWYpt0yRsxELEe4.*AAJTSQACMDIAAlNLABxSWjhjSkRHNk5zYnpDZlRPWUs0cVJuUXN6TVE9AAR0eXBlAANDVFMAAlMxAAIwMQ..*"
}
}'
Response:
[
{
"resource": "https://pets.clinic.com:443/app/v1/pets/all",
"actions": {
"GET": true
},
"attributes": {},
"advices": {},
"ttl": 9223372036854775807
}
]
Test Policy Evaluation for Requirement #2
Test Case - Check Denny McDonald access to /v1/pets
endpoint.
Expected Result - Since Denny McDonald is a Manager, the server must MATCH POLICY and return ACTIONS ALLOWED.
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/realms/pbac/policies?_action=evaluate' \
--header 'Content-Type: application/json' \
--header 'Accept-API-Version: resource=2.1' \
--header 'Cookie: amlbcookie=01; iPlanetDirectoryPro=PRrXH0XU7ABss3Y0Fw45HGUXxDY.*AAJTSQACMDIAAlNLABxCc3NyYWpXb1prU0wwejJsSUl2ckhuRmRBQlE9AAR0eXBlAANDVFMAAlMxAAIwMQ..*' \
--data-raw '{
"resources": [
"https://pets.clinic.com:443/app/v1/pets/all"
],
"application": "PetsPolicySet",
"subject": {
"ssoToken": "sAxFGSegOzhPDDbv0KbeYoBHlZg.*AAJTSQACMDIAAlNLABxUYklydHBHV0N2TDB1L2pINUxZeWtteEZCbWc9AAR0eXBlAANDVFMAAlMxAAIwMQ..*"
}
}'
Response:
[
{
"resource": "https://pets.clinic.com:443/app/v1/pets/all",
"actions": {
"DELETE": true,
"POST": true,
"PUT": true
},
"attributes": {},
"advices": {},
"ttl": 9223372036854775807
}
]
Test Case - Check Alice who is also a Manager access to /v1/pets
endpoint.
Expected Result - Since the manager policy requires the sn
to start with the letters “Mc”, the server will not MATCH ANY POLICY and return empty actions.
Request:
curl --location --request POST 'https://identity.sqoopdata.local:17143/openam/json/realms/root/realms/pbac/policies?_action=evaluate' \
--header 'Content-Type: application/json' \
--header 'Accept-API-Version: resource=2.1' \
--header 'Cookie: amlbcookie=01; iPlanetDirectoryPro=GTp5MD3J3tq237M0xM7VTW1Aq2E.*AAJTSQACMDIAAlNLABxTdTFCMFMvVFhPbWhGT2U4VW9HY0ZnVmI0TDg9AAR0eXBlAANDVFMAAlMxAAIwMQ..*' \
--data-raw '{
"resources": [
"https://pets.clinic.com:443/app/v1/pets/all"
],
"application": "PetsPolicySet",
"subject": {
"ssoToken": "Y4pZG7g4oW0qm8wd9vENJaFwhBY.*AAJTSQACMDIAAlNLABxXZnRJK0ZjY1VzYklUY2lkdjB0ZUVQM1NvaXc9AAR0eXBlAANDVFMAAlMxAAIwMQ..*"
}
}'
Response:
[
{
"resource": "https://pets.clinic.com:443/app/v1/pets/all",
"actions": {},
"attributes": {},
"advices": {},
"ttl": 9223372036854775807
}
]
Common Issues
Issue - Policy evalution yields empty actions with 200 response code.
Explanation 1 - A response with empty actions could mean AM couldn’t match the access request with any configured policies. Check your access request and ensure it satisfies at least one policy.
Explanation 2 - If you use an LDAP Filter environmental condition in your policy, you must configure the Policy Configuration
service to point to the correct Identity repository. By default, AM uses the Config
repository configured in this service.
Example Response:
[
{
"resource": "https://pets.clinic.com:443/app/v1/pets/all",
"actions": {},
"attributes": {},
"advices": {},
"ttl": 9223372036854775807
}
]
GitHub Source Code
The companion source code for this blog post includes AM configuration for the Authorization and Postman collection. You can find the source code at our repository hosted at Github here.
Summary
We did what we set out to do! Using ForgeRock AM, we decoupled authorization by centralizing it at AM using Policies.
Using Policy-based authorization, we successfully implemented ABAC and RBAC access models to protect REST endpoints.
If you find yourself going down this path, you can use our companion source code and postman collection as a reference implementation.
If you enjoyed reading this post but require further help with your authorization requirements, we would be thrilled to speak with you. You can reach us at contact@sqoopdata.com.