Personnaliser les revendications émises dans le JSON Web Token (JWT) pour les applications d’entreprise

La plateforme d’identités Microsoft prend en charge l’authentification unique (SSO) avec la plupart des applications pré-intégrées dans les applications personnalisées et la galerie d’applications Microsoft Entra. Quand un utilisateur s’authentifie auprès d’une application par l’intermédiaire de la plateforme d’identités Microsoft en utilisant le protocole OIDC, la plateforme d’identités Microsoft envoie un jeton à l’application. L’application valide et utilise le jeton pour inscrire l’utilisateur au lieu de demander un nom d’utilisateur et un mot de passe.

Ces jetons JWT (JSON Web tokens) utilisés par les applications OIDC et OAuth contiennent des éléments d’information sur l’utilisateur, appelés revendications. Une revendication concerne ce qu’un fournisseur d’identité déclare sur un utilisateur dans le jeton qu’il émet sur cet utilisateur. Dans une réponse OIDC, les données de revendication sont généralement contenues dans le jeton d’ID émis par le fournisseur d’identité sous la forme d’un JWT.

Afficher ou modifier des revendications

Conseil

Les étapes décrites dans cet article peuvent varier légèrement en fonction du portail de départ.

Pour afficher ou modifier les revendications émises dans le jeton JWT dans l’application :

  1. Connectez-vous au Centre d’administration de Microsoft Entra au minimum en tant qu’Administrateur d’application cloud.
  2. Accédez à Identité>Applications>Applications d’entreprise>Toutes les applications.
  3. Sélectionnez successivement l’application, Authentification unique dans le menu de gauche, puis Modifier dans la section Revendications et attributs.

Une application peut nécessiter une personnalisation des revendications pour différentes raisons. Par exemple, lorsqu’une application a besoin d’un ensemble différent d’URI ou de valeurs de revendication. À l’aide de la section Revendications et attributs, vous pouvez ajouter ou supprimer une revendication pour votre application. Vous pouvez également créer une revendication personnalisée spécifique pour une application en fonction du cas d’usage.

Les étapes suivantes décrivent comment attribuer une valeur constante :

  1. Sélectionnez la revendication que vous souhaitez modifier.
  2. Entrez la valeur constante sans guillemets dans Attribut source conformément à votre organisation, puis sélectionnez Enregistrer.

La vue d’ensemble des attributs affiche la valeur constante.

Transformations de revendications spéciales

Vous pouvez utiliser les fonctions spéciales de transformation de revendication suivantes.

Fonction Description
ExtractMailPrefix() Supprime le suffixe de domaine de l’adresse e-mail ou du nom d’utilisateur principal. Cette fonction extrait seulement la première partie du nom d'utilisateur. Par exemple, joe_smith plutôt que joe_smith@contoso.com.
ToLower() Convertit les caractères de l’attribut sélectionné en minuscules.
ToUpper() Convertit les caractères de l’attribut sélectionné en majuscules.

Ajouter des revendications spécifiques à l’application

Pour ajouter des revendications spécifiques à l’application :

  1. Dans Attributs utilisateur et revendications, sélectionnez Ajouter une revendication pour ouvrir la page Gérer les revendications des utilisateurs.
  2. Entrez le nom des revendications. La valeur n’a pas besoin de suivre strictement un modèle URI. Si vous avez besoin d’un modèle d’URI, vous pouvez l’indiquer dans le champ Namespace.
  3. Sélectionnez la Source où la revendication va récupérer sa valeur. Vous pouvez sélectionner un attribut utilisateur dans le menu déroulant d’attribut de la source ou appliquer une transformation à l’attribut utilisateur avant de l’émettre en tant que réclamation.

Transformations de revendication

Pour appliquer une transformation à un attribut utilisateur :

  1. Dans Gérer les revendications, sélectionnez Transformation comme source de revendication pour ouvrir la page Gérer la transformation.
  2. Sélectionnez la fonction dans la liste déroulante de transformation. Selon la fonction sélectionnée, fournissez des paramètres et une valeur constante à évaluer dans la transformation.
  3. Traiter la source comme valeurs multiples est une case à cocher indiquant si la transformation doit être appliquée à toutes les valeurs ou uniquement à la première. Par défaut, le premier élément d’une revendication à valeurs multiples est appliqué aux transformations. Lorsque vous cochez cette case, cela garantit qu’elle est appliquée à tous. Cette case à cocher est activée uniquement pour les attributs multiples. Par exemple : user.proxyaddresses.
  4. Pour appliquer plusieurs transformations, sélectionnez Ajouter une transformation. Vous pouvez appliquer un maximum de deux transformations à une revendication. Par exemple, vous pouvez d’abord extraire le préfixe e-mail de user.mail. Ensuite, mettez la chaîne en majuscules.

Vous pouvez utiliser les fonctions suivantes pour transformer des revendications.

