Sitecore 9与IdentityServer3,无限循环的联合身份验证

Wil*_*per 7 sitecore identityserver3

我一直在努力使用IdentityServer 3作为IDP,使用Sitecore 9进行联合身份验证.我已经按照http://blog.baslijten.com/enable-federated-authentication-and-configure-auth0-as-an-identity-provider-in-sitecore-9-0/中的示例查看了Auth0,并且已将其转换为IDS3.但我所经历的是IDP和Sitecore之间的无限循环.

似乎在身份验证时,IdentityServer 3会重定向回Sitecore,而Sitecore无法将身份验证转换为Cookie.我留下了一个.nonce cookie.Sitecore没有看到经过身份验证的用户,会重定向到IDP,直到我停止进程.

我的IdentityProviderProcessor(带虚拟值):

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\\user@domain.com", 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 = "user@domain.com";
                        virtualUser.Profile.Name = "My User";

                        // Login the virtual user
                        Sitecore.Security.Authentication.AuthenticationManager.LoginVirtualUser(virtualUser);

                        return Task.FromResult(0);
                    },
                },
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我的配置文件:

<?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>
Run Code Online (Sandbox Code Playgroud)

请注意,我可以实现此目的的唯一方法是在验证时创建VirtualUser.由于几乎完全没有关于这个主题的文档,我不确定这是否是一个必要的步骤,或者如果我设置它的方式有问题.

目前,VirtualUser就像一个冠军,我们可能会保持这一点.但我想知道,在这里需要创建一个VirtualUser,还是我做错了什么?

感谢您的任何意见.

Vya*_*kin 8

我在整体配置中看到了几个问题,但最重要的是第一个问题(当然必须删除解决方法):

  1. 的实现IdentityProvidersProcessor必须包含只有一个中间件配置验证外部供应商,如UseOpenIdConnectAuthenticationUseAuth0Authentication或者UseFacebookAuthentication.它不能配置Cookie身份验证,因为它是为您在已经完成Sitecore.Owin.Authentication.config:

    <pipelines>
        ...
        <owin.initialize>
            ...
            <processor type="Sitecore.Owin.Authentication.Pipelines.Initialize.CookieAuthentication, Sitecore.Owin.Authentication"
                       resolve="true" patch:before="processor[@method='Authenticate']" />
            ...
        </owin.initialize>
    </pipelines>
    
    Run Code Online (Sandbox Code Playgroud)

    注意:如果您需要处理任何OWIN cookie身份验证事件,请使用相应的管道 owin.cookieAuthentication.*

    操作:

    1. 删除您的UseCookieAuthentication中间件.
    2. 使用 string authenticationType = this.GetAuthenticationType();设定SignInAsAuthenticationType的财产OpenIdConnectAuthenticationOptions对象(authenticationType变量是在代码中使用).
  2. 不是问题,但Sitecore.Owin.Authentication.Extensions命名空间中存在可以替换整个foreach语句的扩展方法:

    notification.AuthenticationTicket.Identity.ApplyClaimsTransformations(new TransformationContext(this.FederatedAuthenticationConfiguration, identityProvider));
    
    Run Code Online (Sandbox Code Playgroud)
  3. 您尝试手动构建虚拟用户并对其进行身份验证,但是当您修复第一个问题时,Sitecore会对其进行处理.

    操作:SecurityTokenValidated处理程序替换为:

    SecurityTokenValidated = notification =>
    {
        notification.AuthenticationTicket.Identity
          .ApplyClaimsTransformations(new TransformationContext(this.FederatedAuthenticationConfiguration, identityProvider));
        return Task.CompletedTask;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  4. 另一个"不是问题,但是......":非RTM Sitecore 9.0构建就是这种情况,但现在您不需要setIdpClaim为每个身份提供者手动指定转换.在federatedAuthentication/sharedTransformations节点中指定的所有转换都将自动为所有身份提供程序执行.

    行动:删除额外的转换

    <!--SetIdpClaim transformation-->
    <transformation name="set idp claim" ref="federatedAuthentication/sharedTransformations/setIdpClaim" />
    
    Run Code Online (Sandbox Code Playgroud)
  5. 确保您在RedirectUri酒店拥有适当的价值.它必须RedirectUris在相应的IdentityServer3.Core.Models.Client对象的属性中显示.


完成所有操作后,您的外部用户将进行身份验证,但尚未分配任何角色.当任何一个为真时,用户已分配角色:

  1. 用户存在于DB中,并在那里分配了角色.
  2. 用户的ClaimsIdentity对象具有" http://schemas.microsoft.com/ws/2008/06/identity/claims/role "类型的声明.

分配角色声明的最佳方法是使用声明转换.

示例:假设您要将sitecore\Developer角色分配给包含在对象ID为3e12be6e-58af-479a-a4dc-7a3d5ef61c71的组中的所有Azure AD用户.AzureAD身份提供程序的声明转换如下所示:

    <transformation name="developer role" type="Sitecore.Owin.Authentication.Services.DefaultTransformation,Sitecore.Owin.Authentication">
        <sources hint="raw:AddSource">
            <claim name="groups" value="3e12be6e-58af-479a-a4dc-7a3d5ef61c70" />
        </sources>
        <targets hint="raw:AddTarget">
            <claim name="http://schemas.microsoft.com/ws/2008/06/identity/claims/role" value="sitecore\Developer " />
         </targets>
    </transformation>
Run Code Online (Sandbox Code Playgroud)

重要说明: AzureAD默认情况下不会发回组声明.您需要设置的值groupMembershipClaimsSecurityGroup在应用程序清单.


现在您的用户有角色,但它的配置文件没有填写.与声明转换不同,属性映射配置在所有身份提供者之间共享.其背后的一般思想是为不同的身份提供者应用个性化的声明转换,并接收您希望看到的声明类型的"规范化"声明身份.

例如,第一个提供者为您提供"第二名"声明,第二个提供"姓氏",第三个提供" http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname ".然后你为相应的提供者写了两个声明转换,它们将"second name"映射到"surname"和" http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname "到"surname":

在第一个提供者配置节点中:

    <transformation name="surname" type="Sitecore.Owin.Authentication.Services.DefaultTransformation,Sitecore.Owin.Authentication">
        <sources hint="raw:AddSource">
            <claim name="second name" />
        </sources>
        <targets hint="raw:AddTarget">
            <claim name="surname" />
        </targets>
    </transformation>
Run Code Online (Sandbox Code Playgroud)

在第二个提供程序配置节点中:

    <transformation name="surname" type="Sitecore.Owin.Authentication.Services.DefaultTransformation,Sitecore.Owin.Authentication">
        <sources hint="raw:AddSource">
            <claim name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" />
        </sources>
        <targets hint="raw:AddTarget">
            <claim name="surname" />
        </targets>
    </transformation>
Run Code Online (Sandbox Code Playgroud)

从现在开始,您有一个规范化的ClaimsIdentity,您可以编写一个属性映射:

    <map name="surname" type="Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication" resolve="true">
      <data hint="raw:AddData">
        <source name="surname" />
        <target name="Surname" />
      </data>
    </map>
Run Code Online (Sandbox Code Playgroud)

可以使用读取用户配置文件数据user.Profile["Surname"].

注意:如果需要,可以轻松实现自定义声明转换和属性映射.