From 0db037b14a3b7a7779be3471b06467671b2efa86 Mon Sep 17 00:00:00 2001 From: Guillaume Lamirand Date: Tue, 30 Sep 2025 09:56:01 +0200 Subject: [PATCH] OPENIG-9596 Update initialization process for IDM --- README.md | 16 +- .../readme.md | 12 +- .../templates/job.yaml | 10 +- .../fapi-as-ig-oauth2-client.json | 285 ++++++++++++++++++ .../fapi-rs-ig-oauth2-client.json | 285 ++++++++++++++++++ .../identity-platform/ig-oauth2-client.json | 4 +- .../managed-objects/apiClient.json | 197 ------------ .../managed-objects/apiClientOrg.json | 122 -------- config/viper/viper-default-configuration.yaml | 4 +- main.go | 8 +- pkg/identity-platform/platform.go | 52 +--- pkg/securebanking/idm.go | 98 ------ pkg/securebanking/idm_test.go | 60 ---- pkg/types/configuration.go | 17 +- 14 files changed, 619 insertions(+), 551 deletions(-) create mode 100644 config/defaults/identity-platform/fapi-as-ig-oauth2-client.json create mode 100644 config/defaults/identity-platform/fapi-rs-ig-oauth2-client.json delete mode 100644 config/defaults/secure-open-banking/managed-objects/apiClient.json delete mode 100644 config/defaults/secure-open-banking/managed-objects/apiClientOrg.json delete mode 100644 pkg/securebanking/idm_test.go diff --git a/README.md b/README.md index 8417003..3d48ba0 100644 --- a/README.md +++ b/README.md @@ -172,14 +172,14 @@ There are a variables used before load the configuration file and these variable | Environment variable | default | description | |------------------------|-----------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `IG.IG_CLIENT_ID` | ig-client | The initializer creates an OAuth2 Client that the SBAT IG will use to authenticate to the FR Platform to ensure that Api Client's can't bypass IG and use the FR Identity Platform APIs directly. The OAuth2 client will be created with this id | -| `IG.IG_CLIENT_SECRET` | add-here-the-password | The initializer creates an OAuth2 Client that the SBAT IG will use to authenticate to the FR Platform to ensure that Api Client's can't bypass IG and use the FR Identity Platform APIs directly. The OAuth2 client will be created with this password | -| `IG.IG_RCS_SECRET` | add-here-the-secret | IG rcs secret for remote consent service | -| `IG.IG_SSA_SECRET` | add-here-the-secret | IG ssa secret for software publisher agent | -| `IG.IG_IDM_USER` | service_account.ig | IG service user account | -| `IG.IG_IDM_PASSWORD` | add-here-the-password | IG service user account password | -| `IG.IG_AGENT_ID` | ig-agent | IG agent id for IG policy agent | -| `IG.IG_AGENT_PASSWORD` | add-here-the-password | Ig agent password for IG policy agent | +| `IG.IG_CLIENT_ID` | ig-client | The initializer creates an OAuth2 Client that the SBAT IG will use to authenticate to the FR Platform to ensure that Api Client's can't bypass IG and use the FR Identity Platform APIs directly. The OAuth2 client will be created with this id | +| `IG.IG_CLIENT_SECRET` | add-here-the-password | The initializer creates an OAuth2 Client that the SBAT IG will use to authenticate to the FR Platform to ensure that Api Client's can't bypass IG and use the FR Identity Platform APIs directly. The OAuth2 client will be created with this password | +| `IG.IG_RCS_SECRET` | add-here-the-secret | IG rcs secret for remote consent service | +| `IG.IG_SSA_SECRET` | add-here-the-secret | IG ssa secret for software publisher agent | +| `IG.IG_AS_IDM_CLIENT_SECRET` | add-here-the-secret | IG secret for IDM Client used on AS | +| `IG.IG_RS_IDM_CLIENT_SECRET` | add-here-the-secret | IG secret for IDM Client used on RS | +| `IG.IG_AGENT_ID` | ig-agent | IG agent id for IG policy agent | +| `IG.IG_AGENT_PASSWORD` | add-here-the-password | Ig agent password for IG policy agent | **Identity variables** diff --git a/_infra/helm/securebanking-openbanking-uk-iam-initializer/readme.md b/_infra/helm/securebanking-openbanking-uk-iam-initializer/readme.md index f8f15ee..cd5ef56 100644 --- a/_infra/helm/securebanking-openbanking-uk-iam-initializer/readme.md +++ b/_infra/helm/securebanking-openbanking-uk-iam-initializer/readme.md @@ -134,16 +134,16 @@ spec: secretKeyRef: name: as-sapig-secrets key: IG_CLIENT_SECRET - - name: IG.IG_IDM_USER + - name: IG.IG_AS_IDM_CLIENT_SECRET valueFrom: secretKeyRef: name: as-sapig-secrets - key: IG_IDM_USER - - name: IG.IG_IDM_PASSWORD + key: IG_AS_IDM_CLIENT_SECRET + - name: IG.IG_RS_IDM_CLIENT_SECRET valueFrom: secretKeyRef: name: as-sapig-secrets - key: IG_IDM_PASSWORD + key: IG_RS_IDM_CLIENT_SECRET - name: IG.IG_AGENT_ID valueFrom: secretKeyRef: @@ -190,8 +190,8 @@ These are the environment variables declared in the `cronjob.yaml`; IDENTITY.REMOTE_CONSENT_ID | secure-open-banking-rcs | | as-sapig-deployment-config/RCS_CONSENT_RESPONSE_JWT_SIGNINGKEYID | | IG.IG_CLIENT_ID | | | as-sapig-secrets | | IG.IG_CLIENT_SECRET | | | as-sapig-secrets | -| IG.IG_IDM_USER | | | as-sapig-secrets | -| IG.IG_IDM_PASSWORD | | | as-sapig-secrets | +| IG.IG_AS_IDM_CLIENT_SECRET | | | as-sapig-secrets | +| IG.IG_RS_IDM_CLIENT_SECRET | | | as-sapig-secrets | | IG.IG_AGENT_ID | | | as-sapig-secrets | | IG.IG_AGENT_PASSWORD | | | as-sapig-secrets | diff --git a/_infra/helm/securebanking-openbanking-uk-iam-initializer/templates/job.yaml b/_infra/helm/securebanking-openbanking-uk-iam-initializer/templates/job.yaml index e571492..3d7472a 100644 --- a/_infra/helm/securebanking-openbanking-uk-iam-initializer/templates/job.yaml +++ b/_infra/helm/securebanking-openbanking-uk-iam-initializer/templates/job.yaml @@ -153,17 +153,17 @@ spec: valueFrom: secretKeyRef: name: as-sapig-secrets - key: IG_CLIENT_SECRET - - name: IG.IG_IDM_USER + key: IG_CLIENT_SECRET + - name: IG.IG_AS_IDM_CLIENT_SECRET valueFrom: secretKeyRef: name: as-sapig-secrets - key: IG_IDM_USER - - name: IG.IG_IDM_PASSWORD + key: IG_AS_IDM_CLIENT_SECRET + - name: IG.IG_RS_IDM_CLIENT_SECRET valueFrom: secretKeyRef: name: as-sapig-secrets - key: IG_IDM_PASSWORD + key: IG_RS_IDM_CLIENT_SECRET - name: IG.IG_AGENT_ID valueFrom: secretKeyRef: diff --git a/config/defaults/identity-platform/fapi-as-ig-oauth2-client.json b/config/defaults/identity-platform/fapi-as-ig-oauth2-client.json new file mode 100644 index 0000000..d93d105 --- /dev/null +++ b/config/defaults/identity-platform/fapi-as-ig-oauth2-client.json @@ -0,0 +1,285 @@ +{ + "coreOAuth2ClientConfig": { + "agentgroup": "", + "status": { + "inherited": false, + "value": "Active" + }, + "userpassword": "{{.Ig.IgAsIdmClientSecret}}", + "clientType": { + "inherited": false, + "value": "Confidential" + }, + "loopbackInterfaceRedirection": { + "inherited": true, + "value": true + }, + "redirectionUris": { + "inherited": false, + "value": [ + "https://httpbin.org/anything" + ] + }, + "scopes": { + "inherited": false, + "value": [ + "fr:idm:*", + "trusted_gateway" + ] + }, + "defaultScopes": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "clientName": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "authorizationCodeLifetime": { + "inherited": true, + "value": 0 + }, + "refreshTokenLifetime": { + "inherited": true, + "value": 0 + }, + "accessTokenLifetime": { + "inherited": true, + "value": 0 + } + }, + "advancedOAuth2ClientConfig": { + "name": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "descriptions": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "requestUris": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "responseTypes": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "grantTypes": { + "inherited": false, + "value": [ + "client_credentials" + ] + }, + "contacts": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "tokenEndpointAuthMethod": { + "inherited": true, + "value": "string" + }, + "sectorIdentifierUri": { + "inherited": true, + "value": "string" + }, + "subjectType": { + "inherited": true, + "value": "string" + }, + "updateAccessToken": { + "inherited": true, + "value": "string" + }, + "clientUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "logoUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "policyUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "isConsentImplied": { + "inherited": true, + "value": true + }, + "mixUpMitigation": { + "inherited": true, + "value": true + } + }, + "coreOpenIDClientConfig": { + "claims": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "postLogoutRedirectUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "clientSessionUri": { + "inherited": true, + "value": "string" + }, + "defaultMaxAge": { + "inherited": true, + "value": 0 + }, + "defaultMaxAgeEnabled": { + "inherited": true, + "value": true + }, + "defaultAcrValues": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "jwtTokenLifetime": { + "inherited": true, + "value": 0 + } + }, + "signEncOAuth2ClientConfig": { + "jwksUri": { + "inherited": true, + "value": "string" + }, + "jwksCacheTimeout": { + "inherited": true, + "value": 0 + }, + "jwkStoreCacheMissCacheTime": { + "inherited": true, + "value": 0 + }, + "tokenEndpointAuthSigningAlgorithm": { + "inherited": true, + "value": "string" + }, + "jwkSet": { + "inherited": true, + "value": "string" + }, + "idTokenSignedResponseAlg": { + "inherited": true, + "value": "string" + }, + "idTokenEncryptionEnabled": { + "inherited": true, + "value": true + }, + "idTokenEncryptionAlgorithm": { + "inherited": true, + "value": "string" + }, + "idTokenEncryptionMethod": { + "inherited": true, + "value": "string" + }, + "idTokenPublicEncryptionKey": { + "inherited": true, + "value": "string" + }, + "clientJwtPublicKey": { + "inherited": true, + "value": "string" + }, + "mTLSTrustedCert": { + "inherited": true, + "value": "string" + }, + "mTLSSubjectDN": { + "inherited": true, + "value": "string" + }, + "mTLSCertificateBoundAccessTokens": { + "inherited": true, + "value": true + }, + "publicKeyLocation": { + "inherited": true, + "value": "string" + }, + "userinfoResponseFormat": { + "inherited": true, + "value": "string" + }, + "userinfoSignedResponseAlg": { + "inherited": true, + "value": "string" + }, + "userinfoEncryptedResponseAlg": { + "inherited": true, + "value": "string" + }, + "userinfoEncryptedResponseEncryptionAlgorithm": { + "inherited": true, + "value": "string" + }, + "requestParameterSignedAlg": { + "inherited": true, + "value": "string" + }, + "requestParameterEncryptedAlg": { + "inherited": true, + "value": "string" + }, + "requestParameterEncryptedEncryptionAlgorithm": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionResponseFormat": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionSignedResponseAlg": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionEncryptedResponseAlg": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionEncryptedResponseEncryptionAlgorithm": { + "inherited": true, + "value": "string" + } + }, + "coreUmaClientConfig": { + "claimsRedirectionUris": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + } + } +} \ No newline at end of file diff --git a/config/defaults/identity-platform/fapi-rs-ig-oauth2-client.json b/config/defaults/identity-platform/fapi-rs-ig-oauth2-client.json new file mode 100644 index 0000000..80c3408 --- /dev/null +++ b/config/defaults/identity-platform/fapi-rs-ig-oauth2-client.json @@ -0,0 +1,285 @@ +{ + "coreOAuth2ClientConfig": { + "agentgroup": "", + "status": { + "inherited": false, + "value": "Active" + }, + "userpassword": "{{.Ig.IgRsIdmClientSecret}}", + "clientType": { + "inherited": false, + "value": "Confidential" + }, + "loopbackInterfaceRedirection": { + "inherited": true, + "value": true + }, + "redirectionUris": { + "inherited": false, + "value": [ + "https://httpbin.org/anything" + ] + }, + "scopes": { + "inherited": false, + "value": [ + "fr:idm:*", + "trusted_gateway" + ] + }, + "defaultScopes": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "clientName": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "authorizationCodeLifetime": { + "inherited": true, + "value": 0 + }, + "refreshTokenLifetime": { + "inherited": true, + "value": 0 + }, + "accessTokenLifetime": { + "inherited": true, + "value": 0 + } + }, + "advancedOAuth2ClientConfig": { + "name": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "descriptions": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "requestUris": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "responseTypes": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "grantTypes": { + "inherited": false, + "value": [ + "client_credentials" + ] + }, + "contacts": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "tokenEndpointAuthMethod": { + "inherited": true, + "value": "string" + }, + "sectorIdentifierUri": { + "inherited": true, + "value": "string" + }, + "subjectType": { + "inherited": true, + "value": "string" + }, + "updateAccessToken": { + "inherited": true, + "value": "string" + }, + "clientUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "logoUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "policyUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "isConsentImplied": { + "inherited": true, + "value": true + }, + "mixUpMitigation": { + "inherited": true, + "value": true + } + }, + "coreOpenIDClientConfig": { + "claims": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "postLogoutRedirectUri": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "clientSessionUri": { + "inherited": true, + "value": "string" + }, + "defaultMaxAge": { + "inherited": true, + "value": 0 + }, + "defaultMaxAgeEnabled": { + "inherited": true, + "value": true + }, + "defaultAcrValues": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + }, + "jwtTokenLifetime": { + "inherited": true, + "value": 0 + } + }, + "signEncOAuth2ClientConfig": { + "jwksUri": { + "inherited": true, + "value": "string" + }, + "jwksCacheTimeout": { + "inherited": true, + "value": 0 + }, + "jwkStoreCacheMissCacheTime": { + "inherited": true, + "value": 0 + }, + "tokenEndpointAuthSigningAlgorithm": { + "inherited": true, + "value": "string" + }, + "jwkSet": { + "inherited": true, + "value": "string" + }, + "idTokenSignedResponseAlg": { + "inherited": true, + "value": "string" + }, + "idTokenEncryptionEnabled": { + "inherited": true, + "value": true + }, + "idTokenEncryptionAlgorithm": { + "inherited": true, + "value": "string" + }, + "idTokenEncryptionMethod": { + "inherited": true, + "value": "string" + }, + "idTokenPublicEncryptionKey": { + "inherited": true, + "value": "string" + }, + "clientJwtPublicKey": { + "inherited": true, + "value": "string" + }, + "mTLSTrustedCert": { + "inherited": true, + "value": "string" + }, + "mTLSSubjectDN": { + "inherited": true, + "value": "string" + }, + "mTLSCertificateBoundAccessTokens": { + "inherited": true, + "value": true + }, + "publicKeyLocation": { + "inherited": true, + "value": "string" + }, + "userinfoResponseFormat": { + "inherited": true, + "value": "string" + }, + "userinfoSignedResponseAlg": { + "inherited": true, + "value": "string" + }, + "userinfoEncryptedResponseAlg": { + "inherited": true, + "value": "string" + }, + "userinfoEncryptedResponseEncryptionAlgorithm": { + "inherited": true, + "value": "string" + }, + "requestParameterSignedAlg": { + "inherited": true, + "value": "string" + }, + "requestParameterEncryptedAlg": { + "inherited": true, + "value": "string" + }, + "requestParameterEncryptedEncryptionAlgorithm": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionResponseFormat": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionSignedResponseAlg": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionEncryptedResponseAlg": { + "inherited": true, + "value": "string" + }, + "tokenIntrospectionEncryptedResponseEncryptionAlgorithm": { + "inherited": true, + "value": "string" + } + }, + "coreUmaClientConfig": { + "claimsRedirectionUris": { + "inherited": true, + "value": [ + "Unknown Type: any" + ] + } + } +} \ No newline at end of file diff --git a/config/defaults/identity-platform/ig-oauth2-client.json b/config/defaults/identity-platform/ig-oauth2-client.json index b29d4d1..6d9a4bd 100644 --- a/config/defaults/identity-platform/ig-oauth2-client.json +++ b/config/defaults/identity-platform/ig-oauth2-client.json @@ -23,7 +23,6 @@ "scopes": { "inherited": false, "value": [ - "fr:idm:*", "dynamic_client_registration", "trusted_gateway" ] @@ -81,8 +80,7 @@ "grantTypes": { "inherited": false, "value": [ - "client_credentials", - "password" + "client_credentials" ] }, "contacts": { diff --git a/config/defaults/secure-open-banking/managed-objects/apiClient.json b/config/defaults/secure-open-banking/managed-objects/apiClient.json deleted file mode 100644 index e31129e..0000000 --- a/config/defaults/secure-open-banking/managed-objects/apiClient.json +++ /dev/null @@ -1,197 +0,0 @@ -[ - { - "operation": "add", - "field": "objects/-", - "value": { - "name": "apiClient", - "schema": { - "$schema": "http://forgerock.org/json-schema#", - "type": "object", - "title": "apiClient", - "description": "Secure Banking apiClient", - "icon": "fa-cogs", - "properties": { - "_id": { - "title": "IDM Internal ID", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": null, - "isVirtual": false, - "deleteQueryConfig": false - }, - "id": { - "title": "API Client ID", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": null, - "isVirtual": false, - "deleteQueryConfig": false - }, - "softwareId": { - "title": "software_id", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": null, - "isVirtual": false, - "deleteQueryConfig": false - }, - "name": { - "title": "API Client Name", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true - }, - "description": { - "title": "Description", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true - }, - "logoUri": { - "title": "Logo URI", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true - }, - "jwksUri": { - "title": "JWKS URI", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true - }, - "jwks": { - "title": "JWK Set", - "type": "object", - "viewable": true, - "searchable": false, - "userEditable": false - }, - "roles": { - "title": "Roles", - "type": "array", - "items": { - "type": "string" - }, - "viewable": true, - "searchable": false, - "userEditable": true - }, - "ssa": { - "title": "Software Statement Assertion", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": null, - "minLength": null, - "isVirtual": false - }, - "apiClientOrg": { - "title": "API Client Organisation", - "type": "relationship", - "viewable": true, - "searchable": false, - "userEditable": false, - "returnByDefault": false, - "reverseRelationship": true, - "reversePropertyName": "apiClients", - "validate": false, - "properties": { - "_ref": { - "type": "string" - }, - "_refProperties": { - "type": "object", - "properties": { - "_id": { - "type": "string", - "required": false, - "propName": "_id" - } - } - } - }, - "resourceCollection": [ - { - "path": "managed/apiClientOrg", - "label": "apiClientorg", - "query": { - "queryFilter": "true", - "fields": [ - "id", - "name" - ], - "sortKeys": [] - }, - "notify": false - } - ], - "description": null, - "requiredByParent": false, - "isVirtual": false, - "notifySelf": false, - "referencedRelationshipFields": null, - "referencedObjectFields": null, - "deleteQueryConfig": false - }, - "oauth2ClientId": { - "title": "OAuth2 Client ID", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": "OAuth2 Client ID", - "isVirtual": false, - "deleteQueryConfig": false - }, - "deleted": { - "title": "Deleted", - "type": "boolean", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": "Has the ApiClient record been deleted", - "isVirtual": false, - "default": false - } - }, - "order": [ - "_id", - "softwareId", - "name", - "description", - "deleted", - "logoUri", - "jwksUri", - "ssa", - "apiClientOrg", - "oauth2ClientId" - ], - "required": [ - "name", - "oauth2ClientId", - "ssa", - "deleted" - ], - "mat-icon": null - }, - "onRead": { - "type": "text/javascript", - "globals": {}, - "source": "if (object.softwareId === undefined) {\n object.softwareId = object.id\n}" - }, - "iconClass": "fa fa-database", - "type": "Managed Object" - } - } -] diff --git a/config/defaults/secure-open-banking/managed-objects/apiClientOrg.json b/config/defaults/secure-open-banking/managed-objects/apiClientOrg.json deleted file mode 100644 index 08535cf..0000000 --- a/config/defaults/secure-open-banking/managed-objects/apiClientOrg.json +++ /dev/null @@ -1,122 +0,0 @@ -[ - { - "operation": "add", - "field": "objects/-", - "value": { - "name": "apiClientOrg", - "schema": { - "$schema": "http://forgerock.org/json-schema#", - "type": "object", - "title": "apiClientOrg", - "description": "apiClientOrg Details", - "icon": "fa-bank", - "properties": { - "name": { - "title": "API Client Organisation Name", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": "API Client Organisation Name", - "isVirtual": false, - "deleteQueryConfig": false - }, - "id": { - "title": "API Client Organisation ID", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true, - "description": "API Client Organisation ID", - "isVirtual": false, - "policies": [ - { - "policyId": "unique", - "params": {} - } - ], - "deleteQueryConfig": false - }, - "created": { - "title": "Timestamp", - "type": "string", - "viewable": true, - "searchable": true, - "userEditable": true - }, - "_id": { - "title": "Internal IDM Identifier", - "type": "string", - "viewable": true, - "searchable": false, - "userEditable": false, - "description": null, - "minLength": null, - "isVirtual": false - }, - "apiClients": { - "description": null, - "title": "API Clients", - "viewable": true, - "searchable": false, - "userEditable": false, - "policies": [], - "returnByDefault": false, - "minLength": null, - "type": "array", - "items": { - "type": "relationship", - "reverseRelationship": true, - "reversePropertyName": "apiClientOrg", - "validate": false, - "properties": { - "_ref": { - "type": "string" - }, - "_refProperties": { - "type": "object", - "properties": { - "_id": { - "type": "string", - "required": false, - "propName": "_id" - } - } - } - }, - "resourceCollection": [ - { - "path": "managed/apiClient", - "label": "apiClient", - "query": { - "queryFilter": "true", - "fields": [], - "sortKeys": [] - }, - "notify": false - } - ], - "notifySelf": false - }, - "requiredByParent": false, - "isVirtual": false, - "referencedRelationshipFields": null, - "referencedObjectFields": null, - "deleteQueryConfig": false - } - }, - "order": [ - "name", - "id", - "created", - "_id", - "apiClients" - ], - "required": [], - "mat-icon": "" - }, - "iconClass": "fa fa-database", - "type": "Managed Object" - } - } -] diff --git a/config/viper/viper-default-configuration.yaml b/config/viper/viper-default-configuration.yaml index b7c8ef0..91db003 100644 --- a/config/viper/viper-default-configuration.yaml +++ b/config/viper/viper-default-configuration.yaml @@ -36,8 +36,8 @@ IG: # Root key for parameter values related with IG platform component service c IG_CLIENT_SECRET: password # The OAuth2 client secret to be used by IG to authenticate to the FR Platform IG_RCS_SECRET: password # IG rcs secret for remote consent service IG_SSA_SECRET: password # IG ssa secret for software publisher agent - IG_IDM_USER: service_account.ig # IG service user account - IG_IDM_PASSWORD: 0penBanking! # IG service user account password + IG_AS_IDM_CLIENT_SECRET: 0penBanking! + IG_RS_IDM_CLIENT_SECRET: 0penBanking! IG_AGENT_ID: ig-agent # IG agent id for IG policy agent IG_AGENT_PASSWORD: password # Ig agent password for IG policy agent IDENTITY: # Root key for parameter values related with identity platform configuration diff --git a/main.go b/main.go index 9f203a1..a979348 100644 --- a/main.go +++ b/main.go @@ -122,17 +122,15 @@ func main() { time.Sleep(5 * time.Second) - platform.CreateIGServiceUser() - platform.CreateIGOAuth2Client() + platform.CreateIGCoreOAuth2Client() + platform.CreateIGAsOAuth2Client() + platform.CreateIGRsOAuth2Client() platform.CreateIGPolicyAgent() platform.ApplySystemClients(session.Cookie) time.Sleep(5 * time.Second) - fmt.Println("Attempt to Add IAM Managed Objects...") - securebanking.AddIamManagedObjects() - securebanking.CreateApiJwksEndpoint() } diff --git a/pkg/identity-platform/platform.go b/pkg/identity-platform/platform.go index 309f35c..4cf5a10 100644 --- a/pkg/identity-platform/platform.go +++ b/pkg/identity-platform/platform.go @@ -12,56 +12,34 @@ import ( "go.uber.org/zap" ) -func CreateIGServiceUser() { - if httprest.ServiceIdentityExists(common.Config.Ig.IgIdmUser) { - zap.L().Info("Skipping creation of IG service user") - return - } +// CreateIGOAuth2Client - +func CreateIGCoreOAuth2Client() { + createIGOAuth2Client(common.Config.Ig.IgClientId, "ig-oauth2-client.json") +} - zap.L().Info("Creating IG service user") - - user := &types.ServiceUser{ - UserName: common.Config.Ig.IgIdmUser, - SN: "Service Account", - GivenName: "IG", - Mail: "ig@acme.com", - Password: common.Config.Ig.IgIdmPassword, - AuthzRole: []types.AuthzRole{ - { - Ref: "internal/role/openidm-admin", - }, - }, - } - path := "/openidm/managed/user/?_action=create" - //FIDC IDM default user managed objects use a different naming pattern _user Eg:alpha_user - if common.Config.Environment.CloudType == "FIDC" { - path = "/openidm/managed/" + common.Config.Identity.AmRealm + "_user/?_action=create" - } - _, s := httprest.Client.Post(path, user, map[string]string{ - "Accept": "*/*", - "Content-Type": "application/json", - "Connection": "keep-alive", - }) +func CreateIGAsOAuth2Client() { + createIGOAuth2Client("fapi-as-ig-client", "fapi-as-ig-oauth2-client.json") +} - zap.S().Infow("IG Service User", "statusCode", s) +func CreateIGRsOAuth2Client() { + createIGOAuth2Client("fapi-rs-ig-client", "fapi-rs-ig-oauth2-client.json") } -// CreateIGOAuth2Client - -func CreateIGOAuth2Client() { - if httprest.OAuth2AgentClientsExist(common.Config.Ig.IgClientId) { - zap.S().Infof("Skipping creation of IG Oauth2 client. OAuth2 client %s already exists", common.Config.Ig.IgClientId) +func createIGOAuth2Client(clientId string, oauth2ConfigFile string) { + if httprest.OAuth2AgentClientsExist(clientId) { + zap.S().Infof("Skipping creation of IG Oauth2 client. OAuth2 client %s already exists", clientId) return } - zap.S().Infof("Creating IG OAuth2 client with id %s", common.Config.Ig.IgClientId) + zap.S().Infof("Creating IG OAuth2 client with id %s", clientId) oauth2Client := &types.OAuth2Client{} - err := common.Unmarshal(common.Config.Environment.Paths.ConfigIdentityPlatform+"ig-oauth2-client.json", &common.Config, oauth2Client) + err := common.Unmarshal(common.Config.Environment.Paths.ConfigIdentityPlatform+oauth2ConfigFile, &common.Config, oauth2Client) if err != nil { panic(err) } - path := fmt.Sprintf("/am/json/"+common.Config.Identity.AmRealm+"/realm-config/agents/OAuth2Client/%s", common.Config.Ig.IgClientId) + path := fmt.Sprintf("/am/json/"+common.Config.Identity.AmRealm+"/realm-config/agents/OAuth2Client/%s", clientId) s := httprest.Client.Put(path, oauth2Client, map[string]string{ "Accept": "application/json", "Content-Type": "application/json", diff --git a/pkg/securebanking/idm.go b/pkg/securebanking/idm.go index fda80a3..e050487 100644 --- a/pkg/securebanking/idm.go +++ b/pkg/securebanking/idm.go @@ -1,111 +1,13 @@ package securebanking import ( - "encoding/json" "io/ioutil" "secure-banking-uk-initializer/pkg/common" "secure-banking-uk-initializer/pkg/httprest" - "strings" "go.uber.org/zap" ) -//objectNames - retrieve filenames from a path. the .json extension will be trimed and -// a list of filenames will be returned -func objectNames(relativePath string) []string { - files, err := ioutil.ReadDir(relativePath) - if err != nil { - zap.L().Fatal(err.Error()) - } - - var names []string - for _, f := range files { - name := strings.TrimSuffix(f.Name(), ".json") - names = append(names, name) - } - return names -} - -//MissingObjects - return a list of missing managed object names in idm. -// supply an array of managed object names to query against. -func missingObjects(objectNames []string) []string { - path := "/openidm/config/managed" - result := &OBManagedObjects{} - b, _ := httprest.Client.Get(path, map[string]string{ - "Accept": "application/json", - "X-Requested-With": "ForgeRock Identity Cloud Postman Collection", - }) - - err := json.Unmarshal(b, result) - if err != nil { - panic(err) - } - - var missObjects = objectNames - for _, o := range result.Objects { - for i, objectName := range missObjects { - zap.S().Infow("checking", "object", o) - if strings.Contains(o.Name, objectName) { - zap.S().Infow("ManagedObject found", "name", objectName) - missObjects = append(missObjects[:i], missObjects[i+1:]...) - break - } - } - } - return missObjects -} - -// OBManagedObjects model -type OBManagedObjects struct { - ID string `json:"_id"` - Objects []struct { - Name string `json:"name"` - } `json:"objects"` -} - -// AddIAMManagedObjects - Add managed objects to IDM. This will look for json in the managed objects config directory -// and add them to IDM if they dont already exist. -func AddIamManagedObjects() { - configPath := common.Config.Environment.Paths.ConfigSecureBanking + "managed-objects/" - managedObjectFilenames := objectNames(configPath) - mObjects := missingObjects(managedObjectFilenames) - - zap.S().Infow("Attempting to add Managed Object definitions", "definitions", mObjects) - patches := make([]map[string]interface{}, 0) - for _, o := range mObjects { - patches = append(patches, unmarshallManagedObjectPatch(o, configPath)...) - - } - patchManagedObjects(patches) -} - -func patchManagedObjects(managedObjectPatches []map[string]interface{}) { - zap.S().Infow("Patching Managed Object definitions", "patches", managedObjectPatches) - - path := "/openidm/config/managed" - s := httprest.Client.Patch(path, managedObjectPatches, map[string]string{ - "Accept": "*/*", - "Content-Type": "application/json", - "Connection": "keep-alive", - }) - - zap.S().Infow("Managed object created", "statusCode", s) -} - -func unmarshallManagedObjectPatch(name string, objectFolderPath string) []map[string]interface{} { - b, err := ioutil.ReadFile(objectFolderPath + name + ".json") - if err != nil { - panic(err) - } - - patch := make([]map[string]interface{}, 0) - err = json.Unmarshal(b, &patch) - if err != nil { - panic(err) - } - return patch -} - func CreateApiJwksEndpoint() { zap.L().Info("Creating API JWKS Endpoint") b, err := ioutil.ReadFile(common.Config.Environment.Paths.ConfigSecureBanking + "create-jwks-endpoint.json") diff --git a/pkg/securebanking/idm_test.go b/pkg/securebanking/idm_test.go deleted file mode 100644 index aa800ea..0000000 --- a/pkg/securebanking/idm_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package securebanking - -import ( - "io/ioutil" - "secure-banking-uk-initializer/pkg/httprest" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" - mocks "secure-banking-uk-initializer/pkg/mocks/am" -) - -func TestWillReturnAllMissingObjects(t *testing.T) { - mockRestReaderWriter := &mocks.RestReaderWriter{} - httprest.Client = mockRestReaderWriter - buffer, _ := ioutil.ReadFile("managed-objects-test.json") - mockRestReaderWriter.On("Get", mock.Anything, mock.Anything). - Return(buffer) - - expectedMissing := []string{"abc", "def"} - allMissing := missingObjects(expectedMissing) - assert.Equal(t, expectedMissing, allMissing) -} - -func TestWillReturnPartialListOfMissingObjects(t *testing.T) { - mockRestReaderWriter := &mocks.RestReaderWriter{} - httprest.Client = mockRestReaderWriter - buffer, _ := ioutil.ReadFile("managed-objects-test.json") - mockRestReaderWriter.On("Get", mock.Anything, mock.Anything). - Return(buffer) - - expectedMissing := []string{"abc", "def"} - allMissing := missingObjects([]string{"anotherObject", "abc", "def", "api_client"}) - assert.Equal(t, expectedMissing, allMissing) -} - -func TestWillReturnNoMissingObjects(t *testing.T) { - mockRestReaderWriter := &mocks.RestReaderWriter{} - httprest.Client = mockRestReaderWriter - buffer, _ := ioutil.ReadFile("managed-objects-test.json") - mockRestReaderWriter.On("Get", mock.Anything, mock.Anything). - Return(buffer) - - expectedMissing := []string{} - allMissing := missingObjects([]string{"anotherObject", "api_client"}) - assert.Equal(t, expectedMissing, allMissing) -} - -func TestWillReturnObjectNamesFromPath(t *testing.T) { - names := objectNames("testconfig/") - expectedNames := []string{"test.user.1", "test1", "test2", "test3"} - - assert.Equal(t, expectedNames, names) -} - -func TestManagedObjectDirectoriesExist(t *testing.T) { - _, err := ioutil.ReadDir("../../config/defaults") - - assert.Nil(t, err, "The managed object config directory config/defaults/ should exist") -} diff --git a/pkg/types/configuration.go b/pkg/types/configuration.go index e13e5f4..1efa113 100644 --- a/pkg/types/configuration.go +++ b/pkg/types/configuration.go @@ -46,15 +46,16 @@ type identity struct { } type ig struct { - IgClientId string `mapstructure:"IG_CLIENT_ID"` - IgClientSecret string `mapstructure:"IG_CLIENT_SECRET"` - IgRcsSecret string `mapstructure:"IG_RCS_SECRET"` - IgSsaSecret string `mapstructure:"IG_SSA_SECRET"` - IgIdmUser string `mapstructure:"IG_IDM_USER"` - IgIdmPassword string `mapstructure:"IG_IDM_PASSWORD"` - IgAgentId string `mapstructure:"IG_AGENT_ID"` - IgAgentPassword string `mapstructure:"IG_AGENT_PASSWORD"` + IgClientId string `mapstructure:"IG_CLIENT_ID"` + IgClientSecret string `mapstructure:"IG_CLIENT_SECRET"` + IgRcsSecret string `mapstructure:"IG_RCS_SECRET"` + IgSsaSecret string `mapstructure:"IG_SSA_SECRET"` + IgAsIdmClientSecret string `mapstructure:"IG_AS_IDM_CLIENT_SECRET"` + IgRsIdmClientSecret string `mapstructure:"IG_RS_IDM_CLIENT_SECRET"` + IgAgentId string `mapstructure:"IG_AGENT_ID"` + IgAgentPassword string `mapstructure:"IG_AGENT_PASSWORD"` } + type environment struct { Verbose bool `mapstructure:"VERBOSE"` Strict bool `mapstructure:"STRICT"`