---
title: Scripted policy conditions
description: Write scripted policy conditions in JavaScript to customize how PingAM evaluates authorization policies
component: pingam
version: 7.5
page_id: pingam:am-authorization:scripted-policy-condition
canonical_url: https://docs.pingidentity.com/pingam/8.1/am-authorization/scripted-policy-condition.html
llms_txt: https://docs.pingidentity.com/pingam/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
keywords: ["Authorization", "Policy", "Administration", "Scripting", "Evaluation"]
page_aliases: ["authorization-guide:scripted-policy-condition.adoc"]
superseded_by: https://docs.pingidentity.com/pingam/8.1/am-authorization/scripted-policy-condition.html
section_ids:
  sec-scripted-policy-condition-prepare: Prepare a demonstration
  scripted-policy-privilege: Policy administrator account
  scripted-policy-enduser: End user account
  scripted-policy-script: Create a script
  scripted-policy-policy: Create a policy
  sec-scripted-policy-condition-evaluate: Try the demonstration
  proc-enable-entitlement-debug-logging: Enable debug logging for scripted policy conditions
  scripting-api-policy: Policy condition script API
  scripted-api-authz-state: Access environment data
  scripting-api-authz-id-repo: Access profile data
  scripting-api-authz-session: Access session data
  scripting-api-authz-response: Set authorization responses
---

# Scripted policy conditions

You can use scripts to tailor the actions PingAM takes as part of policy evaluation.

