I've been struggling to get Federated Authentication working with Sitecore 9 using IdentityServer 3 as the IDP. I've followed the example seen in http://blog.baslijten.com/enable-federated-authentication-and-configure-auth0-as-an-identity-provider-in-sitecore-9-0/ for Auth0, and have converted that to IDS3. But what I experienced was an endless loop between the IDP and Sitecore.
It seems that upon authentication, IdentityServer 3 redirects back to Sitecore, which fails to convert the authentication into a cookie. I'm left with a .nonce cookie instead. Sitecore, not seeing an authenticated user, redirects over to the IDP and this continues until I stop the process.
My IdentityProviderProcessor (with dummy values):
using System.Threading.Tasks;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using Sitecore.Diagnostics;
using Sitecore.Owin.Authentication.Configuration;
using Sitecore.Owin.Authentication.Pipelines.IdentityProviders;
using Sitecore.Owin.Authentication.Services;
namespace xx.xxxx.SC.Foundation.Authentication
{
public class IdentityProviderProcessor : IdentityProvidersProcessor
{
public IdentityProviderProcessor(FederatedAuthenticationConfiguration federatedAuthenticationConfiguration) : base(federatedAuthenticationConfiguration)
{
}
/// <summary>
/// Identityprovidr name. Has to match the configuration
/// </summary>
protected override string IdentityProviderName
{
get { return "ids3"; }
}
protected override void ProcessCore(IdentityProvidersArgs args)
{
Assert.ArgumentNotNull(args, "args");
IdentityProvider identityProvider = this.GetIdentityProvider();
string authenticationType = this.GetAuthenticationType();
args.App.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = "Cookies"
});
args.App.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "xxxx",
ClientId = "xxxx",
Scope = "openid profile xxxx",
RedirectUri = "xxxx",
ResponseType = "id_token token",
SignInAsAuthenticationType = "Cookies",
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = (context) =>
{
var identity = context.AuthenticationTicket.Identity;
foreach (Transformation current in identityProvider.Transformations)
{
current.Transform(identity, new TransformationContext(FederatedAuthenticationConfiguration, identityProvider));
}
var virtualUser = Sitecore.Security.Authentication.AuthenticationManager.BuildVirtualUser("xxxx\\[email protected]", true);
// You can add roles to the Virtual user
virtualUser.Roles.Add(Sitecore.Security.Accounts.Role.FromName("extranet\\MyRole"));
// You can even work with the profile if you wish
virtualUser.Profile.SetCustomProperty("CustomProperty", "12345");
virtualUser.Profile.Email = "[email protected]";
virtualUser.Profile.Name = "My User";
// Login the virtual user
Sitecore.Security.Authentication.AuthenticationManager.LoginVirtualUser(virtualUser);
return Task.FromResult(0);
},
},
});
}
}
}
And my config file:
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:role="http://www.sitecore.net/xmlconfig/role/">
<sitecore role:require="Standalone or ContentDelivery or ContentManagement">
<pipelines>
<owin.identityProviders>
<!-- Processors for coniguring providers. Each provider must have its own processor-->
<processor type="xx.xxxx.SC.Foundation.Authentication.IdentityProviderProcessor, xx.xxxx.SC.Foundation.Authentication" resolve="true" />
</owin.identityProviders>
</pipelines>
<federatedAuthentication type="Sitecore.Owin.Authentication.Configuration.FederatedAuthenticationConfiguration, Sitecore.Owin.Authentication">
<!--Provider mappings to sites-->
<identityProvidersPerSites hint="list:AddIdentityProvidersPerSites">
<!--The list of providers assigned to all sites-->
<mapEntry name="all sites" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication">
<sites hint="list">
<sites hint="list">
<site>modules_website</site>
<site>website</site>
</sites>
</sites>
<identityProviders hint="list:AddIdentityProvider">
<identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='ids3']" />
</identityProviders>
<externalUserBuilder type="Sitecore.Owin.Authentication.Services.DefaultExternalUserBuilder, Sitecore.Owin.Authentication">
<param desc="isPersistentUser">false</param>
</externalUserBuilder>
</mapEntry>
</identityProvidersPerSites>
<!--Definitions of providers-->
<identityProviders hint="list:AddIdentityProvider">
<!--Auth0 provider-->
<identityProvider id="ids3" type="Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication">
<param desc="name">$(id)</param>
<param desc="domainManager" type="Sitecore.Abstractions.BaseDomainManager" resolve="true" />
<!--This text will be showed for button-->
<caption></caption>
<icon></icon>
<!--Domain name which will be added when create a user-->
<domain>sitecore</domain>
<!--list of identity transfromations which are applied to the provider when a user signin-->
<transformations hint="list:AddTransformation">
<!--SetIdpClaim transformation-->
<transformation name="set idp claim" ref="federatedAuthentication/sharedTransformations/setIdpClaim" />
</transformations>
</identityProvider>
</identityProviders>
<sharedTransformations hint="list:AddTransformation">
</sharedTransformations>
</federatedAuthentication>
</sitecore>
</configuration>
Note that the only way I could accomplish this was to create a VirtualUser on validation. Given the near-total lack of documentation on this topic, I'm not sure if this is a needed step, or if something is wrong with the way I've set this up.
For now, the VirtualUser works like a champ and we'll likely keep this in place. I would like to know, however, is the creation of a VirtualUser here required or did I do something wrong?
Thanks for any input.