如何将来自IdentityServer 3的声明存储在Azure AD B2C中或仅将其包括在AAD B2C发行的令牌中 [英] How to store claims from IdentityServer 3 in Azure AD B2C or just include it in tokens issued by AAD B2C

查看:85
本文介绍了如何将来自IdentityServer 3的声明存储在Azure AD B2C中或仅将其包括在AAD B2C发行的令牌中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道是否可以将oid声明或Identity Server 3发出的基本上任何其他声明传播到AAD B2C,并使其成为Azure AD B2C发行的令牌的一部分?我们需要在客户端具有原始ID,而从子索偿和oid索偿中获得的所有内容就是AAD B2C用户帐户的ID.我也想对角色声明做同样的事情.任何帮助将不胜感激.

I'm wondering if it is possible to propagate an oid claim or basically any other claim issued by Identity Server 3 to the AAD B2C and make it be a part of the token issued by Azure AD B2C? We need to have an original ID on the client side and all we can get from sub and oid claims is an ID of an AAD B2C user account. I would also like to do the same with roles claim. Any help would be much appreciated.

这是我的Identity Server配置的TechnicalProfile在自定义策略(TrustFrameworkExtensions.xml)中的样子:

Here is how TechnicalProfile of my Identity Server configuration look like in Custom Policy (TrustFrameworkExtensions.xml):

<TechnicalProfile Id="IdentityServerProfile">
    <DisplayName>IdentityServer</DisplayName>
    <Description>Login with your IdentityServer account</Description>
    <Protocol Name="OpenIdConnect"/>
    <OutputTokenFormat>JWT</OutputTokenFormat>
    <Metadata>
        <Item Key="METADATA">https://{identity_server_hostname}/identity/.well-known/openid-configuration</Item>
        <Item Key="ProviderName">https://{identity_server_hostname}/identity</Item>
        <Item Key="client_id">00000000-0000-0000-0000-000000000000</Item>
        <Item Key="IdTokenAudience">00000000-0000-0000-0000-000000000000</Item>
        <Item Key="response_types">code</Item>
        <Item Key="scope">openid profile customScope</Item>
        <Item Key="UsePolicyInRedirectUri">false</Item>
        <Item Key="AccessTokenResponseFormat">json</Item>
        <Item Key="HttpBinding">POST</Item>
    </Metadata>
    <CryptographicKeys>
        <Key Id="client_secret" StorageReferenceId="B2C_1A_IdentityServerAppSecret"/>
    </CryptographicKeys>
    <OutputClaims>      
        <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="IdentityServer" />
        <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
        <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="tid" />
        <OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="sub" />
    </OutputClaims>
    <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
        <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
        <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
    </OutputClaimsTransformations>
    <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop"/>
</TechnicalProfile>

这是来自Application Instights的原始日志,具有相关的ID:

And here is the original log from Application Instights from the log with given correlationId:

{  

"TenantId":"{tenant} .onmicrosoft.com", "PolicyId":"B2C_1A_signup_signin_capcom", "RedirectUri":" http://localhost:3000/", "AdditionalParameters":{
"client_info":"1", "x-client-SKU":"MSAL.JS", "x-client-Ver":"0.1.5", 客户端请求ID":"a0ef9d95-ba21-4796-ad65-bc9e2b8c5e89" }, "Nonce":"bf198ee6-e084-433d-885c-2bd8f0292b3d", 状态":"7f732141-498e-4445-9efe-9b0d54178ef6", "ClientId":"012c0f85-4568-483f-9bca-054d6201ac00", "ResponseType":"id_token", "ResponseMode":片段", "ResponseRedirector":{
"URI":" http://localhost:3000/", "D":否, "WF":是的, "R":否, "S":假 }, "AppModelVersion":1, "ScopedProviders":[

"TenantId":"{tenant}.onmicrosoft.com", "PolicyId":"B2C_1A_signup_signin_capcom", "RedirectUri":"http://localhost:3000/", "AdditionalParameters":{
"client_info":"1", "x-client-SKU":"MSAL.JS", "x-client-Ver":"0.1.5", "client-request-id":"a0ef9d95-ba21-4796-ad65-bc9e2b8c5e89" }, "Nonce":"bf198ee6-e084-433d-885c-2bd8f0292b3d", "State":"7f732141-498e-4445-9efe-9b0d54178ef6", "ClientId":"012c0f85-4568-483f-9bca-054d6201ac00", "ResponseType":"id_token", "ResponseMode":"fragment", "ResponseRedirector":{
"URI":"http://localhost:3000/", "D":false, "WF":true, "R":false, "S":false }, "AppModelVersion":1, "ScopedProviders":[

] }

我注意到的东西,我发现奇怪的是ResponseType值.在我们的TechnicalProfile中,设置为代码,此处的值为id_token.

Something I've noticed and which I found strange is ResponseType value. In our TechnicalProfile is set to code and here its value is id_token.

对socialIdpUserId的声明最终通过了.问题的根源下面也有一个答案.现在,我仍然对firstname,lastName和displayName有问题.我遵循与socialIdpUserId相同的模式,但是唯一可以看到的是默认值. 这是我为他们配置的:

Claim for socialIdpUserId finally passes through. There is also an answer below what the problem was. Now, I still have a problem with having firstName, lastName and displayName. I've followed the same pattern as I did for socialIdpUserId but the only thing I can see are the default values. Here are my configurations for them:

1)声明类型定义:

