You're viewing OCI IAM documentation for new tenancies in regions that have been updated to use identity domains.

Token Exchange Grant Type: Exchanging a Kerberos Token for a UPST

Use Kerberos token exchange where Kerberos is the authentication provider and you need to exchange Kerberos tokens for IAM tokens or principals to access OCI services. You exchange Kerberos tokens for OCI user principal session tokens (UPST) in IAM.

Kerberos Token Exchange Steps

Use the following steps to exchange a Kerberos token for a UPST:

  1. Step 1: Create a Vault and Add the Keytab File Contents
  2. Step 2: Create the Required IAM Policy
  3. Step 3: Create an Identity Domain Application
  4. Step 4: Generate a SPNEGO Token For a Specific User Principal
  5. Step 5: Use a Service User (Optional)
  6. Step 6: Create an Identity Propagation Trust Configuration
  7. Step 7: Get the OCI UPST

Step 1: Create a Vault and Add the Keytab File Contents

Create a Vault and add the keytab file content as a base64-encoded string. Note: IAM doesn't store the keytab file in its file system.

Use the following steps as a guide:

  1. Create a Vault. See Creating a Vault.
  2. Read the keytab content in Base64 format.
  3. Go to the Vault and store it as is, making sure to check Base64 as the Secret Type Template while creating secret. See Creating a Secret in a Vault.

Step 2: Create the Required IAM Policy

Create an IAM policy in the tenancy to allow an identity domain resource to access Vault. This allows IAM to retrieve the keytab configuration from Vault. Use the following example as a guide:

allow resource iam-domain <domain_displayName> to read secrets from vault in compartment <compartment_ocid> where all {target.secret.id = <secret_ocid_where_the_keytab_is_present>}

Step 3: Create an Identity Domain Application

Create an identity domain Confidential application. After you create the application, save the client id and the client secret in a secure location. See Adding a Confidential Application.

Step 4: Generate a SPNEGO Token For a Specific User Principal

  1. Use Java code to connect to the KDC Server and generate the SPNEGO token.
  2. Copy that SPNEGO token to form the token request.

Use the following Java code example as a guide:

package com.oracle;

import com.sun.security.auth.module.Krb5LoginModule;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;

