Skip to content

IG Extensions Java Module

Dan Badham edited this page May 28, 2024 · 73 revisions

IG Extensions Java Module: secure-api-gateway-ig-extensions

This module extends IG to provide functionality required by the Secure API Gateway (SAPI-G), it is comprised of a collection of reusable and configurable components which can be used in IG routes to implement secure access to different APIs. For example: implementing functionality relating to the FAPI (Financial Grade API) standard, providing a generic Trusted Directory implementation (as described here in this article: Dynamic Client Registration) and so forth.

The following filters, services and data models are included:

Filters

FapiAdvancedDCRValidationFilter

This filter can be used in a route that implements OAuth2 DCR (Dynamic Client Registration) to validate that the request will produce a FAPI compliant OAuth2 client. Specifically, the filter applies validation rules per the FAPI1 Advanced spec.

This filter should be configured in the chain before the filters that actually implement DCR. This means that typically the filter should go near the start of the chain.

The filter only does validation and is agnostic of the particular API for which DCR is being done, such as Open Banking UK. Therefore, it is the task of the filters later in the chain to implement DCR and API specific validations.

If the filter determines that the request is valid, it will pass it on to the next filter in the chain, otherwise, it will return a HTTP error response.

Usage

{
          "name": string,   
          "type": "FAPIAdvancedDCRValidationFilter",
          "config": {
            "clientTlsCertHeader": string,
            "supportedSigningAlgorithms": [ string, ... ],
            "supportedTokenEndpointAuthMethods": [ string, ... ],
            "registrationObjectSigningFieldNames": [ string, ... ]
          }
}

Configuration

"clientTlsCertHeader": string, required

The name of the header in which the client's TLS certificate can be found. The certificate should be a x509 certificate which is PEM encoded then URL encoded. The ssl-client-cert value used in the example below is the header that nginx will add the client certificate to.

"supportedSigningAlgorithms": array of string, optional

The JWS algorithms supported for messaging signing. Default value: ["PS256", "ES256"]

"supportedTokenEndpointAuthMethods": array of string, optional

The DCR token_endpoint_auth_methods supported. Default value: ["tls_client_auth", "self_signed_tls_client_auth", "private_key_jwt"]

"registrationObjectSigningFieldNames": array of string, optional

The fields within the registration request object to validate against the supportedSigningAlgorithms. Default value: ["token_endpoint_auth_signing_alg", "id_token_signed_response_alg", "request_object_signing_alg"]

Example

Minimum configuration to use the filter:

{
          "comment": "Validate that the request will result in an OAuth2 client that is FAPI compliant",
          "name": "FAPIAdvancedDCRValidationFilter",
          "type": "FAPIAdvancedDCRValidationFilter",
          "config": {
            "clientTlsCertHeader": "ssl-client-cert"
          }
}

Filter configuration for Open Banking UK:

{
          "name": "FAPIAdvancedDCRValidationFilter",
          "type": "FAPIAdvancedDCRValidationFilter",
          "config": {
            "clientTlsCertHeader": "ssl-client-cert",
            "supportedSigningAlgorithms": ["PS256"],
            "supportedTokenEndpointAuthMethods": ["tls_client_auth", "private_key_jwt"]
          }
}

FetchApiClientFilter

This filter retrieves ApiClient data from Identity Cloud or IDM using the client_id from the access_token provided with the request.

The ApiClient object is then made accessible to subsequent filters in the chain via AttributesContext as key: "apiClient"

This filter relies on the OAuth2Context being present, as this ensures that the request has been authenticated and that the access token is valid; the client_id is extracted from this context. Therefore, this filter must be installed after a filter that adds the context, such as: OAuth2ResourceServerFilter.

Usage

{
          "name": string,   
          "type": "FetchApiClientFilter",
          "config": {
            "apiClientService": ApiClientService reference
          }
}

Configuration

"apiClientService": ApiClientService reference, required

Reference to an ApiClientService implementation, this handles retrieving the ApiClient data from the datastore.

Example

{
           "name": "FetchApiClientFilter",
           "type": "FetchApiClientFilter",
           "config": {
             "apiClientService": "IdmApiClientService"
           }
}

AuthorizeResponseFetchApiClientFilter

Specialised implementation of FetchApiClientFilter for use in routes which reverse proxy an AS OAuth2 authorization endpoint implemented as per RFC 6749. This implementation runs on the response path instead of the request path, this ensures that the AS has successfully authenticated the client before fetching the ApiClient data.

This filter retrieves ApiClient data from Identity Cloud or IDM using the client_id request URI query parameter.

The ApiClient object is then made accessible to subsequent filters in the chain via AttributesContext as key: "apiClient"

Usage

{
          "name": string,   
          "type": "AuthorizeResponseFetchApiClientFilter",
          "config": {
             "apiClientService": ApiClientService reference
          }
}

Configuration

"apiClientService": ApiClientService reference, required

Reference to an ApiClientService implementation, this handles retrieving the ApiClient data from the datastore.

Example