This example uses a policy condition script written in JavaScript. Find information about the available bindings for policy condition scripts in the [Policy condition script API](#scripting-api-policy).

## Prepare a demonstration

To demonstrate an example policy condition script:

* [Create a policy administrator user](#scripted-policy-privilege).

* [Create an end user](#scripted-policy-enduser).

* [Create a policy condition script](#scripted-policy-script)

* [Create a policy that uses the script](#scripted-policy-policy).

### Policy administrator account

This account represents the policy enforcement point (PEP) account. It has the Entitlement Rest Access privilege required to request PingAM policy decisions over HTTP using the REST API. In a production deployment, use a PEP like PingGateway or an PingAM agent in this role.

1. Create a policy administrator.

   In the AM admin UI, select Realms > *realm name* > Identities > + Add Identity and fill the required fields.

   Record the username and password.

2. Create a group that grants the Entitlement Rest Access privilege to the policy administrator.

   Select Realms > alpha > Identities > Groups > + Add Group to create a group with the following settings:

   * Group ID

     `am-policy-evaluation`

   * Members

     The policy administrator whose username you recorded

   * Privileges

     Entitlement Rest Access

### End user account

This account represents the end user who tries to access online resources.

1. Create a user.

   In the AM admin UI, select Realms > *realm name* > Identities > + Add Identity and fill the required fields.

   Record the username and password.

2. In the Home Address field of the user profile, enter `United States`.

### Create a script

1. In the AM admin UI, [create a script](../am-scripting/manage-scripts-console.html#create-scripts-with-console) with the following values:

   * Name

     `Location Authorization Script`

   * Script Type

     `Policy Condition`

   * Evaluator Version

     `Legacy`

2. In the Script field, paste the following JavaScript:

   > **Collapse: Policy condition example script**
   >
   > ```javascript
   > var userAddress, userIP, resourceHost;
   >
   > if (validateAndInitializeParameters()) {
   >
   >     var countryFromUserIP = getCountryFromUserIP();
   >     logger.message("Country retrieved from user's IP: " + countryFromUserIP);
   >     var countryFromResourceURI = getCountryFromResourceURI();
   >     logger.message("Country retrieved from resource URI: " + countryFromResourceURI);
   >
   >     if (userAddress === countryFromUserIP && userAddress === countryFromResourceURI) {
   >
   >         logger.message("Authorization succeeded");
   >         responseAttributes.put("countryOfOrigin", [countryFromUserIP]);
   >         authorized = true;
   >     } else {
   >         logger.message("Authorization failed");
   >         authorized = false;
   >     }
   >
   > } else {
   >     logger.error("Required parameters not found. Authorization Failed.");
   >     authorized = false;
   > }
   >
   > function getCountryFromUserIP() {
   >
   >     var request = new org.forgerock.http.protocol.Request();
   >     request.setUri("http://ip-api.com/json/" + userIP);
   >   	request.setMethod("GET");
   >
   >     var response = httpClient.send(request).get();
   >     logResponse(response);
   >
   >     var result = JSON.parse(response.getEntity().getString());
   >     if (result) {
   >         return result.country;
   >     }
   > }
   >
   > function getCountryFromResourceURI() {
   >
   >    var request = new org.forgerock.http.protocol.Request();
   >     request.setUri("http://ip-api.com/json/" + encodeURIComponent(resourceHost));
   >   	request.setMethod("GET");
   >
   >     var response = httpClient.send(request).get();
   >     logResponse(response);
   >
   >     var result = JSON.parse(response.getEntity().getString());
   >     if (result) {
   >         return result.country;
   >     }
   > }
   >
   > function validateAndInitializeParameters() {
   >
   >     var userAddressSet = identity.getAttribute("postalAddress");
   >     if (userAddressSet == null || userAddressSet.isEmpty()) {
   >         logger.error("No address specified for user: " + username);
   >         return false;
   >     }
   >     userAddress = userAddressSet.iterator().next();
   >
   >     if (!environment) {
   >         logger.error("No environment parameters specified in the evaluation request.");
   >         return false;
   >     }
   >     var ipSet = environment.get("IP");
   >     if (ipSet == null || ipSet.isEmpty()) {
   >         logger.error("No IP specified in the evaluation request environment parameters.");
   >         return false;
   >     }
   >     userIP = ipSet.iterator().next();
   >
   >     if (!resourceURI) {
   >         logger.error("No resource URI specified.");
   >         return false;
   >     }
   >     resourceHost = resourceURI.match(/^(.*:\/\/)(www\.)?([A-Za-z0-9\-\.]+)(:[0-9]+)?(.*)$/)[3];
   >     return true;
   > }
   > ```

3. Save your changes.

### Create a policy

The policy references the script through environmental conditions.

1. Create a policy set for policies regarding URLs.

   In the AM admin UI, select Realms > *realm name* > Authorization > Policy Sets > + New Policy Set to create a policy set with the following settings:

   * Id

     `am-policy-set`

   * Resource Types

     `URL`

2. Create a policy in the policy set.

   Select Realms > *realm name* > Authorization > Policy Sets > am-policy-set > + Add a Policy to create a policy with the following settings:

   * Name

     `Scripted policy example`

   * Resource Types

     `URL`

   * Resources

     `*://*:*/*`, `*://*:*/*?*`

3. In the new policy, update the settings.

   Allow HTTP GET access by all authenticated users when permitted by the script:

   * Actions

     GET: Allow

   * Subjects

     Type: `Authenticated Users`

   * Environments

     Type: `Script`, Script Name: `Location Authorization Script`

   When modifying settings in the policy editor, select the edit icon [icon: pencil-alt, set=fa]to begin changing the setting, the check icon [icon: check, set=fa]to confirm the change, then Save Changes to commit the change.

4. Verify the policy settings.

   ![Policy settings for the scripted policy example](_images/scripted-policy-example.png)

## Try the demonstration

The `policies?_action=evaluate` endpoint lets a policy administrator make a REST call over HTTP to get a policy decision from PingAM. PingAM policy decisions for URL policies show at least the HTTP actions the user can perform. Find more information in [Request policy decisions over REST](rest-api-authz-policy-decisions.html).

Here, when PingAM grants the user access to complete an HTTP GET request to the resource, the decision includes `"actions":{"GET":true}`. When PingAM denies access, the decision includes `"actions":{}`.

The REST call to the `policies?_action=evaluate` endpoint requires:

* An SSO token ID for the policy administrator making the request.

* An SSO token ID for the end user attempting to access the resource.

* A request body that specifies who is attempting to access what in what way under what conditions.

  1. Get an SSO token for the policy administrator:

     ```bash
     $ curl \
     --request POST \
     --header 'Content-Type: application/json' \
     --header 'X-OpenAM-Username: policy-admin-username' \
     --header 'X-OpenAM-Password: policy-admin-password' \
     --header 'Accept-API-Version: resource=2.0, protocol=1.0' \
     'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/authenticate'
     {
       "tokenId":"policy-admin-tokenId",
       "successUrl":"/am/console",
       "realm":"/alpha"
     }
     ```

  2. Get an SSO token for the end user:

     ```bash
     $ curl \
     --request POST \
     --header 'Content-Type: application/json' \
     --header 'X-OpenAM-Username: end-user-username' \
     --header 'X-OpenAM-Password: end-user-password' \
     --header 'Accept-API-Version: resource=2.0, protocol=1.0' \
     'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/authenticate'
     {
       "tokenId":"end-user-tokenId",
       "successUrl":"/am/console",
       "realm":"/alpha"
     }
     ```

  3. Request evaluation for a request by an end user in the United States to access a resource located in the United States.

     The script lets users access resources located in their country of residence. PingAM grants access when both the user's home country and IP address match the resource location.

     ```bash
     $ curl \
     --header 'iPlanetDirectoryPro: policy-admin-tokenId' \
     --request POST \
     --header 'Content-Type: application/json' \
     --header "Accept-API-Version: resource=2.1" \
     --data '{
       "resources": ["https://www.whitehouse.gov:443/about-the-white-house/"],
       "actions": {"GET": true},
       "application": "am-policy-set",
       "subject": {
         "ssoToken": "end-user-tokenId"
       },
       "environment": {
         "IP": ["8.8.8.8"]
       }
     }' \
     'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/policies?_action=evaluate'
     [{
       "resource": "https://www.whitehouse.gov:443/about-the-white-house/",
       "actions": {
         "GET": true
       },
       "attributes": {
         "countryOfOrigin": ["United States"]
       },
       "advices": {},
       "ttl": <ttl>
     }]
     ```

     The script adds `"attributes":{"countryOfOrigin":["United States"]}` to the result when PingAM grants access.

  4. Request evaluation for a request by an end user in France to access a resource located in the United States.

     The user's IP address (`88.174.153.24`) maps to a French location, so no actions are returned:

     ```bash
     $ curl \
     --header 'iPlanetDirectoryPro: policy-admin-tokenId' \
     --request POST \
     --header 'Content-Type: application/json' \
     --header "Accept-API-Version: resource=2.1" \
     --data '{
       "resources": ["https://www.whitehouse.gov:443/about-the-white-house/"],
       "actions": {"GET": true},
       "application": "am-policy-set",
       "subject": {
         "ssoToken": "end-user-tokenId"
       },
       "environment": {
         "IP": ["88.174.153.24"]
       }
     }' \
     'https://openam.example.com:8443/openam/json/realms/root/realms/alpha/policies?_action=evaluate'
     [{
       "resource": "https://www.whitehouse.gov:443/about-the-white-house/",
       "actions": {},
       "attributes": {},
       "advices": {},
       "ttl": <ttl>
     }]
     ```

     Both the `attributes` and the `actions` fields are empty. To verify the authorization outcome, look for an `Authorization failed` entry in the logs.

## Enable debug logging for scripted policy conditions

These steps show how to enable trace-level debug logging for scripted policy conditions, so that logger output from the default policy condition script is recorded.

|   |                                                                                                                                                                                                           |
| - | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | The script containing the debug output to capture must execute at least once to create the logger.The name of the scripted policy decision logger has the format: `scripts.POLICY_CONDITION.script-UUID`. |

1. Log in as the PingAM administrator, `amAdmin`.

2. Go to the `Logback.jsp` page; for example, `https://openam.example.com:8443/openam/Logback.jsp`.

3. In the Logger list, scroll to select the scripted policy decision logger; for example, `scripts.POLICY_CONDITION.9de3eb62-f131-4fac-a294-7bd170fd4acb`.

4. From the Level list, choose the debug level required.

   In this example, select `Trace`.

5. Click Apply.

   ![Enable debug logging for a scripted conditions.](_images/debug-logging-scripts.png)

   Trace-level debug logging is now enabled for scripted policy conditions, with script output appearing in the `/path/to/openam/var/debug/Policy` debug log file.

   Changes to the `Logback.jsp` page do not persist when PingAM restarts.

   For additional details, refer to [Debug logging](../maintenance/debug-logging.html).

## Policy condition script API

A policy condition script has access to the following specific *bindings*, predefined objects that PingAM injects into the script execution context.

Use these objects in a script to get information such as the authorization state of a request, session properties, and user profile data.

PingAM can return the information in the response to an authorization request.

|   |                                                                                                                                                                                                                                                                                          |
| - | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|   | If you use static methods within policy scripts, you must allowlist those scripts. Otherwise, policy evaluation fails with an exception—​logged in the `Entitlement` debug file—​similar to the following:java.lang.SecurityException: Access to Java class *script-name* is prohibited. |

| Binding              | Description                                                                                         | Further information                                                      |
| -------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `advice`             | Return the condition advice from the script.                                                        | [Set authorization responses](#scripting-api-authz-response)             |
| `authorized`         | Return `true` if the authorization is currently successful, or `false` if authorization has failed. | Server-side scripts must set a value for `authorized` before completing. |
| `environment`        | The environment values passed from the client making the authorization request.                     | [Access environment data](#scripted-api-authz-state)                     |
| `httpClient`         | Make outbound HTTP calls.                                                                           | [Access HTTP services](../am-scripting/script-bindings.html#httpclient)  |
| `identity`           | Access the data stored in the user's profile.                                                       | [Access profile data](#scripting-api-authz-id-repo)                      |
| `logger`             | Write a message to the PingAM debug log.                                                            | [Log script messages](../am-scripting/script-bindings.html#logger)       |
| `responseAttributes` | Add an attribute to the response to the authorization request.                                      | [Set authorization responses](#scripting-api-authz-response)             |
| `scriptName`         | Return the name of the running script.                                                              | [Output script name](../am-scripting/script-bindings.html#scriptName).   |
| `session`            | Access the properties for the current session.                                                      | [Access session data](#scripting-api-authz-session)                      |
| `ttl`                | The time-to-live value for the response to a successful authorization.                              | [Set authorization responses](#scripting-api-authz-response)             |
| `username`           | String identifying the user ID of the subject requesting authorization.                             | -                                                                        |

### Access environment data

The `environment` binding holds data from the client making the authorization request as a Map of `<String, Set<String>`.

For example, the following shows a simple `environment` map with a single entry:

* Policy condition script

* OAuth 2.0 scopes policy script

```none
"environment": {
    "IP": [
        "127.0.0.1"
    ]
}
```

```none
"environment": {
    "clientId": [
        "MyOAuth2Client"
    ]
}
```

|   |                                                                                                                                               |
| - | --------------------------------------------------------------------------------------------------------------------------------------------- |
|   | For information about scripting OAuth 2.0 policy conditions, refer to [OAuth 2.0 scopes policy script API](scripting-api-oauth2-policy.html). |

### Access profile data

Server-side authorization scripts can access the profile data of the subject of the authorization request through the methods of the `identity` object.

|   |                                                                                                   |
| - | ------------------------------------------------------------------------------------------------- |
|   | To access a subject's profile data, they must be logged in and their SSO token must be available. |

* `Set identity.getAttribute(String attributeName)`

  Return the values of the named attribute for the subject of the authorization request.

  For example:

```none
var attribute = identity.getAttribute("attrName").iterator().next();
```

* `void identity.setAttribute(String attributeName, Array attributeValues)`

  Set the named attribute to the values specified by the attribute value for the subject of the authorization request.

  For example:

```none
identity.setAttribute("attrName", ["newValue"]);

// Explicitly persist data
identity.store();
```

* `void identity.addAttribute(String attributeName, String attributeValue)`

  Add an attribute value to the list of attribute values associated with the attribute name for the subject of the authorization request.

  For example:

```none
identity.addAttribute("attrName", ["newValue"]);

// Explicitly persist data
identity.store();
```

|   |                                                                                                     |
| - | --------------------------------------------------------------------------------------------------- |
|   | You must call `identity.store()` to persist changes or they will be lost when the script completes. |

### Access session data

Server-side authorization scripts can access session data for the subject of the authorization request through the methods of the `session` object.

|   |                                                                                                          |
| - | -------------------------------------------------------------------------------------------------------- |
|   | To access the session data of the subject, they must be logged in and their SSO token must be available. |

* `String session.getProperty(String propertyName)`

  Retrieve properties from the session associated with the subject of the authorization request. Refer to the following table for example properties and their values.

> **Collapse: Session properties and example values**
>
> | Key                          | Sample value                                          |
> | ---------------------------- | ----------------------------------------------------- |
> | `AMCtxId`                    | `e370cca2-02d6-41f9-a244-2b107206bd2a-122934`         |
> | `amlbcookie`                 | `01`                                                  |
> | `authInstant`                | `2018-04-04T09:19:05Z`                                |
> | `AuthLevel`                  | `0`                                                   |
> | `CharSet`                    | `UTF-8`                                               |
> | `clientType`                 | `genericHTML`                                         |
> | `FullLoginURL`               | `/openam/XUI/?realm=alpha#login/`                     |
> | `Host`                       | `198.51.100.1`                                        |
> | `HostName`                   | `openam.example.com`                                  |
> | `Locale`                     | `en_US`                                               |
> | `Organization`               | `dc=openam,dc=forgerock,dc=org`                       |
> | `Principal`                  | `uid=amAdmin,ou=People,dc=openam,dc=forgerock,dc=org` |
> | `Principals`                 | `amAdmin`                                             |
> | `Service`                    | `ldapService`                                         |
> | `successURL`                 | `/openam/console`                                     |
> | `sun.am.UniversalIdentifier` | `uid=amAdmin,ou=People,dc=openam,dc=forgerock,dc=org` |
> | `UserId`                     | `amAdmin`                                             |
> | `UserProfile`                | `Required`                                            |
> | `UserToken`                  | `amAdmin`                                             |
> | `webhooks`                   | `myWebHook`                                           |

### Set authorization responses

Server-side authorization scripts can return information in the response to an authorization request with the following methods:

* `void responseAttributes.put(String attributeName, Array attributeValue)`

  Add an attribute to the response to the authorization request.

* `void advice.put(String adviceKey, Array adviceValues`

  Add advice key-value pairs to the response to a failing authorization request.

* `void ttl(Integer ttlValue)`

  Add a time-to-live value, which is a timestamp in milliseconds to the response to a successful authorization. After the time-to-live value the decision is no longer valid.

  If no value is set, `ttlValue` defaults to `Long.MAX_VALUE` (9223372036854775807), which means the decision has no timeout, and can live for as long as the calling client holds on to it. In the case of policy enforcement points, they hold onto the decision for their configured cache timeout.
