Slobodan Topic, Author at Perficient Blogs https://blogs.perficient.com/author/stopic/ Expert Digital Insights Thu, 30 Nov 2023 14:49:13 +0000 en-US hourly 1 https://blogs.perficient.com/files/favicon-194x194-1-150x150.png Slobodan Topic, Author at Perficient Blogs https://blogs.perficient.com/author/stopic/ 32 32 30508587 Sitecore Federated Authentication Troubleshooting https://blogs.perficient.com/2023/11/30/sitecore-federated-authentication-troubleshooting/ https://blogs.perficient.com/2023/11/30/sitecore-federated-authentication-troubleshooting/#comments Thu, 30 Nov 2023 14:49:13 +0000 https://blogs.perficient.com/?p=349731

Introduction

In this blog we will explore Sitecore Federated Authentication Troubleshooting. I used Azure AD B2C as the identity provider in my integration guide you can check here Sitecore federated authentication with azure ad b2c user flow. However the most of these issues are not identity provider specific. When you work on federated authentication there is a good chance that you will fail on your first attempt and potentially face some of the issues described in this blog post. To make your authentication setup hassle-free and smooth here are some of the most common errors and solutions to fix them.

The located assembly’s manifest definition does not match the assembly reference

Since implementing identity providers processor requires adding references to different assemblies like

  • Sitecore.Owin
  • Sitecore.Owin.Authentication
  • Microsoft.Owin
  • Microsoft.IdentityModel.Protocols.OpenIdConnect
  • Microsoft.Owin.Security.OpenIdConnect
  • IdentityModel

you could face an error stating that referenced assemblies version could not be found or not matching referenced version.

The problem:

Because Sitecore distribution comes with its own Identity Server it is already referencing some of these assemblies of certain versions. For example, my local development Sitecore 10.3 instance is referencing IdentityModel.dll version 3.10.10 but the latest NuGet package is version 6.2 at the time of writing this blog post. Installing the latest will cause this error to appear.

The solution:

You need to check specific assembly version on your running Sitecore instance and make sure you add the same version as a reference in your project. To check which version your Sitecore is referencing you can open the Web.config and find your problematic assembly by name. To check assembly version of the actual file in your running instance you can use this powershell command. Navigate to bin folder and run this command:

Get-Item .\IdentityModel.dll | Select-Object Name,@{n='FileVersion';e={$_.VersionInfo.FileVersion}},@{n='AssemblyVersion';e={[Reflection.AssemblyName]::GetAssemblyName($_.FullName).Version}}

NOTE: If you are using Docker containers you can first shell into your running container and check assembly versions there using the same PS command.

Configuration and Sitecore Topology

Since we are using federated authentication to authenticate users for Content Delivery instance, for environments where you have XP Scaled topology, separate CM and CD instances, you should enable the identity configuration only for ContentDelivery role. In cases where your topology is XP single you will have to enable identity configuration for ContentManagement role as well.

The problem:

Enabling federated authentication configuration for ContentManagement could cause redirecting your content authors to Azure AD B2C login page instead of Sitecore’s identity server login page. Sitecore documentation recommends using /sitecore and /sitecore/admin URLs to access Sitecore. In my case this resolves to https://aip.sc/sitecore and https://aip.sc/sitecore/admin and both options redirect to Azure AD B2C.

The solution:

To avoid this, make sure to use environment specific config files to prevent identity configuration patch being applied on upper environment’s CM instances. If you still need to have identity config enabled for ContentManagement role, the safest way you can access Sitecore is to use https://aip.sc/sitecore/login URL. Using old login page should also work for you https://aip.sc/sitecore/login?fbc=1

If you want to find more information about authentication changes which affect Sitecore login page, you can refer to this link: https://doc.sitecore.com/xp/en/developers/103/sitecore-experience-manager/understanding-sitecore-authentication-behavior-changes.html

Redirecting back to http instead of https

The problem:

When you start authentication process and you successfully authenticate, you are redirected back on the page you initially started from. If you don’t see your claims, you didn’t receive any error in the process and it looks like nothing actually happened you should check if you got redirected back on http instead of https. This can happen if you are running behind a proxy such as traefik in docker containers setup.

The solution:

To fix this issue, you should implement the extension method needed for operating a website on a HTTP connection behind a proxy which handles SSL hand-off. Such a proxy adds the X-Forwarded-Proto header to indicate the nature of the client’s connection. This is an example of AppBuilderExtension class

using Owin;
using System;

