Sitecore ADFS Integration

Sitecore ADFS Integration with Sitecore Identity

Requirements

ADFS Server
Sitecore With SI

Assumptions

ADFS Server Already Exists

Sitecore with SI installed

Here are the steps to Implement ADFS

ADFS Changes

Create Groups in ADFS for all the roles in Sitecore and obtain the group id’s for each role from ADFS along with the following details
ClientId
ClientSecret
Authority
Metadata
GroupId
Add Users to ADFS groups

Code changes

Create a new C# .net Core Class Library project

Go to Project Properties and change the Target framework to .Net Standard 2.0

Go to Visual Studio Options and add Package Source to include Sitecore Identity Nuget with the following source

https://sitecore.myget.org/F/sc-identity/api/v3/index.json

Add the following Nuget Packages to your Project

Sitecore.Plugin.IdentityProviders

Microsoft.AspNetCore.Authentication

Microsoft.AspNetCore.Authentication.OpenIdConnect

Add “Ids4AdfsIdentityProvider.cs” file to the root of the project

namespace Adfs
{
    public class Ids4AdfsIdentityProvider : Sitecore.Plugin.IdentityProviders.IdentityProvider
    {
        public string ClientId { get; set; }
        public string ClientSecret { get; set; }
        public string MetadataAddress { get; set; }
        public string Authority { get; set; }
    }
}

Add a configuration folder and Create a class called “AppSettings.cs

namespace Adfs.Configuration
{
    public class AppSettings
    {
        public static readonly string SectionName = "Sitecore:ExternalIdentityProviders:IdentityProviders:Ids4Adfs";
        public Ids4AdfsIdentityProvider Ids4AdfsIdentityProvider { get; set; } = new Ids4AdfsIdentityProvider();
    }
}

Add “ConfigureSitecore.cs” file to root

using Adfs.Configuration;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Sitecore.Framework.Runtime.Configuration;
using System;
using System.Security.Claims;
using System.Threading.Tasks;
namespace Adfs
{
    public class ConfigureSitecore
    {
        private readonly ILogger<ConfigureSitecore> _logger;
        private readonly AppSettings _appSettings;
        public ConfigureSitecore(ISitecoreConfiguration scConfig, ILogger<ConfigureSitecore> logger)
        {
            this._logger = logger;
            this._appSettings = new AppSettings();
            scConfig.GetSection(AppSettings.SectionName);
            scConfig.GetSection(AppSettings.SectionName).Bind((object)this._appSettings.Ids4AdfsIdentityProvider);
        }
        public void ConfigureServices(IServiceCollection services)
        {
            Ids4AdfsIdentityProvider identityProvider = this._appSettings.Ids4AdfsIdentityProvider;
            if (!identityProvider.Enabled)
                return;
            this._logger.LogDebug("Configure '" + identityProvider.DisplayName + "'. AuthenticationScheme = " + identityProvider.AuthenticationScheme + ", ClientId = " + identityProvider.ClientId, Array.Empty<object>());
            new AuthenticationBuilder(services).AddOpenIdConnect(identityProvider.AuthenticationScheme, identityProvider.DisplayName, (Action<OpenIdConnectOptions>)(options =>
            {
                options.SignInScheme = "idsrv.external";
                options.SignOutScheme = "idsrv";
                options.RequireHttpsMetadata = false;
                options.SaveTokens = true;
                options.Authority = identityProvider.Authority;
                options.ClientId = identityProvider.ClientId;
                options.ResponseType = "id_token";
                options.MetadataAddress = identityProvider.MetadataAddress;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "roles"
                };
                options.Events = new OpenIdConnectEvents()
                {
                    OnTokenValidated = (context) =>
                    {
                        ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
                        return Task.FromResult(0);
                    }
                };
            }));
        }
    }
}

Build the Project and Copy the project dll

End of coding

SI changes

Add a new folder in wwwrootsitecore (e.g., Custom.Plugin.IdentityProvider.Ids4Adfs)
Add a manifest file Sitecore.Plugin.manifest in the new folder

<?xml version="1.0" encoding="utf-8"?>
<SitecorePlugin PluginName="Adfs.Ids4Adfs" AssemblyName="Adfs" Version="1.0.0">
  <Dependencies>
    <Dependency name="Sitecore.Plugin.IdentityProviders">4.0.0-r00257</Dependency>
  </Dependencies>
  <Tags>
    <Sitecore>Sitecore</Sitecore>
  </Tags>
</SitecorePlugin>

Add New folder with name “Config”
Add a new XML file (e.g., Custom.Plugin.IdentityProvider.Ids4Adfs.xml) and replace the tokens with ADFS values

