Fermer

novembre 22, 2023

Flux d’utilisateurs / Blogs / Perficient

Flux d’utilisateurs / Blogs / Perficient


Introduction

Ce guide vous montrera comment intégrer l’instance Sitecore Content Delivery à Azure AD B2C à l’aide de l’authentification fédérée. Dans ce guide, nous utiliserons Sitecore 10.3 et un flux utilisateur côté Azure AD B2C. Sitecore reconnaît les utilisateurs visitant votre site Web comme extranet\anonymes et après avoir introduit cette fonctionnalité, sous forme d’inscription et de connexion, vous pourrez en savoir plus sur vos utilisateurs et donc offrir une expérience numérique plus personnalisée. Pour en savoir plus sur les avantages d’une telle intégration et si vous devriez le faire, consultez mon article de blog Intégration de Sitecore et Azure AD B2C

Avant de commencer

Étant donné que l’authentification suit certains protocoles et spécifications, vous devriez probablement vous familiariser avec OAuth et OIDC (OpenID Connect) pour mieux comprendre la situation dans son ensemble en matière d’authentification des utilisateurs.

Conditions préalables

  1. Configuration du locataire Azure AD B2C sur le portail Azure

    • Puisqu’il existe des instructions étape par étape fournies par Microsoft, je ne couvrirai pas la création de locataire sur le portail Azure. Vous pouvez vous référer à ce guide : https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant
    • Si vous disposez déjà d’un locataire Azure AD B2C, vous pouvez ignorer la création et utiliser celui-ci.
    • REMARQUE : Ne confondez pas Azure AD (maintenant Entra ID) avec Azure AD B2C, ce sont deux choses différentes.
    • Les données que vous devez collecter dans cette section pour référence future sont le nom du locataire (ou le domaine du locataire). Vous pouvez trouver ces informations dans le portail Azure lorsque vous recherchez Azure AD B2C et ouvrez la section de gestion des locataires. Dans mon cas, c’est slobodantop.onmicrosoft.com
      Locataire Azure Ad B2c
  1. Enregistrement d’une application client sous le locataire Azure AD B2C

    • Pour enregistrer une application client, vous pouvez vous référer à ce guide : https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=app-reg-ga
    • Après avoir terminé cette opération, vous devriez avoir une application client définie dans la section d’enregistrement de l’application de votre locataire dans le portail Azure. Il doit s’agir d’une application Web avec un RedirectUri approprié, un consentement de l’administrateur pour les étendues openid et offline_access, une autorisation implicite de jeton activée et un secret client valide généré.
    • Données que vous devez collecter à partir de votre application client : ID client, secret client, URI de redirection
      Application cliente Azure Ad B2c
  1. Créer un flux d’utilisateurs

    • Azure AD B2C vous offre la possibilité d’utiliser des stratégies prédéfinies appelées flux d’utilisateurs pour l’inscription, la connexion, la réinitialisation du mot de passe en libre-service et la mise à jour du profil. Pour plus de simplicité, nous utiliserons uniquement le flux d’utilisateurs d’inscription et de connexion. Pour créer ce flux d’utilisateurs, veuillez vous référer à ce guide : https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-user-flow
    • Lors de la création, vous avez la possibilité de sélectionner les attributs utilisateur qui seront collectés lors de l’inscription et les réclamations utilisateur qui seront envoyées dans le jeton d’identification après une authentification réussie.
    • Les données que vous devez collecter après avoir terminé cette section sont le nom du flux utilisateur. Dans mon cas, c’est B2C_1_testflow
      Flux d'utilisateurs Azure Ad B2c

Implémentation du fournisseur d’identité Azure AD B2C pour l’authentification fédérée Sitecore

Pour intégrer avec succès votre instance de diffusion de contenu Sitecore et authentifier les utilisateurs sur Azure Ad B2C à l’aide de l’authentification fédérée, vous devez procéder comme suit :

Créer une configuration pour le fournisseur d’identité

