Identity Gateway 2024.3

PolicyEnforcementFilter

Requests and enforces policy decisions from AM. For more information, refer to IG’s Policy enforcement and AM’s Authorization guide.

Attributes and advices are stored in the policyDecision context. For information, refer to PolicyDecisionContext.

When the PolicyEnforcementFilter is preceded by a SingleSignOnFilter or CrossDomainSingleSignOnFilter in a Chain, it can respond to the following advice types from AM:

  • AuthLevel: The minimum authentication level at which a user agent must authenticate to access a resource.

  • AuthenticateToService: The name of an authorization chain or service to which a user agent must authenticate to access a resource.

  • AuthenticateToRealm: The name of a realm to which a user agent must authenticate to access a resource.

  • AuthScheme: The name of an authentication module to which a user agent must authenticate to access a resource, the policy set name, and the authentication timeout.

  • Transaction: The additional actions that a user agent must perform before having a one-time access to the protected resource.

When the PolicyEnforcementFilter isn’t preceded by a SingleSignOnFilter or CrossDomainSingleSignOnFilter in a Chain, it can’t respond to advices from AM. Requests that return policy decisions with advices fail with an HTTP 403 Forbidden.

Notes on configuring policies in AM

In the AM policy, remember to configure the Resources parameter with the URI of the protected application.

The request URI from IG must match the Resources parameter defined in the AM policy. If the URI of the incoming request is changed before it enters the policy filter (for example, by rebasing or scripting), remember to change the Resources parameter in AM policy accordingly.

WebSocket notifications for policy changes

When WebSocket notifications are set up for changes to policies, IG receives a notification from AM when a policy decision is created, deleted, or updated.

For information about setting up WebSocket notifications, using them to clear the policy cache, and including them in the server logs, refer to WebSocket Notifications.

Usage

{
  "name": string,
  "type": "PolicyEnforcementFilter",
  "config": {
    "amService": AmService reference,
    "pepRealm": configuration expression<string>,
    "ssoTokenSubject": runtime expression<string>,
    "jwtSubject": runtime expression<string>,
    "claimsSubject": map or runtime expression<map>,
    "cache": object,
    "application": configuration expression<string>,
    "environment": map or runtime expression<map>,
    "failureHandler": Handler reference,
    "resourceUriProvider": ResourceUriProvider reference,
    "authenticateResponseRequestHeader": configuration expression<string>,
    "useLegacyAdviceEncoding": configuration expression<boolean> //deprecated
  }
}

Properties

"amService": AmService reference, required

The AM instance to use for policy decisions.

"pepRealm": configuration expression<string>, optional

The AM realm where the policy set is located.

Default: The realm declared for amService.

"ssoTokenSubject": _runtime expression<string>, required if neither of the following properties are present: jwtSubject, claimsSubject

The AM token ID string for the subject making the request to the protected resource.

ssoTokenSubject can take the value of the session token from the following sources:

  • When the PolicyEnforcementFilter is preceded by a SingleSignOnFilter, ${contexts.ssoToken.value}.

  • When the PolicyEnforcementFilter is preceded by a CrossDomainSingleSignOnFilter, ${contexts.ssoToken.value} or ${contexts.cdsso.value}.

  • When the PolicyEnforcementFilter isn’t preceded by a SingleSignOnFilter or CrossDomainSingleSignOnFilter, ssoTokenSubject usually points to the token value.

    The token value can be in the request message, a header, or a cookie. For example, the ssoTokenSubject can point to a header value such as ${request.headers.cookie name}, where cookie name is the AM session cookie name.

    Requests that return a policy decision with advices fail with an HTTP 403 and no advice handling.

"jwtSubject": _runtime expression<string>, required if neither of the following properties are present: ssoTokenSubject, claimsSubject

The JWT string for the subject making the request to the protected resource.

To use the raw id_token (base64, not decoded) returned by the OpenID Connect Provider during authentication, place an AuthorizationCodeOAuth2ClientFilter filter before the PEP filter, and then use ${attributes.openid.id_token} as the expression value.

"claimsSubject": map or runtime expression<map>, required if neither of the following properties are present: jwtSubject, `"ssoTokenSubject`

A map of one or more data pairs with the format Map<String, Object>, where:

  • The key is the name of a claim

  • The value is a claim object, or a runtime expression that evaluates to a claims object

The following formats are allowed:

{
  "claimsSubject": {
    "string": "runtime expression<object>",
    ...
  }
}
{
  "claimsSubject": "runtime expression<map>"
}

The claim "sub" must be specified; other claims are optional.

In the following example, the property is a map whose first value is a runtime expression that evaluates to a JWT claim for the subject, and whose second value is a JWT claim for the subject:

"claimsSubject": {
  "sub": "${attributes.subject_identifier}",
  "iss": "am.example.com"
}

In the following example, the property is a runtime expression that evaluates to a map with the format Map<String, Object>:

"claimsSubject": "${attributes.openid.id_token_claims}"