{
           "name": "AuthorizeResponseFetchApiClientFilter",
           "type": "AuthorizeResponseFetchApiClientFilter",
           "config": {
             "apiClientService": "IdmApiClientService"
           }
}

ParResponseFetchApiClientFilter

Alias of AuthorizeResponseFetchApiClientFilter for use in routes which reverse proxy an AS OAuth 2.0 Pushed Authorization Requests endpoint implemented as per RFC 9126.

Configuration options are the same as AuthorizeResponseFetchApiClientFilter

Example

{
           "name": "ParResponseFetchApiClientFilter",
           "type": "ParResponseFetchApiClientFilter",
           "config": {
             "apiClientService": "IdmApiClientService"
           }
}

FetchTrustedDirectoryFilter

This filter retrieves TrustedDirectory configuration from a TrustedDirectoryService and adds it to the AttributesContext so that it can be used by subsequent filters. The configuration is available via the "trustedDirectory" key of the AttributesContext.

This filter must be installed after a filter that adds the ApiClient context, typically: FetchApiClientFilter.

Usage

{
          "name": string,   
          "type": "FetchTrustedDirectoryFilter",
          "config": {
            "trustedDirectoryService": TrustedDirectoryService reference,
          }
}

Configuration

"trustedDirectoryService": TrustedDirectoryService reference, required

Reference to a TrustedDirectoryService instance. This service will be used to query the TrustedDirectory configuration based on the issuer of the software statement of the ApiClient.

Example

{
            "name": "FetchTrustedDirectoryFilter",
            "type": "FetchTrustedDirectoryFilter",
            "config": {
              "trustedDirectoryService": "TrustedDirectoriesService"
            }
}

FetchApiClientJwksFilter

This filter retrieves the JWKS (JWK Set) containing the keys for an ApiClient that is registered with a TrustedDirectory.

The data is then made available as an org.forgerock.json.jose.jwk.JWKSet via key: "apiClientJwkSet" of the AttributesContext.

This filter relies on both ApiClient and TrustedDriectory data being available in the attributes context, therefore it needs to be installed after filters that set these attributes, typically: FetchApiClientFilter and FetchTrustedDirectoryFilter.

Usage

{
          "name": string,   
          "type": "FetchApiClientJwksFilter",
          "config": {
            "jwkSetService": JwkSetService reference,
          }
}

Configuration

"jwkSetService": JwkSetService reference, required

Reference to a JwkSetService instance. This service will be used to fetch remote JWKS by URI, that is, when the software statement defines a jwks_uri claim. See RestJwkSetService and CaffeineCachingJwkSetService.

Example

{
            "name": "FetchApiClientJwksFilter",
            "type": "FetchApiClientJwksFilter",
            "config": {
              "jwkSetService": "OBJwkSetService"
            }
}

TransportCertValidationFilter

Validates that the client's TLS certificate is valid for use by this client.

This filter will return a HTTP error response if one of the following conditions is true:

  • No client TLS certificate is found or the value is malformed.
  • The client TLS certificate has expired (or it is not yet valid).
  • The certificate does not match a certificate in the ApiClient's JWKS or a matching certificate is not valid for use as a transport certificate.

This filter depends on the ApiClient's JWKSet being available in the AttributesContext. Therefore, it must be installed after a filter that sets this, typically: FetchApiClientJwksFilter.

Usage

{
          "name": string,   
          "type": "TransportCertValidationFilter",
          "config": {
            "clientTlsCertHeader": string,
            "transportCertValidator": TransportCertValidator reference
          }
}

Configuration

"clientTlsCertHeader": string, required

The name of the header in which the client's TLS certificate can be found. The certificate should be a x509 certificate which is PEM encoded then URL encoded. The ssl-client-cert value used in the example below, is the header that nginx will add the client cert to

"transportCertValidator": TransportCerValidator reference, required

Reference to a TransportCertValidator instance. This validator implements the logic to determine if a certificate is valid for use as a transport certificate for a JWKSet. The JWKSet passed to the validator will be the one belonging to the ApiClient.

See DefaultTransportCertValidator.

Example

{
            "name": "TransportCertValidationFilter",
            "type": "TransportCertValidationFilter",
            "config": {
              "clientTlsCertHeader": "ssl-client-cert",
              "transportCertValidator": "TransportCertValidator"
            }
}

TokenEndpointTransportCertValidationFilter

Specialised version of TransportCertValidationFilter that is designed to work with routes that reverse proxy an AS /access_token endpoint. The key difference here, is that validation is carried out on the response path instead of the request path. This change ensures that the AS has authenticated the client.

Validates that the client's TLS certificate is valid for use by this client.

This filter will return a HTTP error response if one of the following conditions is true:

  • No client TLS certificate is found or the value is malformed.
  • The client TLS certificate has expired (or it is not yet valid).
  • The certificate does not match a certificate in the ApiClient's JWKS or a matching certificate is not valid for use as a transport certificate.

Usage

