Token Exchange Grant Type : Échange d'un jeton Kerberos pour une UPST

Utilisez l'échange de jetons Kerberos où Kerberos est le fournisseur d'authentification et vous devez échanger des jetons Kerberos contre des jetons ou des principaux IAM pour accéder aux services OCI. Vous échangez des jetons Kerberos contre des jetons de session d'utilisateur principal OCI (UPST) dans IAM.

Conditions du jeton Kerberos
Terme Description
Kerberos

Un système d'authentification et d'authentification unique multiplateforme. Le protocole Kerberos fournit une authentification mutuelle entre deux entités reposant sur une clé secrète partagée (clés symétriques). L'authentification Kerberos nécessite un client, un serveur et une partie de confiance pour assurer la médiation entre eux, appelé Key Distribution Center (KDC).

Les conditions suivantes sont également requises :

  • Principal : Identité pour un utilisateur (un principal est affecté à un utilisateur) ou identité pour une application offrant des services Kerberos.

  • Un domaine : Environnement de serveur Kerberos, qui peut être un nom de domaine tel que example.com. Chaque domaine Kerberos comporte au moins un KDC de sécurité des services Web.

Le profil de jeton Kerberos de WS-Security permet aux partenaires commerciaux d'utiliser des jetons Kerberos dans des architectures orientées service (SOA).

Centre de distribution de clés Kerberos (CDC) Serveur d'authentification de tierce partie.
Active Directory (AD) Référentiel pour le serveur KDC.
Keytab

Fichier qui stocke la clé de chiffrement réelle qui peut être utilisée au lieu d'une identification par mot de passe pour un principal spécifique. Les fichiers Keytab sont utiles pour les cas d'utilisation non interactifs.

Conseil : L'outil d'administration KDC peut être utilisé pour créer un fichier keytab. Lors de la création du fichier keytab, le type de chiffrement peut être spécifié. Utilisez le type de chiffrement suivant : aes256-cts-hmac-sha1-96.

Mécanisme de négociation GSSAPI simple et protégé (SPNEGO)

Le mécanisme de négociation GSSAPI simple et protégé (SPNEGO) est un " pseudo mécanisme " GSSAPI utilisé par le logiciel client/serveur pour négocier le choix de la technologie de sécurité.

Les tickets Kerberos sont encapsulés dans le jeton SPNEGO afin que le jeton fonctionne avec la couche d'application HTTP.

Format et détails du jeton SPNEGO

Le format de jeton SPNEGO est défini dans la RFC 4178. Le jeton est une structure de données sérialisée qui contient les champs suivants :

  • mechTypes : Séquence d'identificateurs d'objet (OID) qui répertorie les mécanismes d'authentification pris en charge.
  • mechToken : Jeton de mécanisme optimiste. Il s'agit d'un jeton utilisé pour négocier le mécanisme d'authentification réel qui sera utilisé.
  • krb5Creds : Un objet blob Kerberos. Il s'agit d'un objet binaire qui contient les informations d'authentification Kerberos.

Le jeton SPNEGO est encodé dans ASN.1. Voici un exemple de jeton SPNEGO :