namespace AuthIntegrationPlayground.Identity.Extensions.Owin
{    
    public static class AppBuilderExtensions
    {
        private const string ForwardedProtoHeaderAdded = "ForwardedProtoHeaderAdded";
        
        public static IAppBuilder UseForwardedProtoHeader(this IAppBuilder app)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }

            // No need to add more than one instance of this middleware to the pipeline.
            if (app.Properties.ContainsKey(ForwardedProtoHeaderAdded))
            {
                return app;
            }

            app.Properties[ForwardedProtoHeaderAdded] = true;

            app.Use(async (context, next) =>
            {
                var request = context.Request;

                if (request.Scheme != Uri.UriSchemeHttps && string.Equals(request.Headers["X-Forwarded-Proto"], Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
                {
                    context.Request.Scheme = "https";
                }

                await next.Invoke();
            });

            return app;
        }
    }
}

And this is how we can use it inside AzureADB2CIdentityProvider.cs

protected override void ProcessCore(IdentityProvidersArgs args)
{
    try
    {        
        //OpenIdConnectAuthenticationOptions
        
        args.App.UseForwardedProtoHeader();//<--- App builder extension
        args.App.UseOpenIdConnectAuthentication(options);
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

IDX21323: RequireNonce is ‘[PII is hidden]’ Error

This is one of the most annoying errors which can turn your Sitecore federated authentication troubleshooting into a endless loop of searching for a solution and trying it to see if it works.

The problem:

Root cause of this error is a well known issue in asp.net Katana implementation. More about this issue can be found here https://github.com/aspnet/AspNetKatana/wiki/System.Web-response-cookie-integration-issues. In essence this error will show when OpenIdConnect could not validate nonce value due to a missing nonce cookie. However this error can be misleading and can appear for many different reasons:

  • Not using Sitecore’s GetSignInUrlInfo pipeline to generate the valid sign in URL
  • Website domain and the redirectURI domain are different and Sitecore does not have access to the nonce cookie after successful authentication
  • Nonce cookie is returning from the server but the browser blocks it. This could happen if you’re not using https. It can even be due to time difference(time not set properly) browser can mark cookie as expired
  • Clearing Cookies between the sign in URL generation and redirect back from the external provider

Some less obvious issues that could produce this error:

  • Disabled xDB and/or xDB.Tracking in some cases
  • Token endpoint URL inside OnCodeRecieved is not resolving properly (misconfiguration)

The solution:

From development standpoint the easiest solution to fix this error is adding CookieManager = new SystemWebCookieManager() inside OpenIdConnectAuthenticationOptions.

If this doesn’t work and you are unable to determine what is causing the issue you can try the following:

  • Probably the best way for Sitecore federated authentication troubleshooting is just using Visual Studio debugger. Connect your VS debugger to the running instance and put breakpoints inside notification methods and your AuthController. For this to work make sure you publish as debug not release. Step by step go thru authentication starting from generating signin URL to receiving claims and showing them on the page. Pay attention to endpoint URLs and OpenIdConnectAuthenticationOptions properties
  • Try finding more information by looking at Owin.log or your system’s Event Viewer
  • If you implemented any custom logic inside notification methods(calling external services or modifying authentication request) try commenting it out

Generic ‘An Error Occurred’ error message

In some cases, usually after extending or changing your code, you could face the exception message which will just say ‘An Error Occurred’. In this case your best bet is to revisit complete authentication setup and make sure all integral parts are there. Be aware of any code changes which could be affecting the authentication process. If you suspect this error is coming from Azure AD B2C, having Application Insights can help you determine the actual cause of this error.

Summary

In this blog we went over some of the most common issues you can face during Sitecore and Azure AD B2C integration. Since this integration is complex in its nature there are many factors that can affect the outcome. Assembly versions, configurations on Sitecore and Azure AD B2C side, custom code or external dependencies could cause authentication to fail. The key note for successful Sitecore federated authentication troubleshooting in general is to think in a way which will lead you towards finding the root cause and therefore being able to fix it. Often you will find yourself searching for an answer on internet without even knowing what is the error.

Final word of advice

Here are a few advices for making it easier for you when working on federated authentication.

  • Avoid implementing it all at once – It is not advisable to do complete implementation with all the claim transformations, custom user builder, pulling user data from external APIs, extending xConnect contact model etc. before being able to authenticate with a minimum required for authentication. It is not necessarily a bad thing but if you start facing errors during authentication you could have a hard time finding out what is causing the authentication to fail. Instead, try implementing just a minimum which works without issues and then move to extending it according to your needs.
  • Avoid using different guides as reference – If you are using different guides as a reference and referencing different parts of those guides you could end up having the unusable solution and ultimately rewriting complete implementation from start. The reason is there are different guides for different Sitecore versions and some outdated guides for Azure AD B2C. You should always refer to Sitecore’s and Microsoft’s documentation since it is up to date, as well following guides which are specific for your Sitecore version and project setup.
  • Keep in mind the final result – After a few iterations you will reach desired state for your authentication process. But before you start working on it you should plan in advance. It is a good thing to have everything documented in one place. For complex scenarios you should always have diagrams supporting your solution. You should know the use cases for your claims and access tokens(if any) so you can get things done in a way which will support it at the end. With this documented knowledge you will see the long term benefit since you can use it as a future reference.
]]>
https://blogs.perficient.com/2023/11/30/sitecore-federated-authentication-troubleshooting/feed/ 1 349731
Sitecore Federated Authentication with Azure AD B2C: User Flow https://blogs.perficient.com/2023/11/22/sitecore-federated-authentication-with-azure-ad-b2c-user-flow/ https://blogs.perficient.com/2023/11/22/sitecore-federated-authentication-with-azure-ad-b2c-user-flow/#comments Wed, 22 Nov 2023 12:19:43 +0000 https://blogs.perficient.com/?p=349207

