A common usage of “Dynamic Client Registration” is in the OpenBanking world where a financial institution will like to allow third party service providers (TPP) to dynamically register themselves as OAuth clients. These TPPs, will then, have access to the said financial institute’s OpenBanking APIs.
On the Ping Identity website, there is a excellent “to do” article on how PingFederate and Open Banking Org work together.
This article documents how to use the PingFederate’s Dynamic Client Registration APIs without stepping into the OpenBanking world. Here we will use the default plugin provided in PingFederate’s SDK to validate a software statement generated using an OpenSSL CA. Please note that certificates required can be generated/requested from any CA (Public or Private), so I will not get into details of how to use OpenSSL to do that. There are numerous blogs on the web to help achieve that.
Let us start with the pre-requisites:
- A PingFederate cluster with, at least, one engine node. I am running these instances on Docker Desktop 22.214.171.124.
- Dynamic Client Registration on PingFederate requires OAuth client storage in an external data store, such as a database or LDAP directory.
So, I have the external DB running on a Postgres 9.6.15 container. Follow the Ping Identity’s documentation to configure this.
- I use curl as REST API client and used OpenSSL to generate a “signing” and MTLS certificates.
For configuration purposes you need the signing certificate’s issuer/CA certificate to imported in “Trusted CAs” on PingFedrate and Public key from the signing certificate in JWKS format.
- You will need a JAVA compilation Environment (ANT, preferably) to compile “SoftwareStatementValidatorPlugin” available in the “pingfederate_9.3.3/pingfederate/sdk/plugin_src/dynamic_client_registration_example/” directory.
Import the plugin
For the purpose of this exercise we are not going to make any changes to the “SoftwareStatementValidatorPlugin” available in the “pingfederate/sdk/plugin_src/dynamic_client_registration_example/” directory.
- Once the plugin has been compiled, it needs to be copied to “pingfederate/server/default/deploy/” folder of your PingFederate Console and Engine instances.
- Restart the instances once the plugin has been copied.
There maybe up to three certificates in play here:
- Certificate used to sign the Software Statement
Our plugin will validate the Software Statement. Hence PingFederate needs to trust a certificate which has signed the Software Statement.
My OpenSSL issued certificate which has the extension “KeyUsage” set to “Digital Signatures” will be used for this purpose. I have this certificate in a p12/pfx format. Later in the document, I have pasted the perl code to extract the private key from this pfx/p12 file.
We will call this the signing certificate in this document.
I used https://keytool.online to convert public key to JWKS format but It is strongly recommended NOT to use production keys on online tools.
- Certificate Used by the client to sign the request JWT.
For this exercise I have kept the requests as unsigned. So, we will not this certificate for now.
- Certificate used by the client to establish MTLS with AS.
I have generated another certificate issued by the same Root CA. This certificate should be an SSL Client certificate. This certificate will be referred as “MTLS client certificate” in this document.
Import CA certificate to PingFederate
We need to trust the issuer of the above certificates, so we will “import” the issuer by logging on to the PingFederate console and clicking on “import” button in “Security”>> Trusted CAs”.
Generate software statement
As per the RFC 7591 : “A software statement is a JSON Web Token(jwt) that asserts metadata values about the client software as a bundle.”
This jwt has three components:
- JOSE Header which contains the information like type, cryptographic algorithms used for signing and encryption.
- Payload which will contain the claims made by the TPP/Client to the Authorization Server (PingFederate in our case) during registration.
I used the following perl code to base64url encode my header and payload:
These two strings are separated by a “.” and then signed:
Please note that $pkcs12_file is the signing certificate in P12/PFX format.
Finally, my jwt will be the concatenation of three strings separated by a “.”:
Configure PingFederate for Dynamic Client Registration:
- Click on “Create New Instance” in “OAuth Server”>> “Client Registration Policies”.
- If the “SoftwareStatementValidatorPlugin” was imported successfully then you should see this under “Type”.
- The JWKS in the screen shot below corresponds to the private key used to sign the Software statement above. There are multiple ways to convert your public key to a JWKS format. You can extract exponent and modulus using openssl commands and manually create a JWKS.
- Next go to “OAuth Server”>> “Client Settings” and Enable DYNAMIC CLIENT REGISTRATION :
Protecting the Endpoint
In our client settings we have set “Require Initial Access Token” to true. Hence the API call to the /as/clients.oauth3 endpoint will be protected by OAuth.
For this I had create an OAuth client which was restricted to one scope (conveniently named DynamicClientRegistration).
We can put this OAUTH client behind MTLS and or assign complex IDP authentication policies. For this exercise I have used implicit grant and a simple PCV based HTTP basic auth adapter.
Request for Registration
Request for initial access token
Request for registration