Fonction Description
ExtractMailPrefix() Supprime le suffixe de domaine de l’adresse e-mail ou du nom d’utilisateur principal. Cette fonction extrait seulement la première partie du nom d'utilisateur. Par exemple, joe_smith plutôt que joe_smith@contoso.com.
Join() Crée une nouvelle valeur en joignant deux attributs. Si vous le souhaitez, vous pouvez utiliser un séparateur entre les deux attributs. Pour la transformation de revendication NameID, la fonction Join() a un comportement spécifique lorsque l’entrée de transformation a une partie de domaine. Elle supprime la partie de domaine de l’entrée avant de la joindre au séparateur et au paramètre sélectionné. Par exemple, si l’entrée de la transformation est joe_smith@contoso.com et que le séparateur est @ et que le paramètre est fabrikam.com, cela se traduit en joe_smith@fabrikam.com.
ToLowercase() Convertit les caractères de l’attribut sélectionné en minuscules.
ToUppercase() Convertit les caractères de l’attribut sélectionné en majuscules.
Contains() Génère un attribut ou une constante si l’entrée correspond à la valeur spécifiée. Sinon, vous pouvez spécifier une autre sortie s’il n’existe aucune correspondance.
Par exemple, vous pouvez émettre une revendication où la valeur est l’adresse e-mail utilisateur si elle contient le domaine @contoso.com. Dans ce cas, nous vous conseillons de générer le nom d’utilisateur principal. Pour effectuer cette fonction, vous configurez les valeurs suivantes :
Paramètre 1 (entrée) : user.email
Valeur : « @contoso.com »
Paramètre 2 (sortie) : user.email
Paramètre 3 (sortie s’il n’existe aucune correspondance) : user.userprincipalname
EndWith() Génère un attribut ou une constante si l’entrée se termine par la valeur spécifiée. Sinon, vous pouvez spécifier une autre sortie s’il n’existe aucune correspondance.
Par exemple, vous pouvez émettre une revendication dont la valeur est l’ID d’employé de l’utilisateur, si l’ID d’employé se termine par 000. Dans ce cas, nous vous recommandons d’obtenir un attribut d’extension en sortie. Pour effectuer cette fonction, vous configurez les valeurs suivantes :
Paramètre 1 (entrée) : user.employeeid
Valeur : "000"
Paramètre 2 (sortie) : user.employeeid
Paramètre 3 (sortie, s’il n’existe aucune correspondance) : user.extensionattribute1
StartWith() Génère un attribut ou une constante si l’entrée commence par la valeur spécifiée. Sinon, vous pouvez spécifier une autre sortie s’il n’existe aucune correspondance.
Par exemple, vous pouvez émettre une revendication dont la valeur est l’ID d’employé de l’utilisateur, si la valeur de Pays/région commence par US. Dans ce cas, nous vous recommandons d’obtenir un attribut d’extension en sortie. Pour effectuer cette fonction, vous configurez les valeurs suivantes :
Paramètre 1 (entrée) : user.country
Valeur : "US"
Paramètre 2 (sortie) : user.employeeid
Paramètre 3 (sortie, s’il n’existe aucune correspondance) : user.extensionattribute1
Extract() - After matching Retourne la sous-chaîne après qu’elle ait atteint la valeur spécifiée.
Par exemple, si la valeur de l’entrée est Finance_BSimon, la valeur correspondante est Finance_ et la sortie de la revendication est BSimon.
Extract() - Before matching Retourne la sous-chaîne jusqu’à ce qu’elle corresponde à la valeur spécifiée.
Par exemple, si la valeur de l’entrée est BSimon_US, la valeur correspondante est _US et la sortie de la revendication est BSimon.
Extract() - Between matching Retourne la sous-chaîne jusqu’à ce qu’elle corresponde à la valeur spécifiée.
Par exemple, si la valeur de l’entrée est Finance_BSimon_US, la première valeur correspondante est Finance_, la seconde _US et la sortie de la revendication est BSimon.
ExtractAlpha() - Prefix Retourne la partie alphabétique du préfixe de la chaîne.
Par exemple, si la valeur de l’entrée est BSimon_123, elle retourne BSimon.
ExtractAlpha() - Suffix Retourne la partie alphabétique du suffixe de la chaîne.
Par exemple, si la valeur de l’entrée est 123_Simon, elle retourne Simon.
ExtractNumeric() - Prefix Retourne la partie numérique du préfixe de la chaîne.
Par exemple, si la valeur de l’entrée est 123_BSimon, elle retourne 123.
ExtractNumeric() - Suffix Retourne la partie numérique du suffixe de la chaîne.
Par exemple, si la valeur de l’entrée est BSimon_123, elle retourne 123.
IfEmpty() Génère un attribut ou une constante en sortie si l’entrée est Null ou vide.
Par exemple, si vous souhaitez générer un attribut stocké dans un attribut d’extension si l’ID d’employé pour un utilisateur donné est vide. Pour effectuer cette fonction, configurez les valeurs suivantes :
Paramètre 1 (entrée) : user.employeeid
Paramètre 2 (sortie) : user.extensionattribute1
Paramètre 3 (sortie s’il n’existe aucune correspondance) : user.employeeid
IfNotEmpty() Génère un attribut ou une constante en sortie si l’entrée n’est pas Null ou vide.
Par exemple, si vous souhaitez générer un attribut stocké dans un attribut d’extension si l’ID d’employé pour un utilisateur donné n’est pas vide. Pour effectuer cette fonction, vous configurez les valeurs suivantes :
Paramètre 1 (entrée) : user.employeeid
Paramètre 2 (sortie) : user.extensionattribute1
Substring() – Longueur fixe Extrait des parties d’un type de revendication de chaîne, en commençant au caractère à la position spécifiée et retourne le nombre spécifié de caractères.
SourceClaim - Source de la revendication sur laquelle la transformation doit être exécutée.
StartIndex - Position du caractère de départ de base zéro d’une sous-chaîne de cette instance.
Length - Longueur des caractères de la sous-chaîne.
Par exemple :
sourceClaim - PleaseExtractThisNow
StartIndex - 6
Longueur – 11
Output: ExtractThis
Substring() – EndOfString Extrait des parties d’un type de revendication de chaîne, en commençant au caractère à la position spécifiée et retourne le reste de la revendication de l’index de début spécifié.
SourceClaim : source de la revendication de la transformation.
StartIndex - Position du caractère de départ de base zéro d’une sous-chaîne de cette instance.
Par exemple :
sourceClaim - PleaseExtractThisNow
StartIndex - 6
Output: ExtractThisNow
RegexReplace() La transformation RegexReplace() accepte comme paramètres d’entrée :
- Paramètre 1 : un attribut utilisateur comme entrée regex
- Une option permettant d’approuver la source comme étant à valeurs multiples
- Un modèle d’expression régulière
- Un modèle de remplacement Le modèle de remplacement peut contenir un format de texte statique, ainsi que des références pointant vers des groupes de sortie regex et des paramètres d’entrée en plus.