For an example that uses claimsSubject as a map, refer to Example policy enforcement using claimsSubject on this reference page.

"application": configuration expression<string>, optional

The ID of the AM policy set to use when requesting policy decisions.

Default: iPlanetAMWebAgentService, provided by AM’s default policy set

cache: object, optional

Enable and configure caching of policy decisions from AM, based on Caffeine. For more information, see the GitHub entry, Caffeine.

When a request matches a cached policy decision, IG can reuse the decision without asking AM for a new decision. When caching is disabled, IG must ask AM to make a decision for each request.

{
  "cache": {
    "enabled": configuration expression<boolean>,
    "defaultTimeout": configuration expression<duration>,
    "executor": Executor service reference,
    "maximumSize": configuration expression<number>,
    "maximumTimeToCache": configuration expression<duration>,
    "onNotificationDisconnection": configuration expression<enumeration>
  }
}

Default: Policy decisions are not cached.

Policy decisions that contain advices are never cached.

The following code example caches AM policy decisions without advices for these times:

  • One hour, when the policy decision doesn’t provide a ttl value.

  • The duration specified by the ttl, when ttl is shorter than one day.

  • One day, when ttl is longer than one day.

"cache": {
  "enabled": true,
  "defaultTimeout": "1 hour",
  "maximumTimeToCache": "1 day"
}
enabled: configuration expression<boolean>, optional

Enable or disable caching of policy decisions.

Default: false

defaultTimeout: configuration expression<duration>, optional

The default duration for which to cache AM policy decisions.

If an AM policy decision provides a valid ttl value to specify the time until which the policy decision remains valid, IG uses that value or the maxTimeout.

Default: 1 minute

"executor": Executor service reference, optional

An executor service to schedule the execution of tasks, such as the eviction of entries in the cache.

Default: ForkJoinPool.commonPool()

"maximumSize": configuration expression<number>, optional

The maximum number of entries the cache can contain.

Default: Unlimited/unbound.

maximumTimeToCache: configuration expression<duration>, optional

The maximum duration for which to cache AM policy decisions.

If the ttl value provided by the AM policy decision is after the current time plus the maximumTimeToCache, IG uses the maximumTimeToCache.

The duration cannot be zero or unlimited.

onNotificationDisconnection: configuration expression<enumeration>, optional

The strategy to manage the cache when the WebSocket notification service is disconnected, and IG receives no notifications for AM events. If the cache is not cleared it can become outdated, and IG can allow requests on revoked sessions or tokens.

Cached entries that expire naturally while the notification service is disconnected are removed from the cache.

Use one of the following values:

  • NEVER_CLEAR

    • When the notification service is disconnected:

      • Continue to use the existing cache.

      • Deny access for requests that are not cached, but do not update the cache with these requests.

    • When the notification service is reconnected:

      • Continue to use the existing cache.

      • Query AM for incoming requests that are not found in the cache, and update the cache with these requests.

  • CLEAR_ON_DISCONNECT

    • When the notification service is disconnected:

      • Clear the cache.

      • Deny access to all requests, but do not update the cache with these requests.

    • When the notification service is reconnected:

      • Query AM for all requests that are not found in the cache. (Because the cache was cleared, the cache is empty after reconnection.)

      • Update the cache with these requests.

  • CLEAR_ON_RECONNECT

    • When the notification service is disconnected:

      • Continue to use the existing cache.

      • Deny access for requests that are not cached, but do not update the cache with these requests.

    • When the notification service is reconnected:

      • Query AM for all requests that are not found in the cache. (Because the cache was cleared, the cache is empty after reconnection.)

      • Update the cache with these requests.

Default: CLEAR_ON_DISCONNECT

"environment": map or runtime expression<map>, optional

A map of one or more data pairs with the format Map<String, Object>, where:

  • The key is the name of a field in the request environment or context, such as a request header

  • The value is the object to forward to AM with a policy decision request, or a runtime expression that evaluates to the object

The following formats are allowed:

{
  "claimsSubject": {
    "string": "runtime expression<object>",
    ...
  }
}
{
  "claimsSubject": "runtime expression<map>"
}

AM uses environment conditions to set the circumstances under which a policy applies. For example, environment conditions can specify that the policy applies only during working hours or only when accessing from a specific IP address.

Forward any HTTP header or any value that the AM policy definition can use.

In the following example, the property is a map whose values are runtime expressions that evaluate to request headers, an ID token, and the IP address of the subject making the request:

"environment": {
  "H-Via": "${request.headers['Via']}",
  "H-X-Forwarded-For": "${request.headers['X-Forwarded-For']}",
  "H-myHeader": "${request.headers['myHeader']}",
  "id_token": [
    "${attributes.openid.id_token}"
  ],
  "IP": [
    "${contexts.client.remoteAddress}"
  ]
}
"failureHandler": Handler reference, optional

Handler to treat the request if it is denied by the policy decision.