Introduction

This guide will show you how to integrate Sitecore Content Delivery instance with Azure AD B2C using federated authentication. In this guide we will be using Sitecore 10.3 and a User Flow on Azure AD B2C side. Sitecore recognizes users visiting your website as extranet\anonymous and after introducing this feature, in form of sign up and sign in, you will be able to find out more about your users and therefore offer more customized digital experience. To find out more about benefits of such integration and whether you should do it, check out my blog post Sitecore and Azure AD B2C Integration

Before we get started

Since authentication follows certain protocols and specifications you should probably familiarize yourself with OAuth and OIDC (OpenID Connect) to better understand big picture when it comes to authenticating users.

Prerequisites

  1. Setting up Azure AD B2C Tenant on Azure Portal

    • Since there is a step-by-step instruction provided by Microsoft, I won’t be covering Tenant creation on Azure Portal. You can refer to this guide: https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-tenant
    • If you already have Azure AD B2C Tenant, you can skip creation and use that one.
    • NOTE: Do not mistake Azure AD (now Entra ID) for Azure AD B2C, those are two different things.
    • Data you need to collect from this section for future reference is tenant name (or tenant domain). You can find this information in azure portal when you search for Azure AD B2C and open tenant management section. In my case that is slobodantop.onmicrosoft.com
      Azure Ad B2c Tenant
  1. Registering a Client Application under Azure AD B2C Tenant

    • To register a Client Application you can refer to this guide: https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-register-applications?tabs=app-reg-ga
    • After completing this you should have a Client Application set under your tenant App registration section in azure portal. This should be a Web application with proper RedirectUri, admin consent for openid and offline_access scopes, enabled Token Implicit Grant and valid client secret generated.
    • Data you need to collect from your client application: Client Id, Client Secret, Redirect URI
      Azure Ad B2c Client Application
  1. Create User Flow

    • Azure AD B2C offers you an option to use predefined policies called user flows for sign up, sign in, self-service password reset and profile update. For simplicity we will use just Sign Up & Sign In user flow. To create this user flow please refer to this guide: https://learn.microsoft.com/en-us/azure/active-directory-b2c/tutorial-create-user-flows?pivots=b2c-user-flow
    • During creation you have an option to select user attributes which will be collected on sign up, and user claims which will be sent inside ID Token after successful authentication.
    • Data you need to collect after completing this section is user flow name. In my case this is B2C_1_testflow
      Azure Ad B2c User Flow

Implementing Azure AD B2C Identity Provider for Sitecore Federated Authentication

To successfully integrate your Sitecore content delivery instance and authenticate users on azure ad b2c using federated authentication you need to do the following:

Create configuration for identity provider

This is an example of a configuration file which has a purpose to:

  1. Hold our authentication settings
  2. Add identity provider under federated authentication section
  3. Set IdentityProvidersProcessor pipeline so it can be used by 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>

When it comes to identity provider configuration you need to aware of your Sitecore instance topology and add <sitecore role:require= attribute accordingly.

Create AzureADB2CIdentityProvider

The minimum which you need to implement for an authentication to work is:

  1. Create a class which inherits Sitecore.Owin.Authentication.Pipelines.IdentityProviders.IdentityProvidersProcessor
  2. Override Name property and ProcessCore method
  3. Set OpenIdConnectAuthenticationOptions and implement notification methods
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);
        }
    }
}