Si vous avez besoin d’autres transformations, soumettez votre idée dans le Forum de commentaires Microsoft Entra ID sous la catégorie Application SaaS.

Transformation des revendications basées sur regex

L’image suivante montre un exemple du premier niveau de transformation :

Screenshot of the first level of transformation.

Le tableau suivant fournit des informations sur le premier niveau de transformations. Les actions répertoriées dans le tableau correspondent aux étiquettes de l’image précédente. Sélectionnez Modifier pour ouvrir le panneau de transformation des revendications.

Action Champ Description
1 Transformation Sélectionnez l’option RegexReplace() dans les options Transformation pour utiliser la méthode de transformation de revendications basée sur regex pour la transformation des revendications.
2 Parameter 1 Entrée pour la transformation d’expression régulière. Par exemple, user.mail qui a une adresse e-mail utilisateur telle que admin@fabrikam.com.
3 Treat source as multivalued Certains attributs utilisateur d’entrée peuvent être des attributs utilisateur à valeurs multiples. Si l’attribut utilisateur sélectionné prend en charge plusieurs valeurs et que l’utilisateur souhaite utiliser plusieurs valeurs pour la transformation, il devra sélectionner Traiter la source comme étant à valeurs multiples. Si cette option est sélectionnée, toutes les valeurs sont utilisées pour la correspondance regex. Sinon, seule la première valeur est utilisée.
4 Regex pattern Expression régulière évaluée par rapport à la valeur de l’attribut utilisateur sélectionné comme Paramètre 1. Par exemple, une expression régulière pour extraire l’alias utilisateur de l’adresse e-mail utilisateur est représentée comme suit : (?'domain'^.*?)(?i)(\@fabrikam\.com)$.
5 Add additional parameter Plusieurs attributs utilisateur peuvent être utilisés pour la transformation. Les valeurs des attributs seraient ensuite fusionnées avec la sortie de transformation regex. Jusqu’à cinq autres paramètres sont pris en charge.
6 Replacement pattern Le modèle de remplacement est le modèle de texte, qui contient des espaces réservés pour le résultat regex. Tous les noms de groupes doivent être placés entre accolades, par exemple {nom_groupe}. Supposez que l’administration souhaite utiliser un alias d’utilisateur avec un autre nom de domaine, par exemple xyz.com, et fusionner le nom de pays avec celui-ci. Dans ce cas, le modèle de remplacement serait {country}.{domain}@xyz.com, où {country} sera la valeur du paramètre d’entrée et {domain} sera la sortie de groupe de l’évaluation de l’expression régulière. Dans ce cas, le résultat attendu est US.swmal@xyz.com.

