Skip to main content

Sitecore Single Sign-On using Custom Identity Provider

Sitecore Single Sign-On using Custom Identity Provider


In the previous blog, we discussed Azure AD Integration with Sitecore for content management. Now in this blog, we are going to discuss how we can allow the end users to log in through SSO. Single Sign On allows users to enter credentials only one time instead of entering the credentials on each application.

Sitecore identity server that comes with Sitecore 9.1 allows you to log in through an external identity provider like Azure Active Directory, Facebook, Apple, or Google. It is built on Federation Authentication. Sitecore Identity.

Below are the steps:

Step 1: Configure OpenID Connect

Create a pipeline processor to configure OpenID connect to talk to custom identity providers.


using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.Owin.Infrastructure;
using Microsoft.Owin.Security.Notifications;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using Sitecore.Abstractions;
using Sitecore.Owin.Authentication.Configuration;
using Sitecore.Owin.Authentication.Pipelines.IdentityProviders;
using Sitecore.Owin.Authentication.Services;
using System;
using System.Collections.ObjectModel;
using System.Threading.Tasks;
namespace XXX
{
public class DemoProjectIdentityProvider : IdentityProvidersProcessor
{
protected override string IdentityProviderName => "DemoProjectIdentityProvider";
protected BaseLog Log { get; }
public Collection<string> Scopes { get; } = new Collection<string>();
private readonly ICookieManager cookieManager;
readonly string clientId = Sitecore.Configuration.Settings.GetSetting("ClientId");
readonly string redirectUri = Sitecore.Configuration.Settings.GetSetting("RedirectUri");
readonly string clientSecret = Sitecore.Configuration.Settings.GetSetting("ClientSecret");
readonly string authority = Sitecore.Configuration.Settings.GetSetting("Authority");
readonly string postLogoutRedirectUri = Sitecore.Configuration.Settings.GetSetting("PostLogoutRedirectUri");
readonly string errorUri = Sitecore.Configuration.Settings.GetSetting("ErrorMessage");
public DemoProjectIdentityProvider(
FederatedAuthenticationConfiguration federatedAuthenticationConfiguration,
ICookieManager cookieManager,
BaseSettings settings) : base(federatedAuthenticationConfiguration, cookieManager, settings)
{
this.cookieManager = cookieManager ?? throw new ArgumentNullException(nameof(cookieManager));
}
protected override void ProcessCore(IdentityProvidersArgs args)
{
var authenticationType = this.GetAuthenticationType();
var identityProvider = this.GetIdentityProvider();
var saveSigninToken = identityProvider.TriggerExternalSignOut;
var oidcOptions = this.SetupOidcOptions(authenticationType, saveSigninToken);
args.App.UseOpenIdConnectAuthentication(oidcOptions);
}
public OpenIdConnectAuthenticationOptions SetupOidcOptions(
string authenticationType,
bool saveSigninToken)
{
var oidcOptions = new OpenIdConnectAuthenticationOptions
{
AuthenticationType = authenticationType,
Authority = authority,
ClientId = clientId,
ClientSecret = clientSecret,
ResponseType = OpenIdConnectResponseType.IdTokenToken,
RedirectUri = redirectUri,
PostLogoutRedirectUri = postLogoutRedirectUri,
Scope = OpenIdConnectScope.OpenIdProfile + " " + OpenIdConnectScope.OfflineAccess,
SaveTokens = true,
Notifications = new OpenIdConnectAuthenticationNotifications
{
RedirectToIdentityProvider = this.RedirectToIdentityProviderAsync,
SecurityTokenValidated = this.SecurityTokenValidatedAsync
},
TokenValidationParameters =
{
SaveSigninToken = saveSigninToken
},
};
return oidcOptions;
}
private Task RedirectToIdentityProviderAsync(
RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions>
notification)
{
var owinContext = notification.OwinContext;
var protocolMessage = notification.ProtocolMessage;
var user = Sitecore.Context.User;
if (protocolMessage.RequestType == OpenIdConnectRequestType.Authentication)
{
protocolMessage.RedirectUri = postLogoutRedirectUri;
}
if (protocolMessage.RequestType == OpenIdConnectRequestType.Logout)
{
protocolMessage.PostLogoutRedirectUri = postLogoutRedirectUri;
protocolMessage.IdTokenHint = this.GetIdTokenHint(owinContext);
}
return Task.CompletedTask;
}
private Task SecurityTokenValidatedAsync(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
{
var identityProvider = this.GetIdentityProvider();
var identity = notification.AuthenticationTicket.Identity;
foreach (var current in identityProvider.Transformations)
{
current.Transform(identity, new TransformationContext(this.FederatedAuthenticationConfiguration, identityProvider));
}
return Task.CompletedTask;
}
}
}

Step 2: Patch File

Create a patch file that will register a custom Sitecore identity.
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
<sitecore>
<settings>
<setting name="ClientId" value="XXX" />
<setting name="RedirectUri" value="XXX" />
<setting name="ClientSecret" value="XXX" />
<setting name="Authority" value="XXX" />
<setting name="PostLogoutRedirectUri" value="XXX" />
<setting name="ErrorMessage" value="XXX" />
</settings>
<federatedAuthentication type="Sitecore.Owin.Authentication.Configuration.FederatedAuthenticationConfiguration, Sitecore.Owin.Authentication">
<identityProvidersPerSites hint="list:AddIdentityProvidersPerSites">
<mapEntry name="sites with extranet domain" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication" resolve="true" patch:instead="*[@name='sites with extranet domain']">
<sites hint="list">
<site>DemoWebsite</site>
</sites>
<identityProviders hint="list:AddIdentityProvider">
<identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='DemoProjectIdentityProvider']" />
</identityProviders>
<externalUserBuilder type="Sitecore.Owin.Authentication.Services.DefaultExternalUserBuilder, Sitecore.Owin.Authentication" resolve="true">
<IsPersistentUser>false</IsPersistentUser>
</externalUserBuilder>
</mapEntry>
</identityProvidersPerSites>
<identityProviders>
<identityProvider id="DemoProjectIdentityProvider" type="Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication">
<param desc="name">$(id)</param>
<param desc="domainManager" type="Sitecore.Abstractions.BaseDomainManager" resolve="true" />
<caption>Go to login</caption>
<domain>extranet</domain>
<triggerExternalSignOut>true</triggerExternalSignOut>
<transformations hint="list:AddTransformation">
<transformation name="Idp Claim" type="Sitecore.Owin.Authentication.Services.SetIdpClaimTransform, Sitecore.Owin.Authentication" />
<transformation name="set id_token claim" type="Sitecore.Owin.Authentication.Services.SaveIdTokenInClaim, Sitecore.Owin.Authentication" />
<transformation type="Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication">
<sources hint="raw:AddSource">
<claim name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" />
</sources>
<targets hint="raw:AddTarget">
<claim name="Email" />
</targets>
<keepSource>false</keepSource>
</transformation>
</transformations>
</identityProvider>
</identityProviders>
<propertyInitializer type="Sitecore.Owin.Authentication.Services.PropertyInitializer, Sitecore.Owin.Authentication">
<maps hint="list">
<map name="set SSO FullName" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true" patch:source="Project.NAC.AzureAD.config">
<data hint="raw:AddData">
<source name="full_name" />
<target name="FullName" />
</data>
</map>
<map name="Given Name" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true">
<data hint="raw:AddData">
<!--<source name="given_name" />-->
<source name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" />
<target name="Name" />
</data>
</map>
</maps>
</propertyInitializer>
</federatedAuthentication>
<pipelines>
<owin.identityProviders>
<processor type="XXX.DemoProjectIdentityProvider, XXX" resolve="true" id="DemoProjectIdentityProvider">
<scopes hint="list">
<scope name="openid">openid</scope>
<scope name="profile">profile</scope>
<scope name="offline_access">offline_access</scope>
</scopes>
</processor>
</owin.identityProviders>
</pipelines>
</sitecore>
</configuration>