NegTokenInit ::= SEQUENCE
{
mechTypes SEQUENCE OF Oid,
mechToken OCTET STRING,
krb5Creds [0] KerberosCreds OPTIONAL
}
GSSAPI Interface de programme d'application générique de services de sécurité
API du service IAM Token Exchange Service de domaine d'identité IAM OAuth : /oauth2/v1/token. L'API accepte les en-têtes/données utiles d'authentification standard basés sur OAuth et les signatures OCI. Pour savoir comment utiliser un client OAuth avec un domaine d'identité pour accéder aux API REST, voir Utilisation de OAuth 2 pour accéder à l'API REST.
Configuration de l'approbation de propagation des identités Utilisez les configurations d'approbation de propagation d'identité pour établir l'approbation entre l'identité OCI et un fournisseur d'identités externe et valider le jeton du fournisseur d'identités externe et le mappage de l'identité d'utilisateur du fournisseur d'identités externe avec l'identité d'utilisateur dans IAM. L'approbation de propagation des identités facilite également la propagation des identités d'un fournisseur d'identités externe vers OCI. La conception de point d'extrémité /IdentityPropagationTrust est générique et fonctionne avec n'importe quel fournisseur de nuage. Pour créer une configuration d'approbation de propagation d'identité, voir Étape 6 : Créer une configuration d'approbation de propagation d'identité.
Utilisateur du service Utilisateur sans privilèges de connexion interactifs. Ces utilisateurs de service peuvent être accordés à des groupes et à des rôles de service. Les applications peuvent utiliser ces utilisateurs de service ou l'utilisateur connecté peut se faire passer pour eux pour obtenir une UPST temporaire. L'utilisation d'un utilisateur de service est facultative. Pour plus d'informations sur l'utilisation des utilisateurs du service, voir Étape 5 : Utiliser un utilisateur du service (facultatif).
Jeton de session du principal d'utilisateur (UPST) Un jeton généré par IAM. Également appelé jeton de sécurité. Il représente l'utilisateur du service authentifié.

Étapes d'échange de jetons Kerberos

Utilisez les étapes suivantes pour échanger un jeton Kerberos contre un UPST :

  1. Étape 1 : Créer une chambre forte et ajouter le contenu du fichier Keytab
  2. Étape 2 : Créer la politique IAM requise
  3. Étape 3 : Créer une application de domaine d'identité
  4. Étape 4 : Générer un jeton SPNEGO pour un principal d'utilisateur spécifique
  5. Étape 5 : Utiliser un utilisateur du service (facultatif)
  6. Étape 6 : Créer une configuration d'approbation de propagation d'identité
  7. Étape 7 : Obtenir l'OCI UPST

Étape 1 : Créer une chambre forte et ajouter le contenu du fichier Keytab

Créez une chambre forte et ajoutez le contenu du fichier keytab en tant que chaîne encodée par base64. Note : Le service IAM ne stocke pas le fichier keytab dans son système de fichiers.

Reportez-vous aux étapes suivantes :

  1. Créer une chambre forte. Voir Création d'une chambre forte.
  2. Lisez le contenu du fichier keytab au format Base64.
  3. Allez à la chambre forte et stockez-la telle quelle, en veillant à vérifier Base64 en tant que modèle de type de clé secrète lors de la création de la clé secrète. Voir Création d'une clé secrète dans une chambre forte.

Étape 2 : Créer la politique IAM requise

Créez une politique IAM dans la location pour permettre à une ressource de domaine d'identité d'accéder à la chambre forte. Cela permet à IAM d'extraire la configuration du fichier keytab de la chambre forte. Reportez-vous à l'exemple suivant :

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

Étape 3 : Créer une application de domaine d'identité

Créer une application confidentielle de domaine d'identité. Après avoir créé l'application, enregistrez l'ID client et la clé secrète client dans un emplacement sécurisé. Voir Ajouter une application confidentielle.

Étape 4 : Générer un jeton SPNEGO pour un principal d'utilisateur spécifique

  1. Utilisez du code Java pour vous connecter au serveur KDC et générer le jeton SPNEGO.
  2. Copiez ce jeton SPNEGO pour former la demande de jeton.

Reportez-vous à l'exemple de code Java suivant :

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;

    }
}

Étape 5 : Utiliser un utilisateur du service (facultatif)

Un utilisateur de service est un utilisateur de domaines d'identité dont l'attribut serviceUser est réglé à true.

Note

