-
Notifications
You must be signed in to change notification settings - Fork 1
IG Extensions Java Module
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
- FetchApiClientFilter
- AuthorizeResponseFetchApiClientFilter
- ParResponseFetchApiClientFilter
- FetchTrustedDirectoryFilter
- FetchApiClientJwksFilter
- TransportCertValidationFilter
- TokenEndpointTransportCertValidationFilter
- ConsentRequestAccessAuthorisationFilter
- AddCertificateToAttributesContextFilter
- AccessTokenResponseIdTokenReSignFilter
- AuthorizeResponseJwtReSignFilter
- RouteMetricsFilter
- FapiAuthorizeRequestValidationFilter
- FapiParRequestValidationFilter
- ManageApiClientFilter
- Services
- Data Models
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.
{
"name": string,
"type": "FAPIAdvancedDCRValidationFilter",
"config": {
"clientTlsCertHeader": string,
"supportedSigningAlgorithms": [ string, ... ],
"supportedTokenEndpointAuthMethods": [ string, ... ],
"registrationObjectSigningFieldNames": [ string, ... ]
}
}
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.
The JWS algorithms supported for messaging signing.
Default value: ["PS256", "ES256"]
The DCR token_endpoint_auth_methods supported.
Default value: ["tls_client_auth", "self_signed_tls_client_auth", "private_key_jwt"]
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"]
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"]
}
}
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.
{
"name": string,
"type": "FetchApiClientFilter",
"config": {
"apiClientService": ApiClientService reference
}
}
Reference to an ApiClientService implementation, this handles retrieving the ApiClient data from the datastore.
{
"name": "FetchApiClientFilter",
"type": "FetchApiClientFilter",
"config": {
"apiClientService": "IdmApiClientService"
}
}
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"
{
"name": string,
"type": "AuthorizeResponseFetchApiClientFilter",
"config": {
"apiClientService": ApiClientService reference
}
}
Reference to an ApiClientService implementation, this handles retrieving the ApiClient data from the datastore.
{
"name": "AuthorizeResponseFetchApiClientFilter",
"type": "AuthorizeResponseFetchApiClientFilter",
"config": {
"apiClientService": "IdmApiClientService"
}
}
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
{
"name": "ParResponseFetchApiClientFilter",
"type": "ParResponseFetchApiClientFilter",
"config": {
"apiClientService": "IdmApiClientService"
}
}
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.
{
"name": string,
"type": "FetchTrustedDirectoryFilter",
"config": {
"trustedDirectoryService": TrustedDirectoryService reference,
}
}
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.
{
"name": "FetchTrustedDirectoryFilter",
"type": "FetchTrustedDirectoryFilter",
"config": {
"trustedDirectoryService": "TrustedDirectoriesService"
}
}
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.
{
"name": string,
"type": "FetchApiClientJwksFilter",
"config": {
"jwkSetService": JwkSetService reference,
}
}
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.
{
"name": "FetchApiClientJwksFilter",
"type": "FetchApiClientJwksFilter",
"config": {
"jwkSetService": "OBJwkSetService"
}
}
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.
{
"name": string,
"type": "TransportCertValidationFilter",
"config": {
"clientTlsCertHeader": string,
"transportCertValidator": TransportCertValidator reference
}
}
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
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.
{
"name": "TransportCertValidationFilter",
"type": "TransportCertValidationFilter",
"config": {
"clientTlsCertHeader": "ssl-client-cert",
"transportCertValidator": "TransportCertValidator"
}
}
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.
{
"name": string,
"type": "TokenEndpointTransportCertValidationFilter",
"config": {
"certificateRetriever": CertificateRetriever reference
"trustedDirectoryService": TrustedDirectoryService reference,
"jwkSetService": JwkSetService reference,
"transportCertValidator": TransportCertValidator reference
}
}
Reference to a CertificateRetriever, which is used to fetch the client's mTLS certificate from the Request / Context.
See HeaderCertificateRetriever and ContextCertificateRetriever.
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.
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.
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.
{
"name": "TokenEndpointTransportCertValidationFilter",
"type": "TokenEndpointTransportCertValidationFilter",
"config": {
"certificateRetriever": "HeaderCertificateRetriever",
"trustedDirectoryService": "TrustedDirectoriesService",
"jwkSetService": "OBJwkSetService",
"transportCertValidator": "TransportCertValidator"
}
}
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.
{
"name": string,
"type": "ConsentRequestAccessAuthorisationFilter",
"config": {
"consentRequestUserIdClaim": string,
"ssoTokenUserIdKey": string
}
}
Name of the claim in the consent request JWT which contains the userId
Defaults to: "username"
Key within SsoTokenContext.info which contains the userId
Defaults to: "uid"
{
"name": "ConsentRequestAccessAuthorisationFilter",
"type": "ConsentRequestAccessAuthorisationFilter"
}
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
{
"name": string,
"type": "AddCertificateToAttributesContextFilter",
"config": {
"certificateRetriever": CertificateRetriever reference,
"certificateAttributeName": string
}
}
Reference to a com.forgerock.sapi.gateway.mtls.CertificateRetriever
object, typically this will be a
HeaderCertificateRetriever
The name of the attribute to store the certificate in.
Defaults to: "clientCertificate"
{
"name": "AddCertificateToAttributesContextFilter",
"type": "AddCertificateToAttributesContextFilter",
"config": {
"certificateRetriever": "HeaderCertificateRetriever"
}
}
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.
{
"name": string,
"type": "AccessTokenResponseIdTokenReSignFilter",
"config": {
"jwtReSigner": JwtReSigner reference
}
}
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.
{
"name": "AccessTokenResponseIdTokenReSignFilter",
"type": "AccessTokenResponseIdTokenReSignFilter",
"config": {
"jwtReSigner": "jwtReSigner"
}
}
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.
{
"name": string,
"type": "AuthorizeResponseJwtReSignFilter",
"config": {
"jwtReSigner": JwtReSigner reference
}
}
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.
{
"name": "AuthorizeResponseJwtReSignFilter",
"type": "AuthorizeResponseJwtReSignFilter",
"config": {
"jwtReSigner": "jwtReSigner"
}
}
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
{
"name": string,
"type": "RouteMetricsFilter",
"config": {
"metricsContextSupplier": MetricsContextSupplier reference
}
}
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:
{
"name": "RouteMetricsFilter",
"type": "RouteMetricsFilter"
}
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.
{
"name": string,
"type": "FapiAuthorizeRequestValidationFilter"
}
None
{
"name": "FapiAuthorizeRequestValidationFilter",
"type": "FapiAuthorizeRequestValidationFilter"
}
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.
{
"name": string,
"type": "FapiParRequestValidationFilter"
}
None
{
"name": "FapiParRequestValidationFilter",
"type": "FapiParRequestValidationFilter"
}
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.
{
"name": string,
"type": "ManageApiClientFilter",
"config": {
"apiClientService": ApiClientService reference,
"apiClientOrgService": ApiClientOrganisationService reference,
"clientIdRequestParameterLocator": ClientIdRequestParameterLocator reference
}
}
Reference to an ApiClientService implementation, this handles retrieving the ApiClient data from the datastore.
Reference to an ApiClientOrganisationService implementation, this handles retrieving the ApiClient data from the datastore.
Reference to an ClientIdRequestParameterLocator implementation.
When the Authorisation Server is AM, then the QueryParamClientIdRequestParameterLocator should be used.
{
"name": "ManageApiClientFilter",
"type": "ManageApiClientFilter",
"config": {
"apiClientService": "IdmApiClientService",
"apiClientOrgService": "IdmApiClientOrgService",
"clientIdRequestParameterLocator": {
"name": "QueryParamClientIdRequestParameterLocator",
"type": "QueryParamClientIdRequestParameterLocator"
}
}
}
These are classes that provide functionality for use by the filters above and/or the IG scripts.
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.
{
"name": string,
"type": "RestJwkSetService",
"config": {
"handler": Handler reference
}
}
Reference to the handler instance to use when making the HTTP REST calls.
Defaults to: "clientHandler" which is the default ClientHandler name.
{
"name": "OBJwkSetService",
"type": "RestJwkSetService",
"config": {
"handler": "OBClientHandler"
}
}
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.
{
"name": string,
"type": "CaffeineCachingJwkSetService",
"config": {
"handler": Handler reference,
"maxCacheEntries": long,
"expireAfterWriteDuration": duration
}
}
Reference to the handler instance to use when making the HTTP REST calls.
Defaults to: "clientHandler" which is the default ClientHandler name.
Max number of entries in the cache; when this limit is exceeded, entries are evicted using the LRU algorithm.
Defaults to: 100
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"
{
"name": "OBJwkSetService",
"type": "CaffeineCachingJwkSetService",
"config": {
"handler": "OBClientHandler",
"maxCacheEntries": 500,
"expireAfterWriteDuration": "24 hours"
}
}
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.
{
"name": "RsaJwtSignatureValidator",
"type": "RsaJwtSignatureValidator"
}
Implementation of the TrustedDirectoryService interface. Retrieves TrustedDirectory configuration for an issuer by name, directories to support are configured in config.
{
"name": string,
"type": "StaticTrustedDirectoryService",
"config": {
"trustedDirectories": [ TrustedDirectory reference, ... ]
}
}
"trustedDirectories": array of TrustedDirectory, required
The TrustedDirectory objects to support.
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}"
}
}
]
}
}
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
{
"name": string,
"type": "DefaultTransportCertValidator",
"config": {
"validKeyUse": string
}
}
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.
This example is for a validator of Open Banking Transport Certificates.
{
"name": "OBTransportCertValidator",
"type": "DefaultTransportCertValidator",
"config": {
"validKeyUse": "tls"
}
}
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
{
"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
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.
- IG heap reference: https://backstage.forgerock.com/docs/ig/7.2/reference/heap-objects.html
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.
{
"name": string,
"type": "HeaderCertificateRetriever",
"config": {
"certificateHeaderName": string
}
}
The name of the header that contains the certificate
{
"name": "HeaderCertificateRetriever",
"type": "HeaderCertificateRetriever",
"config": {
"certificateHeaderName": "ssl-client-cert"
}
}
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.
{
"name": string,
"type": "ContextCertificateRetriever",
"config": {
"certificateAttributeName": string
}
}
The name of the attribute that contains the certificate
Defaults to "clientCertificate"
{
"name": "HeaderCertificateRetriever",
"type": "HeaderCertificateRetriever",
"config": {
"certificateHeaderName": "ssl-client-cert"
}
}
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.
{
"name": "TokenEndpointMetricsContextSupplier",
"type": "TokenEndpointMetricsContextSupplier"
}
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
{
"name": string,
"type": "JwtReSigner",
"config": {
"verificationSecretsProvider": SecretsProvider reference,
"verificationSecretId": string,
"signingKeyId": string,
"signingSecretsProvider": SecretsProvider reference,
"signingKeySecretId": string
}
}
Reference to a SecretsProvider that contains the AM secrets used to verify the id_token was signed by AM before re-signing it.
The secretId of the verification key in the verificationSecretsProvider.
The kid value to specify in the re-signed JWS header
Reference to a SecretsProvider that contains the signing private key for the signingKeyId used to sign the JWT produced by this filter.
The secretId of the signing private key in the signingSecretsProvider.
Service that handles CRUD operations for ApiClient data stored in IDM.
Implements the ApiClientService interface.
{
"name": string,
"type": "IdmApiClientService",
"config": {
"clientHandler": Handler reference,
"idmManagedObjectsBaseUri": string,
"apiClientManagedObjName": string
}
}
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.
The base URI to the IDM managed objects REST API.
The name of the managed object in IDM that contains ApiClients.
Defaults to: "apiClient".
{
"name": "IdmApiClientService",
"type": "IdmApiClientService",
"config": {
"clientHandler": "IDMClientHandler",
"idmManagedObjectsBaseUri": "https://&{identity.platform.fqdn}/openidm/managed"
}
}
Service that handles CRUD operations for ApiClientOrganisation data stored in IDM.
Implements the ApiClientOrganisationService interface.
{
"name": string,
"type": "IdmApiClientOrganisationService",
"config": {
"clientHandler": Handler reference,
"idmManagedObjectsBaseUri": string,
"apiClientOrgManagedObjName": string
}
}
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.
The base URI to the IDM managed objects REST API.
The name of the managed object in IDM that contains ApiClientOrganisation data.
Defaults to: "apiClientOrg".
{
"name": "IdmApiClientService",
"type": "IdmApiClientService",
"config": {
"clientHandler": "IDMClientHandler",
"idmManagedObjectsBaseUri": "https://&{identity.platform.fqdn}/openidm/managed"
}
}
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.
The OAuth2 Client ID for this client. This is generated and assigned at registration.
This ID can uniquely identify the ApiClient.
The Client ID for this client as defined in the software statement used at registration (not necessarily unique).
Name of the client
The URI of the JWKS that contains the keys which can be used by this ApiClient for transport and signing purposes.
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
The ApiClientOrganisation that owns this ApiClient (and the registered SSA).
The organisation id as issued by a trusted directory
The name of the organisation.
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.
The value that can be expected to be found in the issuer field of Software Statements issued by this directory.
The URI of the JWKS that can be used to validate software statement assertions (SSAs) issued by this directory.
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.
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.
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.
The software statement claim that contains the Organisation Id of the Organisation which owns the software.
The software statement claim that contains the unique Id of the software.
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 represents the metrics data gathered when a request has been processed by a particular route
Unix epoch timestamp in milliseconds representing the time at which the event was created
Description of the type of this event e.g. route-metrics
IG routeId of the route which produced the event
Path portion of the request URI
HTTP method of the request
Time to process the request and produce a response
HTTP Status Code of the response
Flag indicating if the httpStatusCode represents a success or not.
The id of the ApiClient making the request
The id of the ApiClientOrganisation that the ApiClient belongs to
Name of the TrustedDirectory that the ApiClient is registered with
Custom contextual information which may be supplied on a per-request basis.
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.
-
The Secure API Gateway (SAPI-G) Documentation
- SAPI-G Implementation Status
- Understanding SAPI-G
- Deployment
- Protect Custom APIs using SAPI-G
- Testing
- Troubleshooting