Generate valid authentication request

To initiate authentication against identity provider using Sitecore federated authentication you need two things.

  1. Generate Sign In Url using GetSignInUrlInfoPipeline
    This is usually placed inside the controller which is then used by a custom rendering responsible for authenticating users. This pipeline accepts argument called returnUrl which is used to redirect user after successful authentication. Typically user ends up on the same page where authentication initially started.

    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. Use generated sign in url as a POST request which will start authentication process.
    Easiest ways of achieving this is to create and submit form on the frontend when user click on custom login rendering.
    This is an example .cshtml view for custom login rendering

    @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>

Testing Sitecore Federated Authentication

  • Place your custom authentication rendering on a page. Typically it is part of the header, but for simplicity I am just placing it on a page where it can be clicked to start authentication
  • Click on Sign In button to start authentication process. You should be redirected to Azure AD B2C sign in page
  • If you have an account you can simply sign in using your credentials. If you don’t have an account you can use sign up option to create one. After completing sign up flow you will be signed in
  • After returning to Sitecore page after successful authentication rendering displays user claims from azure ad b2c

This is how the complete flow looks like.

Azure Ad B2c User Flow

Summary

In this blog I have covered the quickest and easiest way to integrate Sitecore and Azure AD B2C. This covers prerequisites you need on Azure AD B2C side, configuration and implementation for azure ad b2c identity provider in Sitecore and basic custom rendering to start authentication process.
This is a good starting point which can be used to further extend and customize your authentication. In some cases this will be sufficient to match client’s requirements. Since we can’t change how user flow is operating internally, any custom user sign up and sign in journey should be implemented using Azure AD B2C Custom policies.

Here are some steps we can take after initial integration:

  • Create custom user builder which will make sure user is created in a way that matches our needs
  • Use claim transformations to map Azure AD B2C claim names and values to more friendly named claims
  • Create OWIN user extension to make claims easily accessible
  • Add custom claims to collect additional user data
  • Use custom page content for our user flow so we can change the appearance of sign in page

Sitecore federated authentication additional resources

Here is a list of links where you can find more information relevant to authentication protocols, azure ad b2c and Sitecore federated authentication.

]]>
https://blogs.perficient.com/2023/11/22/sitecore-federated-authentication-with-azure-ad-b2c-user-flow/feed/ 1 349207
Sitecore and Azure AD B2C Integration https://blogs.perficient.com/2023/11/22/sitecore-and-azure-ad-b2c-integration/ https://blogs.perficient.com/2023/11/22/sitecore-and-azure-ad-b2c-integration/#comments Wed, 22 Nov 2023 11:30:46 +0000 https://blogs.perficient.com/?p=348567

Introduction

In this blog post, we will explore the benefits of Sitecore and Azure AD B2C integration and how its advanced authentication and authorization capabilities can help businesses provide a more secure and personalized digital experience for their customers. Sitecore first introduced Identity Server as a feature in Sitecore 9, which was released in October 2017. Identity Server was introduced as a replacement for identity management system which relied on the ASP.NET Membership Provider. This built-in support for Identity Server made it easier to integrate Azure AD B2C as an identity provider within the Sitecore ecosystem.

Understanding Azure B2C

Azure AD B2C is a cloud-based identity and access management (IAM) solution that enables businesses to manage user identities and access to their digital assets. It provides a range of features, such as user authentication and authorization to help businesses protect their digital assets from unauthorized access. With Azure AD B2C, businesses can also collect and manage user data, allowing them to create personalized digital experiences. Significant level of customization options enables seamless experience, branding and user journeys which can align with any specific requirements.

Setting Up Sitecore and Azure AD B2C Integration

Setting up Sitecore and Azure AD B2C integration involves several steps.
  1. Creating an Azure AD B2C tenant and configuring the identity provider settings.
  2. Configuring Sitecore to use Azure AD B2C as the primary identity provider.
    • This involves configuring Sitecore’s federated authentication module to forward login requests to Azure AD B2C.
    • Configuring Sitecore’s roles and permissions based on Azure AD B2C user attributes.
  3. Configuring Sitecore to use Azure AD B2C for collecting user data.
    • This involves mapping user attributes from Azure AD B2C to the corresponding xConnect contact facets and extending xConnect contact model if needed.

Here are the most significant benefits when considering Sitecore and Azure AD B2C integration.

Advanced Authentication Capabilities:

Azure AD B2C provides a wide range of authentication methods,
including social identities like Facebook and Google, multi-factor authentication, and passwordless authentication.
This gives businesses the flexibility to choose the authentication method that best suits their needs,
and also provides additional security options beyond what is available with Sitecore’s Identity Server.

