API Connect — Using custom hooks in Dev Portal to share application credentials with Identity Provider
Overview
This article describes how to use custom hooks in the API Connect v2018. Developer Portal to share application credentials with Identity Provider (IdP) like IBM Security Access Manager.
It is common in enterprise that they have existing IdP that handles API Security like OAuth and OIDC. Applications needs to interact with these Enterprise IDP to obtain access tokens or id tokens before calling APIs published in APIC gateway. Applications need to provide application credentials (client_id and client secret) for this exchange. In APIC, application credentials are created when an application developer register their application(s) on the Developer Portal. Sometimes, there is requirement to share application credentials created in APIC with existing Enterprise IDP.
To do this, in APIC Developer Portal, this is a custom hook mechanism that allows you to handle some of these application life cycle events so that you can “do something” with it. E.g. when an application is created or when a client_id is reset, we can define hooks/functions to handle these events.
Before we begin, we need to understand the relationship between application, credentials, client_id and client_secret.
- An application have one (1) or up to twenty (20) credentials. Each application has a unique identifier,
app_id
. An application have one or many redirect URLs. - Each credential has a pair of
client_id
andclient_secret
. It also has a unique identifier,cred_id
; that does not change. - The
client_id
andclient_secret
can be changed. When you reset theclient_id
both theclient_id
andclient_secret
are changed.When you reset theclient_id
, only theclient_secret
is changed.
The following implementation assumes that the IDP provides a set of REST interfaces that can be used to create, update or delete an application with its credentials. The IDP should have the following object model.
- Application object with fields — id, name, redirect_url (comma-separated)
- Credential object with fields — id, client_id, client_secret, app_id as foreign key
Custom Hook
The following are a list of custom hooks:
1. modulename_apic_app_create
This hook is called when an application is created. As part of this, a credential is also automatically created. Therefore, you will need to send the following information to the IDP: app_id
, cred_id
, app_name
, redirect_url
list, cred_id
, client_id
, client_secret
. The IDP should create an application object, a credential object and associate the credential object to the application. It also creates a redirect_url object.
Use the POST method and with the following URL and payload.
POST /apps HTTP/1.1
Host: {idp_hostname}
Accept: application/json
Content-Type: application/json; charset=iso-8859-1{
"id": {app_id},
"name": {app_name},
"title": {app_title},
"credential": {
"id": {cred_id},
"client_id": {client_id},
"client_secret": {client_secret}
}
"redirect_endpoints": [
{redirect_url_1},
{redirect_url_2}
]
}
2. modulename_apic_app_update
This hook is called when an application is updated — where only the name and the redirect_url
is updated. The IDP should update the name
, title
and redirect_url
of the application object.
Use the PUT method and with the following URL and payload.
PUT /apps/{app_id} HTTP/1.1
Host: {idp_hostname}
Accept: application/json
Content-Type: application/json; charset=iso-8859-1{
"name": {app_name},
"title": {app_title},
"redirect_endpoints": [
{redirect_url_1},
{redirect_url_2}
]
}
3. modulename_apic_app_delete
This hook is called when an application is deleted. The IDP should delete the application object and all the credential objects by its app_id
.
Use the DELETE method and with the following URL and payload.
DELETE /apps/{app_id} HTTP/1.1
Host: {idp_hostname}
4. modulename_apic_app_clientid_reset
This hook is called when the client_id
is reset (together with the client_secret
). The IDP should update the credential object with new client_id
and client_secret
.
Use the PUT method and with the following URL and payload.
PUT /apps/{app_id}/credentials/{cred_id} HTTP/1.1
Host: {idp_hostname}
Accept: application/json
Content-Type: application/json; charset=iso-8859-1{
"client_id": {client_id},
"client_secret": {client_secret}
}
5. modulename_apic_app_clientsecret_reset
This hook is called when the client_secret
is reset. The IDP should update the credential object with new client_secret
.
Use the PUT method and with the following URL and payload.
PUT /apps/{app_id}/credentials/{cred_id} HTTP/1.1
Host: {idp_hostname}
Accept: application/json
Content-Type: application/json; charset=iso-8859-1{
"client_secret": {client_secret}
}
7. modulename_apic_app_creds_create
This hook is called when a new credential is created for an existing application. The IDP should create a new credential object and map it to an existing application object.
Use the POST method and with the following URL and payload.
POST /apps/{app_id}/credentials/{cred_id} HTTP/1.1
Host: {idp_hostname}
Accept: application/json
Content-Type: application/json; charset=iso-8859-1{
"credential": {
"client_id": {client_id},
"client_secret": {client_secret}
}
}
8. modulename_apic_app_creds_delete
This hook is called when the credential is deleted. The IDP should delete the credential object.
Use the DELETE method and with the following URL and payload.
DELETE /apps/{app_id}/credentials/{cred_id} HTTP/1.1
Host: {idp_hostname}
Accept: application/json
Content-Type: application/json; charset=iso-8859-1
9. modulename_apic_app_creds_update
This hook is called when the title of the credential is updated. The IDP should update the credential object. This is no need to handle this because the title of the credential is not important to the IDP.
How to create custom module
1. Create the module
- Create a folder, say
app-push-cred-module
. Change directory into the folder. - Create a custom
.module
file. The name of my module isapp_cred_push
. - Add the hook function in this
.module
file. The name of my module isapp_cred_push
; so the file name isapp_cred_push.module
. This module file is a PHP code. - Prefix the function with your custom module name with the following format
moduleName_apic_app_create
.
function app_cred_push_apic_app_create($node, $app) {
}
5. Create a info.yaml
file in the same folder. The name of my module is app_cred_push.info.yaml
. E.g.
name: App Credentials Push Module
description: Send HTTP request containing application credentials when it is created or changed.
package: Custom
type: module
version: 1.0
core: 8.x
6. You need to know a bit of PHP to code this. There is a sample implementation in the Github — https://github.com/khongks/app-cred-push-module.git.
2. Package the module
- Package the module using zip or tar to include the folder. From the folder
app-cred-push-module
.
? cd ..
? zip -r app-cred-push-module.zip app-cred-push-module
3. Install the module
- Sign in as
admin
in the Developer Portal. - Go to the Manage > Extend and click on Install new module.
- On the Install new module page, choose file and click Install.
- Click on Enable newly added modules to return to the list tab for the Extend page.
- Find your module, check the box and click Enable.
4. Troubleshoot
- To log into a file, use the following in your PHP code.
\Drupal::logger('app_cred_push')->info('apic_app_create hook called');
2. To view the logs, ssh into the portal server and run the following:
? sudo -i
? kubectl get poNAME READY STATUS RESTARTS AGE
apic-portal-apic-portal-db-cljxp 2/2 Running 0 8d
apic-portal-apic-portal-nginx-664c6c5b59-r6pv7 1/1 Running 0 25d
apic-portal-apic-portal-www-q2wdj 2/2 Running 0 8d
ptl-backup-4pjvb-pfvqj 0/1 Completed 0 8d
ptl-backup-662vt-g2rn8 0/1 Completed 0 8d
ptl-backup-p54nf-j4ln7 0/1 Error 0 8d
ptl-list-backups-kvsx8-rn85l 0/1 Error 0 8d
ptl-list-backups-vr5rp-xs9xk 0/1 Completed 0 8d
? kubectl logs apic-portal-apic-portal-www-q2wdj web --tail=1000 -f
3. Ensure that your PHP code can be compiled (no syntax error) — because it will crash your portal site.
4. If you crash your portal site, you need to correct the error within the container.
? kubectl -it exec apic-portal-apic-portal-www-q2wdj -c web bash
5. Go to the folder (as follows), edit and correct the error in the file.
? cd /web/platforms/devportal-8.x-2018.4.1.7-20190910-0421/sites/{org}.{catalog}.{portal-web-endpoint}/modules/{module-name}
for example:
? cd /web/platforms/devportal-8.x-2018.4.1.7-20190910-0421/sites/think-provider-organization.test.portal-web.think.org/modules/app-cred-push-module
References
- Custom modules development: using hooks. List of hook functions is found here.
2. Installing custom modules
3. Deleting custom modules
4. Disabling modules
Disclaimer:
All opinions expressed here are very much my own and not of IBM. All codes/scripts/artifacts are provided as-is with no support unless otherwise stated.