Sitecore 9.1 IdentityServer On-Premise AD via ADFS
Which the launch of Sitecore 9.1 came the introduction of the identity server to Sitecore list roles. You can find a lot more information about the Identity Server here https://identityserver.io/- Personally I think this I is great enhancement and add are more easy extendable way of enabling 3 party authentication providers to Sitecore. As standard the Identity server runs on Sitecore HOST https://doc.sitecore.com/developers/91/sitecore-experience-management/en/sitecore-host.html And ships with the possibility to use Azure AD and the Identiytserver.Contrib.Membership module allowing for cloud AD and the old DB style of authenticating in Sitecore. This also means the the old Sitecore AD module is now deprecated and no longer supported. So in this blog post I will show how to integrated a On Premise Ad with Sitecore Idenityserver hosted on Sitecore Host.
First you need a AD of course and then you need ADFS server to act as a authentication provide to the Identityserver. This however is a little out of scope for this post. But here is two great links on how to configure and forward AD groups as roles
https://stackoverflow.com/questions/55494354/user-groups-as-claims-through-openid-connect-over-adfs
Before we get to code you need to know about this nuget feed related to Sitcore Identity
https://sitecore.myget.org/F/sc-identity/api/v3/index.json
Since this feed contains some of packages needed. So this project or solution rather is to use OpenId Connect against the with the ADFS server
The solution consist of three class’ i will briefly show them here below
The App Settings classe seen below for retrieving the Setting for the Provider
public class AppSettings { public static readonly string SectionName = "Sitecore:ExternalIdentityProviders:IdentityProviders:ADFS"; public ADFSIdentityProvider ADFSIdentityProvider { get; set; } = new ADFSIdentityProvider(); }
The ADFSIdentityProvider which allows for a type strong way of accessing settings related to the module.
public class ADFSIdentityProvider { public bool Enabled { get; set; } public string Authority { get; set; } public string ClientId { get; set; } public string AuthenticationScheme { get; set; } public string MetadataAddress { get; set; } public string DisplayName { get; set; } }
And the CongifugreSitecore class which handles the communication with ADFS server
using System; using System.Security.Claims; using System.Threading.Tasks; 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; namespace Sitecore.IdentityServer.ADFS { public class ConfigureSitecore { private readonly ILogger _logger; private readonly AppSettings _appSettings; public ConfigureSitecore(ISitecoreConfiguration scConfig, ILogger logger) { this._logger = logger; this._appSettings = new AppSettings(); scConfig.GetSection(AppSettings.SectionName); scConfig.GetSection(AppSettings.SectionName).Bind((object)this._appSettings.ADFSIdentityProvider); } public object IdentityServerConstants { get; private set; } public void ConfigureServices(IServiceCollection services) { ADFSIdentityProvider adfsProvider = this._appSettings.ADFSIdentityProvider; if (!adfsProvider.Enabled) return; _logger.LogDebug($"Adding ADFS clientId {adfsProvider.ClientId} Authority {adfsProvider.Authority} Scheme {adfsProvider.AuthenticationScheme}"); new AuthenticationBuilder(services).AddOpenIdConnect(adfsProvider.AuthenticationScheme, adfsProvider.DisplayName, (Action)(options => { options.SignInScheme = "idsrv.external"; options.SignOutScheme = "idsrv"; options.RequireHttpsMetadata = false; options.SaveTokens = true; options.Authority = adfsProvider.Authority; options.ClientId = adfsProvider.ClientId; options.ResponseType = "id_token"; options.MetadataAddress = adfsProvider.MetadataAddress; options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = "roles" }; //Added to enable DEBUG to see all claims //Can be removed in production options.Events = new OpenIdConnectEvents() { OnTokenValidated = (context) => { //This identity include all claims ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity; //ADD break POINT to see all the claims, return Task.FromResult(0); } }; })); } } }
With the solution build you can deploy this to your Identity Server in sitecoreruntime folder in a production folder. The installationor placement of files should look like below.
The Sitecore Plugin manifest should point to your assembly name an example given below.
And for the configuration files placed in Config folder is here an examplereplace clientid and autherityaddress and metaaddress with your own values
with that in place you can go ahead and restart the application pool for the identityserver to load in the configurations and you should see the AD login button.
clicking on the button should take you t your ADFS server for authentication, after taht you should be redirect to Sitecore.
Mapping of claims to roles works the same as with Sitecore Azure Ad implementation.
You can find the code for this on github
https://github.com/istern/Sitecore.IdentityServer.ADFS
I am having problems with your code for the ConfigureServices method. Can you double check that it is pasted in to this blog post correctly? I see some > that I suspect are supposed to be greater than signs. I get errors in Visual Studio saying “Delegate Action does not take 1 argument”
Sorry I will try to verify the pasted code, did you try the code from github ?
Is there a Github link? I didn’t see one.
Sorry forgot to paste it here but here you go https://github.com/istern/Sitecore.IdentityServer.ADFS
Also I’ve removed the html tags now
Please let me know if that fixed your issue
There was one more error that I fixed. It’s on line 36. It should read Action. Thanks!
So the GitHub part worked ?
Yes the code in GitHub compiled properly. The code in this post has an error on line 36 in the ConfigureSitecore class.
Perfect thank you for the update. Let me know if you have any issues.
I’ve updated the code in post to reflect it
Is there something I have to do in Sitecore config to get this custom ADFS sign in to show up? I have followed everything in your post but when I go to sign in I don’t see AD as an option. Is there some config I have to do to tell Sitecore to use this new custom ADFS authentication provider?
Have you placed everything as shown in the image under the sitecoreruntime folder ? and have you also recycled the identityserver apppool ?
Yes I have placed everything as shown in the image. And I have recycled the IdentityServer app pool. I see a button that says “Go to login” (which is the default after installing 9.1). I don’t see “AD”.
Argh okay no I get it you’re not on the Identityserver please try to enter the url for the identityServer in your browser instead of hitting Sitecore directly. Remember to use https.
Also it is difficult to tell from the image exactly where the files are supposed to go. Does my DLL go in the “production” folder or the “sitecore” folder?
it goes it to the production folder.
can you see this in message in the log “Adding ADFS clientId…….”
in the web.config found in the root of the identityserver set stdoutLogEnabled=”true”
it goes it to the production folder.
can you see this in message in the log “Adding ADFS clientId…….”
in the web.config found in the root of the identityserver set stdoutLogEnabled=”true”
Also can you give an example of what an AuthorityAddress and a MetaAddress might look like? Are these URLs to the ADFS server?
I’ve updated with better image also note I’ve removed the “PT.” part so it matches from code from github I’ve just validated against a clean sitecore install, so please try that.
Authority could be something like https://adfs.yourdomain.com/adfs
MetaAdress could be https://adfs.yourdomain.com/FederationMetadata/2007-06/FederationMetadata.xml
please let me know if that enables the button.
Ok. At the moment I do not have ADFS set up yet. I just wanted to get the Sitecore stuff set up first. Will the AD button show up if I put in a dummy address for Authority and MetaAddress? Or will it fail without the correct addresses?
No I’ve just tested with filling in the text “dummy” can you show how you placed everything in your runtimefolder ? and the content of the manifest files for the module ?
Let me know if you manage to get the button, please verify the correct names for folders and files placed in the runtime folder
Here’s what I don’t get. How does Sitecore know to use the new stuff that we added to Identity Server? When I look at this file – App_Config/Sitecore/Owin.Authentication.IdentityServer/Sitecore.Owin.Authentication.IdentityServer.config I see an IdentityProviders node. In there is an IdentityProvider that has an id of SitecoreIdentityServer. It has a node called “caption” that says “Go to login”. This is what controls the text of the button. So it seems like Sitecore is using this config file to figure out how to set up the button on the login screen and where that button should go. Unless I am misunderstanding how this works.
Did you og Through the installation using sif and is there a hostname present in confit files that points to that site. You can verify it by looking in the iis manager to se if you have a identity server site and after that verify it has a valid ssl certificate that is trusted !
This instance was an upgrade from 9.0 to 9.1. I followed the guide and installed IdentityServer using SIF. I do have an IdentityServer site in IIS. How do I verify that it has a valid SSL cert that is trusted?
I don’t know with the upgrade but I’m pretty sure you can find a guide on the Sitecore doc site about enabling identity server. With the default install for Sitecore XP it will install an IdentityServer
I do have an IdentityServer installed. It is up and running.
Okay can you see the ad button when you visit the identityserver in a browser
Should I be able to open up the IdentityServer in a browser? When I try to do that I get an error saying that there is an error on the web.config file and that the config file is invalid. But when I look at it it seems fine.
Can you set log output to true and look at the log files ? Remember to restart app pool
it should look somethin like this below
aspNetCore processPath=”dotnet” arguments=”.\Sitecore.IdentityServer.Host.dll” stdoutLogEnabled=”true” stdoutLogFile=”.\logs\stdout”
I’ve added example configuration files to the github project, files that belongs to runtime folder shown in the picture in blog post
Yes I set log output to true. I restarted the app pool. Where are the IdentityServer logs supposed to be? Is there a log directory somewhere in the IdentityServer site? Or do the IdentityServer logs show up in the regular Sitecore log folder? According to the IdentityServer config file the logs are supposed to go in “\logs\stdout”. But that folder does not exist in the IdentityServer folder.
Strange it should be created during install or when the site starts
Are you able to open up a browser and go to your IdentityServer? Something like this: http://myIdentityServer. Does that work for you?
Yes but remember to use https
Hmmm – when I try that (with HTTPS) I get a 500.19 internal server error. “The requested page cannot be accessed because the related configuration data for the page is invalid.” Seems to be a problem with my web.config file. Can you add your Identity Server web.config file to GitHub?
Try to remove everything from the runtime folder if it still fails something went wrong during installation
Anything in the log files ??
No. There isn’t even a logs directory created.
Strange never experienced that before.
Have verified all prerequisite are ok for the installation .net core and so on is installed
Figured out part of my problem. I didn’t have the ASP.NET Core hosting bundle installed. The Sitecore documentation just said I need the .NET Core Runtime. In reality I need the full hosting module. Otherwise I can’t run a .NET Core site in IIS. So that is working now. I can browse to my Identity Server site. And it created the Logs folder and I am getting log file created now! But I still don’t see the “AD” button. Instead I see a button that says “Go to login”. Where is the text for the button defined?
The go to login is on the Sitecore cm server not the identityserver so be sure you’re on the correct url ie the identityserver
Ok. Maybe I am confused. How do I sign in to Sitecore with Identity Server? First I go to my browser and enter http://mysitecorecm.local/sitecore right? And does it automatically take me to the Identity Server? Am I supposed to see a page on the Identity Server to sign in? This is really really confusing.
I have seen cases where I was not correctly redirected to identity server but simply just enter the url in your browser for the identityserver..
I think I am finally understanding what is going on here. If Identity Server has errors or doesn’t start or something then you get sent to the Sitecore CM login page (which looks identical to the Identity Server login page and has the “Go to login” button). If Identity Server is working properly then I see the Identity Server sign in page. The problem is that they are almost identical. For a long time my Identity Server wasn’t working. But I never got any error or anything. I was just sent to the CM sign in page. So I was fooled in to thinking it was working correctly. But it wasn’t. So I think I am getting close. At the moment I am having problems with my custom DLL that I created using your code. I don’t think the versions of the supporting DLLs match the versions that are in the Identity Server root directory. But I can work on fixing that. Whew. This is complicated.
Have you tried using the example configuration from github and what is in the log ? Remember the dLl should also be in runtime folder not the root folder
Where should my custom DLL be placed? In the sitecoreruntime folder? In the production folder?
Production folder
I finally got it working!! My first problem was that I didn’t have the necessary .NET Core hosting software installed (the Sitecore documentation wasn’t specific enough). My second problem was that I wasn’t putting my custom DLL in the right place. It was hard to tell from the image in this blog post. My third problem was that when I built my custom DLL I used different versions of the referenced Microsoft DLLs than the ones that come with Identity Server. So I had to delete that project and make sure I picked the same versions of everything from Nuget as Identity Server uses. My fourth problem was that I was missing a tag in my config XML file. Once I fixed all of those problems then it worked! Thank you so very much for helping me with this. You don’t know how much I appreciate it!
You’re welcome glad you got it to work
One more question. What is the endpoint URL that I have to configure in ADFS for my Sitecore instance? I assume that I have to set up something in ADFS to tell it where to go after authentication.
If you’re thinking of the cm server that needs to point to your identityserver
No. I am assuming that somewhere in ADFS I have to tell ADFS where to send the user after a successful login right? Don’t I have to give ADFS a URL to send the user to after they finish logging in? Or does ADFS just know to send the user back to the Identity Server?
again are you talking after authentication on the adfs server or identityserver if the you mean the adfs It Will return the user to the identityserver … not need to configure anything there. And the identityserver will have a callback parameter in the url from site or you really should read about this in the is identityserver “standard” documentation
Ok. Thanks. The reason I am asking is that the client I am working with is asking for a Sitecore URL that they need to enter in to ADFS. I have read all of the documentation but most of it doesn’t make much sense to me since I have no experience with ADFS at all.
That shouldn’t be necessary. All authentication communication seen from the adfs server is against/with the identityserver is doesn’t need to know about the Sitecore server
I am trying to understand the differences between what you did here and the official Sitecore documentation (https://doc.sitecore.com/developers/91/sitecore-experience-management/en/configure-federated-authentication.html). The Sitecore documentation for how to set up Federated Authentication is very, very different from what you did. The Sitecore doc talks about all kinds of stuff you have to do on the Sitecore CM server. Your approach just drops some stuff in the Identity Server folders. Is there a reason that these approaches are so different?
Have you read the documentation from Sitecore on identityserver and the identityserver 4 documentation.
All I did was configure adfs and plugin The code from this blog on the identityserver.
Yes I have read all of the Sitecore documentation on Identity Server. None of the Sitecore documentation shows an approach that is at all like yours. The examples show in the Sitecore documentation are very different.
Identityserver is isolated, so be sure it is enabled and you can login to Sitecore from it, then you can install this module in the identityserver. The rest is now configurations in the identityserver and setting up adfs, no additional work in Sitecore (only if you want some user naming stuff)
Hi iStern,
My mandate is to setup SSO authentication in Sitecore 9.1 via ADFS. Your article is exactly what I need to do. But I’m getting error when trying to connect to ADFS from the Identity server:
[13:37:14] Microsoft.AspNetCore.Server.Kestrel [Error] Connection id “”0HLP2CFCNEEJ0″”, Request id “”0HLP2CFCNEEJ0:00000001″”: An unhandled exception was thrown by the application.
System.InvalidOperationException: IDX20803: Unable to obtain configuration from: ‘[PII is hidden by default. Set the ‘ShowPII’ flag in IdentityModelEventSource.cs to true to reveal it.]’. —> Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 1, position 1.
Any help will be appreciate.
Regards,
I Think it could something wrong with your configuration
Or have you Tested With a breakpoint to see what you got back from adfs
How does the Roles and Group’s Claim transformations work with your custom sub provider code
The same way as if you were using azure ad
Hi thomas, thanks for your reply , i have the subprovider code in place and required transforamtions on Ids end. But after succesful auth from ADFS , Sitecore CM is throwing an error ” You dont have access to the system” Nothing in the sitecore or Ids logs,
So after success auth – request is redirected to Sitecore CM – Any ideas what could be going wrong .. Also, what does the “hdl” parameter signify here
http://cm.local/identity/externallogin?authenticationType=SitecoreIdentityServer&ReturnUrl=%2fidentity%2fexternallogincallback%3fReturnUrl%3d%26sc_site%3dshell%26authenticationSource%3dDefault&sc_site=shell&hdl=AB071AD9D1E44FD2BA5F63AE2AB124AD
Usually it’s because you are missing roles ie no roles are added to the user, often this is because of wrong mappings, try to map the name
Claim to the role isadminstrator just for testing, and have a looke in the indentityserver logs as well.
nvm , pl disregard my above comment , i played around with the settings in ADFS and I am able to login now
Perfect just glad it worked
I am still struggling with the button as I done everything mentioned in post as well as comments section. Can you please help?
You need to be more specific button ? can you see the button, is the button not redirecting ?
I managed to configure to get adfs page on login button click but I am getting error message that ‘redirect_url’ is invalid.
Error details: MSIS9224: Received invalid OAuth authorization request. The received ‘redirect_uri’ parameter is not a valid registered redirect URI for the client identifier…
Where valid redirected_url should be defined?
In settings as explained in the post. It should basically point to the same page as your users is logging in on your adfs server
I managed to login using AD credentials but I am again redirected to Sitecore login page. On the top right I see “Log out” button and some random characters next to it.
What could be root cause of this?
Perfect . Then it is working. Now you just need to map ad roles to Sitecore roles if you want them to use the Sitecore client you should map an ad role to sitecore\client or something like that
But I have added:
Sorry, I tried to copy paste the code. I have added AzureADUserToAdminUser tag with claim isAdmin set to true, so I assume that should do mapping.
Don’t think your user on your local ad does have that claim the code on GitHub also have a comment about where you can set a breakpoint to see your claims. If you unsure about what claims your users have.
One more question. I found code where I can set breakpoint in ConfigureSitecore.cs but I am not sure how to debug it since when I attach identityserver process in VS, I see the message “The breakpoint will not currently be hit”. Is it possible to do debugging on identityserver process?
Since it is a dotnet hosted app you should connect to the dotnet service not w3p process
I managed to debug and to see claims. I see one more claim “nameidentifier” but I am not sure how it should be mapped since I have “name” claim as well. Still have the same issue.
If you look in the documentation for Sitecore adfs you car see an example on how to map a claim to a user and set the attribute isadministrator
I figured out that I don’t have ‘groups’ claim but it worked after I tried other claim which I found after debugging. Thanks a lot.
You’re welcome
Hi, I have added group claim to adfs but I cannot see it when I debug:
ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
Do you maybe have some suggestion?
Hi, I have added group claim to adfs but I cannot see it when I debug:
ClaimsIdentity identity = context.Principal.Identity as ClaimsIdentity;
Do you maybe have some suggestion?
Have a look at the links in the post some or try google how to setup adfs to forward ad roles as claims