L’image suivante montre un exemple du second niveau de transformation :

Screenshot of second level of claims transformation.

Le tableau suivant fournit des informations sur le second niveau de transformations. Les actions répertoriées dans le tableau correspondent aux étiquettes de l’image précédente.

Action Champ Description
1 Transformation Les transformations de revendications basées sur des expressions régulières ne sont pas limitées à la première transformation, et peuvent également être utilisées comme transformation de deuxième niveau. Toute autre méthode de transformation peut être utilisée comme première transformation.
2 Parameter 1 Si RegexReplace() est sélectionnée comme transformation de deuxième niveau, la sortie de la transformation de premier niveau est utilisée comme entrée pour la transformation de deuxième niveau. Pour appliquer la transformation, l’expression régulière de deuxième niveau doit correspondre à la sortie de la première transformation.
3 Regex pattern Le modèle Regex est l’expression régulière de la transformation de deuxième niveau.
4 Parameter input Entrées d’attribut utilisateur pour les transformations de deuxième niveau.
5 Parameter input Les administrateurs peuvent supprimer le paramètre d’entrée sélectionné s’ils n’en ont plus besoin.
6 Replacement pattern Le modèle de remplacement est le modèle de texte qui contient des espaces réservés pour le nom du groupe de résultats, le nom du groupe de paramètres d’entrée et la valeur de texte statique de regex. Tous les noms de groupes doivent être placés entre accolades, par exemple {group-name}. Supposez que l’administration souhaite utiliser un alias d’utilisateur avec un autre nom de domaine, par exemple xyz.com, et fusionner le nom de pays avec celui-ci. Dans ce cas, le modèle de remplacement serait {country}.{domain}@xyz.com, où {country} sera la valeur du paramètre d’entrée et {domain} sera la sortie de groupe de l’évaluation de l’expression régulière. Dans ce cas, le résultat attendu est US.swmal@xyz.com.
7 Test transformation La transformation RegexReplace() est évaluée uniquement si la valeur de l’attribut utilisateur sélectionné pour Paramètre 1 correspond à l’expression régulière fournie dans la zone de texte Modèle regex. S’ils ne correspondent pas, la valeur de revendication par défaut est ajoutée au jeton. Pour valider l’expression régulière par rapport à la valeur du paramètre d’entrée, une expérience de test est disponible dans le panneau de transformation. Cette expérience de test fonctionne uniquement sur des valeurs factices. Lorsque d’autres paramètres d’entrée sont utilisés, le nom du paramètre est ajouté au résultat de test au lieu de la valeur réelle. Pour accéder à la section test, sélectionnez Tester la transformation.

L’image suivante montre un exemple de test des transformations :

Screenshot of testing the transformation.

Le tableau suivant fournit des informations sur le test des transformations. Les actions répertoriées dans le tableau correspondent aux étiquettes de l’image précédente.

Action Champ Description
1 Test transformation Sélectionnez le bouton de fermeture (X) pour masquer la section de test et faire réapparaître le bouton Tester la transformation sur le panneau.
2 Test regex input Accepte l’entrée utilisée pour l’évaluation du test d’expression régulière. Dans le cas où la transformation de revendications basées sur une expression régulière est configurée en tant que transformation de deuxième niveau, fournissez une valeur qui est la sortie attendue de la première transformation.
3 Run test Une fois que l’entrée regex de test est fournie et que le modèle Regex, le modèle de remplacement et les paramètres d’entrée sont configurés, l’expression peut être évaluée en sélectionnant Exécuter le test.
4 Test transformation result Si l’évaluation réussit, la sortie de la transformation de test s’affiche en face de l’étiquette Résultat de la transformation de test.
5 Remove transformation La transformation de deuxième niveau peut être supprimée en sélectionnant Supprimer la transformation.
6 Specify output if no match Lorsqu’une valeur d’entrée regex est configurée par rapport au Paramètre 1 qui ne correspond pas à l’expression régulière, la transformation est ignorée. Dans ce cas, l’attribut utilisateur de remplacement peut être configuré, qui sera ajouté au jeton de la revendication en cochant la case Spécifiez la sortie s’il n’y a aucune correspondance.
7 Parameter 3 Si un attribut utilisateur de remplacement doit être retourné en l’absence de correspondance et Spécifier la sortie si aucune correspondance est vérifiée, un attribut utilisateur de remplacement peut être sélectionné à l’aide de la liste déroulante. Cette liste déroulante est disponible en face de Paramètre 3 (sortie si aucune correspondance).
8 Summary En bas du panneau, un résumé complet du format est affiché, qui explique la signification de la transformation par du texte simple.
9 Add Une fois les paramètres de configuration de la transformation vérifiés, vous pouvez l’enregistrer dans une stratégie de revendications en sélectionnant Ajouter. Sélectionnez Enregistrer dans le panneau Gérer la revendication pour enregistrer les modifications.