Ceci est un exemple de fichier de configuration dont le but est de :

  1. Conservez nos paramètres d’authentification
  2. Ajouter un fournisseur d’identité dans la section d’authentification fédérée
  3. Définir le pipeline IdentityProvidersProcessor pour qu’il puisse être utilisé par Sitecore
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
    <sitecore role:require="Standalone or ContentDelivery or ContentManagement">
        <settings>
            <setting name="Identity.AzureADB2C.ClientId" value="aeb68fe7-78a9-45a3-bff6-9c49dfeae67a"/>
            <setting name="Identity.AzureADB2C.ClientSecret" value="your-client-application-secret"/>
            <setting name="Identity.AzureADB2C.Authority" value="https://slobodantop.b2clogin.com/{0}/{1}"/>
            <setting name="Identity.AzureADB2C.TenantId" value="slobodantop.onmicrosoft.com"/>
            <setting name="Identity.AzureADB2C.CustomPolicyId" value="B2C_1_testflow"/>
            <setting name="Identity.AzureADB2C.TokenValidator" value="nonce"/>
            <setting name="Identity.AzureADB2C.ResponseType" value="code id_token"/>
            <setting name="Identity.AzureADB2C.Scope" value="openid offline_access"/>
            <setting name="Identity.AzureADB2C.RedirectUri" value="/auth-response"/>
            <setting name="Identity.AzureADB2C.HostName" value="https://aip.sc"/>
        </settings>       
        <pipelines>
            <owin.identityProviders>
                <processor type="AuthIntegrationPlayground.Identity.IdentityProviders.AzureADB2CIdentityProvider, AuthIntegrationPlayground" resolve="true" />
            </owin.identityProviders>
        </pipelines>
        <federatedAuthentication type="Sitecore.Owin.Authentication.Configuration.FederatedAuthenticationConfiguration, Sitecore.Owin.Authentication">
            <identityProvidersPerSites hint="list:AddIdentityProvidersPerSites">
                <mapEntry name="aip" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication" resolve="true">
                    <sites hint="list">
                        <site>aip</site>
                    </sites>

                    <identityProviders hint="list:AddIdentityProvider">
                        <identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='AzureADB2C']" />
                    </identityProviders>
                </mapEntry>
            </identityProvidersPerSites>

            <identityProviders hint="list:AddIdentityProvider">
                <identityProvider id="AzureADB2C" type="Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication" >
                    <param desc="name">$(id)</param>
                    <param desc="domainManager" type="Sitecore.Abstractions.BaseDomainManager" resolve="true" />
                    <caption>Log in with Azure AD B2C</caption>
                    <icon>/assets/b2c.png</icon>
                    <domain>extranet</domain>
                    <enabled>true</enabled>                 
                </identityProvider>
            </identityProviders>
        </federatedAuthentication>
    </sitecore>
</configuration>

En ce qui concerne la configuration du fournisseur d’identité, vous devez connaître la topologie de votre instance Sitecore et ajouter l’attribut

Créer AzureADB2CIdentityProvider

Le minimum que vous devez mettre en œuvre pour qu’une authentification fonctionne est :

  1. Créer une classe qui hérite de Sitecore.Owin.Authentication.Pipelines.IdentityProviders.IdentityProvidersProcessor
  2. Remplacer la propriété Name et la méthode ProcessCore
  3. Définir OpenIdConnectAuthenticationOptions et implémenter les méthodes de notification
using IdentityModel.Client;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Security.Notifications;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using Sitecore.Abstractions;
using Sitecore.Diagnostics;
using Sitecore.Owin.Authentication.Configuration;
using Sitecore.Owin.Authentication.Extensions;
using Sitecore.Owin.Authentication.Pipelines.IdentityProviders;
using Sitecore.Owin.Authentication.Services;
using System;
using System.Threading.Tasks;

namespace AuthIntegrationPlayground.Identity.IdentityProviders
{
    public class AzureADB2CIdentityProvider : IdentityProvidersProcessor
    {
        protected override string IdentityProviderName => "AzureADB2C";

