Sitecore Identity Part 3: Connecting to External Identity Provider

Introduction

Sitecore Identity Provider was implemented based on IdentityServer4 framework. IdentityServer4 doesn’t dictate how authentication to be done or what application can use the identity provider. It’s up to the implementer to decide that. In previous blog article, we discussed how a third party application can authenticate using Sitecore Identity Provider. In this blog we will look at the other side of Sitecore Identity. We know that Sitecore Identity authenticates users using the membership provider, but Sitecore Identity can delegate the authentication to other identity provider too. In fact Sitecore Identity comes with inbuilt AzureAd subprovider. If you enable it you should be able to authenticate against the Azure Active Directory. I added the following updated diagram to show how subprovider fits into the architecture.

Sitecore Identity with Subproviders

Configuring Azure Ad Subprovider

Sitecore provided some documentation about how to configure out of the box Azure Ad subprovider. It’s not in very detail and it takes some effort to configure it. I was going to write about it, but I had a problem setting it up end to end. So, I posted this question in Stack Exchange and through that I found this excellent blog post which explains everything in detail. I am skipping that part. I captured the following animation to show you how authentication happens once you setup Azure Ad subprovider.

If you setup the loginpage attribute of the shell site in Sitecore.Owin.Authentication.IdentityServer.config as
$(loginPath)shell/SitecoreIdentityServer/IdS4-AzureAd, Sitecore will skip Sitecore Identity Provider and use Azure Ad provider directly to authenticate.

Custom External Subprovider

Let’s write some code to implement a custom subprovider. I will be utilizing IdentityServer Demo site https://demo.identityserver.io/ to create our subprovider. The reason to use IdentityServer Demo is, it is simple and no configuration is needed on the IdentityServer side. If you go to that site, you will find several grant types. The one we will be using is Implicit grant type and the ClientId for that is ‘implicit’. Our subprovider will be using this ClientId to get access to the IdentityServer identity provider.
Sitecore Identity is a Sitecore Host application. Sitecore Host is a new framework introduced in Sitecore 9.1 that you can use to create Sitecore Services. The benefit of creating services using Sitecore Host is that, you get all the common features of Sitecore Host, like logging, Dependency Injection etc. right out off the bat. The subprovider we will be creating is a Sitecore Host plugin and since Sitecore Host supports dynamic plugin loading, our plugin will be loaded as soon as we drop the plugin the ‘sitecoreruntime’ folder under Sitecore Identity root folder.
You can find the plugin project in the github repo. It’s name is
Sitecore.Plugin.IdentityProvider.Ids4Demo. Here are the important code snippets.


The Sitecore.Plugin.IdentityProvider.Ids4Demo.xml contains the configuration of the subprovider. The <Enabled> property should be true to make the subprovider available to Sitecore Identity. <AuthenticationSchema> is to identify the subprovider and it is used along with the IdentityProvider name in Sitecore to configure which subprovider to be used for different site. <ClientId> contains the Id to be used to connect to IdentityServer demo provider. <DisplayName> is button caption that will be used in the Sitecore Identity login page for this subprovider.<ClaimsTranformations> are used to translate claims from the subprovider to Sitecore Identity claims.

ConfigureSitecore class adds the subprovider in the services collection with appropriate option. In our case the code adds Authority as IdentityServer demo provider and also indicates that it is an external Identity Server to be used for sign in.

Copy the code as shown the following directory structure under the Sitecore Identity root folder.

sitecoreruntime
│ license.xml

└───production
│ Sitecore.Plugin.IdentityProvider.Ids4Demo.dll
│ Sitecore.Plugin.IdentityProvider.Ids4Demo.xml

└───sitecore
└───Sitecore.Plugin.IdentityProvider.Ids4Demo
│ Sitecore.Plugin.manifest

└───Config
Sitecore.Plugin.IdentityProvider.Ids4Demo.xml

Launch Sitecore shell site. As you are redirected to Sitecore Identity site you should see new login button in the site for the new subprovider as shown in the below picture.

Click on the new subprovider button, it should take you to IdentityServer demo provider for authentication. Enter username bob and password bob, you will be signed and redirected to Sitecore Identity provider. It works like below.


Unfortunately, at this point, when website is redirected to Sitecore Identity, it is throwing a server error. The log shows the following error, ‘ The payload was invalid’.

System.Security.Cryptography.CryptographicException: The payload was invalid.
   at Microsoft.AspNetCore.DataProtection.Cng.CbcAuthenticatedEncryptor.DecryptImpl(Byte* pbCiphertext, UInt32 cbCiphertext, Byte* pbAdditionalAuthenticatedData, UInt32 cbAdditionalAuthenticatedData)
   at Microsoft.AspNetCore.DataProtection.Cng.Internal.CngAuthenticatedEncryptorBase.Decrypt(ArraySegment`1 ciphertext, ArraySegment`1 additionalAuthenticatedData)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData)
   at Microsoft.AspNetCore.DataProtection.DataProtectionCommonExtensions.Unprotect(IDataProtector protector, String protectedData)
   at IdentityServer4.Infrastructure.DistributedCacheStateDataFormatter.Unprotect(String protectedText, String purpose)
   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.ReadPropertiesAndClearState(OpenIdConnectMessage message)
   at Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler.HandleRemoteAuthenticateAsync()

