Keycloak Config - bcgov/SIMS GitHub Wiki

Useful links

Instances

SSO Team

BSCS Integration

Configuring a Keycloak instance

Getting access

  1. Access the master instance with your IDIR account (SSO Team needed to provide access).
  2. Configure the IDIR identity provider and give realm administrator access to your own user.
  3. Access the console link to execute further configurations.

Reference: https://stackoverflow.developer.gov.bc.ca/questions/939/940

Identity Providers

IDIR

This is the only IDP that must be configured while in the master instance.

  • Create a new identity provider as shown below.

image

  • Set the below properties and leave the others with the default values, setting [dev/test] accordingly to the environment.
    • Alias: idir
    • Display name: idir
    • First login flow: first broker login
    • Sync Mode: force
    • Authorization URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/auth?kc_idp_hint=idir
    • Token URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/token
    • Logout URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/logout
    • User Info URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/userinfo
    • Client Authentication: Client secret sent as post
    • Client ID: provided using the Common Hosted Single Sign-on portal (how to get client/secret).
    • Client Secret: provided using the Common Hosted Single Sign-on portal (how to get client/secret).
    • Validate Signatures: true
    • Use JWKS URL: true
    • JWKS URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/certs
  • Once the IDIR identity provider is configured, find the user and associate the /Realm Administrator role to it. image
  • The remaining configurations can be done using the console link.

Where to find credentials (Client ID/Secret)

Access the BCeID - Common Hosted Single Sign-on (CSS) and look for the below information.

image

Configuring mappers

  • identity_provider
    • name: identity_provider
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: identity_provider
    • User Attribute Name: identityProvider

BCeID (basic/business)

  • Create a new identity provider as shown below.

image

  • Set the below properties and leave the others with the default values. As per team decision DEV/TEST is pointing to TEST.
    • Alias: bceidboth
    • Display name: bceidboth
    • First login flow: first broker login
    • Sync Mode: force
    • Authorization URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/auth?kc_idp_hint=bceidboth
    • Token URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/token
    • Logout URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/logout
    • User Info URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/userinfo
    • Client Authentication: Client secret sent as post
    • Client ID: provided using the Common Hosted Single Sign-on portal (how to get client/secret).
    • Client Secret: provided using the Common Hosted Single Sign-on portal (how to get client/secret).
    • Validate Signatures: true
    • Use JWKS URL: true
    • JWKS URL: https://[dev/test].loginproxy.gov.bc.ca/auth/realms/standard/protocol/openid-connect/certs

Configuring mappers

  • identity_provider
    • name: identity_provider
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: identity_provider
    • User Attribute Name: identity_provider
  • bceid_username
    • name: bceid_username
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: bceid_username
    • User Attribute Name: idp_user_name
  • bceid_business_guid
    • name: bceid_business_guid
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: bceid_business_guid
    • User Attribute Name: bceid_business_guid
  • bceid_business_name
    • name: bceid_business_name
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: bceid_business_name
    • User Attribute Name: bceid_business_name

BCSC

  • Create a new identity provider as shown below.

image

Configuring mappers

  • identity_provider
    • name: identity_provider
    • Sync Mode: force,
    • Mapper Type: Hardcoded Attribute
    • Claim: identity_provider
    • User Attribute Name: bcsc
  • birthdate
    • name: birthdate
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: birthdate
    • User Attribute Name: birthdate
  • firstName
    • name: firstName
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: given_names
    • User Attribute Name: firstName
  • lastName
    • name: lastName
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: family_name
    • User Attribute Name: lastName
  • username
    • name: username
    • Sync Mode: force,
    • Mapper Type: Username Template Importer
    • Template: ${CLAIM.sub}@bcsc
  • Country
    • name: Country
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: address.country
    • User Attribute Name: country
  • Locality (City/town)
    • name: Locality (City/town)
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: address.locality
    • User Attribute Name: locality
  • Street Address
    • name: Street Address
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: address.street_address
    • User Attribute Name: street_address
  • Region (State or Province)
    • name: Region (State or Province)
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: address.region
    • User Attribute Name: region
  • Postal Code
    • name: Postal Code
    • Sync Mode: force,
    • Mapper Type: Attribute Importer
    • Claim: address.postal_code
    • User Attribute Name: postal_code

