注意
在 Azure Active Directory B2C 中,自定义策略主要用于解决复杂的情况。 在大多数情况下,建议你使用内置用户流。 如果尚未这样做,请从 Active Directory B2C 中的自定义策略入门了解自定义策略新手包。
Azure AD B2C 使用 Azure Active Directory (Azure AD) 条件访问作为工具来汇集信号、做出决策,以及实施组织策略。 通过策略条件自动执行风险评估意味着,一旦识别风险登录便可立即修正或阻止。
注意
此功能目前以公共预览版提供。
协议
“Protocol”元素的“Name”属性必须设置为 Proprietary。 handler 属性必须包含 Azure AD B2C 使用的协议处理程序程序集的完全限定名称:
Web.TPEngine.Providers.ConditionalAccessProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
以下示例显示了一个条件访问技术配置文件:
<TechnicalProfile Id="ConditionalAccessEvaluation">
<DisplayName>Conditional Access Provider</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ConditionalAccessProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="OperationType">Evaluation</Item>
</Metadata>
条件访问评估
每次登录时,Azure AD B2C 都会评估所有策略,确保只有满足所有要求时才向该用户授予访问权限。 “阻止访问”优先于所有其他配置设置。 在使用本地帐户登录期间,条件访问技术配置文件的“评估”模式会评估 Azure AD B2C 收集的信号。 条件访问技术配置文件的结果是一组由条件访问评估生成的声明。 Azure AD B2C 策略在下一个业务流程步骤中使用这些声明来执行操作,例如阻止用户或使用多重身份验证对用户进行质询。 可以为该模式配置以下选项。
元数据
| Attribute | 必须 | 说明 |
|---|---|---|
| OperationType | 是 | 必须是 Evaluation。 |
输入声明
InputClaims 元素包含要发送到条件访问的声明的列表。 还可将声明名称映射到条件访问技术配置文件中定义的名称。
| ClaimReferenceId | 必须 | 数据类型 | 说明 |
|---|---|---|---|
| UserId | 是 | 字符串 | 登录的用户的标识符。 |
| AuthenticationMethodsUsed | 是 | stringCollection | 用户用于登录的方法列表。 可能的值:Password 和 OneTimePasscode。 |
| IsFederated | 是 | boolean | 指示用户是否使用了联合帐户登录。 值必须是 false。 |
| IsMfaRegistered | 是 | boolean | 指示用户是否已注册了用于多重身份验证的电话号码。 |
InputClaimsTransformations 元素可能包含一系列 InputClaimsTransformation 元素,这些元素用于修改输入声明,或者用于生成新的声明并将其发送到条件访问服务。
输出声明
OutputClaims 元素包含由 ConditionalAccessProtocolProvider 生成的声明列表。 还可将声明名称映射到下面定义的名称。
| ClaimReferenceId | 必须 | 数据类型 | 说明 |
|---|---|---|---|
| 挑战 | 是 | stringCollection | 用于修正查明的威胁的操作列表。 可能的值:block |
| MultiConditionalAccessStatus | 是 | stringCollection |
OutputClaimsTransformations 元素可能包含用于修改输出声明或生成新输出声明的 OutputClaimsTransformation 元素集合。
示例:计算
以下示例展示了用于评估登录威胁的条件访问技术配置文件。
<TechnicalProfile Id="ConditionalAccessEvaluation">
<DisplayName>Conditional Access Provider</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ConditionalAccessProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="OperationType">Evaluation</Item>
</Metadata>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="IsMfaRegistered" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="UserId" />
<InputClaim ClaimTypeReferenceId="AuthenticationMethodsUsed" />
<InputClaim ClaimTypeReferenceId="IsFederated" DefaultValue="false" />
<InputClaim ClaimTypeReferenceId="IsMfaRegistered" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="conditionalAccessClaimCollection" PartnerClaimType="Challenges" />
<OutputClaim ClaimTypeReferenceId="ConditionalAccessStatus" PartnerClaimType="MultiConditionalAccessStatus" />
</OutputClaims>
</TechnicalProfile>
补救
条件访问技术配置文件的“修正”模式会告知 Azure AD B2C 已修正登录过程中查明的威胁。 可以为修正模式配置以下选项。
元数据
| Attribute | 必须 | 说明 |
|---|---|---|
| OperationType | 是 | 必须是 Remediation。 |
输入声明
InputClaims 元素包含要发送到条件访问的声明的列表。 还可将声明名称映射到条件访问技术配置文件中定义的名称。
| ClaimReferenceId | 必须 | 数据类型 | 说明 |
|---|---|---|---|
| ChallengesSatisfied | 是 | stringCollection | 满足的质询列表(质询声明),用于修正从评估模式返回的已查明威胁。 |
InputClaimsTransformations 元素可能包含一系列 InputClaimsTransformation 元素,这些元素用于修改输入声明,或者用于在调用条件访问服务之前生成新的声明。
输出声明
条件访问协议提供程序不返回任何 OutputClaims,因此无需指定输出声明。 但是,只要设置了 DefaultValue 属性,就可以包含条件访问协议提供程序不会返回的声明。
OutputClaimsTransformations 元素可能包含用于修改输出声明或生成新输出声明的 OutputClaimsTransformation 元素集合。
示例:补救
以下示例展示了用于修正所查明的威胁的条件访问技术配置文件:
<TechnicalProfile Id="ConditionalAccessRemediation">
<DisplayName>Conditional Access Remediation</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ConditionalAccessProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="OperationType">Remediation</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="conditionalAccessClaimCollection" PartnerClaimType="ChallengesSatisfied" />
</InputClaims>
</TechnicalProfile>
若要使此示例正常工作,请将以下示例中所示的声明添加到扩展文件中的 ClaimsSchema 节:
<!-- Conditional Access claims -->
<ClaimType Id="conditionalAccessClaimCollection">
<DisplayName>Conditional Access claims</DisplayName>
<DataType>stringCollection</DataType>
<AdminHelpText>The list of claims which are the result of CA check</AdminHelpText>
</ClaimType>
<ClaimType Id="ConditionalAccessStatus">
<DisplayName>The status of CA evaluation</DisplayName>
<DataType>stringCollection</DataType>
<AdminHelpText>The status of CA evaluation</AdminHelpText>
</ClaimType>
<ClaimType Id="AuthenticationMethodsUsed">
<DisplayName>Authentication methods used</DisplayName>
<DataType>stringCollection</DataType>
<AdminHelpText>The list of authentication methods used</AdminHelpText>
</ClaimType>
<ClaimType Id="AuthenticationMethodUsed">
<DisplayName>Authentication method used</DisplayName>
<DataType>string</DataType>
<AdminHelpText>The authentication method used</AdminHelpText>
</ClaimType>
<ClaimType Id="IsFederated">
<DisplayName>IsFederated</DisplayName>
<DataType>boolean</DataType>
<AdminHelpText>Is user authenticated via an external identity provider</AdminHelpText>
</ClaimType>
<ClaimType Id="IsMfaRegistered">
<DisplayName>IsMfaRegistered</DisplayName>
<DataType>boolean</DataType>
<AdminHelpText>Is user registered for MFA</AdminHelpText>
</ClaimType>
<ClaimType Id="CAChallengeIsMfa">
<DisplayName>CAChallengeIsMfa</DisplayName>
<DataType>boolean</DataType>
</ClaimType>
<ClaimType Id="CAChallengeIsChgPwd">
<DisplayName>CAChallengeIsChgPwd</DisplayName>
<DataType>boolean</DataType>
</ClaimType>
<ClaimType Id="CAChallengeIsBlock">
<DisplayName>CAChallengeIsBlock</DisplayName>
<DataType>boolean</DataType>
</ClaimType>
<ClaimType Id="responseMsg">
<DisplayName>responseMsg</DisplayName>
<DataType>string</DataType>
<AdminHelpText>A claim responsible for holding response messages to send to the relying party</AdminHelpText>
<UserHelpText>A claim responsible for holding response messages to send to the relying party</UserHelpText>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
<!-- End of Conditional Access claims -->
添加以下声明转换:
<!--Conditional Access Transformations-->
<ClaimsTransformation Id="AddToAuthenticationMethodsUsed" TransformationMethod="AddItemToStringCollection">
<InputClaims>
<InputClaim ClaimTypeReferenceId="AuthenticationMethodUsed" TransformationClaimType="item" />
<InputClaim ClaimTypeReferenceId="AuthenticationMethodsUsed" TransformationClaimType="collection" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="AuthenticationMethodsUsed" TransformationClaimType="collection" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreatePasswordAuthenticationMethodClaim" TransformationMethod="CreateStringClaim">
<InputParameters>
<InputParameter Id="value" DataType="string" Value="Password" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="AuthenticationMethodUsed" TransformationClaimType="createdClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateOneTimePasscodeAuthenticationMethodClaim" TransformationMethod="CreateStringClaim">
<InputParameters>
<InputParameter Id="value" DataType="string" Value="OneTimePasscode" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="AuthenticationMethodUsed" TransformationClaimType="createdClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="IsMfaRegisteredCT" TransformationMethod="DoesClaimExist">
<InputClaims>
<InputClaim ClaimTypeReferenceId="strongAuthenticationPhoneNumber" TransformationClaimType="inputClaim" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="IsMfaRegistered" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="SetCAChallengeIsMfa" TransformationMethod="StringCollectionContains">
<InputClaims>
<InputClaim ClaimTypeReferenceId="conditionalAccessClaimCollection" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="item" DataType="string" Value="mfa" />
<InputParameter Id="ignoreCase" DataType="string" Value="true" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsMfa" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="SetCAChallengeIsChgPwd" TransformationMethod="StringCollectionContains">
<InputClaims>
<InputClaim ClaimTypeReferenceId="conditionalAccessClaimCollection" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="item" DataType="string" Value="chg_pwd" />
<InputParameter Id="ignoreCase" DataType="string" Value="true" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsChgPwd" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="SetCAChallengeIsBlock" TransformationMethod="StringCollectionContains">
<InputClaims>
<InputClaim ClaimTypeReferenceId="conditionalAccessClaimCollection" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="item" DataType="string" Value="block" />
<InputParameter Id="ignoreCase" DataType="string" Value="true" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsBlock" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
添加以下技术配置文件:
<TechnicalProfile Id="GenerateCAClaimFlags">
<DisplayName>GenerateCAClaimFlags</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="CAChallengeIsMfa" />
<OutputClaim ClaimTypeReferenceId="CAChallengeIsChgPwd" />
<OutputClaim ClaimTypeReferenceId="CAChallengeIsBlock" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="SetCAChallengeIsMfa" />
<OutputClaimsTransformation ReferenceId="SetCAChallengeIsChgPwd" />
<OutputClaimsTransformation ReferenceId="SetCAChallengeIsBlock" />
</OutputClaimsTransformations>
</TechnicalProfile>
<!--This is a self-asserted technical profile that we will use to show a block screen-->
<TechnicalProfile Id="ShowBlockPage">
<DisplayName>Show Block message</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.selfasserted.profileupdate</Item>
<Item Key="TokenLifeTimeInSeconds">3600</Item>
<Item Key="AllowGenerationOfClaimsWithNullValues">true</Item>
<Item Key="setting.showContinueButton">false</Item>
<Item Key="setting.showCancelButton">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="responseMsg" DefaultValue="The user is blocked due to conditional access check." />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="responseMsg" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
<EnabledForUserJourneys>Always</EnabledForUserJourneys>
</TechnicalProfile>
在 TrustFrameworkPolicy 元素中,添加以下示例中所示的这些 SubJourney:
<SubJourneys>
<SubJourney Id="ConditionalAccess_Evaluation" Type="Call">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="ConditionalAccessEvaluation" TechnicalProfileReferenceId="ConditionalAccessEvaluation" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>conditionalAccessClaimCollection</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="GenerateCAClaimFlags" TechnicalProfileReferenceId="GenerateCAClaimFlags" />
</ClaimsExchanges>
</OrchestrationStep>
</OrchestrationSteps>
</SubJourney>
<SubJourney Id="ConditionalAccess_Remediation" Type="Call">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>conditionalAccessClaimCollection</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="ConditionalAccessRemediation" TechnicalProfileReferenceId="ConditionalAccessRemediation" />
</ClaimsExchanges>
</OrchestrationStep>
</OrchestrationSteps>
</SubJourney>
添加使用新声明的用户旅程,如以下示例所示:
<UserJourneys>
<UserJourney Id="SignUpOrSignInWithCA">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsigninsam">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Check if the user has selected to sign in using one of the social providers -->
<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" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- For social IDP authentication, attempt to find the user account in the directory. -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>socialIdpAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="UserJourneyContext" TechnicalProfileReferenceId="SimpleUJContext" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="5" Type="InvokeSubJourney">
<JourneyList>
<Candidate SubJourneyReferenceId="ConditionalAccess_Evaluation" />
</JourneyList>
</OrchestrationStep>
<!--MFA based on Conditional Access-->
<OrchestrationStep Order="6" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>CAChallengeIsMfa</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>CAChallengeIsMfa</Value>
<Value>false</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-InputOrVerify" />
</ClaimsExchanges>
</OrchestrationStep>
<!--Save MFA phone number: The precondition verifies whether the user provided a new number in the previous step. If so, the phone number is stored in the directory for future authentication requests.-->
<OrchestrationStep Order="7" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>newPhoneNumberEntered</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserWriteWithObjectId" TechnicalProfileReferenceId="AAD-UserWritePhoneNumberUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="8" Type="ClaimsExchange" >
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>CAChallengeIsBlock</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>CAChallengeIsBlock</Value>
<Value>true</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="ShowBlockPage" TechnicalProfileReferenceId="ShowBlockPage" />
</ClaimsExchanges>
</OrchestrationStep>
<!--If a user has reached this point, this means a remediation was applied-->
<!-- You can add a precondition here to call remediation only if a Conditional Access challenge was issued-->
<OrchestrationStep Order="9" Type="InvokeSubJourney">
<JourneyList>
<Candidate SubJourneyReferenceId="ConditionalAccess_Remediation" />
</JourneyList>
</OrchestrationStep>
<OrchestrationStep Order="10" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
</UserJourneys>
下面是引用此 UserJourney 的信赖方文件的示例:
<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="contoso.partner.onmschina.cn"
PolicyId="ha-sam-signup_signin-CA"
PublicPolicyUri="http://contoso.partner.onmschina.cn/B2C_1A_signup_signin_CA"
DeploymentMode="Development"
UserJourneyRecorderEndpoint="urn:journeyrecorder:applicationinsights"
<BasePolicy>
<TenantId>contoso.partner.onmschina.cn</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInWithCA" />
<UserJourneyBehaviors>
<SingleSignOn Scope="Tenant" />
<SessionExpiryType>Absolute</SessionExpiryType>
<SessionExpiryInSeconds>604800</SessionExpiryInSeconds>
<JourneyInsights TelemetryEngine="ApplicationInsights" InstrumentationKey="<add your app insights instrumentation key" DeveloperMode="true" ClientEnabled="false" ServerEnabled="true" TelemetryVersion="1.0.0" />
</UserJourneyBehaviors>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="signInName" />
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub" />
<OutputClaim ClaimTypeReferenceId="CAChallengeIsMfa" />
<OutputClaim ClaimTypeReferenceId="CAChallengeIsBlock" />
<OutputClaim ClaimTypeReferenceId="conditionalAccessClaimCollection" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>