L'utilisation d'un utilisateur du service est facultative. Si l'emprunt d'identité d'utilisateur est utilisé dans le cadre de la configuration de l'approbation, les utilisateurs du service sont nécessaires. Sinon, tout autre utilisateur du domaine d'identité est utilisé. Seuls les administrateurs de domaine d'identité peuvent créer, remplacer, mettre à jour ou supprimer un utilisateur du service. D'autres administrateurs peuvent lire les utilisateurs du service et leurs attributs.

Pour utiliser un utilisateur de service, créez-en un sans privilèges de connexion interactifs. Ces utilisateurs de service peuvent être accordés à des groupes et à des rôles de service. Vos applications peuvent utiliser ces utilisateurs de service ou l'utilisateur connecté peut se faire passer pour eux afin d'obtenir un jeton UPST temporaire.

Les utilisateurs du service ont les caractéristiques suivantes :

  • Doit avoir une valeur userName. Le prénom et le nom ne sont pas requis.
  • Peut avoir une adresse de courriel (facultatif).
  • Peut être membre de groupes et de rôles d'application.
  • Impossible d'avoir des clés d'API.
  • Impossible d'utiliser des points d'extrémité en libre-service.
  • Impossible d'avoir des mots de passe et les politiques de mot de passe ne s'appliquent pas.

Exemple de demande : Créer un utilisateur du service

Voici un exemple de demande avec les attributs minimum requis pour créer un utilisateur de service.

## 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"
}

Exemple de réponse : Créer un utilisateur de service

Voici un exemple de réponse lors de la création d'un utilisateur de service.

{
    "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"
    ]
}

Étape 6 : Créer une configuration d'approbation de propagation d'identité

La configuration de l'approbation de propagation d'identité est utilisée pour établir l'approbation entre l'identité OCI et les fournisseurs de services en nuage externes, la validation du jeton de fournisseur en nuage et le mappage de l'identité d'utilisateur du fournisseur en nuage avec l'identité d'utilisateur des domaines d'identité service.

Description détaillée d'une configuration d'approbation de propagation d'identité
Attribut Obligatoire? Descriptions et exemples
nom Oui

Nom de la fiducie.

type Oui

Type de jeton :

  • spnego
  • jwt
  • saml
  • crédentiel aws
émetteur Oui

Utilisez l'émetteur pour trouver l'identification de la fiducie. Par exemple, si le jeton SPNEGO est généré à l'aide du principal de service, IAMSp, IAMSp est la valeur de l'émetteur.

Exemple : IAMTokenExchangeServicePrincipal

active Oui

Si cette option est activée, true.

Si cette option est désactivée, false.

oauthClients Oui

Liste des clients OAuth autorisés à obtenir des jetons pour un partenaire de confiance spécifique.

Exemple :
"oauthClients": [
 "oauthclient-id"
 ],
allowImpersonation (utilisez serviceUser) Non

Valeur booléenne. Indique si l'UPST résultant doit contenir l'utilisateur authentifié comme sujet ou s'il doit emprunter l'identité d'un utilisateur de service dans IAM.

impersonatingServiceUser

Oui, si allowImpersonation est réglé à true.

Indique quel principal résultant empruntera l'identité en fonction du nom de la revendication de jeton et des conditions de valeur. Vous pouvez :

  • Autorisez un principal d'emprunt d'identité spécifique pour tous les utilisateurs authentifiés par le fournisseur d'identités (IdP).
  • Définissez des règles pour définir les conditions d'emprunt d'identité :
    • Basé sur le nom de la revendication de jeton
    • Condition : contient (co) ou est égal à (eq)
    • Valeur :
      • Peut être une chaîne.
      • Le tableau de valeurs et les valeurs complexes/composites ne sont pas pris en charge.
      • Avec la condition égal à : la carte générique (*) est autorisée.
      • Avec la condition contient : la carte générique (*) n'est pas prise en charge.
    • Emprunt d'identité du principal.

