Sitecore 9 联合身份验证与 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饼干。 Sitecore 没有看到经过身份验证的用户,而是重定向到 IDP,这种情况一直持续到我停止该过程为止。

My 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);
},
},
});
}
}
}

还有我的配置文件:

<?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>

请注意,我完成此操作的唯一方法是在验证时创建一个虚拟用户。 鉴于几乎完全缺乏有关此主题的文档,我不确定这是否是必需的步骤,或者我设置它的方式是否有问题。

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

感谢您的任何输入。

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

  1. IdentityProvidersProcessor的实现必须包含一个中间件,用于配置对外部提供程序的身份验证,例如UseOpenIdConnectAuthenticationUseAuth0AuthenticationUseFacebookAuthentication.它不得配置 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>
    

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

    行动:

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

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

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

    SecurityTokenValidated = notification =>
    {
    notification.AuthenticationTicket.Identity
    .ApplyClaimsTransformations(new TransformationContext(this.FederatedAuthenticationConfiguration, identityProvider));
    return Task.CompletedTask;
    }
    
  4. 另一个"不是问题,但是..":非 RTM Sitecore 9.0 版本就是这种情况,但现在您无需为每个身份提供商手动指定setIdpClaim转换。在"联合身份验证/共享转换">节点中指定的所有转换都会自动为所有身份提供程序执行。

    操作:删除额外的转换

    <!--SetIdpClaim transformation-->
    <transformation name="set idp claim" ref="federatedAuthentication/sharedTransformations/setIdpClaim" />
    
  5. 确保在RedirectUri属性中具有适当的值。它必须显示在相应 IdentityServer3.Core.Models.Client 对象的RedirectUris属性中。


完成所有操作后,外部用户将进行身份验证,但尚未分配任何角色。当满足以下任一条件时,用户已分配角色:

  1. 用户存在于数据库中,并且它已在其中分配了角色。
  2. 用户的 ClaimIdentity 对象具有"http://schemas.microsoft.com/ws/2008/06/identity/claims/role"类型的声明。

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

示例:假设你要将 Sitecore\开发人员角色分配给对象 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="sitecoreDeveloper " />
</targets>
</transformation>

重要说明:默认情况下,AzureAD 不会发回组声明。需要将groupMembershipClaims的值设置为应用清单中的SecurityGroup


现在,您的用户具有角色,但其配置文件未填充。 与声明转换不同,属性映射配置在所有标识提供者之间共享。 这背后的一般思想是为不同的标识提供者应用个性化声明转换,并接收具有预期看到的声明类型的"规范化"ClaimIdentity。

例如,第一个提供者给你"第二个名字"声明,第二个提供者给你"姓氏",第三个提供者给你"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"。然后,为相应的提供程序编写两个声明转换,将"第二个名字"映射到"姓氏",将"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"映射到"姓氏":

在 FIST 提供程序配置节点中:

<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>

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

<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>

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

<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>

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

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

最新更新