{
          "name": string,   
          "type": "TokenEndpointTransportCertValidationFilter",
          "config": {
            "certificateRetriever": CertificateRetriever reference 
            "trustedDirectoryService": TrustedDirectoryService reference,
            "jwkSetService": JwkSetService reference,
            "transportCertValidator": TransportCertValidator reference
          }
}

Configuration

"certificateRetriever": CertificateRetriever reference, required

Reference to a CertificateRetriever, which is used to fetch the client's mTLS certificate from the Request / Context.

See HeaderCertificateRetriever and ContextCertificateRetriever.

"trustedDirectoryService": TrustedDirectoryService reference, required

Reference to a TrustedDirectoryService instance. This service will be used to query the TrustedDirectory configuration based on the issuer of the software statement of the ApiClient.

"jwkSetService": JwkSetService reference, required

Reference to a JwkSetService instance. This service will be used to fetch remote JWKS by URI, that is, when the software statement defines a jwks_uri claim. See RestJwkSetService and CaffeineCachingJwkSetService.

"transportCertValidator": TransportCerValidator reference, required

Reference to a TransportCertValidator instance. This validator implements the logic to determine if a certificate is valid for use as a transport certificate for a JWKSet. The JWKSet passed to the validator will be the one belonging to the ApiClient.

See DefaultTransportCertValidator.

Example

{
            "name": "TokenEndpointTransportCertValidationFilter",
            "type": "TokenEndpointTransportCertValidationFilter",
            "config": {
              "certificateRetriever": "HeaderCertificateRetriever",
              "trustedDirectoryService": "TrustedDirectoriesService",
              "jwkSetService": "OBJwkSetService",
              "transportCertValidator": "TransportCertValidator"
            }
}

ConsentRequestAccessAuthorisationFilter

Filter that protects access to a consent request by validating that an end user browser session belongs to the same user that is specified in the signed consent request JWT (sent from AM). This can be used in filter chains which protect Remote Consent flows.

This filter depends on the SsoTokenContext and JwtValidationContext, therefore it must be installed after filters which add these contexts.

The SsoTokenContext is used to determine the user that is logged in, by inspecting the session "uid".

The JwtValidationContext is used to determine the user that owns the consent request, by inspecting the "username" claim. It is assumed that consent request JWT has been fully validated, that the signature has been verified and that the "exp", "iat", "iss" and "aud" claims have all been validated.

If the SSO user matches the consent user then this filter passes the request on to the next handler in the chain. Otherwise, this filter responds with HTTP 401.

If any exceptions are raised when extracting the user data from the contexts then this filter responds with HTTP 500. This is because an exception indicates either an error in the IG configuration or AM configuration; there is no action that an end user can take to resolve the issue.

Usage

{
          "name": string,   
          "type": "ConsentRequestAccessAuthorisationFilter",
          "config": {
            "consentRequestUserIdClaim": string,
            "ssoTokenUserIdKey": string
          }
}

Configuration

"consentRequestUserIdClaim": string, optional

Name of the claim in the consent request JWT which contains the userId

Defaults to: "username"

"ssoTokenUserIdKey": string, optional

Key within SsoTokenContext.info which contains the userId

Defaults to: "uid"

Example

{
            "name": "ConsentRequestAccessAuthorisationFilter",
            "type": "ConsentRequestAccessAuthorisationFilter"
}

AddCertificateToAttributesContextFilter

Filter that uses a com.forgerock.sapi.gateway.mtls.CertificateRetriever to retrieve a client's mTLS certificate and adds it to the AttributesContext so that downstream filters can use it.

Downstream filters can then use the ContextCertificateRetriever to retrieve the certificate from the context

Usage

{
          "name": string,   
          "type": "AddCertificateToAttributesContextFilter",
          "config": {
            "certificateRetriever": CertificateRetriever reference,
            "certificateAttributeName": string
          }
}

Configuration

"certificateRetriever": CertificateRetriever reference, required

Reference to a com.forgerock.sapi.gateway.mtls.CertificateRetriever object, typically this will be a HeaderCertificateRetriever

"certificateAttributeName": string, optional

The name of the attribute to store the certificate in.

Defaults to: "clientCertificate"

Example

{
          "name": "AddCertificateToAttributesContextFilter",
          "type": "AddCertificateToAttributesContextFilter",
          "config": {
            "certificateRetriever": "HeaderCertificateRetriever"
          }
}

AccessTokenResponseIdTokenReSignFilter

This filter aims to fix an issue in AM relating to signing of the id_token JWTs returned by the /access_token endpoint. The issue is that the wrong kid is used by AM, see JwtReSigner for further details.

Usage

{
          "name": string,   
          "type": "AccessTokenResponseIdTokenReSignFilter",
          "config": {
            "jwtReSigner": JwtReSigner reference
          }
}

Configuration

"jwtReSigner": JwtReSigner reference, required

Reference to a JwtReSigner that contains the AM secrets used to verify the JWT was signed by AM before re-signing it with the correct key.

Example

{
          "name": "AccessTokenResponseIdTokenReSignFilter",
          "type": "AccessTokenResponseIdTokenReSignFilter",
          "config": {
            "jwtReSigner": "jwtReSigner"
          }
}

