无法通过Azure AD B2C自定义策略将SAML IdP的Claims传递至SAML SP
问题描述
我正尝试通过Azure AD B2C自定义策略,将部分Claims从SAML IdP传递至SAML SP。目前可以正常登录,且能看到SAML IdP返回的相关属性,但无法将这些属性传递给SAML SP。我首先希望能传递groups Claims,同时希望避免调用MS Graph的REST接口来实现此功能,假设这些Claims已存在于Claims Bag中,希望找到简便的传递方法。
提供的自定义策略代码
登录策略(B2C_1A_SAML_TF_SP_SignIn)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <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="myb2.onmicrosoft.com" PolicyId="B2C_1A_SAML_TF_SP_SignIn" PublicPolicyUri="http://myb2.onmicrosoft.com/B2C_1A_SAML_TF_SP_SignIn" TenantObjectId="f8cba1c5-22e8-4ddc-98c3-3b6afc4d5350" DeploymentMode="Development" UserJourneyRecorderEndpoint="urn:journeyrecorder:applicationinsights"> <BasePolicy> <TenantId>myb2.onmicrosoft.com</TenantId> <PolicyId>B2C_1A_SAML_TFExtensions</PolicyId> </BasePolicy> <RelyingParty> <DefaultUserJourney ReferenceId="X-SignIn" /> <TechnicalProfile Id="PolicyProfile"> <DisplayName>PolicyProfile</DisplayName> <Protocol Name="SAML2"/> <OutputClaims> <OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="objectId"/> <OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="" /> <OutputClaim ClaimTypeReferenceId="displayName" /> <OutputClaim ClaimTypeReferenceId="givenName" /> <OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="last_name"/> <OutputClaim ClaimTypeReferenceId="ipaddr"/> <OutputClaim ClaimTypeReferenceId="groups" DefaultValue="" /> <OutputClaim ClaimTypeReferenceId="role" /> </OutputClaims> <SubjectNamingInfo ClaimType="objectId" ExcludeAsClaim="false"/> </TechnicalProfile> </RelyingParty> </TrustFrameworkPolicy>
用户旅程配置(X-SignIn)
<UserJourneys> <UserJourney Id="X-SignIn"> <OrchestrationSteps> <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.x-signin"> <ClaimsProviderSelections> <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" /> <ClaimsProviderSelection TargetClaimsExchangeId="X-SignIn" /> </ClaimsProviderSelections> <ClaimsExchanges> <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="2" Type="ClaimsExchange"> <Preconditions> <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> <Value>objectId</Value> <Action>SkipThisOrchestrationStep</Action> </Precondition> </Preconditions> <ClaimsExchanges> <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" /> <ClaimsExchange Id="X-SignIn" TechnicalProfileReferenceId="X-SAML2" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="3" Type="ClaimsExchange"> <Preconditions> <Precondition Type="ClaimEquals" ExecuteActionsIf="true"> <Value>authenticationSource</Value> <Value>localAccountAuthentication</Value> <Action>SkipThisOrchestrationStep</Action> </Precondition> </Preconditions> <ClaimsExchanges> <ClaimsExchange Id="AADUserReadUsingAlternativeSecurityId" TechnicalProfileReferenceId="AAD-UserReadUsingAlternativeSecurityId-NoError" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="4" Type="ClaimsExchange"> <Preconditions> <Precondition Type="ClaimsExist" ExecuteActionsIf="true"> <Value>objectId</Value> <Action>SkipThisOrchestrationStep</Action> </Precondition> </Preconditions> <ClaimsExchanges> <ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="5" Type="ClaimsExchange"> <Preconditions> <Precondition Type="ClaimEquals" ExecuteActionsIf="false"> <Value>authenticationSource</Value> <Value>socialIdpAuthentication</Value> <Action>SkipThisOrchestrationStep</Action> </Precondition> </Preconditions> <ClaimsExchanges> <ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" /> </ClaimsExchanges> </OrchestrationStep> <OrchestrationStep Order="6" 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="7" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="Saml2AssertionIssuer"/> </OrchestrationSteps> <ClientDefinition ReferenceId="DefaultWeb" /> </UserJourney> </UserJourneys>
SAML追踪器信息
- SAML IdP:已确认返回包含
groups在内的目标属性 - SAML断言发布者:当前输出的断言中未包含目标
groups属性
解决方案
要将SAML IdP返回的Claims传递到SAML SP,需完成以下配置调整:
1. 确保SAML IdP技术配置文件捕获目标Claims
在B2C_1A_SAML_TFExtensions策略的X-SAML2技术配置文件中,添加groups的输出声明,映射到IdP实际返回的属性名称:
<TechnicalProfile Id="X-SAML2"> <DisplayName>X SAML IdP</DisplayName> <Protocol Name="SAML2"/> <Metadata> <!-- 保留现有元数据配置 --> </Metadata> <OutputClaims> <!-- 保留其他已配置的Claims --> <OutputClaim ClaimTypeReferenceId="groups" PartnerClaimType="urn:oid:1.2.840.113556.1.4.221"/> <!-- 替换为IdP返回的groups属性名称 --> </OutputClaims> <!-- 保留其他配置 --> </TechnicalProfile>
提示:PartnerClaimType的值需与SAML IdP返回的属性名称完全匹配,可通过SAML追踪器确认。
2. 移除RelyingParty中groups的默认值
当前PolicyProfile中groups声明的DefaultValue=""会覆盖Claims Bag中的实际值,需删除该属性:
<OutputClaim ClaimTypeReferenceId="groups" /> <!-- 移除DefaultValue属性 -->
3. 确认groups的ClaimType定义正确
在扩展策略的BuildingBlocks节点中,确保groups的ClaimType数据类型与IdP返回的格式匹配(多组用stringCollection,单组用string):
<BuildingBlocks> <ClaimsSchema> <ClaimType Id="groups"> <DisplayName>Groups</DisplayName> <DataType>stringCollection</DataType> </ClaimType> <!-- 其他ClaimType定义 --> </ClaimsSchema> </BuildingBlocks>
4. 验证用户旅程中Claims的持续性
检查用户旅程X-SignIn的编排步骤,确保后续的AAD用户读取/写入步骤不会清除或覆盖groups Claim。例如,AAD-UserReadUsingAlternativeSecurityId-NoError等技术配置文件的<OutputClaims>中不要包含groups,避免覆盖从IdP获取的值。
验证
修改配置后重新上传策略,通过SAML追踪器检查最终发送给SP的断言,确认groups Claim已成功包含在其中。
内容的提问来源于stack exchange,提问作者rkcp613