        // OAuth provider setting
        private string ClientId => Settings.GetSetting(Constants.AzureADB2CSettings.ClientId, "");
        private string ClientSecret => Settings.GetSetting(Constants.AzureADB2CSettings.ClientSecret, "");
        private string Authority => Settings.GetSetting(Constants.AzureADB2CSettings.Authority, "");
        private string TenantId => Settings.GetSetting(Constants.AzureADB2CSettings.TenantId, "");
        private string CustomPolicy => Settings.GetSetting(Constants.AzureADB2CSettings.CustomPolicyId, "");
        private string TokenValidator => Settings.GetSetting(Constants.AzureADB2CSettings.TokenValidator, "");
        private string ResponseType => Settings.GetSetting(Constants.AzureADB2CSettings.ResponseType, "");
        private string Scope => Settings.GetSetting(Constants.AzureADB2CSettings.Scope, "");
        private string RedirectUri => Settings.GetSetting(Constants.AzureADB2CSettings.RedirectUri, "");
        private string HostName => Settings.GetSetting(Constants.AzureADB2CSettings.HostName, "");

        private readonly string idToken = "id_token";
        private readonly string authErrorRelativePath = "/500-error";

        protected IdentityProvider IdentityProvider { get; set; }

        public AzureADB2CIdentityProvider(
            FederatedAuthenticationConfiguration federatedAuthenticationConfiguration,
            ICookieManager cookieManager,
            BaseSettings settings)
            : base(federatedAuthenticationConfiguration, cookieManager, settings)
        {
        }
        
        protected override void ProcessCore(IdentityProvidersArgs args)
        {
            try
            {
                Assert.ArgumentNotNull(args, nameof(args));

                var aadInstance = string.Format(this.Authority, this.TenantId, this.CustomPolicy);
                var metaAddress = $"{aadInstance}/v2.0/.well-known/openid-configuration";
                IdentityProvider = this.GetIdentityProvider();
                var authenticationType = this.GetAuthenticationType();

                var options = new OpenIdConnectAuthenticationOptions(authenticationType)
                {
                    Caption = IdentityProvider.Caption,
                    RedirectUri = string.Concat(this.HostName, this.RedirectUri),//https://aip.sc/auth-response url where authority will post back authorization code
                    ClientId = this.ClientId,// client application identifier
                    ResponseType = this.ResponseType,//code id_token this is what the authority will return after successful authentication
                    Authority = aadInstance,//https://slobodantop.b2clogin.com/slobodantop.onmicrosoft.com/B2C_1_signintest/v2.0 authority instance responsible to authenticate users
                    MetadataAddress = metaAddress,//https://slobodantop.b2clogin.com/slobodantop.onmicrosoft.com/B2C_1_signintest/v2.0/.well-known/openid-configuration holds authority configuration such as endpoint urls and authentication options supported. You can open this url in browser and examine the document
                    UseTokenLifetime = false, //indicates if we want authentication session lifetime(authentication cookie) to match lifetime of the token
                    ClientSecret = this.ClientSecret,// client application secret
                    TokenValidationParameters = new TokenValidationParameters { NameClaimType = this.TokenValidator },// in our case this is nonce
                    Scope = this.Scope,// openid offline_access are used per oidc specification. You can introduce any custom scopes if you want to have more granular authorization policies when it comes to protecting api resources. If you want to receive access token for specific scope in the response you will have to add 'token' to ResponseType.

                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = this.OnAuthenticationFailed,
                        AuthorizationCodeReceived = this.OnAuthorizationCodeReceived
                    }
                };

                args.App.UseOpenIdConnectAuthentication(options);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
        {
            if (notification.Exception != null)
            {
                Log.Info($"Azure AD B2C authentication failed with exception.\n {notification.Exception.Message}", this);

                notification.HandleResponse();

                // If you face IDX21323 error try adding CookieManager = new SystemWebCookieManager() inside OpenIdConnectAuthenticationOptions.
                // More info is available here https://github.com/aspnet/AspNetKatana/wiki/System.Web-response-cookie-integration-issues.
                // However, we keep this code to safeguard authentication. This fallback option will authenticate but it will lose returnUrl and user will be redirected to the home page.
                if (notification.Exception.Message.Contains("IDX21323"))
                {
                    notification.HandleResponse();
                    /* This line of code is the key to solve error 
                   IDX21323: RequireNonce is '[PII is hidden]'. OpenIdConnectProtocolValidationContext.Nonce was null, OpenIdConnectProtocol.ValidatedIdToken.Payload.Nonce was not null. 
                   The nonce cannot be validated. If you don't need to check the nonce, set OpenIdConnectProtocolValidator.RequireNonce to 'false'. Note if a 'nonce' is found it will be evaluated.
                   */
                    notification.OwinContext.Authentication.Challenge();
                    return Task.CompletedTask;
                }
            }

            notification.HandleResponse();
            notification.Response.Redirect(authErrorRelativePath);

            return Task.CompletedTask;
        }

        private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
        {
            // Exchange code for access and ID token
            var tokenClient = new TokenClient(string.Concat(notification.Options.Authority, "/oauth2/v2.0/token"), ClientId, ClientSecret);
            var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(notification.Code, notification.RedirectUri);
            if (tokenResponse.IsError)
            {
                HandleAuthorizationError(notification);
                return;
            }

            notification.AuthenticationTicket.Identity.ApplyClaimsTransformations(new TransformationContext(this.FederatedAuthenticationConfiguration, this.IdentityProvider));
        }

        private void HandleAuthorizationError(AuthorizationCodeReceivedNotification notification)
        {
            // Log Error
            notification.HandleResponse();
            notification.Response.Redirect(authErrorRelativePath);
        }
    }
}

Générer une demande d’authentification valide

Pour lancer l’authentification auprès du fournisseur d’identité à l’aide de l’authentification fédérée Sitecore, vous avez besoin de deux choses.