Improved Security:

Security is a critical concern for any business operating online, and Sitecore and Azure AD B2C integration provides an enhanced level of security for
user authentication and authorization. With Azure AD B2C, businesses can take advantage of multi-factor authentication.
Azure AD B2C supports several MFA methods, such as SMS, email, or phone call.
Sitecore can leverage these MFA methods to provide an additional layer of security for user authentication.
Conditional access policies allow businesses to control access to their digital assets based on user attributes, such as device type, IP address, or location.
These added layers of security helps prevent unauthorized access, phishing attacks, and other cyber threats that can compromise sensitive data.

Personalized User Experiences:

Sitecore and Azure AD B2C integration also enable businesses to create more personalized user experiences.
This is achieved by using Azure AD B2C to collect user data, such as user preferences or behavior, and use it to create more relevant and engaging experiences for the customers.
User data is stored in a centralized location and can easily accessed and managed using Microsoft Graph API or Azure AD B2C portal.
Businesses can leverage user data to create targeted marketing campaigns and personalized content based on user preferences.
By tailoring content and offers to individual users, businesses can drive higher engagement and conversion rates.

Seamless Integration:

Sitecore and Azure AD B2C integration is designed to be seamless, making it easy for businesses to set up and manage.
With Azure AD B2C, businesses can manage user identities, profiles, and permissions, all within a single cloud-based platform.
This makes it easier for businesses to manage user data, streamline workflows, and reduce administrative overhead.
In addition to these benefits, Sitecore and Azure AD B2C integration also provides businesses with greater scalability, flexibility, and cost savings.
By leveraging cloud-based services, businesses can scale their digital experiences to meet the demands of their customers, while only paying for the resources they use.

Centralized Identity Management:

Azure AD B2C provides a centralized location for managing user identities,
which simplifies the process of managing user access across multiple applications and environments.
This reduces the risk of errors and makes it easier to maintain a secure identity environment.

Scalability and Availability:

Azure AD B2C is a cloud-based service that is designed to be highly scalable and available.
This means that businesses can easily scale up or down based on demand, and also benefit from the high availability and redundancy provided by Microsoft’s cloud infrastructure.

Compliance and Regulation:

Azure AD B2C provides compliance with industry regulations such as GDPR and HIPAA,
as well as support for authentication standards like OpenID Connect and OAuth 2.0.
This makes it easier for businesses to comply with regulatory requirements and ensure the security of user data.

Integration with Other Azure Services:

Azure AD B2C integrates seamlessly with other Azure services, such as Azure Active Directory and Azure Key Vault,
which provides additional security and management options for businesses.
Additionally, Azure AD B2C can be easily integrated with other cloud-based services, such as Microsoft Dynamics 365 and Salesforce.

There are some downsides as well which we need to point out.

Complexity:

Azure AD B2C is a more complex system than Sitecore’s Identity Server, and it may take longer to set up and configure.
As Azure AD B2C is a separate service, developers and administrators will need to learn a new set of tools and technologies to use it effectively.
This may require additional resources and expertise, and could result in a steeper learning curve for those who are not familiar with Azure AD B2C.

Cost:

While Sitecore’s Identity Server is included in the Sitecore license, Azure AD B2C is a separate service that requires a subscription.
Depending on the size and complexity of your organization, the cost of using Azure AD B2C may be higher than using Sitecore’s Identity Server.

Dependency on External Service:

Because Azure AD B2C is a cloud-based service, it introduces a dependency on an external service provider.
This may result in increased latency, and could potentially cause issues with service availability or performance.

Integration Challenges:

Depending on the complexity of your existing infrastructure, integrating Azure AD B2C with your Sitecore implementation may require additional development and configuration work.
This could result in longer development timelines or higher development costs.

In conclusion

Sitecore and Azure AD B2C integration provides businesses with a powerful set of tools to improve their digital experiences.
By combining Sitecore’s robust content management capabilities with Azure AD B2C’s advanced identity and access management features,
Sitecore can provide businesses with MFA, conditional access policies, and user data collection for personalization.
This integration can provide a more secure, personalized, and seamless user experience.
With this integration, businesses can better engage with their customers, drive higher conversion rates, and ultimately grow their business.
Setting up Sitecore and Azure B2C integration involves several technical steps, but the benefits of this integration definitely make it worth the effort.
]]>
https://blogs.perficient.com/2023/11/22/sitecore-and-azure-ad-b2c-integration/feed/ 1 348567