Ce nouvel article sera certainement un reminder pour moi et vous en ce qui concerne l’utilisation de Azure Active Directory B2C pour la gestion de l’authentification et de l’identité et des rôles dans les applications.
Cet article vient en réponse au fait que AD B2C ne supporte pas nativement la gestion des rôles et la fourniture de ceux-ci dans le protocole OpenID Connect. Nous allons voir ensemble comment contourner ce problème facilement au travers des extensions B2C….
Azure Active Directory B2C
Vous connaissez sûrement Azure Active Directory, peut-être moins B2C.
C’est tout simplement un provider de gestion des identités en tant que service proposé par Microsoft Azure, basé sur Active Directory.

Il permet de fournir rapidement et simplement une solution d’authentification sécurisée à vos applications pour les clients de votre entreprise. Cette solution permet également de fournir une solution de SSO (Single Sign On) pour les applications qui l’utilisent.
Enfin, en plus de proposer une personnalisation des interfaces utilisateurs de login/register/logout etc … Il supporte également la fédération d’authentification en utilisant les protocoles standard d’authentification comme :
- OAuth 2.0,
- OpenID Connect,
- SAML
Attributs Personnalisés
En effet Azure Active Directory B2C ne propose pas la gestion des rôles « out-of-the-box » ! Cependant, grâce aux attributs personnalisés il est toutefois possible de pouvoir en disposer.
Par défaut les 14 attributs suivants sont disponibles pour vos utilisateurs :

Vous pouvez également définir jusqu’à 100 attributs supplémentaires pour vos utilisateurs. Ces attributs permettent alors à B2C de vous fournir des informations d’identités supplémentaires pour la gestion de vos utilisateurs.
Les valeurs de ces attributs peuvent être alors renseignés par vos utilisateurs directement lors de leur inscription (via les « User Flows ») ou également par votre CRM …
Création d’un attribut personnalisé
La première étape consiste donc à créer votre attribut personnalisé. Dans votre portail Azure B2C, rendez-vous dans l’onglet « User Attributes » et cliquer sur « Add » :


Entrer un nom d’attribut valide et sélectionner le type de cet attribut, puis cliquer sur « Create ».
Collecter l’attribut à l’enregistrement
En fonction du type d’attribut que vous souhaitez ajouter à votre utilisateur, vous pouvez opter pour demander à l’utilisateur de saisir la valeur durant son enregistrement. La fenêtre d’enregistrement initial de votre utilisateur affichera alors les éléments graphiques qui permettront de le collecter et de l’enregistrer …
Notez que les opérations de Login/Logout/Register sont gérés dans AD B2C au travers de « User Flows ». Ces flux d’utilisateurs permettent de gérer les comportements de votre provider d’identité en fonction des actions que vous souhaitez proposer aux utilisateurs.
Si vous n’avez pas encore créé de flux utilisateurs, créez en un et sélectionnez SignUp and Sign In :

Une fois votre flux d’utilisateurs disponible vous pouvez alors lui demander de collecter vos attributs. Rendez-vous dans « User Attributes ».

Les attributs cochés ici seront alors demandés à l’utilisateur durant son enregistrement dans Azure Active Directory B2C.
Revendications
Maintenant que vous avez votre attribut et qu’il est renseigné (via le flux d’utilisateur), nous pouvons demander à Azure Active Directory B2C de retourner à l’application demandant l’authentification l’attribut en question dans les revendications d’applications (Claims).
Rendez-vous dans le flux d’utilisateur que vous avez précédemment créé puis sélectionnez « Application Claims » :