I couldn’t get to the bottom of this problem. I checked the id_token and payload looks valid. So, I opened a support ticket with Sitecore. I have to wait until Sitecore provides me an explanation of why the error is happening for other Identity Providers, but not for Azure Ad. Same problem is happening with Okta too.

I decided to publish this blog before the issue is solved because, I don’t see any problem with the approach. As soon as I get a resolution, I will update the blog. Finger crossed.

References

Update

Sitecore answered the question about the issue I mentioned above and it resolved the issue. In the ConfigureSitecore class ConfigureServices method CallbackPath was missing. After I added options.CallbackPath = “/signin-idsrv”; my custom identity provider started working without any problem. I updated the code in Github also.

Advertisements

About Himadri Chakrabarti

I am a solutions architect and a Sitecore MVP. I am focused on Sitecore and Ecommerce development. Opinions expressed in my blogs are my own.
This entry was posted in Security, Sitecore, sitecore Identity and tagged , , , , , , . Bookmark the permalink.

17 Responses to Sitecore Identity Part 3: Connecting to External Identity Provider

  1. Manikantha says:

    Hi Himadri,
    It is really nice to see the steps on how to setup using identity provider, for which documents are heavily missing. Can you please let me know whether you are able to resolve the last issue which you faced?

    Regards,
    Manik

    • I updated the blog post.

      • Manik says:

        I took the latest git code , copied the files as you have suggested in the respective folder. Post that sitecore identity server stopped loading.

      • Manik says:

        I took your latest code and deployed it as suggested in the respective folders. Post the changes i am not able to load the identity server.

      • Please provide more information. What are you trying to achieve? Is you Sitecore application working with Identity Server?

      • Manik says:

        Yes my identity provider is working with Azure Ad configuration as you have suggested , But i am not able to connect external identity provider using Sitecore.Plugin.IdentityProvider.Ids4Demo.
        Done these steps – post downloading your sample code
        sitecoreruntime
        │ license.xml

        └───production
        │ Sitecore.Plugin.IdentityProvider.Ids4Demo.dll (Restored the packages and copied the same)
        │ Sitecore.Plugin.IdentityProvider.Ids4Demo.xml

        └───sitecore
        └───Sitecore.Plugin.IdentityProvider.Ids4Demo
        │ Sitecore.Plugin.manifest (Created this file similar to azureAD)

        2.0.0-r00157

        Sitecore


        └───Config
        Sitecore.Plugin.IdentityProvider.Ids4Demo.xml (Copied the xml from the downloaded code).

        Post all these steps : I am getting the following error – HTTP Error 502.5 – Process Failure

      • At what point you are getting 502 error? Sitecore.Plugin.IdentityProvider.Ids4Demo.xml in the production folder is not needed. What’s your .Net Core version? Try this in command prompt dotnet –version

      • Also, please take a look at the log file in identityserver logs folder. Something should be logged when that error occurs.

  2. Divya says:

    Hello Himadri, deployed your code and config files. when accessing sitecore shell it redirects to identity server and the external login button is available now below Login button. Clicked on it and provided the user as bob (pwd bob) and then it tries to redirect to shell but fails with error as An unexpected error occurred. Stuck with this error for more than 3 weeks and frustrated with it. Can you please help here. I can share the logs too and there is no information about that error.

    • Divya,
      Please check the last section of the post. I recently updated the article. You will find the fix there. The code in Github is also updated. You can update the code from there too if you have cloned the repo. Thanks.

      • Divya says:

        Yes Himadri, I have downloaded the lastest code from the GitHub. As I was receiving 500 error : An unexpected error, I installed new instance of Sitecore on my local and on that instance am not receiving this unexpected error but receiving “Access denied” on the shell. Not sure if am doing the right claim transformation or any more config changes is needed on the sitecore side.

        Here is portion of my config file on the Identity server.

        External Demo
        true
        implicit
        https://demo.identityserver.io/.well-known/openid-configuration

        Below is the ValidatedAuthorizeRequest section from the Identity server log file

        ValidatedAuthorizeRequest
        “{
        \”ClientId\”: \”Sitecore\”,
        \”ClientName\”: \”Sitecore\”,
        \”RedirectUri\”: \”http://dvsitecore.sc/identity/signin\”,
        \”AllowedRedirectUris\”: [
        \”{AllowedCorsOrigin}/identity/signin\”,
        \”{AllowedCorsOrigin}/signin-oidc\”
        ],
        \”SubjectId\”: \”1\”,
        \”ResponseType\”: \”code id_token token\”,
        \”ResponseMode\”: \”form_post\”,
        \”GrantType\”: \”hybrid\”,
        \”RequestedScopes\”: \”openid sitecore.profile\”,
        \”State\”: \”OpenIdConnect.AuthenticationProperties=W2yAL1kE3kUnEhXEdHOHwFIXQp8lTUaW75YxYix6Mzpeedq53v01hhQ1dxx4BMvPS_CAzSVMNPDOIZ-G6sKiZaUJ6dcBaUoMjnsndTzTdeAsiQks_ehPi8ykJsUuib4n0qU7DVU9tRQe4Rl-8fVPebMDnTjTrCDHgGenWfhToBp82p_r7GN5JEZenS6Ok4n7AH_-CDhgYbNDaQiYOzzq9A\”,
        \”Nonce\”: \”636947870910904551.YjA1ZjkyZmYtZmM0Ni00OThjLWIyY2MtYmRkYmMxYmM3YTlmZWVlMTIxMGUtY2Y3OS00Njk1LTg5MTAtYTI0YTQyZTg3YmVl\”,
        \”PromptMode\”: \”login\”,
        \”SessionId\”: \”a8cbe6b23e9f86fe3d302d21228d0e1f\”,
        \”Raw\”: {
        \”client_id\”: \”Sitecore\”,
        \”response_mode\”: \”form_post\”,
        \”response_type\”: \”code id_token token\”,
        \”scope\”: \”openid sitecore.profile\”,
        \”state\”: \”OpenIdConnect.AuthenticationProperties=W2yAL1kE3kUnEhXEdHOHwFIXQp8lTUaW75YxYix6Mzpeedq53v01hhQ1dxx4BMvPS_CAzSVMNPDOIZ-G6sKiZaUJ6dcBaUoMjnsndTzTdeAsiQks_ehPi8ykJsUuib4n0qU7DVU9tRQe4Rl-8fVPebMDnTjTrCDHgGenWfhToBp82p_r7GN5JEZenS6Ok4n7AH_-CDhgYbNDaQiYOzzq9A\”,
        \”nonce\”: \”636947870910904551.YjA1ZjkyZmYtZmM0Ni00OThjLWIyY2MtYmRkYmMxYmM3YTlmZWVlMTIxMGUtY2Y3OS00Njk1LTg5MTAtYTI0YTQyZTg3YmVl\”,
        \”redirect_uri\”: \”http://dvsitecore.sc/identity/signin\”,
        \”sc_account_prefix\”: \”sitecore\\\”,
        \”prompt\”: \”login\”,
        \”sc_message\”: \”You do not have access to the system. If you think this is wrong, please contact the system administrator.\”,
        \”x-client-SKU\”: \”ID_NET451\”,
        \”x-client-ver\”: \”5.2.2.0\”
        }
        }”
        2019-05-29T23:24:51.1681361-05:00 [INF] (Sitecore STS/WMDW7750843) Showing login: request contains prompt=null

      • Divya,
        “Access Denied” error is happening because you don’t have proper claim transformation. Please read the “Configuring Azure Ad Subprovider” section and check the stackexchange question I posted. Azure AD provides a way to transform user to Sitecore Admin user via group id. So, it takes you to the Sitecore Launchpad. There is no such thing for demo.identityserver.io and I didn’t find a way to transform the user to admin user.

      • Divya says:

        Himadri Thank you for quick reply and yes , i have reading your blog everyday.

    • Manik says:

      Hi Divya,

      In the logs are you seeing some error related to username from handleloginlink pipeline?

      Regards,
      Manik

      • Divya says:

        Manik,
        It is not related to it.
        I dont see any error information in the Logs. In the log file I see Untransformed claims: [ ..] Issued claims:[…] …………… ValidatedAuthorizeRequest {…} ……Request finished……. then no other information is logged on the identity server or sitecore side.

  3. Manik says:

    Hi Himadri,
    I have tried your deployment structure , but for me the external login but is not available.

    Deployed structure :
    In sitecore runtime folder i have created production folder and copied the Sitecore.Plugin.IdentityProvider.Ids4Demo.dll and created a config folder and copied Sitecore.Plugin.IdentityProvider.Ids4Demo.xml
    In the sitecore folder which is at root host level copied config folder and manifest file.

    Did i missed anything in setting up the structure? Can you please give me a look over of how it should look like.

    Thanks,
    Manik

    • Manik says:

      Error: Unsuccessful login with external provider. I am able to get that external identity provider running but it is giving an error when i use demoidentity server – Authenticated from identity server but i am getting following error.
      ERROR Unable to get and an external login info via Microsoft.Owin.Security.AuthenticationManagerExtensions.GetExternalLoginInfoAsync. Most probably the identity does not have a ‘http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier’ claim.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.