Configuring user access with OpenID

Operational Decision Manager (ODM) for production can be configured with OpenID Connect (OIDC), which is an authentication framework that is built on the OAuth 2.0 protocol. ODM servers use it to verify a user's identity with an OIDC provider, and to authorize access to the ODM applications and APIs. The servers also use it to obtain basic profile information about the user.

Before you begin

To help you manage authentication using different single sign-on (SSO) tools, check out the following step-by-step tutorials:

If you encounter a problem configuring OIDC, see the troubleshooting documentation:

About this task

You must configure a basic or LDAP authentication registry for your ODM services before you can configure ODM with OpenID. To better understand ODM roles, see User roles and groups.

ODM with OpenID uses hardcoded roles with six users and six groups for each role. All authenticated users have by default the rtsUser role.

The following lines show the ODM configuration.

rtsAdministrators:
<user name="rtsAdmUser1" access-id="${odm.rtsAdministrators.user1}"/>
<user name="rtsAdmUser2" access-id="${odm.rtsAministrators.user2}"/>
<user name="rtsAdmUser3" access-id="${odm.rtsAdministrators.user3}"/>
<user name="rtsAdmUser4" access-id="${odm.rtsAdministrators.user4}"/>
<user name="rtsAdmUser5" access-id="${odm.rtsAdministrators.user5}"/>
<user name="rtsAdmUser6" access-id="${odm.rtsAdministrators.user6}"/>
<group name="rtsAdmGroup1" access-id="${odm.rtsAdministrators.group1}"/>
<group name="rtsAdmGroup2" access-id="${odm.rtsAdministrators.group2}"/>
<group name="rtsAdmGroup3" access-id="${odm.rtsAdministrators.group3}"/>
<group name="rtsAdmGroup4" access-id="${odm.rtsAdministrators.group4}"/>
<group name="rtsAdmGroup5" access-id="${odm.rtsAdministrators.group5}"/>
<group name="rtsAdmGroup6" access-id="${odm.rtsAdministrators.group6}"/>

Similar users and groups exist for the other roles rtsConfigManagers, rtsInstallers, resAdministrators, resExecutors, resMonitors, and resDeployers. You can find an example in the Example section at the end of this topic.

You need to create a number of secrets before you can install an ODM instance with OpenID and use web application single sign-on (SSO). The following diagram shows the ODM services with OpenID after a successful installation.

ODM web application SSO
The following procedure defines the main steps to configure ODM with OpenID.
  • You need to configure the connection to the OpenID server.
    • Create an OpenID administrator secret to be referenced by the oidc.adminRef parameter.
    • Create a secret with the OpenID certificates to be referenced by the customization.securitySecretRef parameter.
    • Set the allowed domain names in the oidc.allowedDomains parameter.
The following steps take place post-installation.
  • If you choose to use NodePort to access ODM services, you must manually register the URLs of the ODM services to the OpenID server, after deployment, by editing the configmap named release_name-odm-oidc-redirect-uris-configmap.
  • You can define the mapping between the Liberty roles and the LDAP groups by updating the secret release_name-odm-oidc-auth-secret. This default secret sets the OpenID admin user with all the administrator roles.