AuthorizeResponseJwtReSignFilter

This filter aims to fix an issue in AM relating to signing of the JWTs returned by the /authorize endpoint. The issue is that the wrong kid is used by AM, see JwtReSigner for further details.

Usage

{
          "name": string,   
          "type": "AuthorizeResponseJwtReSignFilter",
          "config": {
            "jwtReSigner": JwtReSigner reference
          }
}

Configuration

"jwtReSigner": JwtReSigner reference, required

Reference to a JwtReSigner that contains the AM secrets used to verify the JWT was signed by AM before re-signing it with the correct key.

Example

{
          "name": "AuthorizeResponseJwtReSignFilter",
          "type": "AuthorizeResponseJwtReSignFilter",
          "config": {
            "jwtReSigner": "jwtReSigner"
          }
}

RouteMetricsFilter

This filter is responsible for reporting metrics for the route that it is configured in. The metrics are published as RouteMetricsEvent objects, with one event being published per request processed by the route.

The filter should be installed as the first filter in the chain in order to get the most accurate response time data.

RouteMetricsEvent objects contain ApiClient metadata, this filter expects to find the ApiClient in the attributes context in the response path. This means that the attributes context needs to be populated correctly prior to this filter processing the response.

For further documentation see: Capturing Route Metrics

Usage

{
          "name": string,   
          "type": "RouteMetricsFilter",
          "config": {
            "metricsContextSupplier": MetricsContextSupplier reference
          }
}

Configuration

"metricsContextSupplier": MetricsContextSupplier reference, optional

Reference to a com.forgerock.sapi.gateway.metrics.MetricsContextSupplier object that extracts contextual information from the request being processed and stores it in the RouteEventMetrics.context field.

Default is to not supply contextual information.

Example implementations:

Example

{
          "name": "RouteMetricsFilter",
          "type": "RouteMetricsFilter"
}

FapiAuthorizeRequestValidationFilter

This filter validates that requests made to an AS OAuth 2.0 /authorize endpoint (RFC 6749) are FAPI compliant.

This involves checking that fields which are mandatory for FAPI compliance are provided in the request JWT param.

Usage

{
          "name": string,   
          "type": "FapiAuthorizeRequestValidationFilter"
}

Configuration

None

Example

{
          "name": "FapiAuthorizeRequestValidationFilter",
          "type": "FapiAuthorizeRequestValidationFilter"
}

FapiParRequestValidationFilter

This filter validates that requests made to an AS OAuth 2.0 /par endpoint (RFC 9126) are FAPI compliant.

This involves checking that fields which are mandatory for FAPI compliance are provided in the request JWT param.

Usage

{
          "name": string,   
          "type": "FapiParRequestValidationFilter"
}

Configuration

None

Example

{
          "name": "FapiParRequestValidationFilter",
          "type": "FapiParRequestValidationFilter"
}

ManageApiClientFilter

Filter to manage ApiClient in a datastore as part of protecting an OAuth2.0 /register (DCR) endpoint.

Supports CRUD operations for ApiClients as part of DCR calls, the following operations are supported:

  • POST requests create a new ApiClient and ApiClientOrganisation (if the organisation does not already exist) in the data store.
  • GET requests fetch the ApiClient from the data store.
  • PUT requests update the ApiClient in the data store.
  • DELETE requests delete the ApiClient from the data store.

All operations add the ApiClient object to the AttributesContext, making the ApiClient available to other filters.

These operations occur on the response path and only take place if the response from the upstream is a success, this ensures that the Authorization Server has validated and processed the request first.

Usage

{
          "name": string,   
          "type": "ManageApiClientFilter",
          "config": {
            "apiClientService": ApiClientService reference,
            "apiClientOrgService": ApiClientOrganisationService reference,
            "clientIdRequestParameterLocator": ClientIdRequestParameterLocator reference
          }
}

Configuration

"apiClientService": ApiClientService reference, required

Reference to an ApiClientService implementation, this handles retrieving the ApiClient data from the datastore.

"apiClientOrganisationService": ApiClientOrganisationService reference, required

Reference to an ApiClientOrganisationService implementation, this handles retrieving the ApiClient data from the datastore.

"clientIdRequestParameterLocator": ClientIdRequestParameterLocator reference, required

Reference to an ClientIdRequestParameterLocator implementation.

When the Authorisation Server is AM, then the QueryParamClientIdRequestParameterLocator should be used.

Example

{
          "name": "ManageApiClientFilter",
          "type": "ManageApiClientFilter",
          "config": {
            "apiClientService": "IdmApiClientService",
            "apiClientOrgService": "IdmApiClientOrgService",
            "clientIdRequestParameterLocator": {
              "name": "QueryParamClientIdRequestParameterLocator",
              "type": "QueryParamClientIdRequestParameterLocator"
            }
          }
}

Services

These are classes that provide functionality for use by the filters above and/or the IG scripts.

RestJwkSetService

