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.
A cross-platform authentication and single sign-on system. The Kerberos protocol provides mutual authentication between two entities relying on a shared secret (symmetric keys). Kerberos authentication requires a client, a server, and a trusted party to mediate between them called the Key Distribution Center (KDC).
The following is also required:
A Principal: An identity for a user (a user is assigned a principal), or an identity for an application offering Kerberos services.
A Realm: A Kerberos server environment, which can be a domain name such as example.com. Each Kerberos realm has at least one Web Services Security KDC.
The Kerberos Token profile of WS-Security allows business partners to use Kerberos tokens in service-oriented architectures (SOAs).
Kerberos Key Distribution Center (KDC)
A third-party authentication server.
Active Directory (AD)
A repository for the KDC server.
Keytab
A file that stores the actual encryption key that can be used instead of a password challenge for a specific principal. Keytab files are useful for noninteractive use cases.
Tip: The KDC admin tool can be used to create a keytab file. During keytab creation, the encryption type can be specified. Use the following encryption type: aes256-cts-hmac-sha1-96.
Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO)
Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) is a GSSAPI "pseudo mechanism" used by client/server software to negotiate the choice of security technology.
Kerberos tickets are wrapped as part of the SPNEGO token so that the token works with HTTP based application layer.
SPNEGO Token Format and Details
The SPNEGO token format is defined in RFC 4178. The token is a serialized data structure that contains the following fields:
mechTypes: A sequence of object identifiers (OID) that lists the supported authentication mechanisms.
mechToken: An optimistic mechanism token. This is a token that's used to negotiate the actual authentication mechanism that will be used.
krb5Creds: A Kerberos blob. This is a binary blob that contains the Kerberos authentication information.
The SPNEGO token is encoded in ASN.1. The following is an example of a SPNEGO token:
Generic Security Services Application Program Interface
IAM Token Exchange Service API
IAM identity domain OAuth service: /oauth2/v1/token. The API accepts both standard OAuth based authentication headers/payload, and OCI Signatures. To learn how to use an OAuth client with an identity domain to access the REST APIs, see Using OAuth 2 to Access the REST API.
Identity Propagation Trust Configuration
Use Identity Propagation Trust configurations to establish the trust between OCI Identity and an external identity provider and validate the external identity provider token and the mapping of the external identity provider's user identity with the user identity in IAM. Identity Propagation Trust also facilitates identity propagation from an external identity provider into OCI. The /IdentityPropagationTrust endpoint design is generic and works with any cloud provider. To create an Identity Propagation Trust configuration, see Step 6: Create an Identity Propagation Trust Configuration.
Service User
A user without interactive login privileges. These Service Users can be granted to groups and service roles. Applications can use these Service Users or the logged-in user can impersonate them to obtain a temporary UPST. Using a Service User is optional. For more information about using Service Users, see Step 5: Use a Service User (Optional).
User Principal Session Token (UPST)
An IAM generated token. Also known as a security token. It represents the authenticated Service User.
Kerberos Token Exchange Steps
Use the following steps to exchange a Kerberos token for a UPST:
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 🔗
Use Java code to connect to the KDC Server and generate the SPNEGO token.
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.
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.
Use Issuer to help find the Trust identification. For example, if the SPNEGO token is generated using the service principal, IAMSp, then IAMSp is the issuer value.
Example: IAMTokenExchangeServicePrincipal
active
Yes
If enabled, true.
If disabled, false.
oauthClients
Yes
A list of OAuth Clients who are allowed to get tokens for a specific trusted partner.
Example:
"oauthClients": [
"oauthclient-id"
],
allowImpersonation (make use of serviceUser)
No
Boolean value. Specifies whether the resulting UPST should contain the authenticated user as the subject, or if it should impersonate a Service User in IAM.
impersonatingServiceUser
Yes, if allowImpersonation is set to true.
Specifies which resulting principal is going to impersonate based on the token claim name and the value conditions. You can:
Allow a specific impersonating principal for all the identity provider (IdP) authenticated users.
Set rules to define impersonation conditions:
Based on the Token claim name
Condition: contains (co) or equals (eq)
Value:
Can be a string.
Array of values and complex/composite values aren't supported.
With equals condition: wild card (*) is allowed.
With contains condition: wild card (*) isn't supported.
Impersonating principal.
Example:
Rule: "username" eq kafka*
Mapped Service User: kafka
Result: All the authenticated users starting with the kafka prefix are impersonated with the IAM Service User kafka. The resulting UPST contains kafka as the authenticated user principal.
If impersonation is allowed, the resulting OCI security token (UPST), will have the original authenticated user related claim (source_authn_prin) as well to indicate on whose behalf impersonation is done.
If subject claim name is configured, it will be used to extract that claim value.
If subject claim name isn't configured, it defaults to sub in the incoming token. If sub claim itself isn't present, it's ignored.
Evaluation stops with the first matched rule and the corresponding resulting principal is returned using the display name attribute. If no rules are matched, then the token request fails with errors.
keytab
Yes, if the token type is SPNEGO.
Retrieves the keytab configuration from Vault.
Important:
The token exchange service retrieves the secret information based on the secret OCID and the secret version.
If keytab is rotated in the KDC server, then you must update the secret information in the Identity Propagation Trust configuration.
If keytab is rotated in Vault, then you must update the secret information in the Identity Propagation Trust configuration.
Request Example: Create an Identity Propagation Trust Configuration
The following shows an example of a request to create an Identity Propagation Trust configuration.
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>"
}