Procedure

  1. Configure the connection to the OpenID server.
    1. Create the OpenID administrator secret.
      The administrator secret is used to call the OpenID REST API to register the URLs of the ODM services. The registration process can provide useful information for the ODM services, including the OAuth 2.0 client ID and client secret.

      You create a secret by running the following command.
      kubectl create secret generic my_openid_admin_secret 
        --from-literal=adminUser=OPENID-ADMIN-USERNAME
        --from-literal=adminPassword=OPENID-ADMIN-PASSWORD
      Make a note of the secret name (my-openid-admin-secret) so that you can set the oidc.adminRef parameter in the configuration of your ODM instance.

    2. Import and specify the OIDC server certificate to enable secure communication.
      You must set the customization.trustedCertificateList parameter as described in Importing the certificate of an external service.
    3. Set the allowed domain names in the oidc.allowedDomains parameter.
      You must provide at least the domain name of the OpenID server as requests are redirected by OpenID, which is the server URL without https.

      Domains that are specified in the allowed domains parameter are considered safe from Cross-Site Request Forgery (CSRF) attacks. All requests that originate from components in these domains are accepted.

      Refer to Advanced configuration for optional configuration parameters.

  2. Specify these OpenID parameters in the values.yaml file that you use to install an ODM instance, for example:
    license: true
    image: 
      repository: cp.icr.io/cp/cp4a/odm
      pullSecrets: 
      - ibm-entitlement-key
    usersPassword: my-password
    
    # OpenID configuration
    oidc:
      enabled: true
      serverUrl: my-openid-serverUrl
      adminRef: my-openid-admin-secret
      allowedDomains: my-openid-allowed-domains

    For more information about the OpenID parameters, see Production configuration parameters.

    The following excerpt shows how to install an ODM instance with the values.yaml file:
    helm install release_name -f values.yaml ibm-helm/ibm-odm-prod
    For more information about installation, see Installing a Helm release of ODM for production.
  3. Register the URLs of the ODM services to the OpenID server.

    To make the ODM URLs accessible, a list of URLs must be registered to the OpenID server. For more information, see OpenID Connect Dynamic Client Registration 1.0 External link opens a new window or tab.

    Depending on your target platform you can use routes, Ingress, or node ports. For details on these different mechanisms, refer to Configuring external access.

    • Optional: Using routes on OpenShift®
      The routes are automatically created with the following hostnames.
      Decision Center: decisioncenter.odm.release_name.hostname
      Decision Runner: decisionrunner.odm.release_name.hostname
      Decision Server Console: decisionserverconsole.odm.release_name.hostname
      Decision Server Runtime: decisionserverruntime.odm.release_name.hostname
      The service URLs that correspond to these routes are registered automatically to the OpenID server.
    • Optional: Using Ingress on Kubernetes
      The URL list can be built with the following command:
      my-ingress="https://dc.mycompany.com/openid/redirect/odm,
      https://decisionrunner.mycompany.com/openid/redirect/odm,
      https://decisionserverconsole.mycompany.com/openid/redirect/odm,
      https://decisionserverruntime.mycompany.com/openid/redirect/odm"
      Make a note of the name of the list so that you can set the oidc.redirectUris parameter in the configuration of your ODM instance. 

      If you set service.ingress.enabled and service.ingress.host, the ingresses are automatically created.

    • Using node ports

      If you want to use node ports to access ODM services, you must register redirect URLs after the Helm chart installation (step 7) because ports cannot be known before the installation. A job with its associated pod name release_name-odm-oidc-job-registration is created to register the ODM redirect URL. As the oidc.redirectUris parameter is empty, a default configmap named release_name-odm-oidc-redirect-uris-configmap is created with a parameter redirect-uris: "TO_FILL". You must edit the configmap to replace "TO_FILL" with the ODM redirect URLs.

      To build the ODM redirect URL:
      1. Retrieve the cluster-info-ip and the service ports dc-port, dr-port, dsc-port, dsr-port details as documented here Completing post-deployment tasks.
      2. Edit the configmap.
        kubectl edit cm release_name-odm-oidc-redirect-uris-configmap
      3. Replace "TO_FILL" with:
        https://cluster-info-ip:dc-port/openid/redirect/odm,
        https://cluster-info-ip:dr-port/openid/redirect/odm,
        https://cluster-info-ip:dsc-port/openid/redirect/odm,
        https://cluster-info-ip:dsr-port/openid/redirect/odm