Client Scopes

  • address
    • Settings
      • Name: address
      • Protocol: openid-connect
      • Type: Optional
    • Mappers
      • address
        • User Attribute Name for Street: street_address
        • User Attribute Name for Locality: locality
        • User Attribute Name for Region: region
        • User Attribute Name for Postal Code: postal_code
        • User Attribute Name for Country: country
        • User Attribute Name for Formatted Address: formatted
  • business-bceid
    • Settings
      • Name: business-bceid
      • Protocol: openid-connect
      • Type: None
    • Mappers
      • BCeID Business Guid
        • Mapper Type: User Attribute
        • Name: BCeID Business Guid
        • User Attribute: bceid_business_guid
        • Token Claim Name: bceid_business_guid
  • client-roles
    • Settings
      • Name: client-roles
      • Protocol: openid-connect
      • Type: None
    • Mappers
      • client-roles
        • Mapper Type: User Client Role
        • Name: client-roles
        • Token Claim Name: resource_access.${client_id}.roles
        • Add to ID Token: Off. IMPORTANT! Add to ID Token must be explicitly set to Off to minimize the size of the ID Token so it doesn't cause issues with SiteMinder logouts.
  • default-name-scope
    • Settings
      • Name: default-name-scope
      • Protocol: openid-connect
      • Type: None
    • Mappers
      • lastName
        • Mapper Type: User Property
        • Name: lastName
        • Property: lastName
        • Token Claim Name: lastName
        • Claim JSON Type: String
      • givenNames
        • Name: givenNames
        • Property: firstName
        • Token Claim Name: givenNames
        • Claim JSON Type: String
  • identity-provider
    • Settings
      • Name: identity-provider
      • Protocol: openid-connect
      • Type: None
    • Mappers
      • idpUsername
        • Mapper Type: User Attribute
        • Name: idpUsername
        • User Attribute: idp_user_name
        • Token Claim Name: idp_user_name
        • Claim JSON Type: String
      • Identity Provider
        • Mapper Type: User Attribute
        • Name: Identity Provider
        • User Attribute: identity_provider
        • Token Claim Name: identity_provider
        • Claim JSON Type: String
  • load-test-gateway-audience-scope (!!STRICTLY FOR DEV ENVIRONMENT ONLY!!)
    • Settings
      • Name: load-test-gateway-audience-scope
      • Protocol: openid-connect
      • Type: None
    • Mappers
      • load-test-gateway
        • Mapper Type: Audience
        • Name: load-test-gateway
        • Included Custom Audience: load-test-gateway
  • sims-api-audience-scope
    • Settings
      • Name: sims-api-audience-scope
      • Protocol: openid-connect
      • Type: None
    • Mappers
      • sims-api-audience
        • Mapper Type: Audience
        • Name: sims-api-audience
        • Included Custom Audience: sims-api
  • username
    • Settings
      • Name: username
      • Protocol: openid-connect
      • Type: None
    • Mappers
      • userName
        • Mapper Type: User Property
        • Name: userName
        • Property: username
        • Token Claim Name: userName
        • Claim JSON Type: String

Allowing mononymous names

By default, if the identity provider does not provide all information to create an account, the user will be redirected to a screen to provide the missing information. To allow users with mononymous names (where the first name is not present), we should disable this behavior, as shown below.

image

Clients

Ministry (AEST)

  • Create the client as below.