  1. Générer une URL de connexion à l’aide de GetSignInUrlInfoPipeline
    Celui-ci est généralement placé à l’intérieur du contrôleur qui est ensuite utilisé par un rendu personnalisé chargé d’authentifier les utilisateurs. Ce pipeline accepte l’argument appelé returnUrl qui est utilisé pour rediriger l’utilisateur après une authentification réussie. En règle générale, l’utilisateur se retrouve sur la même page où l’authentification a initialement démarré.
    using AuthIntegrationPlayground.Models;
    using Sitecore.Abstractions;
    using Sitecore.Diagnostics;
    using Sitecore.Mvc.Controllers;
    using Sitecore.Pipelines.GetSignInUrlInfo;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Web.Mvc;
    
    namespace AuthIntegrationPlayground.Controllers
    {
        public class AuthController : SitecoreController
        {
            private readonly BaseCorePipelineManager _corePipelineManager;
    
            private const string IdentityProviderName = "AzureADB2C";
    
            public AuthController(BaseCorePipelineManager corePipelineManager)
            {
                Assert.ArgumentNotNull(corePipelineManager, nameof(corePipelineManager));
    
                _corePipelineManager = corePipelineManager;            
            }
    
            public ActionResult AzureADB2CLogin()
            {
                var user = Sitecore.Security.Accounts.User.Current;
                var profile = user.Profile;
    
                var model = new LoginModel();
                
                if (!Sitecore.Context.PageMode.IsExperienceEditor && !Sitecore.Context.PageMode.IsExperienceEditorEditing)
                {
                    if (!profile.IsAnonymous)
                    {
                        var userIdentity = (ClaimsIdentity)profile.ProfileUser.Identity;
                        var claims = userIdentity.Claims.Select(claim => $"{claim.Type} : {claim.Value}");
                        model.UserClaims.AddRange(claims);
                    }
                    else 
                    {
                        // generate sign in url with valid returnUrl
                        var site = Sitecore.Sites.SiteContext.Current.Name;
                        var returnUrl = System.Web.HttpContext.Current.Request.RawUrl;
                        var args = new GetSignInUrlInfoArgs(site: site, returnUrl: returnUrl ?? "/");
                        GetSignInUrlInfoPipeline.Run(_corePipelineManager, args);
                        var urlInfo = args.Result.FirstOrDefault(x => x.IdentityProvider == IdentityProviderName);
                        var signInUrl = urlInfo?.Href;
    
                        model.SignInUrl = signInUrl;
                    }
                }
    
                return View("~/Views/Auth/Login.cshtml", model);
            }
        }
    }