This service provides functionality for retrieving JWKS (JWK Sets) via a REST API call. Implements the com.forgerock.sapi.gateway.jwks.JwkSetService interface, which can be used whenever an instance of this interface is required.

Usage

{
      "name": string,
      "type": "RestJwkSetService",
      "config": {
        "handler": Handler reference
      }
}

Configuration

"handler": Handler reference, optional

Reference to the handler instance to use when making the HTTP REST calls.

Defaults to: "clientHandler" which is the default ClientHandler name.

Example

{
      "name": "OBJwkSetService",
      "type": "RestJwkSetService",
      "config": {
        "handler": "OBClientHandler"
      }
}

CaffeineCachingJwkSetService

This service wraps a RestJwkSetService and provides caching support by utilising the caffeine library. This does not introduce an additional dependency, as caffeine is already used by IG.

Implements the com.forgerock.sapi.gateway.jwks.JwkSetService interface, which can be used whenever an instance of this interface is required.

Usage

{
      "name": string,
      "type": "CaffeineCachingJwkSetService",
      "config": {
        "handler": Handler reference,
        "maxCacheEntries": long,
        "expireAfterWriteDuration": duration
      }
}

Configuration

"handler": Handler reference, optional

Reference to the handler instance to use when making the HTTP REST calls.

Defaults to: "clientHandler" which is the default ClientHandler name.

"maxCacheEntries": long, optional

Max number of entries in the cache; when this limit is exceeded, entries are evicted using the LRU algorithm.

Defaults to: 100

"expireAfterWriteDuration": duration, optional

Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after either the entry was created or the entry's value was updated.

The duration type is a lapse of time expressed in English.

Defaults to: "5 minutes"

Example

{
      "name": "OBJwkSetService",
      "type": "CaffeineCachingJwkSetService",
      "config": {
        "handler": "OBClientHandler",
        "maxCacheEntries": 500,
        "expireAfterWriteDuration": "24 hours"
      }
}

RsaJwtSignatureValidator

This validator validates that a SignedJWT has been signed by an RSA key belonging to a JWKSet. The particular key in the JWKSet is matched on kid (key id) specified in the JWT header.

If the signature is valid, the validateSignature method returns normally, otherwise, it throws a SignatureException providing an error message with details as to why validation failed.

Signature validation cases:

  • kid missing from the JWT header
  • JWT header alg is not one of [PS256, PS384, PS512]
  • No JWK exists in the JWKSet with matching kid
  • Matching JWK is not a RsaJWK
  • Matching JWK does not have sig use
  • JWT signature does not validate against the public key for the matching JWK

The validator has no configuration options, it can be created as per the below example.

Example

{
      "name": "RsaJwtSignatureValidator",
      "type": "RsaJwtSignatureValidator"
}

StaticTrustedDirectoryService

Implementation of the TrustedDirectoryService interface. Retrieves TrustedDirectory configuration for an issuer by name, directories to support are configured in config.

Usage

 {
      "name": string,
      "type": "StaticTrustedDirectoryService",
      "config": {
        "trustedDirectories": [ TrustedDirectory reference, ... ]
      }
}

Configuration

"trustedDirectories": array of TrustedDirectory, required

The TrustedDirectory objects to support.

Example

This example configures the Open Banking Test Directory and the SAPI-G Test Directory.

{
  "name": "TrustedDirectoryService",
  "type": "StaticTrustedDirectoryService",
  "comment": "Used to obtain meta information about a trusted directory by look up using the 'iss' field value",
  "config": {
    "trustedDirectories": [
      {
        "name": "Open Banking Test Directory",
        "type": "TrustedDirectory",
        "config": {
          "directoryJwksUri": "https://keystore.openbankingtest.org.uk/keystore/openbanking.jwks",
          "issuer": "OpenBanking Ltd",
          "softwareStatementJwksUriClaimName": "software_jwks_endpoint",
          "softwareStatementOrgIdClaimName": "org_id",
          "softwareStatementOrgNameClaimName": "org_name",
          "softwareStatementSoftwareIdClaimName": "software_id",
          "softwareStatementRedirectUrisClaimName": "software_redirect_uris",
          "softwareStatementRolesClaimName": "software_roles",
          "softwareStatementClientNameClaimName": "software_client_name"
        }
      },
      {
        "name": "Secure API Gateway Test Directory",
        "type": "TrustedDirectory",
        "config": {
          "directoryJwksUri": "https://&{ig.fqdn}/jwkms/testdirectory/jwks",
          "issuer": "test-publisher",
          "softwareStatementJwksClaimName": "software_jwks",
          "softwareStatementOrgIdClaimName": "org_id",
          "softwareStatementOrgNameClaimName": "org_name",
          "softwareStatementSoftwareIdClaimName": "software_id",
          "softwareStatementRedirectUrisClaimName": "software_redirect_uris",
          "softwareStatementRolesClaimName": "software_roles",
          "softwareStatementClientNameClaimName": "software_client_name",
          "disabled": "${!security.enableTestTrustedDirectory}"
        }
      }
    ]
  }
}

