1

I have issue with configuration of OpenID Connect with Sitecore Federated Authentication. On the final step of login process in the call to /identity/externallogincallback the cookies are missing. I do not understand it is caused by my configuration or I missing something. The description is shown below.

Issue: Federated Authentication with OpenID Connect is not working. After typing credentials error showed below occurs:

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.

The final /identity/externallogincallback request does not contain any cookies required for authentication. Then the authentication returns failure.

Description It looks the login process is working correct to the final step. The method OnSecurityTokenValidated inside OpenIDIdentityProviderProcessor is invoked and run without errors. The claims are loaded correctly and the debuger says that user is authenticated.

enter image description here

From the debugging I see that the login process is correct, then the /identity/signin-openID POST is called (it is set as redirect URI). It is called without any cookies. Then the /identity/externalcallogincallback is set and there is also any cookies into that request. It causes that inside the Sitecore.Owin.Authentication.Pipelines.Initialize.HandleLoginLink.HandleExternalLoginCallbackUrl the code

await context.Authentication.GetExternalLoginInfoWithWhitespacesAsync().ConfigureAwait(false);

is returning null and then the error Error: Unsuccessful login with external provider. is shown on page.

Nuget Packages:

  • Sitecore.Owin 9.1.1
  • Sitecore.Owin.Authentication 9.1.0
  • Microsoft.Owin.Security.OpenIdConnect 4.0.0

The redirectURI is defined as:

  <!-- your Sitecore instance Url-->
  <setting name="OpenID.RedirectUri" role:require="Standalone or ContentManagement">
    <patch:attribute name="value">https://site.sc/signin-openID</patch:attribute>
  </setting>

The federated authentication config is shown below. The Identity server is disabled.

    <federatedAuthentication>
  <identityProviders hint="list:AddIdentityProvider">
    <!--<identityProvider id="SitecoreIdentityServer">
      <enabled>false</enabled>
    </identityProvider>-->
    <identityProvider id="openID" type="Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication">
      <param desc="name">$(id)</param>
      <param desc="domainManager" type="Sitecore.Abstractions.BaseDomainManager" resolve="true" />
      <caption>Open ID</caption>
      <domain>ActiveDirectory</domain>
      <icon>/sitecore/shell/themes/standard/Images/24x24/msazure.png</icon>
      <transformations hint="list:AddTransformation">

        <!-- IDP Transformation -->
        <transformation name="Idp Claim" type="Sitecore.Owin.Authentication.Services.SetIdpClaimTransform, Sitecore.Owin.Authentication" />

        <!-- Name Identifier Claim-->
        <transformation name ="Name identifier claim" type="Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication">
          <sources hint="raw:AddSource">
            <claim name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" />
          </sources>
          <targets hint="raw:AddTarget">
            <claim name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" />
          </targets>
          <keepSource>true</keepSource>
        </transformation>
      </transformations>
    </identityProvider>
  </identityProviders>

  <identityProvidersPerSites>
    <mapEntry name="openID" type="Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication">
      <sites hint="list">
        <site>shell</site>
        <site>login</site>
        <site>admin</site>
        <site>service</site>
        <site>modules_shell</site>
        <site>modules_website</site>
        <site>website</site>
        <site>scheduler</site>
        <site>system</site>
        <site>publisher</site>
        <site>website</site>
      </sites>

      <!-- Registered identity providers for above providers -->
      <identityProviders hint="list:AddIdentityProvider">
        <identityProvider ref="federatedAuthentication/identityProviders/identityProvider[@id='openID']" />
      </identityProviders>

      <!-- ExternalUserBuilder is what creates a user with customusername in Sitecore and assigns roles based on claim transformation configured above -->
      <externalUserBuilder type="Sitecore.Owin.Authentication.Services.DefaultExternalUserBuilder, Sitecore.Owin.Authentication">
        <param desc="isPersistentUser">true</param>
      </externalUserBuilder>
    </mapEntry>
  </identityProvidersPerSites>

  <!-- Property initializer assigns claim values to sitecore user properties -->
  <propertyInitializer type="Sitecore.Owin.Authentication.Services.PropertyInitializer, Sitecore.Owin.Authentication">
    <maps hint="list">

      <map name="map Roles" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
        <data hint="raw:AddData">
          <source name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role"/>
          <target name="Roles"/>
        </data>
      </map>

      <map name="set idp" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
        <data hint="raw:AddData">
          <source name="http://schemas.microsoft.com/identity/claims/objectidentifier"/>
          <target name="idp"/>
        </data>
      </map>

      <map name="set email" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
        <data hint="raw:AddData">
          <source name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"/>
          <target name="Email"/>
        </data>
      </map>

      <map name="set name" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
        <data hint="raw:AddData">
          <source name="name"/>
          <target name="Name"/>
        </data>
      </map>

      <map name="set FullName" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication">
        <data hint="raw:AddData">
          <source name="name"/>
          <target name="FullName"/>
        </data>
      </map>

    </maps>
  </propertyInitializer>     
</federatedAuthentication>

 public class OpenIDIdentityProviderProcessor : IdentityProvidersProcessor
{
    private readonly IActiveDirectoryCrudService _activeDirectoryService;