La transformation RegexReplace() est également disponible pour les transformations de revendications de groupe.

Validations de transformation

Un message fournit plus d’informations lorsque les conditions suivantes se produisent après avoir sélectionné Ajouter ou Exécuter un test :

  • Les paramètres d’entrée avec des attributs utilisateur en double ne sont pas autorisés.
  • Paramètres d’entrée inutilisés trouvés. Les paramètres d’entrée définis doivent avoir un usage respectif dans le texte du modèle de remplacement.
  • L’entrée regex de test fournie ne correspond pas à l’expression régulière fournie.
  • Aucune source pour les groupes dans le modèle de remplacement n’est trouvée.

Émettre des revendications basées sur des conditions

Vous pouvez spécifier la source d’une revendication en fonction du type d’utilisateur et du groupe auquel appartient l’utilisateur.

Le type d’utilisateur peut être :

  • Tous- Tous les utilisateurs sont autorisés à accéder à l’application.
  • Membres : Membre natif du locataire
  • Tous les invités : l’utilisateur est déplacé à partir d’une organisation externe avec ou sans Microsoft Entra ID.
  • Invités Microsoft Entra : l’utilisateur invité appartient à une autre organisation utilisant Microsoft Entra ID.
  • Invités externes : l’utilisateur invité appartient à une organisation externe qui n’a pas Microsoft Entra ID.

Un cas où le type d’utilisateur est utile est lorsque la source d’une revendication est différente pour un invité et un employé accédant à une application. Vous pouvez spécifier que si l’utilisateur est un employé, obtenir l’ID de nom à partir de user.email. Si l’utilisateur est un invité, le NameID provient de user.extensionattribute1.

Pour ajouter une condition de revendication :

  1. Dans Gérer les revendications, développez les conditions de la revendication.
  2. Sélectionnez le type d’utilisateur.
  3. Sélectionnez le ou les groupes auxquels l’utilisateur doit appartenir. Vous pouvez sélectionner jusqu’à 50 groupes uniques sur l’ensemble des revendications pour une application donnée.
  4. Sélectionnez la Source où la revendication va récupérer sa valeur. Vous pouvez sélectionner un attribut utilisateur dans le menu déroulant d’attribut de la source ou appliquer une transformation à l’attribut utilisateur avant de l’émettre en tant que réclamation.

L’ordre dans lequel vous ajoutez les conditions est important. Microsoft Entra évalue d’abord toutes les conditions avec la source Attribute, puis évalue toutes les conditions avec la source Transformation pour choisir la valeur à émettre dans la revendication. Microsoft Entra ID évalue les conditions avec la même source du début à la fin. La revendication émet la dernière valeur qui correspond à l’expression dans la revendication. Les transformations, telles que IsNotEmpty et Contains, agissent comme des restrictions.

Par exemple, Britta Simon est figure parmi les utilisateurs invités dans le locataire Contoso. Britta appartient à une autre organisation qui utilise également Microsoft Entra ID. Compte tenu de la configuration suivantes pour l’application Fabrikam, quand Britta tente de se connecter à Fabrikam, la plateforme d’identités Microsoft évalue les conditions comme suit.

Tout d’abord, la plateforme d’identités Microsoft vérifie si le type d’utilisateur de Britta est Tous les invités. Dans la mesure où le type est Tous les invités, la plateforme d’identités Microsoft attribue la source de la revendication à user.extensionattribute1. Ensuite, la plateforme d’identité Microsoft vérifie si le type d’utilisateur de Britta est Invités Microsoft Entra. Dans la mesure où le type est Tous les invités, la plateforme d’identités Microsoft attribue la source de la revendication à user.mail. Enfin, la revendication est émise avec une valeur deuser.mail pour Britta.

Autre exemple, examinons quand Britta Simon tente de se connecter avec la configuration suivante. Microsoft Entra évalue d’abord toutes les conditions avec la source Attribute. La source de la revendication est user.mail lorsque le type d’utilisateur de Britta est Invités Microsoft Entra. Microsoft Entra ID évalue ensuite les transformations. Étant donné que Britta est un invité, user.extensionattribute1 est la nouvelle source de la revendication. Étant donné que Britta se trouve dans Invités Microsoft Entra, user.othermail constitue la nouvelle source de cette revendication. Enfin, la revendication est émise avec une valeur deuser.othermail pour Britta.

Comme dernier exemple, examinons ce qui se passe si Britta n’a pas de user.othermail configuré ou s’il est vide. La revendication revient à user.extensionattribute1 en ignorant l’entrée de condition dans les deux cas.

Considérations de sécurité