Step 3:  Login Button Functionality

Now on clicking on the login button, you need to redirect to SSO so for this controller add below code:
// In Controller
public override ActionResult Index()
{
var model = this.GetModel() as LoginModel;
var args = new GetSignInUrlInfoArgs("DemoWebsite", "/"); //DemoWebsite name must be same which you have mentioned in site in patch file and mention postback URL
GetSignInUrlInfoPipeline.Run(_pipelineManager, args);
model.Result = args.Result;
return View(model);
}
// In View
@foreach (var signIn in Model.Result)
{
using (Html.BeginForm(null, null, FormMethod.Post, new { @action = signIn.Href }))
{
<button type="submit">
<img src="@signIn.Icon" />
Login
</button>
}
}
SXA: In the SXA website you need to add "loginpage" and "requireLogin" properties in "Other properties" section.

Sitecore Single Sign-On Using Custom Identity Provider

You can set "requireLogin" property as true/false, as per your requirement.

Step 4: Secure Page

There could be a possibility that you want to secure only a few pages so in this case on that page restrict "extranet\Anonymous" user.

Step 5: Logout

On the logout button click you can logout virtual user as mentioned below:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOut()
{
Sitecore.Security.Authentication.AuthenticationManager.Logout();
Session.Abandon();
return RedirectToAction("/");
}
view raw LogOut hosted with ❤ by GitHub