    public string AadInstance => Settings.GetSetting("OpenID.AADInstance");
    public string Tenant => Settings.GetSetting("OpenID.Tenant");
    public string ClientId => Settings.GetSetting("OpenID.ClientId");
    public string PostLogoutRedirectUri => Settings.GetSetting("OpenID.PostLogoutRedirectUri");
    public string RedirectUri => Settings.GetSetting("OpenID.RedirectUri");
    public string Authority => string.Format(CultureInfo.InvariantCulture, AadInstance, Tenant);

Identity provider code:

    public class OpenIDIdentityProviderProcessor : IdentityProvidersProcessor
{
    private readonly IActiveDirectoryCrudService _activeDirectoryService;

    public string AadInstance => Settings.GetSetting("OpenID.AADInstance");
    public string Tenant => Settings.GetSetting("OpenID.Tenant");
    public string ClientId => Settings.GetSetting("OpenID.ClientId");
    public string PostLogoutRedirectUri => Settings.GetSetting("OpenID.PostLogoutRedirectUri");
    public string RedirectUri => Settings.GetSetting("OpenID.RedirectUri");
    public string Authority => string.Format(CultureInfo.InvariantCulture, AadInstance, Tenant);

    public OpenIDIdentityProviderProcessor(
        FederatedAuthenticationConfiguration federatedAuthenticationConfiguration,
        ICookieManager cookieManager,
        BaseSettings settings,
        IActiveDirectoryCrudService activeDirectoryCrudService)
        : base(federatedAuthenticationConfiguration, cookieManager, settings)
    {
        _activeDirectoryService = activeDirectoryCrudService;
    }

    public static string OpenIdIdentityProviderName = "openID";
    protected override string IdentityProviderName => OpenIdIdentityProviderName;

    protected override void ProcessCore(IdentityProvidersArgs args)
    {
        Assert.ArgumentNotNull(args, nameof(args));

        IdentityProvider identityProvider = GetIdentityProvider();
        string authenticationType = GetAuthenticationType();

        var options = new OpenIdConnectAuthenticationOptions
        {
            Authority = Authority,
            AuthenticationType = authenticationType,
            AuthenticationMode = AuthenticationMode.Passive,
            Caption = identityProvider.Caption,
            ClientId = ClientId,
            CookieManager = CookieManager,
            RedirectUri = RedirectUri,
            PostLogoutRedirectUri = PostLogoutRedirectUri,
            ResponseType = "id_token",
            Scope = "openid", // email profile address phone groups offline_access
            UseTokenLifetime = true,
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = OnAuthenticationFailed,
                SecurityTokenValidated = OnSecurityTokenValidated
            }
        };

        args.App.CreatePerOwinContext(() => new LoggedInUserProfileService());
        args.App.UseOpenIdConnectAuthentication(options);
    }

    private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
    {
        Log.Error($"FederatedLogin: AuthenticationFailed {context.Exception.Message}", context.Exception, this);

        return Task.CompletedTask;
    }

    private Task OnSecurityTokenValidated(SecurityTokenValidatedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
    {
        var identityProvider = GetIdentityProvider();
        var identity = context.AuthenticationTicket.Identity;
        var claimsIdentity = new ClaimsIdentity(identity.Claims, GetAuthenticationType());

        // Run Transformations
        foreach (var claimsTransformations in identityProvider.Transformations)
        {
            claimsTransformations.Transform(claimsIdentity, new TransformationContext(FederatedAuthenticationConfiguration, identityProvider));
        }

        claimsIdentity.AddClaim(new Claim("id_token", context.ProtocolMessage.IdToken));
        claimsIdentity.AddClaim(new Claim(ActiveDirectoryClaimTypes.PrivateNameIdentifier, identity.Claims.FirstOrDefault(x => x.Type == ActiveDirectoryClaimTypes.NameIdentifier).Value));

        context.AuthenticationTicket = new AuthenticationTicket(claimsIdentity, context.AuthenticationTicket.Properties);

        return Task.CompletedTask;
    }
}
3
  • There are too many things in your question. Can you please ask what is the issue and error msg what you are facing ?
    – Abhay Dhar
    Mar 12, 2020 at 2:17
  • Hi @AbhayDhar. Thank you for your message. I've investigated the issue more and reword my post. I would appreciate if you look on it again :) Best regards
    – klucyszy
    Mar 12, 2020 at 20:25
  • I had implemented via Azure Adb2c - pl chk this for config and code example - sitecore.stackexchange.com/questions/22947/…
    – Abhay Dhar
    Mar 13, 2020 at 14:25

1 Answer 1

1

after talk with Sitecore supports, it appears that all configuration looks good. The one thing that differ from their and my implementations approach of OpenId noticiations. After using Support's approach the OpenId starts working.

Notifications = new OpenIdConnectAuthenticationNotifications
{
    AuthenticationFailed = notification =>
    {
        ...
        return Task.CompletedTask;
    },
    SecurityTokenValidated = notification =>
    {
        ...
        return Task.CompletedTask;
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.