<ClaimType Id="displayName">
    <DisplayName>Display Name</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="unique_name" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="displayName" />
      <Protocol Name="SAML2" PartnerClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" />
    </DefaultPartnerClaimTypes>
    <UserHelpText>Your display name.</UserHelpText>
    <UserInputType>TextBox</UserInputType>
 </ClaimType>
...
<ClaimType Id="givenName">
    <DisplayName>Given Name</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="given_name" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="given_name" />
      <Protocol Name="SAML2" PartnerClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" />
    </DefaultPartnerClaimTypes>
    <UserHelpText>Your given name (also known as first name).</UserHelpText>
    <UserInputType>TextBox</UserInputType>
 </ClaimType>
<ClaimType Id="surname">
    <DisplayName>Surname</DisplayName>
    <DataType>string</DataType>
    <DefaultPartnerClaimTypes>
      <Protocol Name="OAuth2" PartnerClaimType="family_name" />
      <Protocol Name="OpenIdConnect" PartnerClaimType="family_name" />
      <Protocol Name="SAML2" PartnerClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" />
    </DefaultPartnerClaimTypes>
    <UserHelpText>Your surname (also known as family name or last name).</UserHelpText>
    <UserInputType>TextBox</UserInputType>
 </ClaimType>

并在我的IdP的技术资料中输出声明:

And output claims in the technical profile for my IdP:

<TechnicalProfiles>
    <TechnicalProfile Id="CapcomProfile">
...
   <OutputClaims>
    <OutputClaim ClaimTypeReferenceId="displayName" />
    <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="firstName" DefaultValue="No" />
    <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="lastName" DefaultValue="Name" />
...

最后,RP输出定义:

<OutputClaims>
  <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="displayName" />
  <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="givenName"  />
  <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="surname" DefaultValue="Not found in IdP" />
...

有什么建议吗?

推荐答案

最后,我完成了这项工作,现在我的大部分主张都已通过.问题很可能是由于我的关键策略B2C_1A_CapcomIdentityServerAppSecret中缺少来自Azure AD应用程序的适当的客户端机密引起的.因此,请仔细检查一下是否已从AAD应用程序密钥复制了适当的密钥到策略密钥.

In the end, I made this work and now most of my claims are passing through. Most likely, the problem was caused by lack of appropriate Client Secret from Azure AD application in my Key Policies, B2C_1A_CapcomIdentityServerAppSecret to be more specific. So, double check it if you have copied over the appropriate one from AAD Application keys to you Policy Keys.

