首页 > 解决方案 > Azure B2C - 提供的令牌不包含有效的颁发者

问题描述

我正在使用 Azure B2C 连接到外部 OpenID Connect 身份提供程序,我在 B2C 中创建了一个基本用户流,它可以工作但只带回少量声明,因此我需要创建一个自定义策略来将自定义输入参数传递给我的IDP 并收集额外的索赔。

我从 SocialAndLocalAccount 示例开始,并使用 IDP 的详细信息进行了修改:

TrustFrameworkBase.xml(缩减为技术配置文件 + 用户旅程)

      ...
      <ClaimType Id="sub">
        <DisplayName>Subject</DisplayName>
        <DataType>string</DataType>
        <DefaultPartnerClaimTypes>
          <Protocol Name="OpenIdConnect" PartnerClaimType="sub" />
        </DefaultPartnerClaimTypes>
        <UserHelpText />
      </ClaimType>
      <ClaimType Id="ui_locales">
        <DisplayName>UI Locales</DisplayName>
        <DataType>string</DataType>
        <UserHelpText>Special parameter passed for account authentication to Tell Us Once.</UserHelpText>
      </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>
      <ClaimType Id="DateOfBirth">
        <DisplayName>Date Of Birth</DisplayName>
        <DataType>string</DataType>
        <DefaultPartnerClaimTypes>
          <Protocol Name="OAuth2" PartnerClaimType="birthdate" />
          <Protocol Name="OpenIdConnect" PartnerClaimType="birthdate" />
          <Protocol Name="SAML2" PartnerClaimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/dateofbirth" />
        </DefaultPartnerClaimTypes>
        <UserHelpText>Your date of birth.</UserHelpText>
        <UserInputType>TextBox</UserInputType>
      </ClaimType>
      ...
    <ClaimsProvider>
      <Domain>tellusonce</Domain>
      <DisplayName>Tell Us Once</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="TUO-OpenIdConnect">
          <DisplayName>Tell Us Once Login</DisplayName>
          <Description>Login through Tell Us Once</Description>
          <Protocol Name="OpenIdConnect" />
          <Metadata>
            <Item Key="client_id">this is where i put my client id</Item>
            <Item Key="ProviderName">Tell Us Once</Item>
            <Item Key="METADATA">this is where my metadata is</Item>
            <Item Key="response_types">code</Item>
            <Item Key="response_mode">form_post</Item>
            <Item Key="scope">openid</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="UsePolicyInRedirectUri">false</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_TellUsOnceSecret" />
          </CryptographicKeys>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid profile" />
            <InputClaim ClaimTypeReferenceId="prompt" DefaultValue="login" />
            <InputClaim ClaimTypeReferenceId="ui_locales" DefaultValue="en-US" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="sub" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="middleName" DefaultValue="" />
            <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
            <OutputClaim ClaimTypeReferenceId="DateOfBirth" PartnerClaimType="birthdate" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="ITP-B2C" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="ITP-Auth-DEV-OIDC" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
          </OutputClaimsTransformations>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
    ...
  <UserJourneys>
    <UserJourney Id="SignUpOrSignInOidc">
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
          <ClaimsProviderSelections>
            <ClaimsProviderSelection TargetClaimsExchangeId="TUO-OIDCExchange" />
          </ClaimsProviderSelections>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="TUO-OIDCExchange" TechnicalProfileReferenceId="TUO-OpenIdConnect" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- For social IDP authentication, attempt to find the user account in the directory. -->
        <OrchestrationStep Order="3" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- Create the user in the directory if one does not already exist. -->
        <OrchestrationStep Order="4" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
  </UserJourneys>

TrustFrameworkExtensions.xml