Les applications qui reçoivent des jetons reposent sur des valeurs de revendication qui ne peuvent pas être falsifiées. Lorsque vous modifiez les contenu du jeton par la personnalisation des revendications, ces hypothèses peuvent ne plus être correctes. Les applications doivent explicitement confirmer que les jetons ont été modifiés pour se protéger contre les personnalisations créées par des intervenants malveillants. Protégez-vous contre les personnalisations inappropriées de l’une des manières suivantes :

Sans cela, Microsoft Entra ID retourne un code d’erreur AADSTS50146.

Configurer une clé de signature personnalisée

Pour les applications multi-abonnés, une clé de signature personnalisée doit être utilisée. Ne définissez pas acceptMappedClaims dans le manifeste de l’application. Lorsque vous configurez une application dans le portail Azure, vous recevez un objet d'inscription de l'application et un principal de service dans votre locataire. Cette application utilise la clé de connexion globale Azure, qui ne peut pas être utilisée pour la personnalisation des revendications dans les jetons. Pour obtenir des revendications personnalisées dans des jetons, créez une clé de connexion personnalisée à partir d’un certificat et ajoutez-la au principal du service. Dans le cadre d’un test, vous pouvez utiliser un certificat auto-signé. Une fois que vous avez configuré la clé de signature personnalisée, votre code d’application doit valider la clé de signature de jeton.

Ajoutez les informations suivantes au principal du service :

Extrayez la clé publique et privée de base 64 encodée à partir de l’exportation du fichier PFX de votre certificat. Vérifiez que le keyId pour le keyCredential utilisé pour « Signer » correspond au keyId du passwordCredential. Vous pouvez générer le customkeyIdentifier en obtenant le code de hachage de l’empreinte du certificat.

Requête

Remarque

Commencez par désactiver toute configuration de verrouillage du principal de service sur les applications créées à partir du panneau Inscriptions d’applications du centre d’administration Microsoft Entra avant de tenter d’appliquer un PATCH sur le principal de service, ce qui entraîne une erreur 400 demande incorrecte.

L'exemple suivant présente le format de la requête HTTP PATCH pour ajouter une clé de signature personnalisée à un principal de service. La valeur de la « clé » dans la propriété keyCredentials est raccourcie pour des raisons de lisibilité. La valeur est encodée en base 64. Pour la clé privée, la propriété d’usage est Sign. Pour la clé publique, la propriété d’usage est Verify.

PATCH https://graph.microsoft.com/v1.0/servicePrincipals/f47a6776-bca7-4f2e-bc6c-eec59d058e3e

Content-type: servicePrincipals/json
Authorization: Bearer {token}

{
    "keyCredentials":[
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=", 
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "X509CertAndPassword",
            "usage": "Sign",
            "key":"MIIKIAIBAz.....HBgUrDgMCERE20nuTptI9MEFCh2Ih2jaaLZBZGeZBRFVNXeZmAAgIH0A==",
            "displayName": "CN=contoso"
        },
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "e35a7d11-fef0-49ad-9f3e-aacbe0a42c42",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "AsymmetricX509Cert",
            "usage": "Verify",
            "key": "MIIDJzCCAg+gAw......CTxQvJ/zN3bafeesMSueR83hlCSyg==",
            "displayName": "CN=contoso"
        }

    ],
    "passwordCredentials": [
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
            "keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
            "endDateTime": "2022-01-27T19:40:33Z",
            "startDateTime": "2020-04-20T19:40:33Z",
            "secretText": "mypassword"
        }
    ]
}

Configurer une clé de signature personnalisée à l’aide de PowerShell

Utilisez PowerShell pour initier une application cliente publique MSAL et utilisez le flux Octroi de code d’autorisation pour obtenir un jeton d’accès d’autorisation déléguée pour Microsoft Graph. Utilisez le jeton d’accès pour appeler Microsoft Graph et configurer une clé de signature personnalisée pour le principal du service. Une fois que vous avez configuré la clé de signature personnalisée, votre code d’application doit valider la clé de signature de jeton.

Pour exécuter ce script, vous devez :

  • L'ID de l'objet du principal de service de votre application, qui se trouve dans la section Vue d'ensemble de l'entrée de votre application dans Applications d'entreprise sur le Portail Azure.
  • Une inscription de l’application pour inscrire un utilisateur et obtenir un jeton d’accès pour appeler Microsoft Graph. Obtenez l’ID de l’application (cliente) de cette application dans le panneau Vue d’ensemble de l’entrée de votre application dans Inscriptions d'applications du Portail Azure. L’inscription de l’application doit présenter la configuration suivante :
    • Un URI de redirection de « http://localhost", répertorié dans la configuration de la plateforme des applications mobiles et de bureau.
    • Dans les autorisations de l'API, les permissions déléguées Microsoft Graph Application.ReadWrite.All et User.Read (assurez-vous que vous avez octroyé le consentement administrateur à ces autorisations).
  • Un utilisateur qui se connecte pour obtenir le jeton d’accès Microsoft Graph. L'utilisateur doit avoir l'un des rôles administratifs Microsoft Entra suivants (nécessaire pour mettre à jour le principal de service) :
    • Administrateur d'applications cloud
    • Administrateur d’application
    • Administrateur général
  • Un certificat à configurer en tant que clé de signature personnalisée pour notre application. Vous pouvez soit créer un certificat auto-signé, soit en obtenir un auprès de votre autorité de certification approuvée. Les composants de certificat suivants sont utilisés dans le script :
    • clé publique (généralement un fichier .cer)
    • clé privée au format PKCS#12 (dans le fichier .pfx)
    • mot de passe de la clé privée (fichier pfx)