import javax.security.auth.Subject;
import java.io.IOException;
import java.security.Principal;
import java.security.PrivilegedAction;
import java.util.Base64;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class GenerateSpnegoToken {
    static String servicePrincipal = "HTTP/iamtesp@WINDOWSKDCSERVER.COM";
    static String userPrincipal = "HTTP/<sample-job>@WINDOWSKDCSERVER.COM";
    static String userPrincipalKeyTab = "keytabs/ms/<sample-job>.keytab";
    public static void main(String[] args) throws IOException {
        System.setProperty("sun.security.krb5.debug", "true");
        System.setProperty("sun.security.spnego.debug", "true");
        System.setProperty("java.security.krb5.conf", "ms_krb5.conf");

        String spnegoToken = generateSpnegoToken();
    }
    private static String generateSpnegoToken() {
        Subject subject = getAuthenticateSubject();
        return Subject.doAs(
                subject,
                (PrivilegedAction<String>)
                        () -> {
                            String SPNEGO_OID = "1.3.6.1.5.5.2";
                            String KRB5_MECHANISM_OID = "1.2.840.113554.1.2.2";
                            String KRB5_PRINCIPAL_NAME_OID = "1.2.840.113554.1.2.2.1";

                            try {
                                // Create GSS context for the service principal and the logged-in user
                                Oid krb5Mechanism = new Oid(KRB5_MECHANISM_OID);
                                Oid krb5PrincipalNameType = new Oid(KRB5_PRINCIPAL_NAME_OID);
                                Oid spnegoOid = new Oid(SPNEGO_OID);
                                GSSManager manager = GSSManager.getInstance();
                                GSSName gssServerName =
                                        manager.createName(servicePrincipal, krb5PrincipalNameType, krb5Mechanism);
                                GSSContext gssContext =
                                        manager.createContext(
                                                gssServerName, spnegoOid, null, 240000);
                                gssContext.requestMutualAuth(true);
                                gssContext.requestCredDeleg(true);
                                gssContext.requestLifetime(10);

                                // Generate the SPNEGO token
                                byte[] token = new byte[0];
                                token = gssContext.initSecContext(token, 0, token.length);
                                return Base64.getEncoder().encodeToString(token);
                            } catch (GSSException e) {
                                throw new RuntimeException(e);
                            }
                        });
    }

    private static Subject getAuthenticateSubject() {
        final Map<String, String> options = new HashMap<>();
        options.put("keyTab", userPrincipalKeyTab);
        options.put("principal", userPrincipal);
        options.put("doNotPrompt", "true");
        options.put("isInitiator", "true");
        options.put("refreshKrb5Config", "true");
        options.put("storeKey", "true");
        options.put("useKeyTab", "true");

        // Execute the login
        Subject subject = new Subject();
        Krb5LoginModule krb5LoginModule = new Krb5LoginModule();
        krb5LoginModule.initialize(subject, null, new HashMap<String, String>(), options);
        try {
            krb5LoginModule.login();
            krb5LoginModule.commit();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        Set<Principal> principals = (Set<Principal>) subject.getPrincipals();
        Iterator<Principal> iterator = principals.iterator();
        while (iterator.hasNext()) {
            System.out.println("\nprincipal : " + ((Principal) iterator.next()));
        }

        return subject;

    }
}

Step 5: Use a Service User (Optional)

A Service User is an identity domains User with the attribute serviceUser set to true.

Note

Using a Service User is optional. If user impersonation will be used as part of the Trust configuration, then Service Users are needed. Otherwise, any other identity domain user is used. Only identity domain administrators can create, replace, update or delete a Service User. Other administrators may read Service Users and their attributes.

To use a Service User, create one without interactive login privileges. These Service Users can be granted to groups and service roles. Your applications can use these Service Users or the logged-in user can impersonate them to obtain a temporary UPST token.

Service Users have the following characteristics:

  • Must have a userName. First name and last name isn't required.
  • Can have an email address (Optional).
  • Can be a member of groups and application roles.
  • Can't have API keys.
  • Can't use self-service endpoints.
  • Can't have passwords and password policies don't apply.

Request Example: Create a Service User

The following shows an example of a request with the minimum attributes required to create a Service User.

## POST on https://<domainURL>/admin/v1/Users
## Payload:
{
    "schemas": [
        "urn:ietf:params:scim:schemas:core:2.0:User"
    ],
    "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User": {
        "serviceUser": true
    },
    "userName": "myServiceUserName"
}

Response Example: Create a Service User

The following shows an example of a response when creating a Service User.

{
    "idcsCreatedBy": {
        "type": "App",
        "display": "idcsadmin"
    },
    "id": "<user_id>",
    "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User": {
        "isFederatedUser": false,
        "isGroupMembershipSyncedToUsersGroups": true,
        "serviceUser": true
    },
    "meta": {
        "created": "2023-12-07T06:52:55.380Z",
        "lastModified": "2023-12-07T06:52:55.380Z",
        "version": "<version>",
        "resourceType": "User",
        "location": "https://<domainURL>/admin/v1/Users/<user_id>"
    },
    "active": true,
    "idcsLastModifiedBy": {
        "display": "idcsadmin",
        "type": "App"
    },
    "urn:ietf:params:scim:schemas:oracle:idcs:extension:userState:User": {
        "locked": {
            "on": false
        }
    },
    "ocid": "ocid1.user.region1...<ocid>",
    "userName": "myServiceUserName",
    "schemas": [
        "urn:ietf:params:scim:schemas:core:2.0:User",
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:userState:User",
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:capabilities:User",
        "urn:ietf:params:scim:schemas:oracle:idcs:extension:user:User"
    ]
}

Step 6: Create an Identity Propagation Trust Configuration

The Identity Propagation Trust configuration is used to establish the trust between OCI Identity and the external Cloud providers, the validation of the Cloud provider token, and the mapping of the Cloud provider's user identity with the identity domains service user identity.

Request Example: Create an Identity Propagation Trust Configuration

The following shows an example of a request to create an Identity Propagation Trust configuration.
## POST on https://<domainURL>/admin/v1/IdentityPropagationTrusts
## Payload:
{
 "active": true,
 "allowImpersonation": false,
 "issuer": "idcs_psr_itp",
 "name": "<identity_propagation_trust_name>",
 "oauthClients": [
 "<oauthclient-id>"
 ],
 "keytab": {
 "secretOcid": "<secret_ocid>"
 },
 "subjectMappingAttribute": "userName",
 "subjectType": "User",
 "type": "SPNEGO",
 "schemas": [
 "urn:ietf:params:scim:schemas:oracle:idcs:IdentityPropagationTrust"
 ]
}

Response Example: Create an Identity Propagation Trust Configuration

The following shows an example of a response when creating an Identity Propagation Trust configuration.
  "response": {
    "name": "<identity_propagation_trust_name>",
    "type": "<token_type>",
    "issuer": "idcs_psr_itp",
    "accountId": "<example_account_id>",
    "subjectClaimName": "cognito:username",
    "subjectMappingAttribute": "username",
    "subjectType": "User",
    "clientClaimName": "appId",
    "clientClaimValues": ["<client_claim_value>"],
    "active": true,
    "publicKeyEndpoint": "https://example.identityprovider.com/publickey/<publickey_value>",
    "publicCertificate": "<public_certificate_value>",
    "oauthClients": ["<oauthclient-id>"],

    "allowImpersonation": true,
    "impersonationServiceUsers": [
      {
        "rule": "groups co \"network-admin\"",
        "userId": "<user_id>"
      },
      {
        "rule": "groups co \"tenancy-admin\"",
        "userId": "<user_id>"
      }
    ],
    "keytab": {
      "secretOcid": "<secret_ocid>",
      "secretVersion": "<secret_version>"
    },
    "clockSkewSeconds": 60,
    "id": "<identity_propagation_trust_id>",
    "meta": {
      "created": "2023-11-09T23:26:53.224Z",
      "lastModified": "2023-11-09T23:26:53.224Z",
      "resourceType": "IdentityPropagationTrust",
      "location": "http://example.hostname.com:8990/admin/v1/IdentityPropagationTrusts/<identity_propagation_trust_id>"
    },
    "schemas": [
      "urn:ietf:params:scim:schemas:oracle:idcs:IdentityPropagationTrust"
    ],
    "idcsCreatedBy": {
      "value": "<app_id>",
      "display": "admin",
      "type":"App",
      "$ref": "http://example.hostname.com:8990/admin/v1/Apps/<app_id>"
    },
    "idcsLastModifiedBy": {
      "value": "<app_id>",
      "display": "admin",
      "type":"App",
      "$ref": "http://example.hostname.com:8990/admin/v1/Apps/<app_id>"
    }
  }

Step 7: Get the OCI UPST

UPST Token Request Example: OCI Signature-based

The following shows an example OCI signature-based cURL request.

## OCI Signature Based Request
curl  -X POST -sS https://<domainURL>/oauth2/v1/token -i 
-H 'date: Wed, 06 Dec 2023 01:17:33 GMT' 
-H 'x-content-sha256: <key>' 
-H 'content-type: application/x-www-form-urlencoded;charset=utf-8' 
-H 'content-length: 197' 
-H 'Authorization: Signature version="1",keyId="<key_id>",algorithm="rsa-sha256",headers="(request-target) date host x-content-sha256 content-type content-length",signature="a+aH0b...TLtPA=="'  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'requested_token_type=urn:oci:token-type:oci-upst' \
--data-urlencode 'public_key=<public_key>' \
--data-urlencode 'subject_token=<subject_token>' \
--data-urlencode 'subject_token_type=spnego' \
--data-urlencode 'issuer=<Issuer stored in the Identity Trust Propagation. For example, examplead@kdcserver.com>' -k
{
   "token": "<token_id>"
}

UPST Token Request Example: Identity Domain App-based

The following shows an example OCI identity domain app-based cURL request.

## IAM Domain App Based Request. Note that client credentials can be sent as part of basic authn header or in the payload.  
curl --location ' https://<domainURL>/oauth2/v1/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic <auth_code>' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'requested_token_type=urn:oci:token-type:oci-upst' \
--data-urlencode 'public_key=<public_key>' \
--data-urlencode 'subject_token=<subject_token>' \
--data-urlencode 'subject_token_type=spnego' \
--data-urlencode 'issuer=<Issuer stored in the Identity Trust Propagation. For example, examplead@kdcserver.com>' -k
{
   "token": "<token_id>"
}