Start of Main Content

The Sitecore Identity role, introduced with Sitecore 9.1, is a standalone website that manages Sitecore user logins. It handles logins for content management, the Horizon graphical editor, Sitecore Commerce business tools, and Content Hub (optional). The role supports direct login but also integrates with corporate single sign-on providers. Sitecore Identity ships with an AzureAD integration as a reference. However, per Sitecore's documentation, developers can build more plugins to integrate with other single sign-on providers.

Velir recently built this kind of integration with the Sustainsys.SAML2 library. While building it, we encountered a significant issue, where the libraries required by the Sustainsys.SAML2 library conflicted with those used by Sitecore Identity. Since the latter is a .NET Core application, the assembly binding override in web.config wasn’t available. But we discovered a resolution by patching the deps.json file that ships with Sitecore Identity. This post explains the fix and walks through a sample implementation. A future post will discuss the additional steps needed for a full production implementation.

Integrate Sitecore Identity with your single sign-on provider.

Our Sitecore MVPs can help you configure Sitecore Identity to work with your organization's single sign-on system.

The first step in building the SAML plugin is to create a class library in Visual Studio. When you do so, select .NET Standard instead of the .NET Framework.

: A screenshot from the “Create a new project” screen of Visual Studio, where there are three dropdown menus. They say “C#”, “Windows”, and “Library”. The type of project selected is “Class Library (.NET Standard)” which has the description “A project for creating a class library that targets .NET Standard.”

Sitecore's documentation recommends you edit the project file to reference their own SDK, Sitecore.Framework.Runtime.Build, but this isn’t necessary in our experience. The SDK only adds logic for generating a manifest file, and this file is easy to generate by hand. Adding the SDK caused some build issues for our developers, so we skipped this step during our implementation.

The project contains only one class file, ConfigureSitecore.cs, which connects the Saml2 library to Sitecore Identity via Sitecore's dependency injection framework. We'll save a deep dive into the configuration options for a follow up post. But you can use this file to build a test implementation by modifying the URL on line 21 to your identity server.

To get this to compile, you’ll need to add these NuGet packages, using Package Manager Console. Note the version number of the first ("5.1.1") depends on the version of Sitecore Identity you’re using.

Confirm all packages have been loaded, and that your project compiles.

Deploying the Plugin

Sitecore Identity is built on top of Sitecore Host, which can separate user DLLs and configurations from ones that ship from Sitecore. The sitecoreruntime folder on a stock Sitecore Identity instance contains just the Sitecore license. But if you create a production folder there, your plugin can load on top of the stock installation.

First, you need to deploy the DLLs that the plugin needs. You can generate a folder with these DLLs on the command line, by running dotnet publish in the project root. Note: This is not to be confused with the Publish command in Visual Studio, which has different functionality. This creates a publish folder, indicated below, that contains a recursive list of all dependency DLLs. The full path will be <project root>\bin\debug\netstandard2.0\publish.

Copy the contents of this directory to the Sitecore Identity sitecoreruntime folder.

A screen showing a sample of the dotnet publish PowerShell command you need to run on the project’s root folder. It reads: PS C:\Users\dsolovay\source\SitecoreIdentitySamlDemo\SitecoreIdentitySamlDemo> dotnet publish

Next, create a folder in the Sitecore Identity root, \sitcoreruntime\production, and copy all the DLLs from the publish folder to this location. To enable the plugin, create folder called \siteoreruntime\production\sitecore\<your plugin name>, and copy the following manifest file there. Update the name of the assembly to match yours. The name of this file must be Sitecore.Plugin.manifest since the application searches for that string when loading plugins.

Note: If you modified your project to reference the Sitecore.Framework.Build library as an SDK, you could also generate this file using the dotnet pack command.

Resolving Dependency Conflicts

If everything goes according to plan, Sitecore Identity will stop working, and return a 500 error. A look at the log files will turn up this issue:

System.IO.FileLoadException: Could not load file or assembly 'Microsoft.IdentityModel.Tokens.Saml, Version=5.2.4.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. Could not find or load a specific file. (Exception from HRESULT: 0x80131621)

This issue is caused because two DLLs are referenced by the file Sitecore.IdentityServer.Host.deps.json, located in the Sitecore Identity root folder. The deps.json file is responsible for assembly resolution for .NET Core and .NET Standard applications.

