Sitecore Identity Server with Azure AD Integration / Sitecore 10

·

2 min read

Setting up Azure AD with Sitecore Identity Server are pretty straightforward as the primary use case is to use Azure Active Directory (Azure AD) in Sitecore IS.

The configuration is already predefined in Sitecore instance by default, what we need is just to enable it.

There are excellent posts out there that you might find very helpful as you go through the integration process. eg. https://sitecore.derekc.net/setting-up-azure-active-directory-integration-with-sitecore-identity-server-sitecore-9-1/

Thanks to the helpful guide!

However once you have Azure AD integrated, you will get a surprise when you discover that the Sitecore Username is mapped with some random unfriendly characters which is generated from Sitecore.Owin.Authentication.Services.DefaultExternalUserBuilder.

image.png

The random username is not very user-friendly since the username display in the item version history and within the workflows.

Now let’s see what’s needed to make username friendly.

Create ExternalUserBuilder class inherit from DefaultExternalUserBuilder and override CreateUniqueUserName function

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Sitecore.Diagnostics;
using Sitecore.Owin.Authentication.Configuration;
using Sitecore.Owin.Authentication.Identity;
using Sitecore.Owin.Authentication.Services;
using Sitecore.SecurityModel.Cryptography;
using System;
using System.Linq;

namespace Sitecore.Foundation.SitecoreExtensions.IdentityProvider
{
    public class ExternalUserBuilder : DefaultExternalUserBuilder
    {
        public ExternalUserBuilder(ApplicationUserFactory applicationUserFactory, IHashEncryption hashEncryption) : base(applicationUserFactory, hashEncryption) { }

        protected override string CreateUniqueUserName(UserManager<ApplicationUser> userManager, ExternalLoginInfo externalLoginInfo)
        {
            Assert.ArgumentNotNull((object)userManager, nameof(userManager));
            Assert.ArgumentNotNull((object)externalLoginInfo, nameof(externalLoginInfo));
            var identityProvider = this.FederatedAuthenticationConfiguration.GetIdentityProvider(externalLoginInfo.ExternalIdentity);
            if (identityProvider == null)
                throw new InvalidOperationException("Unable to retrieve identity provider for given identity");
            var domain = identityProvider.Domain;
            var username = "";

            var userNameClaim = externalLoginInfo.ExternalIdentity.Claims.FirstOrDefault(c => c.Type.Equals("email"));

            if (userNameClaim != null)
            {
                username = userNameClaim.Value;
                if (userNameClaim.Value.Contains("@"))
                {
                    username = userNameClaim.Value.Split('@')[0];
                }

                return domain + "\\" + username;
            }


            userNameClaim = externalLoginInfo.ExternalIdentity.Claims.FirstOrDefault(c => c.Type.Equals("name"));

            if (userNameClaim != null)
            {
                username = userNameClaim.Value;
                return domain + "\\" + username;
            }

            return domain + "\\" + externalLoginInfo.DefaultUserName;
        }

    }
}

Next, patch the config to use custom ExternalUserBuilder instead.

<?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 ContentManagement">

        <federatedAuthentication>

            <identityProvidersPerSites hint="list:AddIdentityProvidersPerSites">
                <!--  Defines a list of providers assigned to all sites.  -->
                <mapEntry name="all sites" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication" resolve="true">
                    <!--  The list of site names for which the specified identity providers will work.
               Note: the fedauth.siteNameExpander pipeline processes each site name, which gives the ability to use expressions like
               "regexp:modules_.*" or "database:web" or "domain:extranet"  -->
                    <sites hint="list">
                        <site>regexp:.*</site>
                    </sites>
                    <externalUserBuilder type="Sitecore.Foundation.SitecoreExtensions.IdentityProvider.ExternalUserBuilder, Sitecore.Foundation.SitecoreExtensions" resolve="true">
                        <IsPersistentUser>true</IsPersistentUser>
                    </externalUserBuilder>
                </mapEntry>
            </identityProvidersPerSites>

            <propertyInitializer>
                <maps>
                    <map name="set Email" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true">
                        <data hint="raw:AddData">
                            <source name="email"/>
                            <target name="Email"/>
                        </data>
                    </map>
                    <map name="set Fullname" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true">
                        <data hint="raw:AddData">
                            <source name="name"/>
                            <target name="FullName"/>
                        </data>
                    </map>
                </maps>
            </propertyInitializer>

        </federatedAuthentication>
    </sitecore>
</configuration>

Finally, we get an user-friendly username from AD integration. image.png

Hope this blog is helpful :)