Comments

Popular posts from this blog

Sitecore 10.2 - “Failed to start service ‘Sitecore Marketing Automation Engine’” on Windows 11

Sitecore 10.2 - “Failed to start service ‘Sitecore Marketing Automation Engine' ” on Windows 11 Today I started to install Sitecore 10.2 using Sitecore Instance Manager on Windows 11 and I got this issue “Failed to start service ‘Sitecore Marketing Automation Engine' ” . Error : On event viewer it was showing the below error: I also tried to run ‘ Sitecore.MAEngine.exe ’ like this C:\Windows\system32>C:\inetpub\wwwroot\sclocal102xconnect.dev.local\App_Data\jobs\continuous\AutomationEngine\Sitecore.MAEngine.exe Which was throwing below error: Starting Marketing Automation Engine... 2022-01-29 22:21:11 ERR Error initializing XConnect client. System.AggregateException: One or more errors occurred. ---> Sitecore.XConnect.XdbCollectionUnavailableException: An error occurred while sending the request. ---> System.Net.Http.HttpRequestException: An error occurred while sending the request. ---> System.Net.WebException: The underlying connection was closed: An unexpected err...

Azure AD Integration with Sitecore 10.2

 Azure AD Integration with Sitecore 10.2 Sitecore identity server that comes with Sitecore 9.1 allows you to log in through an external identity provider like Azure Active Directory, Facebook, Apple, or Google. It is built on Federation Authentication. What is Federation Authentication? Federation authentication is a technology to allows users to access multiples application, tools, and domains using one credential. Using one set of credential user can access multiple applications, and resources after authentication.  Federation authentication consists of two systems, the Identity provider and the Service provider. Identity providers that maintain/create/manage identity information like name, email address, device, and location. Some examples of identity providers are Azure AD, Google, Facebook, and Apple. Service providers basically refer to a website, software, or app that the user is trying to access and SP basically relies on the identity provider to authenticate the user ...

Sitecore 9 Forms: Google reCaptcha field

Sitecore 9 Forms: Google reCaptcha field  Re-Captcha is the most important part of any form’s submission. Google reCaptcha run internet bot detector and determined whether a user is a bot or not.  Sitecore Forms does not provide Google reCaptcha field, which was available in WFFM before, so I have created my custom Google reCaptcha.   Below you can find step by step process to create Google reCaptcha field. Create patch config for reCaptcha Sitekey and SecretKey <?xml version="1.0"?> <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/"> <sitecore> <settings> <setting name="ReCaptchaSiteKey" value="site-key" /> <setting name="ReCaptchaSecretKey" value="secret-key" /> </settings> </sitecore> </configuration> Create new viewmodel class RecaptchaViewMode...