<?xml version="1.0" encoding="utf-8"?>
<Settings>
    <Sitecore>
        <ExternalIdentityProviders>
            <IdentityProviders>
                <Ids4Adfs type="Sitecore.Plugin.IdentityProviders.IdentityProvider, Sitecore.Plugin.IdentityProviders">
                    <AuthenticationScheme>IdS4-Ids4Adfs</AuthenticationScheme>
                    <DisplayName>Login with ADFS</DisplayName>
                    <Enabled>true</Enabled>
                    <ClientId>#{ClientId}#</ClientId>
                    <ClientSecret>#{ClientSecret}#</ClientSecret>
                    <Authority>#{Authority}#</Authority>
                    <MetadataAddress>#{Metadata}#</MetadataAddress>
                    <ClaimsTransformations>
                        <ClaimsTransformation1 type="Sitecore.Plugin.IdentityProviders.DefaultClaimsTransformation, Sitecore.Plugin.IdentityProviders">
                            <SourceClaims>
                                <Claim1 type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn" />
                            </SourceClaims>
                            <NewClaims>
                                <Claim1 type="email" />
                            </NewClaims>
                        </ClaimsTransformation1>
                        <!--Place transformation rules here. -->
                        <ClaimsTransformation2 type="Sitecore.Plugin.IdentityProviders.DefaultClaimsTransformation, Sitecore.Plugin.IdentityProviders">
                            <SourceClaims>
                                <Claim1 type="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" />
                            </SourceClaims>
                            <NewClaims>
                                <Claim1 type="name" />
                            </NewClaims>
                        </ClaimsTransformation2>
                        <AzureGroupTransformation type="Sitecore.Plugin.IdentityProviders.DefaultClaimsTransformation, Sitecore.Plugin.IdentityProviders">
                            <SourceClaims>
                                <Claim1 type="http://schemas.xmlsoap.org/claims/Group" value="#{GroupIdFromAdfs}#"/>
                            </SourceClaims>
                            <NewClaims>
                                <Claim1 type="http://www.sitecore.net/identity/claims/isAdmin" value="true" />
                            </NewClaims>
                        </AzureGroupTransformation>
                    </ClaimsTransformations>
                </Ids4Adfs>
            </IdentityProviders>
        </ExternalIdentityProviders>
    </Sitecore>
</Settings>

Note: the above xml maps only admin role, you can add more claims to the xml for other roles

Restart SI app and open sitecore login page and verify that Login to ADFS button is available

CM changes

Add a new patch config in Include folder for mapping roles for the claims setup in SI and replace the tokens with actual values

<?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">
        <federatedAuthentication>
            <identityProvidersPerSites>
                <mapEntry name="all sites">
                  <identityProviders hint="list:AddIdentityProvider">
                    <identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='SitecoreIdentityServer/IdS4-Ids4Adfs']" />
                  </identityProviders>
                </mapEntry>
            </identityProvidersPerSites>
            <identityProviders>
                <!-- An example of how to add an identity provider as a sub-provider of the Identity Server.
             The 'name' property must be in the following format: SitecoreIdentityServer/[AuthenticationScheme], where the 'AuthenticationScheme' equals the
             authentication scheme of an external identity provider that is configured on the Identity Server.

             Notes:
               1. The 'TriggerExternalSignOut' and 'Transformations' properties are inherited from the the Identity Server provider node and can not be overridden.
               2. To use a sub-provider, the 'Enabled' property of the Identity Server provider must be set to 'Enabled'. -->
         
                <identityProvider id="SitecoreIdentityServer/IdS4-Ids4Adfs" 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 Sitecore Identity: Azure AD</caption>
                  <icon>/sitecore/shell/themes/standard/Images/24x24/msazure.png</icon>
                  <domain>sitecore</domain>
                  <transformations hint="list:AddTransformation">
                    <!-- you need to have an Idp Claim for this to work -->
                    <!-- This is to transform AD group into Sitecore Role.  -->
                    <transformation name="Transform to Sitecore Author Role" type="Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication">
                      <sources hint="raw:AddSource">
                        <claim name="http://schemas.xmlsoap.org/claims/Group" value="#{GroupIdFromAdfs}#" />
                      </sources>
                      <targets hint="raw:AddTarget">
                        <claim name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" value="sitecoreAdmin" />
                      </targets>
                      <keepSource>true</keepSource>
                    </transformation>
                  </transformations>
                </identityProvider>
            </identityProviders>
      </federatedAuthentication>
    </sitecore>
</configuration>

Restart CM instance and try logging in to Sitecore using the Login to ADFS button

You will now be able to login with ADFS login and see the Sitecore launchpad with the features assigned to the logged in ADFS user.

This has been tested in Sitecore 9.3 and Sitecore 10.2

Spread the love

Leave a Reply

Your email address will not be published. Required fields are marked *