image

  • Set the below properties
    • Access Type: public
    • Valid Redirect URIs:
      • https://[dev/test].sims.studentaidbc.ca/*
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca/* (to be removed)
      • http://localhost:8080/* (do not add it for PROD)
    • Web Origins:
      • https://[dev/test].sims.studentaidbc.ca
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca (to be removed)
      • http://localhost:8080/* (do not add it for PROD)
    • Backchannel Logout Session Required: false
  • Disable "Full Scope Allowed" as shown below.

image

  • Configure Client Scopes as shown below.

image

Groups configurations

The Ministry client is the only one currently using Keycloak groups and roles. The list of groups and roles is kept in the internal Microsoft Teams files General>Files>Analisys>SIMS Users Profiles and Access Permissions.

The below mappers must be created to have "groups" presents on the token.

image image

The roles must be created as shown below.

image

The groups must be created as below.

image

For every group, the specific roles must be configured under the specific client, as shown below.

image

Forms Roles Import

Generate the roles from DB
SELECT jsonb_pretty(
    json_build_object(
        'roles', json_build_object(
	        'client', json_build_object(
            'aest', (
                SELECT json_agg(row_to_json(t))
                FROM (
                    WITH auth_roles (auth_role, order_value) AS (
                        VALUES
                            ('view-form-submitted-data', 1),
                            ('view-form-history-list', 2),
                            ('view-decision-history', 3),
                            ('assess-item-decision', 4),
                            ('assess-final-decision', 5)
                    )
                    select distinct
                        CONCAT('forms.', dfc.authorization_key, '.', ar.auth_role) AS name,
                        CONCAT(dfc.form_category, ' role for ', dfc.authorization_key, ' authorization.') AS description
                    FROM
                        sims.dynamic_form_configurations dfc
                        CROSS JOIN auth_roles ar
                    WHERE
                        dfc.form_category IN ('Student appeal', 'Student form')
                    ORDER BY
                        name
                ) t
            )
           )
        )
    )::jsonb
);
Keycloak Partial Import
image
  1. Access Real Settings
  2. Actions
  3. Partial Import
  4. Paste the JSON generated from the DB
  5. Mark the roles as the items to be imported
  6. Select "Skip" options to allow appending the new roles
  7. Import

Institution

  • Create the client as below.

image

  • Set the below properties
    • Access Type: public
    • Valid Redirect URIs:
      • https://[dev/test].sims.studentaidbc.ca/*
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca/* (to be removed)
      • http://localhost:8080/* (do not add it for PROD)
    • Web Origins:
      • https://[dev/test].sims.studentaidbc.ca
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca (to be removed)
      • http://localhost:8080 (do not add it for PROD)
    • Backchannel Logout Session Required: false
  • Configure Client Scopes as shown below.

image

Students

  • Create the client as below.

image

  • Set the below properties
    • Access Type: public
    • Valid Redirect URIs:
      • https://[dev/test].sims.studentaidbc.ca/*
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca/* (to be removed)
      • http://localhost:8080/* (do not add it for PROD)
    • Web Origins:
      • https://[dev/test].sims.studentaidbc.ca
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca (to be removed)
      • http://localhost:8080 (do not add it for PROD)
    • Backchannel Logout Session Required: false
  • Configure Client Scopes as shown below.

image

Supporting Users (Parent/Partners)

  • Create the client as below.

image

  • Set the below properties
    • Access Type: public
    • Valid Redirect URIs:
      • https://[dev/test].sims.studentaidbc.ca/*
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca/* (to be removed)
      • http://localhost:8080/* (do not add it for PROD)
    • Web Origins:
      • https://[dev/test].sims.studentaidbc.ca
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca (to be removed)
      • http://localhost:8080 (do not add it for PROD)
    • Backchannel Logout Session Required: false
  • Configure Client Scopes as shown below.

image

Load test gateway (!!STRICTLY FOR DEV ENVIRONMENT ONLY!!)

  • Create the client as below.

image

  • Set the below properties

    • Access Type: confidential
    • Service Accounts Enabled: ON
    • Valid Redirect URIs:
      • https://[dev/test]-aest-sims.apps.silver.devops.gov.bc.ca/*
  • Make sure in credentials tab the right client authenticator is selected image

  • Configure Client Scopes as shown below.

image

Allowing duplicated user emails

Out-of-box Keycloak is configured to prevent two users to be created using the same email. If the second user is tried to be created and the same email is already associated with a different user, the below error will be displayed on the screen.

image

For non-production environment tests users can share many times the same email. To allow the email duplication we need to explicitly have it configured as below.

image

External API access (service accounts)

This section explains how to create a service account for external clients to access external SIMS API endpoints.

Swagger API documentation

Swagger DEV

Swagger TEST

Create an external parent client(For internal use only, must not be shared with external API consumers)

This client is created exclusively to define all the external client roles that will be assigned to service account user of external clients like sdpr and atbc. Note: The name(client id) of the external parent client must be strictly external.

STEP1: Click on create client

image

STEP2: Provide the client setting details

image image image

Create external client roles on parent client

STEP1: Navigate to client external and go to the roles tab.

image

STEP 2: Click on Create role, add role name(description optional) and save.

image image image

Required client scopes for service account client(individual external client) creation.

Some specific client scopes are required for external service accounts. Please create them before creating any external service account.

Client scope: external-azp-scope

  • Click on "Client scopes" and then on "Create client scope". Then fill in "Name" with "external-azp-scope".

image

  • Go to "Mappers" tab and click on "Configure a new mapper".;
  • Select "Hardcoded claim" in "Mapper type". In "Name" type "external-azp-mapper", in "Token Claim Name" type "azp", in "Claim value" type "external" and click on "Save";

image

Client scope: sims-api-external-audience-scope

  • Click on "Client scopes" and then on "Create client scope". Then fill in "Name" with "sims-api-external-audience-scope".

image

  • Go to "Mappers" tab and click on "Configure a new mapper";
  • Select "Audience" in "Mapper type". In "Name" type "sims-api-external-audience", in "Included Custom Audience" type "sims-api-external" and click on "Save";

image

External service account client(external individual client) creation.

The external service account client is the client that is created to provide access to an external API consumer through service account credentials.

  • On Keycloak, go to Clients and click on "Create client";
  • Type the client ID and click on "Next";

image

  • Turn "Client authentication" on, disable "Standard flow" and "Direct access grants", select "Service accounts roles" and click on "Next";

image

  • Click on "Save" button;

image

  • Select the "Client scopes" tab, remove all client scopes but <clientId>-dedicated and click on "Add client scope" button;
  • Select "sims-api-audience-scope", "sims-api-external-audience-scope", "external-azp-scope" and click on "Add" and select "Default";

image

  • Select the client scope "client-roles" and click on "Add" and select "Default". This client scope "client-roles" is a built in default client scope and not a custom client scope.
image
  • The credentials can be obtained from the "Credentials" tab. The client ID is the service account name and the secret can be copied form "Client Secret" field or regenerated by clicking on "Regenerate" button.

image

Assign external client role(s) to external service account client.

STEP1: Navigate to the service account client and click on tab service account roles

image

STEP2: Click on Assign role and Client roles

image

STEP3: Search and assign the role.

image image

Testing / Troubleshooting

  • Generate a token using the clientId/secret;

image

  • Go to https://jwt.io and paste the access token. The attribute "aud" should contain "sims-api" and "sims-api-external". The attribute "azp" should have the value "external";

image

⚠️ **GitHub.com Fallback** ⚠️