<TrustFrameworkPolicy 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" 
  PolicySchemaVersion="0.3.0.0" 
  TenantId="itpauthdev.onmicrosoft.com" 
  PolicyId="B2C_1A_TrustFrameworkExtensions" 
  PublicPolicyUri="http://itpauthdev.onmicrosoft.com/B2C_1A_TrustFrameworkExtensions" 
  TenantObjectId="ae2201eb-e4e9-44e7-8c73-b52e37ba01f8">
  <BasePolicy>
    <TenantId>itpauthdev.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
  </BasePolicy>
  <BuildingBlocks></BuildingBlocks>
  <ClaimsProviders>
    <ClaimsProvider>
      <Domain>tellusonce</Domain>
      <DisplayName>Tell Us Once</DisplayName>
      <TechnicalProfiles>
        <TechnicalProfile Id="TUO-OpenIdConnect">
          <DisplayName>Tell Us Once Login</DisplayName>
          <Description>Login through Tell Us Once</Description>
          <Protocol Name="OpenIdConnect" />
          <Metadata>
            <Item Key="client_id">this is where i put my client id</Item>
            <Item Key="ProviderName">Tell Us Once</Item>
            <Item Key="METADATA">this is where my metadata is</Item>
            <Item Key="response_types">code</Item>
            <Item Key="response_mode">form_post</Item>
            <Item Key="scope">openid</Item>
            <Item Key="HttpBinding">POST</Item>
            <Item Key="UsePolicyInRedirectUri">false</Item>
          </Metadata>
          <CryptographicKeys>
            <Key Id="client_secret" StorageReferenceId="B2C_1A_TellUsOnceSecret" />
          </CryptographicKeys>
          <InputClaims>
            <InputClaim ClaimTypeReferenceId="acr_values" DefaultValue="urn:id.gov.au:tdif:acr:ip1:cl1" />
            <InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid profile" />
            <InputClaim ClaimTypeReferenceId="prompt" DefaultValue="login" />
            <InputClaim ClaimTypeReferenceId="ui_locales" DefaultValue="en-US" />
          </InputClaims>
          <OutputClaims>
            <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="sub" />
            <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
            <OutputClaim ClaimTypeReferenceId="middleName" DefaultValue="" />
            <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="family_name" />
            <OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
            <OutputClaim ClaimTypeReferenceId="DateOfBirth" PartnerClaimType="birthdate" />
            <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="ITP-B2C" />
            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="ITP-Auth-DEV-OIDC" />
          </OutputClaims>
          <OutputClaimsTransformations>
            <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
            <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
            <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
            <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
          </OutputClaimsTransformations>
        </TechnicalProfile>
      </TechnicalProfiles>
    </ClaimsProvider>
  </ClaimsProviders>
  <UserJourneys>
    <UserJourney Id="SignUpOrSignInOidc">
      <OrchestrationSteps>
        <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
          <ClaimsProviderSelections>
            <ClaimsProviderSelection TargetClaimsExchangeId="TUO-OIDCExchange" />
          </ClaimsProviderSelections>
        </OrchestrationStep>
        <OrchestrationStep Order="2" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="TUO-OIDCExchange" TechnicalProfileReferenceId="TUO-OpenIdConnect" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- For social IDP authentication, attempt to find the user account in the directory. -->
        <OrchestrationStep Order="3" Type="ClaimsExchange">
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <!-- Create the user in the directory if one does not already exist. -->
        <OrchestrationStep Order="4" Type="ClaimsExchange">
          <Preconditions>
            <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
              <Value>objectId</Value>
              <Action>SkipThisOrchestrationStep</Action>
            </Precondition>
          </Preconditions>
          <ClaimsExchanges>
            <ClaimsExchange Id="AADUserWrite" TechnicalProfileReferenceId="AAD-UserWriteUsingAlternativeSecurityId" />
          </ClaimsExchanges>
        </OrchestrationStep>
        <OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
      </OrchestrationSteps>
      <ClientDefinition ReferenceId="DefaultWeb" />
    </UserJourney>
  </UserJourneys>
</TrustFrameworkPolicy>

signin_signup_oidc.xml

<TrustFrameworkPolicy 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
  xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06" 
  PolicySchemaVersion="0.3.0.0" 
  TenantId="itpauthdev.onmicrosoft.com" 
  PolicyId="B2C_1A_signup_signin_oidc" 
  PublicPolicyUri="http://itpauthdev.onmicrosoft.com/B2C_1A_signup_signin" 
  TenantObjectId="ae2201eb-e4e9-44e7-8c73-b52e37ba01f8">
  <BasePolicy>
    <TenantId>itpauthdev.onmicrosoft.com</TenantId>
    <PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
  </BasePolicy>
  <RelyingParty>
    <DefaultUserJourney ReferenceId="SignUpOrSignInOidc" />
    <UserJourneyBehaviors></UserJourneyBehaviors>
    <TechnicalProfile Id="PolicyProfile">
      <DisplayName>PolicyProfile</DisplayName>
      <Protocol Name="OpenIdConnect" />
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="givenName" />
        <OutputClaim ClaimTypeReferenceId="middleName" DefaultValue="" />
        <OutputClaim ClaimTypeReferenceId="surname" />
        <OutputClaim ClaimTypeReferenceId="email" />
        <OutputClaim ClaimTypeReferenceId="DateOfBirth" DefaultValue="ClaimNotFound" />
        <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
        <OutputClaim ClaimTypeReferenceId="identityProvider" />
        <OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
      </OutputClaims>
      <SubjectNamingInfo ClaimType="sub" />
    </TechnicalProfile>
  </RelyingParty>