Advanced configuration

  1. Configure the authorization.
    The authorization is defined in a secret that can contain three files:
    • webSecurity.xml
    • openIdParameters.properties
    • openIdWebSecurity.xml

    By default, a secret is created for you with the name release_name-odm-oidc-auth-secret. This secret contains only a webSecurity.xml file with a basic mapping template between ODM roles and a basic registry of users and groups, providing full access to the odmAdmin user.

    You can modify the secret at run time when the services are available, or you can create a new secret. The Liberty server updates the authorization immediately after you modify the secret. If you prefer to do the configuration before the ODM services are installed, the following procedure explains how to create your own secret.

    1. Configure the mapping between OpenID groups and ODM roles.
      1. Create a webSecurity.xml file to define the mapping to the OpenID groups.

        You can start from this template External link opens a new window or tab.

        See the Example section on how to put all of the definitions that your environment needs into the webSecurity.xml file.

      2. Create a secret for the webSecurity.xml file.
        Note: The secret must be registered with the webSecurity.xml key. If you did use a different file name, for example sample-webSecurity-OIDC.xml, you can still register it by specifying your file name when you create the secret.
        kubectl create secret generic <my-websecurity-secret> --from-file=webSecurity.xml=<path_to_your_file>/sample-webSecurity-OIDC.xml

        Make sure that you create the secret in the same namespace as the namespace that you use for the ODM instance. To create the secret, use the following command.

        kubectl create secret generic my-websecurity-secret --from-file=webSecurity.xml

        Where my-websecurity-secret is the name that you give to the secret.

        Make a note of the secret name so that you can set the customization.authSecretRef parameter in the configuration of your ODM instance.

    2. Optional: If you need to modify the OpenID endpoints or the token format, because the template is not compatible, you can create your own openIdParameters.properties file and provide it to the ODM instance.
      1. This file contains all the necessary properties for ODM OpenID configuration.
        OPENID_SERVER_URL=<oidc.serverUrl>
        OPENID_PROVIDER=<oidc.provider>
        OPENID_CLIENT_ID=__OPENID_CLIENT_ID__ # provided or generated
        OPENID_CLIENT_SECRET=__OPENID_CLIENT_SECRET__ # provided or generated
        OPENID_CLIENT_ASSERTION_ALIAS_NAME=alias_name #optional : private key alias name when using private_key_jwt
        OPENID_ALLOWED_DOMAINS=<oidc.allowedDomains>
        OPENID_AUTHORIZATION_URL=<oidc.serverUrl>/oidc/endpoint/<oidc.provider>/authorize
        OPENID_TOKEN_URL=<oidc.serverUrl>/oidc/endpoint/<oidc.provider>/token
        OPENID_INTROSPECTION_URL=<oidc.serverUrl>/oidc/endpoint/<oidc.provider>/introspect
        OPENID_LOGOUT_URL=<oidc.serverUrl>/oidc/endpoint/<oidc.provider>/logout
        OPENID_TOKEN_FORMAT=NON-JWT
        OPENID_LOGOUT_TOKEN_PARAM=id_token_hint # optional: name of the parameter to provide the id_token on logout. Compulsory on OKTA. 
        Note: If OPENID_CLIENT_ID and OPENID_CLIENT_SECRET are left blank, the values are replaced by the oidc.clientRef secret values.
      2. Re-create the secret <my-websecurity-secret> with the openIdParameters.properties file.
        kubectl create secret generic <my-websecurity-secret>
         --from-file=webSecurity.xml=webSecurity.xml
         --from-file=openIdParameters.properties=openIdParameters.properties
      3. Set the customization.authSecretRef parameter in the helm install command with this secret name.
    3. Optional: If you need to add or modify a parameter to the openidConnectClient tag in the openIdWebSecurity.xml file, you can write your own file and provide it to the ODM instance.
      1. This file contains all the necessary properties for the Liberty OpenID configuration.
        <server>
          <variable name="ServerHost" value="<oidc.serverUrl>"/>
          <openidConnectClient authFilterRef="browserAuthFilter" id="odm" scope="openid"
                               clientId="__OPENID_CLIENT_ID__" clientSecret="__OPENID_CLIENT_SECRET__"
                               signatureAlgorithm="RS256" inboundPropagation="supported" tokenReuse="true"
                               jwkEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/jwk"
                               issuerIdentifier="${ServerHost}/oidc/endpoint/<oidc.provider>"
                               authorizationEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/authorize"
                               tokenEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/token"
                               validationEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/introspect"/>
          <openidConnectClient authFilterRef="apiAuthFilter" id="odmapi" scope="openid"
                               clientId="__OPENID_CLIENT_ID__" clientSecret="__OPENID_CLIENT_SECRET__"
                               signatureAlgorithm="RS256" inboundPropagation="required" tokenReuse="true"
                               jwkEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/jwk"
                               issuerIdentifier="${ServerHost}/oidc/endpoint/<oidc.provider>"
                               authorizationEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/authorize"
                               tokenEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/token"
                               validationEndpointUrl="${ServerHost}/oidc/endpoint/<oidc.provider>/introspect"/>
        </server>
        Important: The authFilterRef, id, and inboundPropagation values must not be modified, as they are used internally. If clientId and clientSecret are left blank, the values are replaced by the oidc.clientRef secret values.

        Depending of the connection type, clientSecret can be optional or mandatory.

      2. Re-create the secret <my-websecurity-secret> with the openIdWebSecurity.xml file.
        kubectl create secret generic <my-websecurity-secret>
         --from-file=webSecurity.xml=webSecurity.xml
         --from-file=openIdWebSecurity.xml=openIdWebSecurity.xml
      3. Set the customization.authSecretRef parameter in the helm install command with this secret name.

        For more information about Liberty endpoints, see OpenID Connect endpoint URLs External link opens a new window or tab.

  2. Optional: Configure a client of ODM to request the authentication token from the OpenID instance.

    Create a secret with an OpenID client ID and password and make sure that you use the following keys.

    kubectl create secret generic my_openid_clientid_secret 
       --from-literal=clientId=MY-OPENID-CLIENT-ID 
       --from-literal=clientSecret=MY-OPENID-CLIENT-SECRET 

    Make a note of the secret name so that you can set the oidc.clientRef parameter in the configuration of your ODM instance.

     
  3. Optional: Set the OpenID provider names in the oidc.provider parameter.
    A Liberty server with OpenID Connect enabled has access to the OpenID Connect token endpoint at the URL oidc.serverUrl/oidc/endpoint/oidc.provider/token. If the oidc.provider parameter is not provided, ums is applied by default.