In the following example, the failureHandler is a chain with a scriptable filter. If there are some advices with the policy decision, the script recovers the advices for processing. Otherwise, it passes the request to the StaticResponseHandler to display a message.

"failureHandler": {
  "type": "Chain",
  "config": {
    "filters": [
      {
        "type": "ScriptableFilter",
        "config": {
          "type": "application/x-groovy",
          "source": [
            "if (contexts.policyDecision.advices['MyCustomAdvice'] != null) {",
            "  return handleCustomAdvice(context, request)",
            "} else {",
            "  return next.handle(context, request)",
            "}"
          ]
        }
      }
    ],
    "handler": {
      "type": "StaticResponseHandler",
      "config": {
        "status": 403,
        "headers": {
          "Content-Type": [ "text/plain; charset=UTF-8" ]
        },
        "entity": "Restricted area. You do not have sufficient privileges."
      }
    }
  }
}

Provide an inline handler configuration object or the name of a handler object declared in the heap. See also Handlers.

Default: HTTP 403 Forbidden, the request stops being executed.

"resourceUriProvider": ResourceUriProvider reference, optional

Use one of the following providers to return a resource URL to include in policy decision requests to AM:

The PolicyEnforcementFilter uses the returned resource URL to identify the policy decision in the policy cache.

When a request matches a cached policy decision, IG can reuse the decision without asking AM for a new decision. When caching is disabled, IG must ask AM to make a decision for each request.

Default: RequestResourceUriProvider configured to use the request URI with all query parameters included.

Maximize the cache hit ratio by managing the returned resource URL in conjuction with AM policies.

Strip all query parameters from the returned resource URL

Consider the following AM policy that matches requests on the specified path. The policy ignores query parameters:

http://ig.example.com:8080/app

The following requests match the path but have additional query parameters:

http://ig.example.com:8080/app?day=monday
http://ig.example.com:8080/app?day=monday&place=london
http://ig.example.com:8080/app?day=monday&place=london&building=x

When includeQueryParams in RequestResourceUriProvider is true, the ResourceUriProvider includes all query parameters in requests for policy decisions. The PolicyEnforcementFilter requests a policy desicion for the first request /app?day=monday and caches the descision. The second request app?day=monday&place=london doesn’t match the cached decision so the PolicyEnforcementFilter requests another policy decision and adds it to the cache. Similarly for the third request.

When includeQueryParams in RequestResourceUriProvider is false, the ResourceUriProvider strips all query parameters from the requests. The PolicyEnforcementFilter requests a policy decision for the first request without query parameters and caches the policy desicion. The following two requests without query parameters match the cached decision and IG uses the cached decision without consulting AM.

Include only specified query parameters in the returned resource URL

Consider a similar example where an AM policy matches requests on the specified path but also requires one query parameter:

http//ig.example.com:8080/app?day=monday

The following requests match the path and query parameter but two of them have additional query parameters:

http://ig.example.com:8080/app?day=monday
http://ig.example.com:8080/app?day=monday&place=london
http://ig.example.com:8080/app?day=monday&place=london&building=x

Because the policy requires a query parameter, you can’t use RequestResourceUriProvider to strip all query parameters from the requests.

Instead, use ScriptableResourceUriProvider to include the ?day=monday query parameter but strip all other query parameters.

Query order is important. The following queries are semantically the same but don’t match: ?day=monday&place=london and ?place=london&day=monday.
"resourceUriProvider": {
  "type": "ScriptableResourceUriProvider",
  "config": {
    "type": "application/x-groovy",
    "source": [
      "// Define a list of parameters to keep",
      "def keepOnly = { [ 'place', 'day' ].contains(it.key) }",
      "// Build a new URI based on the original request URI",
      "return new MutableUri(request.uri).with { uri ->",
      "  // Build a filtered and normalized query string",
      "  uri.rawQuery = new Form().with { form ->",
      "    // Keep only the wanted parameters and sort by name",
      "    form.addAll(request.queryParams.findAll(keepOnly).sort())",
      "    return form.toQueryString()",
      "  }",
      "  // Return the full modified URI",
      "  return uri.toASCIIString()",
      "}"
    ]
  }
}
authenticateResponseRequestHeader: configuration expression<string>, optional

A header to include in a request to manage the way IG handles policy advices from AM. The header name and value is case-insensitive. The header value can be set as follows:

  • HEADER: Return policy advices in a WWW-Authenticate header as base64-encoded JSON in a parameter called advices.

  • Any other value: Return policy advices as parameters in a redirect response (default).

For information about how the header is used in policy enforcement, refer to Deny requests with advices in a header.

Default: x-authenticate-response

useLegacyAdviceEncoding: configuration expression<boolean>, optional
The use of this property is deprecated and should be used only to support SDK in legacy installations. Refer to the Deprecated section of the Release Notes.
  • True: Do not encode advices

  • False: Encode advices with the encoder used by the AM version

Default: False

Examples

For examples of policy enforcement, refer to Policy enforcement.