DefaultTransportCertValidator

Validates that the client certificate provided is valid for use as a transport certificate for the ApiClient's JWKS.

When validating a transport certificate, the key id (kid) is unknown. The validator determines if a JWK in the JWKS matches the certificate by transforming it into a JWK and comparing the x5c[0] value. The x5c[0] value represents the base64 encoded DER PKIX certificate value. The first item in the x5c array must be the certificate, therefore we only check this entry and not the full chain.

Spec for JWK.x5c field: https://www.rfc-editor.org/rfc/rfc7517#section-4.7

Usage

{
      "name": string,
      "type": "DefaultTransportCertValidator",
      "config": {
        "validKeyUse": string
      }
}

Configuration

"validKeyUse": string, optional

Tests the JWK.use field of a matching JWK to see if the use is correct for a transport cert.

NOTE: For Open Banking, the use will be tls. This is a custom Open Banking use value; it does not form part of the JWK spec.

Defaults to null, which skips validating the use.

Example

This example is for a validator of Open Banking Transport Certificates.

{
      "name": "OBTransportCertValidator",
      "type": "DefaultTransportCertValidator",
      "config": {
        "validKeyUse": "tls"
      }
}

CompactSerializationJwsSigner

Implementation of {@link JwsSigner} which produces signed Jws values in compact serialization form, as per JWS Compact Serialization

Includes a Static class Heaplet definition used by IG.

Compute the signature with the properties provided by configuration and produce a base64url encoded UTF-8 parts of the JWS, in accordance with JWS compact serialization

Reading recommendations

Usage

{
  "name": string,
  "type": "ScriptableFilter",
  "config": {
    "type": "application/x-groovy",
    "file": "CustomSignerScript.groovy",
    "args": {
      "signer": "${heap['DefaultSapiJwsSigner-RSASSA-PSS']}"
    }
  }
}

Script sample

// script sample
def payloadMap = [
  "example": "value",
  "key": "value",
  "key2": "value"
]

signer.sign(payloadMap, [Collections.EMPTY_LIST, null])
                .then(signedJwt -> {
                    logger.debug("result {}", signedJwt)
                    // process the signed JWT (string)
                    return response
                }, sapiJwsSignerException -> { // SapiJwsSignerException handler
                    logger.error("Signature fails: {}", sapiJwsSignerException.getMessage())
                    response.status = Status.INTERNAL_SERVER_ERROR
                    response.entity = "{ \"error\":\"" + sapiJwsSignerException.getMessage() + "\"}"
                    return newResultPromise(response)
                })

Signed JWT Validation

  • JWKs URL endpoint to validate the signature: https://keystore.openbankingtest.org.uk/[aspspOrgId]/[aspspOrgId].jwks

Extending JwsSigner

SAPI-G IG extension library provides an interface to implement a custom Signer to address custom signature cases.

To create a custom signer must implement the interface:

  • JwsSigner

Creating a custom Signer to be configured as Object in the IG Heap:

public class CustomJwsSigner implements JwsSigner {

    private final SigningManager signingManager;
    private final Purpose<SigningKey> signingKeyPurpose;
    private final String algorithm;
    private final String kid;
    
    // custom attribute
    private final String customAttribute

    public CustomJwsSigner(
            SecretsProvider secretsProvider,
            String signingKeyId,
            String kid,
            String algorithm,
            String customAttribute
    ) {
        this.signingManager = new SigningManager(secretsProvider);
        this.kid = kid;
        this.algorithm = algorithm;
        this.signingKeyPurpose = Purpose.purpose(signingKeyId, SigningKey.class);
        this.customAttribute = customAttribute;

    }
    @Override
    public Promise<String, SapiJwsSignerException> sign(
            final Map<String, Object> payload,
            final Map<String, Object> criticalHeaderClaims
    ) {
      // compute signature (see as example: DefaultSapiJwsSigner)
    }
    
    // Heaplet used to create CustomSigner object in the Heap
    public static class Heaplet extends GenericHeaplet {
        @Override
        public Object create() throws HeapException {
            final SecretsProvider secretsProvider = config.get("secretsProvider").required()
                    .as(secretsProvider(heap));
            final String signingKeyId = config.get("signingKeyId").required().asString();
            final String kid = config.get("kid").as(evaluatedWithHeapProperties()).required().asString();
            final String algorithm = config.get("algorithm").required().asString();
            
            // custom attribute
            final String customAttribute = config.get("customAttributeName").required().asString();
            
            return new CustomJwsSigner(secretsProvider, signingKeyId, kid, algorithm, customAttribute);
        }
    }
}

Heap Configuration

The heap configuration is included as an object in config.json.

{
    "comment": "Custom signer",
    "name": "CustomJwsSigner-Name",
    "type": "org.example.custom.signer.CustomJwsSigner",
    "config": {
        "algorithm": string,
        "signingKeyId": string,
        "kid": string,
        "secretsProvider": string (Heap secrets provider object name),
        "customAttributeName": string
    }
}