Results

The ODM services are accessible only when the job release_name-odm-oidc-job-registration is complete. If you take the route or Ingress option, the registration is done automatically through the Helm chart parameters. If you use the node port option, refer to Using node ports in step 4 to complete the installation

Rule Designer configuration

To use OpenID with Rule Designer, see Configuring Rule Designer.

Five predefined registered ports are provided to connect to the OpenID server (9081-9085).

You must also import the security certificate that is used in the ODM instance into Rule Designer. For more information, see Importing a security certificate in Rule Designer. To provide the truststore.jks file to the eclipse.ini, you can identify the ODM pods with the kubectl get pods | grep odm command, and then copy the file by running the kubectl cp command.

kubectl cp project_name/ODM_pod_name:/config/security/truststore.jks ./truststore.jks

The default password of the provided truststore.jks file is changeit. The clientId and clientSecret parameters can be set in step 5.

REST API management

If you want to call the REST API, you must get an access token by running a cURL command with the following endpoint.

https://oidc.serverUrl/oidc/endpoint/oidc.provider/token

You can then authenticate with the Bearer access-token. For more information, see Invoking the Token Endpoint for OpenID Connect External link opens a new window or tab.

The following diagram shows the API invocations with OpenID.

ODM service API invocations
Runtime performance

With the default configuration, the access token is validated for all requests. The validation process has an impact on the Decision Server Runtime performance. To improve the performance, LtpaToken cookies are enabled in the openidConnectClient Liberty configuration to manage the token. However, for demanding applications that require high performance, LtpaToken cookies are sometimes not enough. In this case, use basic authentication to call the Decision Server Runtime.

Here are the details for each solution.

  1. Using LtpaToken cookies

    A client that launches a decision service must manage LtpaToken cookies. The following steps describe how to get a cookie.

    1. Get an OpenID access token. For more information, see Invoking the Token Endpoint for OpenID Connect External link opens a new window or tab.
    2. Call a decision service to get a cookie from the access token. For example, the following call uses a cURL command:
      curl -H "Content-Type: application/json" -k --data @loanvalidation.json -H "Authorization: Bearer <TOKENID>" https://DecisionServerRuntime:Port/DecisionService/rest/LoanValidationDS/1.0/loan_validation_with_score_and_grade/1.0 -c cookie.txt
  2. Using basic authentication

    The Liberty OpenID configuration contains a parameter that manages basic authentication. The default configuration in webSecurity.xml provides a basic registry with a resExecutor user that has the resExecutors role, as illustrated in the following code sample.

    <server>
          <basicRegistry id="basic" realm="basic">
            <user name="resExecutor" password="resExecutor"/>
            <group name="basicResExecutors">
              <member name="resExecutor" />
            </group>
          </basicRegistry>
          <variable name="odm.resExecutors.group1" value="group:basic/basicResExecutors"/>
    </server> 

    So you can call a decision service like this:

        curl -H "Content-Type: application/json" -k --data @loanvalidation.json -H "Authorization: Basic cmVzRXhlY3V0b3I6cmVzRXhlY3V0b3I=" https://DecisionServerRuntime:Port/DecisionService/rest/LoanValidationDS/1.0/loan_validation_with_score_and_grade/1.0

    Where cmVzRXhlY3V0b3I6cmVzRXhlY3V0b3I= is the base64 encoding of the current username:password resExecutor:resExecutor

    You can modify the default basic registry, users, and groups by modifying the webSecurity.xml file.