  2. Utilisez l’URL de connexion générée comme requête POST qui lancera le processus d’authentification.
    Le moyen le plus simple d’y parvenir est de créer et de soumettre un formulaire sur le frontend lorsque l’utilisateur clique sur le rendu de connexion personnalisé.
    Ceci est un exemple de vue .cshtml pour le rendu de connexion personnalisé
    @model AuthIntegrationPlayground.Models.LoginModel
    
    <div class="login-button-wrapper">
        <button class="login-button" onclick="signInClick('@Model.SignInUrl')">Sign In</button>
        @if(Model.UserClaims.Any())
        {
            <div>Claims</div>
            foreach (var claim in Model.UserClaims) 
            {
                <div>@claim</div>
            }
        }
    </div>
    
    <script type="text/javascript">
        function signInClick(signInUrl) {
            var formAuth = document.createElement("form");
            formAuth.method = "POST";
            formAuth.action = signInUrl;
            document.body.appendChild(formAuth);
    
            formAuth.submit();
        }
    </script>

Test de l’authentification fédérée Sitecore

  • Placez votre rendu d’authentification personnalisé sur une page. Généralement, cela fait partie de l’en-tête, mais pour plus de simplicité, je le place simplement sur une page où l’on peut cliquer dessus pour démarrer l’authentification.
  • Cliquez sur le bouton Se connecter pour démarrer le processus d’authentification. Vous devriez être redirigé vers la page de connexion Azure AD B2C
  • Si vous avez un compte, vous pouvez simplement vous connecter en utilisant vos identifiants. Si vous n’avez pas de compte, vous pouvez utiliser l’option d’inscription pour en créer un. Après avoir terminé le processus d’inscription, vous serez connecté
  • Après être revenu à la page Sitecore après une authentification réussie, le rendu affiche les revendications des utilisateurs d’Azure Ad B2C.

Voici à quoi ressemble le flux complet.

Flux d'utilisateurs Azure Ad B2c

Résumé

Dans ce blog, j’ai couvert le moyen le plus rapide et le plus simple d’intégrer Sitecore et Azure AD B2C. Cela couvre les conditions préalables dont vous avez besoin du côté Azure AD B2C, la configuration et la mise en œuvre du fournisseur d’identité Azure Ad B2C dans Sitecore et le rendu personnalisé de base pour démarrer le processus d’authentification.
Il s’agit d’un bon point de départ qui peut être utilisé pour étendre et personnaliser davantage votre authentification. Dans certains cas, cela suffira à répondre aux exigences du client. Étant donné que nous ne pouvons pas modifier le fonctionnement du flux d’utilisateurs en interne, tout parcours d’inscription et de connexion personnalisé doit être implémenté à l’aide des stratégies personnalisées Azure AD B2C.

Voici quelques étapes que nous pouvons suivre après l’intégration initiale :

  • Créer un générateur d’utilisateurs personnalisé qui garantira que l’utilisateur est créé d’une manière qui correspond à nos besoins
  • Utiliser les transformations de revendications pour mapper les noms et valeurs des revendications Azure AD B2C à des revendications nommées plus conviviales
  • Créez une extension utilisateur OWIN pour rendre les réclamations facilement accessibles
  • Ajoutez des revendications personnalisées pour collecter des données utilisateur supplémentaires
  • Utiliser le contenu de la page personnalisée pour notre flux d’utilisateurs afin que nous puissions modifier l’apparence de la page de connexion

Ressources supplémentaires pour l’authentification fédérée Sitecore

Voici une liste de liens où vous pouvez trouver plus d’informations sur les protocoles d’authentification, Azure Ad B2C et l’authentification fédérée Sitecore.






Source link

novembre 22, 2023