Now the CustomJwsSigner is an object instantiated by IG that provides signing functionality for use by the filters and/or the IG scripts.

HeaderCertificateRetriever

Retrieves a certificate from a HTTP Header Implements the com.forgerock.sapi.gateway.mtls.CertificateRetriever interface, which can be used whenever an instance of this interface is required.

Usage

{
      "name": string,
      "type": "HeaderCertificateRetriever",
      "config": {
        "certificateHeaderName": string
      }
}

Configuration

"certificateHeaderName": string, required

The name of the header that contains the certificate

Example

{
      "name": "HeaderCertificateRetriever",
      "type": "HeaderCertificateRetriever",
      "config": {
        "certificateHeaderName": "ssl-client-cert"
      }
}

ContextCertificateRetriever

Retrieves a certificate from the AttributesContext Implements the com.forgerock.sapi.gateway.mtls.CertificateRetriever interface, which can be used whenever an instance of this interface is required.

Usage

{
      "name": string,
      "type": "ContextCertificateRetriever",
      "config": {
        "certificateAttributeName": string
      }
}

Configuration

"certificateAttributeName": optional, required

The name of the attribute that contains the certificate

Defaults to "clientCertificate"

Example

{
      "name": "HeaderCertificateRetriever",
      "type": "HeaderCertificateRetriever",
      "config": {
        "certificateHeaderName": "ssl-client-cert"
      }
}

TokenEndpointMetricsContextSupplier

Supplies Context information for the Token Endpoint route (/access_token).

The following fields are extracted from the Token Endpoint Request HTTP form:

  • "grant_type" String which represents the OAuth2.0 grant_type of the token being requested
  • "scopes" List which represents the OAuth2.0 scopes being requested, the scope String from the request is being split on whitespace to produce a List

Implements the com.forgerock.sapi.gateway.metrics.MetricsContextSupplier interface, which can be used whenever an instance of this interface is required.

There is no configuration for this class.

Example

{
      "name": "TokenEndpointMetricsContextSupplier",
      "type": "TokenEndpointMetricsContextSupplier"
}

JwtReSigner

This aims to fix an issue in AM relating to signing of JWTs.

Certain use cases, such as OpenBanking UK, require keys from an external (to AM) jwks_uri be used to sign JWTs. AM can be configured to use these private keys via secret mappings, but there is an issue with how AM determines the kid value to use in the JWS header.

For the OpenBanking UK case, the kid value does not match what is expected which means that clients will not trust JWT values return by AM.

To resolve this issue, this class decodes the JWT returned by AM and creates a new one with the correct kid, it is then signed using a key that must be configured to match the expected key in the external jwks_uri

Usage

{
          "name": string,   
          "type": "JwtReSigner",
          "config": {
            "verificationSecretsProvider": SecretsProvider reference,
            "verificationSecretId": string,
            "signingKeyId": string,
            "signingSecretsProvider": SecretsProvider reference,
            "signingKeySecretId": string
          }
}

Configuration

"verificationSecretsProvider": SecretsProvider reference, required

Reference to a SecretsProvider that contains the AM secrets used to verify the id_token was signed by AM before re-signing it.

"verificationSecretId": string, required

The secretId of the verification key in the verificationSecretsProvider.

"signingKeyId": string, required

The kid value to specify in the re-signed JWS header

"signingSecretsProvider": SecretsProvider reference, required

Reference to a SecretsProvider that contains the signing private key for the signingKeyId used to sign the JWT produced by this filter.

"signingKeySecretId": string, required

The secretId of the signing private key in the signingSecretsProvider.

IdmApiClientService

Service that handles CRUD operations for ApiClient data stored in IDM.

Implements the ApiClientService interface.

Usage

{
          "name": string,   
          "type": "IdmApiClientService",
          "config": {
            "clientHandler": Handler reference,
            "idmManagedObjectsBaseUri": string,
            "apiClientManagedObjName": string
          }
}

Configuration

"clientHandler": Handler reference, required

Reference of the handler to use to call Identity Cloud or IDM; this handler must be configured to provide the correct credentials to Identity Cloud or IDM to get the apiClient managed objects.

"idmManagedObjectsBaseUri" string, required

The base URI to the IDM managed objects REST API.

"apiClientManagedObjName" string

The name of the managed object in IDM that contains ApiClients.

Defaults to: "apiClient".

Example

{
      "name": "IdmApiClientService",
      "type": "IdmApiClientService",
      "config": {
        "clientHandler": "IDMClientHandler",
        "idmManagedObjectsBaseUri": "https://&{identity.platform.fqdn}/openidm/managed"
      }
    }

IdmApiClientOrganisationService

Service that handles CRUD operations for ApiClientOrganisation data stored in IDM.

Implements the ApiClientOrganisationService interface.

Usage

{
          "name": string,   
          "type": "IdmApiClientOrganisationService",
          "config": {
            "clientHandler": Handler reference,
            "idmManagedObjectsBaseUri": string,
            "apiClientOrgManagedObjName": string
          }
}