Sélectionnez ici les revendications que vous souhaitez renvoyer à l’application dans le token d’accès OIDC.
Intégration
Maintenant que nous avons pu voir ensemble comment ajouter des attributs personnalisés et les recevoir dans notre Jeton d’accès sous la forme de revendication, nous pouvons voir ensemble comment les utiliser dans une application pour authentifier les utilisateurs et sécuriser les services de cette application en se basant sur les rôles.
Cet exemple, je vous propose de le réaliser avec une application .NET Core exécutant des services WebApi REST.
Prérequis
Afin de pouvoir utiliser l’authentification basée sur les services Microsoft Azure Active Directory, et pour pouvoir le faire simple, il m’a suffi d’installer les dépendances suivantes via NuGet:
- Microsoft.Identity.Web
- Microsoft.AspNetCore.Authentication.JwtBearer
- Microsoft.AspNetCore.Authentication.OpenIdConnect
Ensuite, pour démarrer la configuration il faut récupérer depuis la console Azure AD B2C de l’instance les éléments suivants :
- l’URL de l’instance (nom de domaine de l’instance)
- Le nom du flux utilisateur précédemment créé,
- Le ClientID de l’application Azure AD (que vous devez créer)
Configuration OpenID Connect
La configuration de la prise en charge de l’authentification OpenID Connect via token JWT se fait dans le Startup.cs durant le BuildServices :
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(
jwtOopts =>
{
},
identityOpts =>
{
identityOpts.Instance = "https://*******.onmicrosoft.com/";
identityOpts.Domain = "*******.onmicrosoft.com";
identityOpts.SignUpSignInPolicyId = "B2C_1_SignUpSignIn";
identityOpts.ClientId = "********-****-****-****-************";
});
Grâce à cette configuration, vous bénéficierez alors de l’authentification de vos clients au travers de Azure AD B2C et des revendications que vous avez sélectionnées dans la partie « Application Claims » de votre flux utilisateur.
Attention, les revendications sur les attributs personnalisés seront présentes dans les claims avec leur nom, préfixé de « extension_ », exemple : « extension_Role ».
Prise en charge du Rôle
Maintenant que nous avons tout pour récupérer le rôle auquel notre utilisateur authentifié appartient, nous pouvons modifier notre configuration d’authentification afin de spécifier à Asp.NET Core Identity comment récupérer ce rôle dans les revendications du jeton JWT.
Pour ce faire, rien de plus simple, dans le snippet précédent modifions les les jwtOpts :
jwtOopts =>
{
jwtOopts.TokenValidationParameters.RoleClaimType = "extension_Role";
},
Ensuite, pour valider l’authentification de nos services avec la gestion du rôle, ajoutons l’attribut suivant (sur nos contrôleurs et/ou actions) :
[Authorize(Roles = « Admin »)]
Modifier les extensions de l’utilisateur
AD B2C ne nous permet pas au travers du portail de manipuler (modifier) ces attributs personnalisés sur les utilisateurs. Pour pouvoir faire cela il vous faudra modifier vos utilisateurs au travers de Microsoft Graph pour pouvoir leur ajouter/modifier les extensions nécessaires.
b2c-extensions-app
b2c-extensions-app est une application qui a été créée dans AD B2C lors de la création du tenant.

Comme vous le voyez dans sa description, cette application est utilisée pour stocker les données d’extension. Nous allons donc pouvoir l’utiliser pour ajouter nos rôles sur les utilisateurs au travers du client Microsoft Graph en C#.
Cette partie est un peu « tricky », puisque pour pouvoir le faire, il vous faudra utiliser l’ID de l’application « b2c-extensions-app » en retirant les « – » :
string extensionName = $"extension_{"********-****-****-****-************".Replace("-", string.Empty)}_Role";
await this.graphClient.Users[item.Id].Request().UpdateAsync(new User
{
AdditionalData = new Dictionary<string, object> { { extensionName, "Admin" } }
});
Conclusion
Azure AD B2C est une solution de gestion des accès et des identitées qui se mettra à l’échelle au fur et à mesure de vos besoins. Microsoft Azure se charge alors de la sécurité de la plateforme d’authentification, en surveillant et en gérant automatiquement les menaces telles que les dénis de service et les attaques par force brute.
Nous avons vu ensemble comment le mettre en œuvre pour réaliser une solution d’authentification basée sur le protocole OpenID Connect. Nous avons pu également ajouter des attributs personnalisés à nos utilisateurs pour les ajouter à nos revendications d’applications et ainsi en bénéficier dans notre backend.
Au travers de AspNet.Core Identity, il est alors facile d’utiliser ces revendications dans la gestion de la sécurité de nos services exposés. Il est également possible de cumuler la gestion des rôles avec une gestion de policies comme suit :
services.AddAuthorization(options=>
{
options.AddPolicy("ContentsEditor", policy =>
{
policy.AddAuthenticationSchemes("Cookie, Bearer");
policy.RequireAuthenticatedUser();
policy.RequireRole("Admin");
policy.RequireClaim("editor", "contents");
});
}
Et dans vos controleurs :
[Authorize(Policy = "ContentsEditor")]
public IActionResult Save(Article article)
{
// ...
}