Exemple :

  • Règle : "username" eq kafka*
  • Utilisateur du service mappé : kafka
  • Résultat : Tous les utilisateurs authentifiés commençant par le préfixe kafka sont empruntés à l'identité de l'utilisateur du service IAM kafka. L'UPST résultante contient kafka comme principal d'utilisateur authentifié.

Si l'emprunt d'identité est autorisé, le jeton de sécurité OCI (UPST) résultant aura la revendication initiale liée à l'utilisateur authentifié (source_authn_prin) ainsi que pour indiquer au nom de qui l'emprunt d'identité est effectué.

  • Si le nom de la réclamation assujettie est configuré, il sera utilisé pour extraire cette valeur de réclamation.
  • Si le nom de la revendication de sujet n'est pas configuré, la valeur par défaut est sub dans le jeton entrant. Si la revendication sub elle-même n'est pas présente, elle est ignorée.
L'évaluation s'arrête avec la première règle mise en correspondance et le principal résultant correspondant est retourné à l'aide de l'attribut de nom d'affichage. Si aucune règle n'est mise en correspondance, la demande de jeton échoue avec des erreurs.
keytab

Oui, si le type de jeton est SPNEGO.

Extrait la configuration du fichier keytab de la chambre forte.

Important :
  • Le service d'échange de jetons extrait les informations de clé secrète en fonction de l'OCID de la clé secrète et de la version de clé secrète.

  • Si la rotation du keytab est effectuée sur le serveur KDC, vous devez mettre à jour les informations de clé secrète dans la configuration de l'approbation de propagation d'identité.

  • Si la rotation du fichier keytab est effectuée dans la chambre forte, vous devez mettre à jour les informations secrètes dans la configuration d'approbation de propagation d'identité.

Exemple de demande : Créer une configuration d'approbation de propagation d'identité

Voici un exemple de demande de création d'une configuration d'approbation de propagation d'identité.
## 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"
 ]
}

Exemple de réponse : Créer une configuration d'approbation de propagation d'identité

Voici un exemple de réponse lors de la création d'une configuration d'approbation de propagation d'identité.
  "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\"",
        "value": "<user_id>"
      },
      {
        "rule": "groups co \"tenancy-admin\"",
        "value": "<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>"
    }
  }

Étape 7 : Obtenir l'OCI UPST

Description détaillée des données utiles de la demande de jeton UPST
Paramètre de demande Valeur valide

grant_type

'grant_type=urn:ietf:params:oauth:grant-type:token-exchange'

requested_token_type

'requested_token_type=urn:oci:token-type:oci-upst'

public_key

'public_key=<public-key-value>'

Le flux de travail de la clé publique :

  1. La charge globale génère une paire de clés.
  2. La clé publique est envoyée dans le cadre de la demande d'échange de jeton, qui est ajoutée en tant que réclamation, jwk, dans l'UPST résultante.
  3. La clé privée est utilisée pour générer les signatures OCI pour l'appel de l'API des services natifs OCI avec l'UPST.
  4. L'authentification des services OCI valide l'UPST, extrait la revendication jwk de l'UPST, puis l'utilise pour valider la signature OCI.

subject_token_type

'subject_token_type=spnego'

  • spnego
  • jwt
  • saml
  • crédentiel aws

subject_token

'subject_token=<subject-token>'

Si le type de jeton est :

  • spnego : Jeton chiffré opaque.
  • jwt ou saml : Valeur d'assertion jwt ou saml telle quelle.
  • aws-credential : Valeur encodée par base64 des données d'identification AWS qui apparaissent au format XML.

issuer

Obligatoire si le type de jeton est spnego.

Exemple :

IAMTokenExchangeServicePrincipal

Exemple de demande de jeton UPST : OCI basée sur une signature

Voici un exemple de demande cURL basée sur une signature OCI.

## 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>"
}

Exemple de demande de jeton UPST : Basé sur une application de domaine d'identité

Voici un exemple de demande cURL basée sur une application de domaine d'identité OCI.

## 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>"
}