Configuration

"clientHandler": Handler reference, required

Reference of the handler to use to call Identity Cloud or IDM; this handler must be configured to provide the correct credentials to Identity Cloud or IDM to get the apiClient managed objects.

"idmManagedObjectsBaseUri" string, required

The base URI to the IDM managed objects REST API.

"apiClientOrgManagedObjName" string

The name of the managed object in IDM that contains ApiClientOrganisation data.

Defaults to: "apiClientOrg".

Example

{
      "name": "IdmApiClientService",
      "type": "IdmApiClientService",
      "config": {
        "clientHandler": "IDMClientHandler",
        "idmManagedObjectsBaseUri": "https://&{identity.platform.fqdn}/openidm/managed"
      }
    }

Data Models

ApiClient

ApiClient represents a registered OAuth2 client of SAPI-G.

The ApiClient data store is currently Identity Cloud or IDM, the FetchApiClientFilter can be used in routes to retrieve this data for the client making the request.

Fields

oauth2ClientId: String

The OAuth2 Client ID for this client. This is generated and assigned at registration.

This ID can uniquely identify the ApiClient.

softwareClientId: String

The Client ID for this client as defined in the software statement used at registration (not necessarily unique).

clientName: String

Name of the client

jwksUri: URI

The URI of the JWKS that contains the keys which can be used by this ApiClient for transport and signing purposes.

softwareStatementAssertion: SignedJwt

The Software Statement Assertions (SSA), which is a signed JWT containing the Software Statement registered by this client. The JWT will have been signed by the TrustedDirectory that issued the software statement.

The iss claim of the SSA will match the TrustedDirectory.issuer value

organisation: ApiClientOrganisation

The ApiClientOrganisation that owns this ApiClient (and the registered SSA).

ApiClientOrganisation

Fields

id: String

The organisation id as issued by a trusted directory

name: String

The name of the organisation.

TrustedDirectory

A Trusted Directory is an external 'trust anchor' that SAPI-G should trust to be the issuer of software statements and the certificates associated with those statements. These directories are trusted by both the ApiClient and ApiProvider.

Fields

issuer: String

The value that can be expected to be found in the issuer field of Software Statements issued by this directory.

directoryJwksUri: String

The URI of the JWKS that can be used to validate software statement assertions (SSAs) issued by this directory.

softwareStatementHoldsJwksUri: boolean

One of the following values:

  • true if the software statement contains a claim that is the URI of the JWKS belonging to a software statement.
  • false if the JWKS is embedded directly into the software statement.
softwareStatementJwksUriClaimName: String

The software statement claim that represents the URI of the JWKS that can be used to validate JWS signatures for JWS objects signed by the software.

softwareStatementJwksClaimName: String

The software statement claim that contains the embedded JWKS object that can be used to validate JWS signatures for JWS objects signed by the software.

softwareStatementOrgIdClaimName: String

The software statement claim that contains the Organisation Id of the Organisation which owns the software.

softwareStatementSoftwareIdClaimName: String

The software statement claim that contains the unique Id of the software.

Example config

Open Banking Test Directory:

{
        "name": "Open Banking Test Directory",
        "type": "TrustedDirectory",
        "config": {
          "directoryJwksUri": "https://keystore.openbankingtest.org.uk/keystore/openbanking.jwks",
          "issuer": "OpenBanking Ltd",
          "softwareStatementJwksUriClaimName": "software_jwks_endpoint",
          "softwareStatementOrgIdClaimName": "org_id",
          "softwareStatementOrgNameClaimName": "org_name",
          "softwareStatementSoftwareIdClaimName": "software_id",
          "softwareStatementRedirectUrisClaimName": "software_redirect_uris",
          "softwareStatementRolesClaimName": "software_roles",
          "softwareStatementClientNameClaimName": "software_client_name"
        }
}

RouteMetricsEvent

RouteMetricsEvent represents the metrics data gathered when a request has been processed by a particular route

Fields

timestamp: long

Unix epoch timestamp in milliseconds representing the time at which the event was created

eventType: String

Description of the type of this event e.g. route-metrics

routeId: String

IG routeId of the route which produced the event

requestPath: String

Path portion of the request URI

httpMethod: String

HTTP method of the request

responseTimeMillis: long

Time to process the request and produce a response

httpStatusCode: int

HTTP Status Code of the response

successResponse: boolean

Flag indicating if the httpStatusCode represents a success or not.

apiClientId: String

The id of the ApiClient making the request

apiClientOrgId: String

The id of the ApiClientOrganisation that the ApiClient belongs to

trustedDirectory: String

Name of the TrustedDirectory that the ApiClient is registered with

context: Map<String, Object>

Custom contextual information which may be supplied on a per-request basis.

fapiInteractionId: String

The x-fapi-interaction-id value returned in the response header, used to trace the request through the platform.

Supplied by a com.forgerock.sapi.gateway.metrics.MetricsContextSupplier implementation, see TokenEndpointMetricsContextSupplier for an example.

Clone this wiki locally