Important

La clé privée doit être au format PKCS#12, car Microsoft Entra ID ne prend pas en charge d’autres types de format. L'utilisation d'un format incorrect peut entraîner l'erreur « Certificat non valide : la valeur de clé est un certificat non valide » lors de l'utilisation de Microsoft Graph pour APPLIQUER UN PATCH au principal de service avec un keyCredentials contenant les informations sur le certificat.

$fqdn="fourthcoffeetest.onmicrosoft.com" # this is used for the 'issued to' and 'issued by' field of the certificate
$pwd="mypassword" # password for exporting the certificate private key
$location="C:\\temp" # path to folder where both the pfx and cer file will be written to

# Create a self-signed cert
$cert = New-SelfSignedCertificate -certstorelocation cert:\currentuser\my -DnsName $fqdn
$pwdSecure = ConvertTo-SecureString -String $pwd -Force -AsPlainText
$path = 'cert:\currentuser\my\' + $cert.Thumbprint
$cerFile = $location + "\\" + $fqdn + ".cer"
$pfxFile = $location + "\\" + $fqdn + ".pfx"
 
# Export the public and private keys
Export-PfxCertificate -cert $path -FilePath $pfxFile -Password $pwdSecure
Export-Certificate -cert $path -FilePath $cerFile

$ClientID = "<app-id>"
$loginURL       = "https://login.microsoftonline.com"
$tenantdomain   = "fourthcoffeetest.onmicrosoft.com"
$redirectURL = "http://localhost" # this reply URL is needed for PowerShell Core 
[string[]] $Scopes = "https://graph.microsoft.com/.default"
$pfxpath = $pfxFile # path to pfx file
$cerpath = $cerFile # path to cer file
$SPOID = "<service-principal-id>"
$graphuri = "https://graph.microsoft.com/v1.0/serviceprincipals/$SPOID"
$password = $pwd  # password for the pfx file
 
 
# choose the correct folder name for MSAL based on PowerShell version 5.1 (.Net) or PowerShell Core (.Net Core)
 
if ($PSVersionTable.PSVersion.Major -gt 5)
    { 
        $core = $true
        $foldername =  "netcoreapp2.1"
    }
else
    { 
        $core = $false
        $foldername = "net45"
    }
 
# Load the MSAL/microsoft.identity/client assembly -- needed once per PowerShell session
[System.Reflection.Assembly]::LoadFrom((Get-ChildItem C:/Users/<username>/.nuget/packages/microsoft.identity.client/4.32.1/lib/$foldername/Microsoft.Identity.Client.dll).fullname) | out-null
  
$global:app = $null
  
$ClientApplicationBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientID)
[void]$ClientApplicationBuilder.WithAuthority($("$loginURL/$tenantdomain"))
[void]$ClientApplicationBuilder.WithRedirectUri($redirectURL)
 
$global:app = $ClientApplicationBuilder.Build()
  
Function Get-GraphAccessTokenFromMSAL {
    [Microsoft.Identity.Client.AuthenticationResult] $authResult  = $null
    $AquireTokenParameters = $global:app.AcquireTokenInteractive($Scopes)
    [IntPtr] $ParentWindow = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle
    if ($ParentWindow)
    {
        [void]$AquireTokenParameters.WithParentActivityOrWindow($ParentWindow)
    }
    try {
        $authResult = $AquireTokenParameters.ExecuteAsync().GetAwaiter().GetResult()
    }
    catch {
        $ErrorMessage = $_.Exception.Message
        Write-Host $ErrorMessage
    }
     
    return $authResult
}
  