Example

The following OpenID groups provide an example of how to map these ODM roles.
  • oidcFullAccess, a group to manage all ODM roles.
  • oidcRtsAdministrator, a group for the rtsAdministrators role.
  • oidcRtsConfigManager, a group for the rtsConfigManagers role.
  • oidcRtsInstaller, a group for the rtsInstallers role.
  • oidcResAdministrator, a group for the resAdministrators role.
  • oidcResMonitor, a group for the resMonitors role.
  • oidcResExecutor, a group for the resExecutors role.
  • oidcResDeployer, a group for the resDeployers role.

The OpenID users and groups must be defined in the OpenID server. The names that you intend to use must exist in an associated registry so that they can be mapped to an ODM user or group.

The following OpenID server definition shows an example of this mapping with an OpenID group group:o=defaultWIMFileBasedRealm/oidcAllRoles defined in a basic registry, and an OpenID group group:o=defaultWIMFileBasedRealm/cn=oidcRtsAdministrator,ou=memberlist,ou=examplegroups,o=example.org defined in an LDAP registry.

<server>
    <federatedRepository id="vmm">
        <primaryRealm name="o=defaultWIMFileBasedRealm">
            <participatingBaseEntry name="o=BasicRegistry"/>
            <participatingBaseEntry name="o=example.org"/>
        </primaryRealm>
    </federatedRepository>
    <basicRegistry id="basicRegistry">
    <!-- User with full access through oidcAllRoles group -->
        <user name="odmAdmin" password="odmAdmin" />
    <!-- Group that has full access -->
        <group name="oidcAllRoles">
            <member name="odmAdmin" />
       </group>
    </basicRegistry>
    <ldapRegistry baseDN="o=example.org" host="mydomain.example.org"
        id="bp" ldapType="IBM Security Directory Server" port="389">
        <ldapEntityType name="PersonAccount">
            <objectClass>mycompanyPerson</objectClass>
            <searchBase>ou=mydomain,o=example.org</searchBase>
        </ldapEntityType>
        <ldapEntityType name="Group">
            <objectClass>groupOfUniqueNames</objectClass>
            <searchBase>ou=memberlist,ou=examplegroups,o=example.org</searchBase>
        </ldapEntityType>
        <idsFilters userFilter="(&amp;(objectclass=Person)(|(uid=%v)(mail=%v)))"
            groupFilter="(&amp;(cn=%v)(objectclass=groupOfUniqueNames))"
            groupMemberIdMap="groupOfUniqueNames:uniqueMember" />
   </ldapRegistry>
</server>
The mapping itself is done with variable definitions and key-value pairs. A sample-webSecurity-OIDC.xml External link opens a new window or tab file on GitHub can be used as a starting point to map your ODM users and groups to the OpenID users and groups. The variable definitions in the sample file use the following scenario:
  • An OpenID user generalAdmin (defined through an LDAP registry). A user that has access to all applications.
  • An OpenID group oidcAllRoles (defined through a basic registry). A group of users that has access to all applications.
  • An OpenID group oidcRtsAdministrator (defined through an LDAP registry). A group of users that has admin access to Decision Center.
  • An OpenID group oidcRtsConfigmanager (defined through an LDAP registry). A group of users that can configure deployments in Decision Center.
  • An OpenID group oidcResAdministrator (defined through an LDAP registry). A group of users that has admin access to Decision Server console.
  • An OpenID group oidcResDeployer (defined through an LDAP registry). A group of users that can deploy in Decision Server console.
  • An OpenID group oidcResMonitor (defined through an LDAP registry). A group of users that can monitor Decision Server console.
  • An OpenID group oidcResExecutor (defined through an LDAP registry). A group of users that can run decisions in Decision Server Runtime.