</TrustFrameworkPolicy>

当我单击“B2C_1A_signin_signup_oidc”并选择“运行用户流程”时,我会看到我的 IDP 的登录屏幕,一旦我成功登录,我就会从我的 IDP 获得授权码响应,我的 IDP 已按照“/authresp”重定向 uri 进行了配置Microsoft 文档(底部的“重定向 Uri”部分),但似乎“/authresp”没有将代码交换为 id_token,因为当它重定向到 jwt.ms 时,我得到“令牌不包含有效的颁发者” .

Fiddler 代码响应

通过使用提琴手的检查员,我可以看到 IDP 的端点正在响应一个看起来像这样的代码(不是实际代码):

<HTML>

<HEAD>
    <TITLE>OIDC Form_Post Response</TITLE>
</HEAD>

<BODY Onload="document.forms[0].submit()">
    <FORM METHOD="POST" ACTION="https://itpauthdev.b2clogin.com/itpauthdev.onmicrosoft.com/oauth2/authresp"> <INPUT
            TYPE="HIDDEN" NAME="code"
            VALUE="4cfed1f1-bfcc-42db-b39c-d79480f6d333.056c6e05-eaec-426a-a5e7-bf9f66f962be.15ac212d-38b7-4e9b-80e2-a948be9360e5" />
        <INPUT TYPE="HIDDEN" NAME="state"
            VALUE="StateProperties=eyJTSUQiOiJ4LW1zLWNwaW0tcmM6M2RkYmRhYjktY2VkZS00MDA4LTliNWYtOGRmZjU2ZDZmZDYzIiveWIlEIjoiMmFtkoc5YjUtMzg0Zi00M2JmLThkMDUtMjIzMGYxNzU1M2JjIiwiVE9CRJI6ImFlMjIwMWViLWU0ZTktNDRlNy04YzczLWI1MmUzN2JhMDFmOCJ9" />
        <INPUT TYPE="HIDDEN" NAME="session_state" VALUE="65e01676-90d1-4c5e-a7f4-66dfd7b3211b" /> <NOSCRIPT>
            <P>JavaScript is disabled. We strongly recommend to enable it. Click the button below to continue .</P>
            <INPUT name="continue" TYPE="SUBMIT" VALUE="CONTINUE" />
        </NOSCRIPT> </FORM>
</BODY>

</HTML>

Fiddler AuthResp 响应

再次使用 Fiddler,我可以看到 AuthResp 没有使用 IDP 的令牌端点交换 id_token 的代码(或遇到错误,我没有得到任何有用的信息)。相反,我回来了:

<html>

<head>
    <title>Object moved</title>
</head>

<body>
    <h2>Object moved to <a
            href="https://jwt.ms/#error=invalid_request&amp;error_description=AADB2C90238%3a+The+provided+token+does+not+contain+a+valid+issuer.+Please+provide+another+token+and+try+again.%0d%0aCorrelation+ID%3a+2ad979b5-384f-43bf-8d05-2230f17553bc%0d%0aTimestamp%3a+2021-02-26+04%3a29%3a08Z%0d%0a">here</a>.
    </h2>
</body>

</html>

问题

  1. 我在某处的文档中读到“OpenIDConnect”技术配置文件将自动交换 id 令牌的代码,但我似乎无法找到该文档,是我的配置缺少步骤还是我必须通过额外的 userjourney 手动执行此操作?
  2. 如果“/authresp”和令牌端点之间存在通信错误,我是否可以在某个地方获得更具描述性的错误消息?jwt.ms 和审计日志都只是说“令牌不包含有效的颁发者”。

JWT错误

标签: azure-ad-b2cazure-ad-b2c-custom-policyidentity-experience-framework

解决方案


该错误意味着来自 OIDC 提供程序的 id 令牌具有与众所周知的 OIDC 配置端点中的颁发者不匹配的颁发者 (iss) 声明。您可以将 issuer 元素添加到 TUO-OpenIdConnect 技术配置文件的元数据中,以使用令牌中显示的值覆盖它。

https://docs.microsoft.com/en-us/azure/active-directory-b2c/openid-connect-technical-profile#metadata

issuer :OpenID Connect 身份提供者的唯一标识符。颁发者元数据的值优先于 OpenID 知名配置端点中指定的颁发者。如果指定,Azure AD B2C 会检查身份提供者返回的令牌中的 iss 声明是否等于颁发者元数据中指定的声明。


推荐阅读