$myvar = Get-GraphAccessTokenFromMSAL
if ($myvar)
{
    $GraphAccessToken = $myvar.AccessToken
    Write-Host "Access Token: " $myvar.AccessToken
    #$GraphAccessToken = "eyJ0eXAiOiJKV1QiL ... iPxstltKQ"
    
 
    #  this is for PowerShell Core
    $Secure_String_Pwd = ConvertTo-SecureString $password -AsPlainText -Force
 
    # reading certificate files and creating Certificate Object
    if ($core)
    {
        $pfx_cert = get-content $pfxpath -AsByteStream -Raw
        $cer_cert = get-content $cerpath -AsByteStream -Raw
        $cert = Get-PfxCertificate -FilePath $pfxpath -Password $Secure_String_Pwd
    }
    else
    {
        $pfx_cert = get-content $pfxpath -Encoding Byte
        $cer_cert = get-content $cerpath -Encoding Byte
        # Write-Host "Enter password for the pfx file..."
        # calling Get-PfxCertificate in PowerShell 5.1 prompts for password
        # $cert = Get-PfxCertificate -FilePath $pfxpath
        $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxpath, $password)
    }
 
    # base 64 encode the private key and public key
    $base64pfx = [System.Convert]::ToBase64String($pfx_cert)
    $base64cer = [System.Convert]::ToBase64String($cer_cert)
 
    # getting id for the keyCredential object
    $guid1 = New-Guid
    $guid2 = New-Guid
 
    # get the custom key identifier from the certificate thumbprint:
    $hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
    $hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($cert.Thumbprint))
    $customKeyIdentifier = [System.Convert]::ToBase64String($hash)
 
    # get end date and start date for our keycredentials
    $endDateTime = ($cert.NotAfter).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
    $startDateTime = ($cert.NotBefore).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
 
    # building our json payload
    $object = [ordered]@{    
    keyCredentials = @(       
         [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid1
            startDateTime = $startDateTime 
            type = "X509CertAndPassword"
            usage = "Sign"
            key = $base64pfx
            displayName = "CN=fourthcoffeetest" 
        },
        [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid2
            startDateTime = $startDateTime 
            type = "AsymmetricX509Cert"
            usage = "Verify"
            key = $base64cer
            displayName = "CN=fourthcoffeetest"   
        }
        )  
    passwordCredentials = @(
        [ordered]@{
            customKeyIdentifier = $customKeyIdentifier
            keyId = $guid1           
            endDateTime = $endDateTime
            startDateTime = $startDateTime
            secretText = $password
        }
    )
    }
 
    $json = $object | ConvertTo-Json -Depth 99
    Write-Host "JSON Payload:"
    Write-Output $json
 
    # Request Header
    $Header = @{}
    $Header.Add("Authorization","Bearer $($GraphAccessToken)")
    $Header.Add("Content-Type","application/json")
 
    try 
    {
        Invoke-RestMethod -Uri $graphuri -Method "PATCH" -Headers $Header -Body $json
    } 
    catch 
    {
        # Dig into the exception to get the Response details.
        # Note that value__ is not a typo.
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
        Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
    }
 
    Write-Host "Complete Request"
}
else
{
    Write-Host "Fail to get Access Token"
}

Valider la clé de signature de jeton

Les applications pour lesquelles le mappage de revendications est activé doivent valider leurs clés de signature de jeton en ajoutant appid={client_id} à leurs demandes de métadonnées OpenID Connect. L'exemple suivant présente le format du document de métadonnée OpenID Connect que vous devez utiliser :

https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration?appid={client-id}

Mettre à jour le manifeste de l’application

Pour les applications monolocataire, vous pouvez définir la propriété acceptMappedClaims sur true dans le manifeste de l’application. Comme documenté sur le type de ressource apiApplication. La définition de la propriété permet à l’application d’utiliser le mappage des revendications sans spécifier de clé de signature personnalisée.

Avertissement

Ne définissez pas la propriété acceptMappedClaims sur true pour les applications à plusieurs abonnés. Si vous le faites, cela pourrait permettre à des intervenants malveillants de créer des politiques de mappage de réclamations pour votre application.

L’audience du jeton demandé est nécessaire pour utiliser un nom de domaine vérifié de votre tenant Microsoft Entra, ce qui signifie que vous devez définir Application ID URI (représenté par identifierUris dans le manifeste de l’application) par exemple sur https://contoso.com/my-api ou (simplement en utilisant le nom du tenant par défaut) https://contoso.onmicrosoft.com/my-api.

Si vous n’utilisez pas un domaine vérifié, Microsoft Entra ID retourne un code d’erreur AADSTS501461 avec le message « AcceptMappedClaims est uniquement pris en charge pour une audience du jeton correspondant au GUID de l’application ou une audience dans les domaines vérifiés du locataire. Modifiez l'identificateur de la ressource, ou utilisez une clé de signature spécifique à l'application. »

Options de revendications avancées

Configurez les options de revendications avancées pour les applications OIDC pour exposer la même revendication que les jetons SAML. Également pour les applications qui ont l’intention d’utiliser la même revendication pour les jetons de réponse SAML2.0 et OIDC.

Configurez les options de revendication avancées en cochant la case sous Options de revendications avancées dans le panneau Gérer les revendications.

Étapes suivantes