Interestingly, the two DLLs, Microsoft.IdentityModel.Tokens.Saml and Microsoft.IdentityModel.Xml, aren’t used by Sitecore Identity but are compile time dependencies, since they’re referenced by a Microsoft DLL that Sitecore Identity uses (Microsoft.IdentityModel.Protocols.WsFederation). It’s also, worth noting that the version of these assemblies, 5.2.0, doesn’t match all the other assemblies in the Microsoft.IdentityModel namespace, which are at 5.2.4, the version required by the Saml library.

We inferred that the specification of 5.2.0 was accidental, and that it was safe to update the file to reference the desired versions. The fix was straightforward once we accepted having to edit a 5000-line generated file. We replaced this section:

"Microsoft.IdentityModel.Tokens.Saml/5.2.0": {
    "dependencies": {
        "Microsoft.IdentityModel.Tokens": "5.2.4",
        "Microsoft.IdentityModel.Xml" "5.2.0",
        "NETStandard.Library": "2.0.3"
    },
    "compile": {
        "lib/netstandard1.4/Microsoft.IdentityModel.Tokens.Saml.dll": {}
    },
    "compileOnly": true
"Microsoft.IdentityModel.Tokens.Saml/5.2.0": {
    "dependencies": {
        "Microsoft.IdentityModel.Tokens": "5.2.4",
        "Microsoft.IdentityModel.Xml" "5.2.0",
        "NETStandard.Library": "2.0.3"
    },
    "compile": {
        "lib/netstandard1.4/Microsoft.IdentityModel.Tokens.Saml.dll": {}
    },
    "compileOnly": true
}

With this section from the deps.json file generated from our plugin (located in the \bin\Debug\netstandard2.0 directory) after a build:

 "Microsoft.IdentityModel.Tokens.Saml/5.2.4": { 
        "dependencies": { 
          "Microsoft.IdentityModel.Tokens": "5.2.4", 
          "Microsoft.IdentityModel.Xml": "5.2.4", 
          "NETStandard.Library": "2.0.3" 
        }, 
        "runtime": { 
          "lib/netstandard1.4/Microsoft.IdentityModel.Tokens.Saml.dll": { 
            "assemblyVersion": "5.2.4.0", 
            "fileVersion": "5.2.4.50619" 
          } 
        } 
      }, 
      "Microsoft.IdentityModel.Xml/5.2.4": { 
        "dependencies": { 
          "Microsoft.IdentityModel.Tokens": "5.2.4", 
          "NETStandard.Library": "2.0.3" 
        }, 
        "runtime": { 
          "lib/netstandard1.4/Microsoft.IdentityModel.Xml.dll": { 
            "assemblyVersion": "5.2.4.0", 
            "fileVersion": "5.2.4.50619" 
          } 
        } 
      }, 

And we replaced this:

"Microsoft.IdentityModel.Tokens.Saml/5.2.0": { 
      "type": "package", 
      "serviceable": true, 
      "sha512": "sha512-db9y9zHTxeVwTi91mqBu4u1h5tlseQxhXMlGBd7bousED/FcEuhRiVK1maXjoHyQTnYbFDGPvYKXxznDI5jBGQ==", 
      "path": "microsoft.identitymodel.tokens.saml/5.2.0", 
      "hashPath": "microsoft.identitymodel.tokens.saml.5.2.0.nupkg.sha512" 
    }, 
    "Microsoft.IdentityModel.Xml/5.2.0": { 
      "type": "package", 
      "serviceable": true, 
      "sha512": "sha512-0WB90AfR16LT0ANCQTb+183yWrusPt4QK1F3f9eL59ZiDKeZLx2AeXgrkDUO+7kG55nCPqmeOUDjHDVK4gsRgA==", 
      "path": "microsoft.identitymodel.xml/5.2.0", 
      "hashPath": "microsoft.identitymodel.xml.5.2.0.nupkg.sha512" 
    }, 

With this from our own deps.json:

"Microsoft.IdentityModel.Tokens.Saml/5.2.4": { 
      "type": "package", 
      "serviceable": true, 
      "sha512": "sha512-00JslaTaHAUtMqiv/C/jQBqqrHkYmTe2n08qqrsHW57xVKTu+vOoi75HqDZbK3SAnRuadevDtvGCHf7V5GOQDQ==", 
      "path": "microsoft.identitymodel.tokens.saml/5.2.4", 
      "hashPath": "microsoft.identitymodel.tokens.saml.5.2.4.nupkg.sha512" 
    }, 
    "Microsoft.IdentityModel.Xml/5.2.4": { 
      "type": "package", 
      "serviceable": true, 
      "sha512": "sha512-v0UUzcpzz+mcR+Fzp8wFrcBt0Br0nJH5vuAdmlUmFqoc/DuDt/u5fcXVFRP3D77l22CQ/Rs3FTXUeXrTvi4gPg==", 
      "path": "microsoft.identitymodel.xml/5.2.4", 
      "hashPath": "microsoft.identitymodel.xml.5.2.4.nupkg.sha512" 
    },  

We also had to copy these two DLLs to the Sitecore Identity root folder, violating the clean isolation of our DLLs from the stock ones. This made us somewhat sad. Having the application and my plugin work somewhat made up for it. We even saw the new button.

The Sitecore login screen with standard username and password fields along with a log in button. Underneath them is a new button this process created which says “SSO Button Text”.

If you've gotten to this point, you can now click the SSO button and be directed to the Sustainsys test login page:

The Sustainsys test login screen with a variety of options for testing logins using the Saml library.

Selecting "John Doe" from the "Use pre-filled values" dropdown and clicking login gets you recognized on Sitecore Identity. Note this username’s appearance in the following screenshot. But if you initiate this from Sitecore content management (CM), you will get a yellow "not authorized' message.

A screenshot from Sitecore showing the logged in username as “John Doe”.

A screenshot from Sitecore showing the error message, “You do not have access to the system. If you think this is wrong, please contact the system administrator.”

Enabling Role Transformation

When logging in to the Sustainsys application, if you pick the user "Admin Almighty", you see these attributes prepopulated:

The Attribute Statements screen from the Sustainsys test login page. The first field says Type “http://schemas.microsoft.com/ws/2008/06/id” with a Value of “Administrator.” The second field says “http://schemas.microsoft.com/ws/2008/06/id” with a Value of “root”. And the third field says “SpecialPowers” with a Value of “All of them”.

We can map these attributes, also called "claims," to Sitecore permissions, using this configuration file, which should be placed at /sitecoreruntime/production/config.

If you recycle the Sitecore Identity application pool and retry your sign in, you’ll log in as an administrator:

The Sitecore Experience Platform homepage for a user logged in as an Administrator. There is access to multiple Marketing Applications and Content Editing options including Email Experience Manager, Experience Analytics, Experience Profile, Federated Experience Manager, Forms, Experience Optimization, List Manager, Campaign Creator, Path Analyzer, Marketing Automation, Marketing Control Panel, Content Editor, Experience Editor, Media Library, Workbox, and Recycle Bin.

Log out, and attempt to log in as JohnDoe, but before clicking “Log in,” add this attribute statement using the + icon on the Sustainsys screen.

The Attribute Statements screen from the Sustainsys test login page. For the Type field it says “http://schemas.microsoft.com/ws/2008/06/identity/claims/role” and for the Value field it says “Author”.

You’ll now get logged in as an Author:

The Sitecore Experience Platform homepage for a user logged in as an Author. There is access to one Marketing Applications and multiple Content Editing options including Experience Optimization, Content Editor, Experience Editor, Media Library, Workbox, and Recycle Bin. There is also access to Control Panel and Desktop.

To recap, we've walked through creating a plugin, adding logic so it talks to an endpoint, resolving dependency conflicts, and proving that role assignment can determine privileges on the Sitecore CM. In a later post, we'll discuss how to make this code production-ready, by adding certificate signing, loading settings from configuration, and improving how Sitecore handles display of the signed in user. We'll also show how to handle users that have a very large number of claims (typically the case in real-world corporate environments), which can cause an application error when Sustainsys tries to convert these claims into a cookie. But for now, we've demonstrated you can connect Sitecore Identity to Sustainsys.SAML2.

A short note of thanks for the following blog posts and resources, which were very helpful in getting this working:

If you’d like to learn more about how to connect Sitecore Identity to Sustainsys.SAML2 or you’d like help integrating another system with Sitecore Identity to allow single sign-on, please contact us. You can also learn more about our Sitecore experience or read our latest thoughts on Sitecore.




Published:

Take advantage of our expertise with your next project.