-
Notifications
You must be signed in to change notification settings - Fork 0
Client Registration
OpenID Connect defines a standard API for Dynamic Client Registration - RFC 7591: OAuth 2.0 Dynamic Client Registration Protocol (rfc-editor.org).
The registration URL can be found at the configuration endpoint https://<hostname>/.well-known/openid-configuration
.
If above properties does not provide JWKs then Dynamic Registration Script methods are invoked :
- for HMAC family ->
public String getDcrHmacSecret(HttpServletRequest httpRequest, Jwt dcr)
link - for key based algs ->
public String getDcrJwks(HttpServletRequest httpRequest, Jwt dcr)
link
If the redirect URI to be added to a client is in the same domain as the server, the URI can be added via the Add Redirect URI field in the Client Registration form. If the URI is in a different domain, it must be added via a sector identifier.
The Janssen Authorization Server uses ClientRegistrationType
interception scripts to enable you to customize the behavior of the OpenID Provider during client registration. Examples of business customizations in the client registration script are validating certificates against a certificate directory, manage client claims, modify scopes, perform validation and checks.
- A Janssen Authorization Server installation
- Client Registration script - included in the default Janssen OpenBanking distribution
- Setting configuration parameters
- Setting third party library (Jose4j) in classpath
- To add or update custom scripts, you can use either jans-cli or curl. jans-cli in interactive mode, option 13 enables you manage custom scripts. For more info, see the docs.
- jans-cli in command line argument mode is more conducive to scripting and automation. To display the available operations for custom scripts, use config-cli.py --info CustomScripts. See the docs for more info.
- To use
curl
see these docs
!!! Note
You can normally find jans-cli.py
in the /opt/jans/jans-cli/
folder.
The client registration custom script will use configuration parameters like SSA Validation endpoint, JWKS endpoints, keystores, trust stores etc which are listed in the tabular format below.
Property | Description | Example |
---|---|---|
clientScopes | Used in SSA validation | ASPSPReadAccess AuthoritiesReadAccess TPPReadAccess |
keyId | Used in SSA Validation, kid used while encoding a JWT sent to token URL | XkwIzWy44xWSlcWnMiEc8iq9s2G |
signingCert | Used in SSA Validation, location of cert used for signing | /etc/certs/obieDir/obsigning-axV5umCvTMBMjPwjFQgEvb_NO_UPLOAD.key |
signingKey | Used in SSA Validation, location of key used for signing | /etc/certs/obieDir/obsigning-axV5umCvTMBMjPwjFQgEvb_NO_UPLOAD.key |
trustKeyStore | Used in SSA Validation, Trust store | /etc/certs/obieDir/ob_transport_root.p12 |
trustKeyStorePassword | Used in SSA Validation, Trust store Password, currently plaintext, but should be encrypted | abcdefg |
transportKeyStore | Used in SSA validation, a .p12 file presented by AS to the token URL | /etc/certs/obieDir/axv5umcvtmbmjpwjfqgevb_openbanking_pre_production_issuing_ca_.p12 |
transportKeyStorePassword | Used in SSA validation | abcdefg |
tokenUrl | Used in SSA validation to obtain token to query SCIM endpoint. Details here - https://openbanking.atlassian.net/wiki/spaces/DZ/pages/1150124033/Directory+2.0+Technical+Overview+v1.5#Directory2.0TechnicalOverviewv1.5-ManageDirectoryInformation | https://matls-sso.openbankingtest.org.uk/as/token.oauth2 |
tppUrl | Used in SSA validation to query SCIM endpoint. Details here - https://openbanking.atlassian.net/wiki/spaces/DZ/pages/1150124033/Directory+2.0+Technical+Overview+v1.5#Directory2.0TechnicalOverviewv1.5-ManageDirectoryInformation | https://matls-api.openbankingtest.org.uk/scim/v2/OBThirdPartyProviders/ |
jwks_endpoint | Used for signing software statement and request object for DCR | https://keystore.openbankingtest.org.uk/keystore/openbanking.jwks |
Steps to add / edit / delete configuration parameters:
-
Place a JSON file containing the above configuration parameters and the custom script in a folder.
-
From this folder, run the following command:
python3 jans-cli-linux-amd64.pyz --operation-id post-config-scripts --data /clientregistration.json \ --cert-file jans_cli_client.crt --key-file jans_cli_client.key
This script uses jose4j library for JavaScript object signing and encryption.
If using the VM distribution:
-
Download the
jose4j-0.7.7.jar
and Place in/opt/jans/jetty/jans-auth/custom/libs/
-
Change your current working directory to
/opt/jans/jetty/jans-auth/webapps
and editjans-auth.xml
to add this line:<Set name="extraClasspath">/opt/jans/jetty/jans-auth/custom/libs/jose4j-0.7.7.jar</Set>
-
Restart the Auth Server,
systemctl restart jans-auth
If using the cloud-native distribution:
-
Download the
jose4j-0.7.7.jar
-
Create a
ConfigMap
containing the jar.
```bash
kubectl create cm jose4j -n <gluu-namespace> --from-file=jose4j-0.7.7.jar
```
-
Add the volume and volume mount to
auth-server
in youroverride.yaml
helm configuration.volumes: - name: jose4j configMap: name: jose4j volumeMounts: - name: jose4j mountPath: "/opt/jans/jetty/jans-auth/custom/libs/jose4j-0.7.7.jar" subPath: jose4j-0.7.7.jar
-
Run helm upgrade.
helm upgrade gluu gluu/gluu -n <gluu-namespace> --version=5.0.0 -f override.yaml
The Client Registration script is available
The following are the mandatory functions which need to be implemented in order to perform registration:
-
Create a class of the type
ClientRegistrationType
and initialize the scriptclass ClientRegistration(ClientRegistrationType): def __init__(self, currentTimeMillis): self.currentTimeMillis = currentTimeMillis def init(self, customScript, configurationAttributes): print "Client registration. Initialization" if (not configurationAttributes.containsKey("param")): print "Client registration. Initialization. Property keyId is not specified" return False else: self.param = configurationAttributes.get("param").getValue2() print "Client registration. Initialized successfully" return True def destroy(self, configurationAttributes): print "Client registration. Destroy" print "Client registration. Destroyed successfully" return True
-
The createClient method contains the main business logic, here the context refers to io.jans.as.server.service.external.context.DynamicClientRegistrationContext. It has several useful methods for SSA validations and options to create and throw custom exception (http status, error and error description):
def createClient(self, context): # 1. obtain client id. certProperty contains the httpRequest.getHeader("X-ClientCert"), inshort client certificate passed to the /register endpoint cert = CertUtils.x509CertificateFromPem(configurationAttributes.get("certProperty").getValue1()) cn = CertUtils.getCN(cert) # 2. validate SSA valid = self.validateSoftwareStatement(cn) if valid == False: print "Invalid software statement" return False print "Client registration. cn: " + cn client.setDn("inum=" + cn + ",ou=clients,o=jans") # 3. Used to indicate that only this is a trusted client (note that consent is managed by Internal OP / consent app) client.setTrustedClient(True) client.setPersistClientAuthorizations(False) # 4. in order to run introspection script, assign it to run for this client client.setAccessTokenAsJwt(True) client.getAttributes().setRunIntrospectionScriptBeforeAccessTokenAsJwtCreationAndIncludeClaims(True) dnOfIntrospectionScript = "inum=CABA-2222,ou=scripts,o=jans" client.getAttributes().getIntrospectionScripts().add(dnOfIntrospectionScript) # 5. mandatory fields which should be set in the script client.setClientId(cn) client.setJwksUri(Jwt.parse(registerRequest.getSoftwareStatement()).getClaims().getClaimAsString("org_jwks_endpoint")) return True
-
Miscellaneous mandatory functions
Used for signing the software statement:
def getSoftwareStatementJwks(self, context): return JwtUtil.getJSONWebKeys(self.jwks_endpoint).toString()
HMAC not applicable, return an empty string:
def getDcrHmacSecret(self, context): return ""
Used for signing the request object (DCR):
def getDcrJwks(self, context): return JwtUtil.getJSONWebKeys(self.jwks_endpoint).toString()
-
An important method of DCR flow to update the client details
-
The updateClient method
This updateClient method is called when the PUT method is called on registration endpoint to update client details. This method should return True for successful update and to reject any update request this method should return False when the request fulfills the condition to reject it:
def updateClient(self, context): print "Client registration. UpdateClient method" return True