不幸的是,这只是解决方案的一部分,因为它无法完全正常工作,而且我也没有在客户端上收到令牌.但是好消息是,在我正确配置了这些键之后,我开始在Application Insights中收到非常有用的异常(您可以在此处看到如何将自定义策略与Application Insights连接起来:

Unfortunately, that was just part of the solution as it stll didn't work completely and I didn't recieve token back on the client. But the good thing was, after I had this keys configured well, I started receiving very useful exceptions in Application Insights (you can see here how to connect you Custom Policies with Application Insights: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-troubleshoot-custom). I highly recommend anyone who has any problem with custom policies to set it up. Also, if you use IdentityServer3 like I do, try with temporary turning on http logging on its side. Here is the example:

LoggingOptions = new LoggingOptions
                {
                    EnableHttpLogging = true
                }

当我在Application Insights中分析跟踪时,发生了大多数异常,因为我错过了一些属性,例如socialIdpUserId,该属性后来在OutputClaimsTransformations中使用.如果将自定义策略上载到Azure并立即收到有关错误的一些详细消息时立即进行检查,则更好.

While I was analyzing traces in Application Insights, most of the exceptions happened because I missed some of the attributes, for example socialIdpUserId, which is later used in OutputClaimsTransformations. It would be better if this was checked immediately when uploading custom policies to the Azure together with receiving some detailed message about an error.

修复此问题后,我终于开始在客户端接收经过IdP身份验证的用户的userId.现在剩下的唯一内容是来自配置文件范围的数据,例如displayName,giveName和Surname,但我希望我也能尽快找到解决方案.您可以在下找到问题描述,作为原始问题的一部分.

After I have this fixed, I finally started receiving userId of my IdP authenticated user on the client side. The only thing now that has left is data from profile scope such as displayName, givenName and surname but I hope I'll find the solution very soon for that as well. You can find problem description under as a part of the original question.

[更新-解决方案]

[UPDATE - SOLUTION]

昨天,在花了很多时间尝试许多不同的事情之后,我终于意识到为什么我们没有把所有索赔都归还给客户.它们实际上不存在于 identity 令牌中,而仅存在于 access 令牌中. AAD B2C 使用第一个 identity token (身份令牌),同时进行自定义策略中定义的映射,这就是重点.最后,我不得不在IdentityServer3方面进行一些小的更改(请看下面的代码).

Yesterday, after quiet a long time spent on trying so many different things, I finally realized why we were not getting all claims back on the client. They actually didn't exist in identity token but only in access token. AAD B2C uses the first one, the identity token, while doing mappings defined in custom policies and that was the whole point. In the end I had to make some small changes on IdentityServer3 side (take a look at the code below).

这就是负责发出声明并生成身份和访问令牌的类现在的样子:

This is how the class which is responsible for issuing claims and generating both identity and access tokens now looks like:

 public class CustomClaimsProvider : DefaultClaimsProvider
{
    private readonly IIndex<string, IClaimsDefinition> claimDefinitions;

    public CustomClaimsProvider(
        IUserService users,
        IIndex<string, IClaimsDefinition> claimDefinitions)
        : base(users)
    {
        this.claimDefinitions = claimDefinitions;
    }

    public override async Task<IEnumerable<Claim>> GetIdentityTokenClaimsAsync(
       ClaimsPrincipal subject,
       Client client,
       IEnumerable<Scope> scopes,
       bool includeAllIdentityClaims,
       ValidatedRequest request)
    {
        var claims = await base.GetIdentityTokenClaimsAsync(subject, client, scopes, includeAllIdentityClaims, request).ConfigureAwait(false);
        return GetAdditionalClaims(scopes, claims);
    }

    public override async Task<IEnumerable<Claim>> GetAccessTokenClaimsAsync(
        ClaimsPrincipal subject,
        Client client,
        IEnumerable<Scope> scopes,
        ValidatedRequest request)
    {
        var claims = await base.GetAccessTokenClaimsAsync(subject, client, scopes, request).ConfigureAwait(false);
        return GetAdditionalClaims(scopes,  claims);
    }

    private IEnumerable<Claim> GetAdditionalClaims(IEnumerable<Scope> scopes, IEnumerable<Claim> claims)
    {
        var scopesList = scopes.ToList();
        var claimsList = claims.ToList();

        foreach (var scope in scopesList.Select(x => x.Name))
        {
            if (claimDefinitions.TryGetValue(scope, out IClaimsDefinition claimDef))
            {
                claimsList.AddRange(claimDef.GetClaims(claims));
            }
        }

        return claimsList;
    }
}

因此,要点是,如果您希望将一些其他声明作为身份令牌的一部分,则还应该重写从DefaultClaimsProvider派生的类中的GetIdentityTokenClaimsAsync方法.

So, the main point is, you should also override GetIdentityTokenClaimsAsync method in the class derived from DefaultClaimsProvider if you want to have some additional claims as a part of your identity token.

这篇关于如何将来自IdentityServer 3的声明存储在Azure AD B2C中或仅将其包括在AAD B2C发行的令牌中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