FAPI- Private Key JWT
When FAPI_CertEAI authenticates a client with MTLS, client_assertion STS chain is not triggered as the client is already authenticated.
The following code snippet triggers client_assertion STS Chain. This ensures client present in client_assertion and MTLS authenticated client matches. To achieve FAPI certification with Private Key JWT, add the following snippet to the API Protection Definition pre token mapping rule:
/* * FAPI - Private_key_jwt * * Ensure this snippet is added within the isFapiCompliantByDefinitionID check * Client Assertion is a form of client authentication. In the case of FAPI, FAPI_CertEAI authenticates a client if mtls client certificate is present. * Therefore, client_assertion is not handled. This code snippet triggeres client_assertion manually and ensures client id of client_assertion jwt and client object created * based of mtls authentication matches. * * client_assertion_required flag enforces client_assertion. * */ var client_assertion_required = true; var client_assertion = stsuu.getContextAttributes().getAttributeValueByName("client_assertion"); if (client_assertion_required && request_type == "access_token" && client_assertion != null){ var base_token = IDMappingExtUtils.stringToXMLElement( "<wss:BinarySecurityToken " + "xmlns:wss=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" " + "wss:EncodingType=\"http://ibm.com/2004/01/itfim/base64encode\" " + "wss:ValueType=\"urn:com:ibm:JWT\">"+client_assertion+"<\/wss:BinarySecurityToken>"); var res = LocalSTSClient.doRequest("http://schemas.xmlsoap.org/ws/2005/02/trust/Validate","https://localhost/sps/oauth/oauth20", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer:", base_token, null) if (res.errorMessage == null){ var client_assertion_stsuu = new STSUniversalUser(); client_assertion_stsuu.fromXML(res.token); IDMappingExtUtils.traceString("FAPI Client Assertion Result: " + client_assertion_stsuu); var claims_str = client_assertion_stsuu.getContextAttributes().getAttributeValueByNameAndType("claim_json", "urn:com:ibm:JWT"); var claims = JSON.parse(claims_str); /* * Check the JWT has not expired */ if ( claims.exp != undefined ){ var expDate = new Date(claims.exp * 1000); var currDate = new Date(); if (expDate < currDate){ OAuthMappingExtUtils.throwSTSCustomUserPageException("JWT has expired.",400,"invalid_request"); } } /* * Validates aud and issuer value in client_assertion jwt against information in definition. */ if ( claims.iss != undefined && claims.aud != undefined){ var def_id = OAuthMappingExtUtils.getClient(claims.iss).getDefinitionID(); var iss = OAuthMappingExtUtils.getDefinitionByID(def_id).getOidc().getIss(); var poc = OAuthMappingExtUtils.getDefinitionByID(def_id).getOidc().getPoc(); if (Array.isArray(claims.aud)){ var found = false; for (var x = 0; x < claims.aud.length; x++ ){ if((claims.aud[x]).includes(iss) || (claims.aud[x]).includes(poc)){ found = true; break; } } if (!found){ OAuthMappingExtUtils.throwSTSCustomUserPageException("aud in request object does not match issuer of client definition.",400,"invalid_request"); } } else if( !((claims.aud).includes(iss) || (claims.aud).includes(poc))){ OAuthMappingExtUtils.throwSTSCustomUserPageException("aud in client_assertion jwt does not match issuer of client definition.",400,"invalid_request"); } } /* * Ensure MTLS authentication credentials present */ var fingerprint = stsuu.getAttributeValueByName("fingerprint"); if (fingerprint == null){ OAuthMappingExtUtils.throwSTSCustomUserPageException("mtls credentials of client is missing.",400,"invalid_request"); } }else{ OAuthMappingExtUtils.throwSTSCustomUserPageException("client_assertion failed.",400,"invalid_request"); } }else if(client_assertion_required && request_type == "access_token" ){ OAuthMappingExtUtils.throwSTSCustomUserPageException("client_assertion is not found in token endpoint.",400,"invalid_request"); }
Parent topic: Achieving Financial-grade API (FAPI) conformance with IBM Security Verify Access