Skip to content

Instantly share code, notes, and snippets.

@rbrayb
Created May 17, 2022 03:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rbrayb/95b4f9586ba724e76c0542b0bf1cbe27 to your computer and use it in GitHub Desktop.
Save rbrayb/95b4f9586ba724e76c0542b0bf1cbe27 to your computer and use it in GitHub Desktop.
Using a QR code with Azure AD B2C
<?xml version="1.0" encoding="utf-8" ?>
<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="yourtenant.onmicrosoft.com"
PolicyId="B2C_1A_QR"
PublicPolicyUri="http://yourtenant.onmicrosoft.com/B2C_1A_QR">
<BasePolicy>
<TenantId>yourtenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TRUSTFRAMEWORKEXTENSIONSMFA</PolicyId>
</BasePolicy>
<BuildingBlocks>
<ClaimsSchema>
<ClaimType Id="verificationCode">
<DisplayName>Verification Code</DisplayName>
<DataType>string</DataType>
<UserHelpText>Enter your verification code</UserHelpText>
<UserInputType>TextBox</UserInputType>
<!--Restriction>
<Pattern RegularExpression="^[0-9]{1,15}$" HelpText="Please enter digits" />
</Restriction-->
</ClaimType>
<!--Expected verify endpoint status-->
<ClaimType Id="template">
<DisplayName>Template</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="Otp">
<DisplayName>Secondary One-time password</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="signInName">
<DisplayName>User name</DisplayName>
<DataType>string</DataType>
<UserHelpText>The username you want to use</UserHelpText>
<UserInputType>TextBox</UserInputType>
</ClaimType>
<!-- TOTP Claims -->
<ClaimType Id="QrCodeScanInstruction">
<DisplayName>Once you've downloaded the Authenticator app, you can use any of the methods below to continue with enrollment.</DisplayName>
<DataType>string</DataType>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
<ClaimType Id="QrCodeVerifyInstruction">
<DisplayName>Enter the verification code from your authenticator app​.</DisplayName>
<DataType>string</DataType>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
<ClaimType Id="qrCodeContent">
<DisplayName>QR Code Text</DisplayName>
<DataType>string</DataType>
<UserHelpText>QR code text</UserHelpText>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
<ClaimType Id="secretKey">
<DisplayName>Secret Key</DisplayName>
<DataType>string</DataType>
<UserHelpText>QR code secret</UserHelpText>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
<ClaimType Id="otpCode">
<DisplayName>Verification code</DisplayName>
<DataType>string</DataType>
<UserHelpText>Enter the 6-digit verification code generated by the the Authenticator app in the box</UserHelpText>
<UserInputType>TextBox</UserInputType>
<Restriction>
<Pattern RegularExpression="^([0-9]{6})|(------)$" HelpText="Enter the 6-digit verification code generated by the the Authenticator app in the box"/>
</Restriction>
</ClaimType>
<ClaimType Id="uriLabel">
<DisplayName>Uri Label</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="issuer">
<DisplayName>Issuer</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="numberOfAvailableDevices">
<DisplayName>Number of available devices:</DisplayName>
<DataType>string</DataType>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
<!-- End TOTP Claims -->
<ClaimType Id="qrChoice">
<DisplayName>Proofup or verify?</DisplayName>
<DataType>string</DataType>
<UserHelpText>Would you like to do?</UserHelpText>
<UserInputType>RadioSingleSelect</UserInputType>
<Restriction>
<Enumeration Text="Proof Up" Value="pru" SelectByDefault="true"/>
<Enumeration Text="Verify" Value="ver" SelectByDefault="false"/>
</Restriction>
</ClaimType>
</ClaimsSchema>
<ClaimsTransformations>
<ClaimsTransformation Id="CreateSubjectClaimFromObjectID" TransformationMethod="CreateStringClaim">
<InputParameters>
<InputParameter Id="value" DataType="string" Value="Not supported currently. Use oid claim."/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="sub" TransformationClaimType="createdClaim"/>
</OutputClaims>
</ClaimsTransformation>
<!-- TOTP -->
<ClaimsTransformation Id="CreateSecret" TransformationMethod="CreateOtpSecret">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="secretKey" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateIssuer" TransformationMethod="CreateStringClaim">
<InputParameters>
<InputParameter Id="value" DataType="string" Value="AzureQR"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="issuer" TransformationClaimType="createdClaim"/>
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateUriLabel" TransformationMethod="FormatStringMultipleClaims">
<InputClaims>
<InputClaim ClaimTypeReferenceId="issuer" TransformationClaimType="inputClaim1"/>
<InputClaim ClaimTypeReferenceId="signInName" TransformationClaimType="inputClaim2"/>
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}:{1}"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="uriLabel" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CreateUriString" TransformationMethod="BuildUri">
<InputClaims>
<InputClaim ClaimTypeReferenceId="uriLabel" TransformationClaimType="path"/>
<InputClaim ClaimTypeReferenceId="secretKey" TransformationClaimType="query.secret"/>
</InputClaims>
<InputParameters>
<InputParameter Id="scheme" DataType="string" Value="otpauth"/>
<InputParameter Id="host" DataType="string" Value="totp"/>
<InputParameter Id="query.issuer" DataType="string" Value="My issuer"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="qrCodeContent" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
<!-- End TOTP -->
</ClaimsTransformations>
<ContentDefinitions>
<ContentDefinition Id="api.selfasserted.totp">
<LoadUri>~/tenant/templates/AzureBlue/selfAsserted.cshtml</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:2.1.9</DataUri>
<Metadata>
<Item Key="DisplayName">Collect information from user page</Item>
</Metadata>
<LocalizedResourcesReferences>
<LocalizedResourcesReference Language="en" LocalizedResourcesReferenceId="api.selfasserted.totp.en"/>
</LocalizedResourcesReferences>
</ContentDefinition>
</ContentDefinitions>
<Localization>
<!-- TOTP localized strings (English) -->
<LocalizedResources Id="api.selfasserted.totp.en">
<LocalizedStrings>
<LocalizedString ElementType="DisplayControl" ElementId="authenticatorAppIconControl" StringId="title_text">Download the Microsoft Authenticator using the download links for iOS and Android or use any other authenticator app of your choice.</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="authenticatorAppIconControl" StringId="DN">Once you&#39;ve downloaded the Authenticator app, you can use any of the methods below to continue with enrollment.</LocalizedString>
<LocalizedString ElementType="ClaimType" ElementId="QrCodeScanInstruction" StringId="DisplayName">Once you've downloaded the Authenticator app, you can use any of the methods below to continue with enrollment.</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="totpQrCodeControl" StringId="title_text">Scan the QR code</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="totpQrCodeControl" StringId="info_msg">You can download the Microsoft Authenticator app or use any other authenticator app of your choice.</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="totpQrCodeControl" StringId="link_text">Can&#39;t scan? Try this</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="authenticatorInfoControl" StringId="title_text">Enter the account details manually</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="authenticatorInfoControl" StringId="account_name">Account Name:</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="authenticatorInfoControl" StringId="display_prefix">Secret</LocalizedString>
<LocalizedString ElementType="DisplayControl" ElementId="authenticatorInfoControl" StringId="collapse_text">Still having trouble?</LocalizedString>
<!-- Verification -->
<LocalizedString ElementType="ClaimType" ElementId="QrCodeVerifyInstruction" StringId="DisplayName">Enter the verification code from your authenticator app​.</LocalizedString>
<LocalizedString ElementType="ClaimType" ElementId="otpCode" StringId="DisplayName">Enter your code.</LocalizedString>
<!-- <LocalizedString ElementType="UxElement" StringId="button_continue">Verify</LocalizedString> -->
</LocalizedStrings>
</LocalizedResources>
</Localization>
<DisplayControls>
<!-- Render the QR code. It takes the URI (qrCodeContent) input claim and renders it as a QR code-->
<DisplayControl Id="totpQrCodeControl" UserInterfaceControlType="QrCodeControl">
<InputClaims>
<InputClaim ClaimTypeReferenceId="qrCodeContent"/>
</InputClaims>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="qrCodeContent" ControlClaimType="QrCodeContent"/>
</DisplayClaims>
</DisplayControl>
<!-- Render the TOTP information. It takes the totpIdentifier and the secretKey input claims and renders as a plan text-->
<DisplayControl Id="authenticatorInfoControl" UserInterfaceControlType="AuthenticatorInfoControl">
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName"/>
<InputClaim ClaimTypeReferenceId="secretKey"/>
</InputClaims>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="signInName"/>
<DisplayClaim ClaimTypeReferenceId="secretKey"/>
</DisplayClaims>
</DisplayControl>
<!-- Render the authenticator apps icon. -->
<DisplayControl Id="authenticatorAppIconControl" UserInterfaceControlType="AuthenticatorAppIconControl"/>
</DisplayControls>
</BuildingBlocks>
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>OTP</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="GenerateOtp">
<DisplayName>Generate one time password</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.OneTimePasswordProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="Operation">GenerateCode</Item>
<Item Key="CodeExpirationInSeconds">1200</Item>
<Item Key="CodeLength">6</Item>
<Item Key="CharacterSet">0-9</Item>
<Item Key="ReuseSameCode">true</Item>
<Item Key="NumRetryAttempts">5</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="identifier"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="otp" PartnerClaimType="otpGenerated"/>
</OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="VerifyOtp">
<DisplayName>Verify one time password</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.OneTimePasswordProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="Operation">VerifyCode</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="identifier"/>
<InputClaim ClaimTypeReferenceId="verificationCode" PartnerClaimType="otpToVerify"/>
</InputClaims>
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserReadUsingUserName">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="LocalAccountType">Username</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided user.</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="signInNames.userName" Required="true"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
<OutputClaim ClaimTypeReferenceId="accountEnabled"/>
<OutputClaim ClaimTypeReferenceId="givenName"/>
<OutputClaim ClaimTypeReferenceId="surname"/>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication"/>
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromObjectID"/>
</OutputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="AAD-ReadCommon"/>
</TechnicalProfile>
<TechnicalProfile Id="AAD-ReadCommon">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="userPrincipalName"/>
<OutputClaim ClaimTypeReferenceId="displayName"/>
<OutputClaim ClaimTypeReferenceId="otherMails"/>
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common"/>
</TechnicalProfile>
<TechnicalProfile Id="SignIn">
<DisplayName>Username signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
<Item Key="language.button_continue">Continue</Item>
<Item Key="setting.showCancelButton">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/>
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName"/>
</InputClaims>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="signInName" Required="true"/>
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD"/>
</TechnicalProfile>
<!-- Set the number of devices to 0 (default value) -->
<TechnicalProfile Id="SetTotpDefaultValue">
<DisplayName>Set Totp Default Values</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="numberOfAvailableDevices" DefaultValue="0"/>
</OutputClaims>
</TechnicalProfile>
<!-- Check the number of devices available for the user.
If the number of available devices is zero it indicates the user hasn't enrolled yet -->
<TechnicalProfile Id="AzureMfa-GetAvailableDevices">
<DisplayName>Get Available Devices</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureMfaProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="Operation">GetAvailableDevices</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="userPrincipalName"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="numberOfAvailableDevices"/>
</OutputClaims>
</TechnicalProfile>
<!-- TOTP session manager-->
<TechnicalProfile Id="SM-MFA-TOTP">
<DisplayName>Session Mananagement Provider</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.SSO.DefaultSSOSessionProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="signInName"/>
<PersistedClaim ClaimTypeReferenceId="issuer"/>
</PersistedClaims>
</TechnicalProfile>
<TechnicalProfile Id="SelectQRMethod">
<DisplayName>QR Method</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</Item>
<!-- <Item Key="setting.showContinueButton">false</Item> -->
<Item Key="setting.showCancelButton">false</Item>
</Metadata>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="qrChoice"/>
</DisplayClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="qrChoice"/>
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="qrChoice"/>
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure MFA</DisplayName>
<TechnicalProfiles>
<!-- Self-asserted technical profile that asks the user to enroll to the TOTP MFA. The technical profile:
1) Creates the TOTP secret
2) Sets the issuer name and the URI
3) Renders the QR code and the authentication URI
-->
<TechnicalProfile Id="EnableOTPAuthentication">
<DisplayName>Sign up with Authenticator app</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.totp</Item>
<Item Key="language.button_continue">Continue</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/>
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateSecret"/>
<InputClaimsTransformation ReferenceId="CreateIssuer"/>
<InputClaimsTransformation ReferenceId="CreateUriLabel"/>
<InputClaimsTransformation ReferenceId="CreateUriString"/>
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="qrCodeContent"/>
<InputClaim ClaimTypeReferenceId="secretKey"/>
</InputClaims>
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="authenticatorAppIconControl"/>
<DisplayClaim ClaimTypeReferenceId="QrCodeScanInstruction"/>
<DisplayClaim DisplayControlReferenceId="totpQrCodeControl"/>
<DisplayClaim DisplayControlReferenceId="authenticatorInfoControl"/>
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
<OutputClaim ClaimTypeReferenceId="secretKey"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA-TOTP"/>
</TechnicalProfile>
<!-- Self-asserted technical profile that verifies the TOTP-->
<TechnicalProfile Id="OTPVerification">
<DisplayName>Sign in with Authenticator app</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.totp</Item>
<Item Key="language.button_continue">Verify</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/>
</CryptographicKeys>
<InputClaims/>
<DisplayClaims>
<DisplayClaim ClaimTypeReferenceId="QrCodeVerifyInstruction"/>
<DisplayClaim ClaimTypeReferenceId="otpCode" Required="true"/>
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
<OutputClaim ClaimTypeReferenceId="otpCode" Required="true"/>
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AzureMfa-BeginVerifyOTP"/>
<ValidationTechnicalProfile ReferenceId="AzureMfa-VerifyOTP"/>
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-MFA-TOTP"/>
</TechnicalProfile>
<TechnicalProfile Id="AzureMfa-BeginVerifyOTP">
<DisplayName>Create Device</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureMfaProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="Operation">BeginVerifyOTP</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="secretKey"/>
<InputClaim ClaimTypeReferenceId="objectId"/>
<InputClaim ClaimTypeReferenceId="userPrincipalName"/>
</InputClaims>
</TechnicalProfile>
<TechnicalProfile Id="AzureMfa-VerifyOTP">
<DisplayName>Verify OTP</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureMfaProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
<Metadata>
<Item Key="Operation">VerifyOTP</Item>
<Item Key="allowTestOtpPassthrough">true</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="otpCode"/>
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<UserJourneys xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06">
<UserJourney Id="Test_QR">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SignIn" TechnicalProfileReferenceId="SignIn"/>
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="UserReadUsingUserName" TechnicalProfileReferenceId="AAD-UserReadUsingUserName"/>
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SelectQRMethod" TechnicalProfileReferenceId="SelectQRMethod"/>
</ClaimsExchanges>
</OrchestrationStep>
<!-- Call the TOTP enrollment sub journey.
If user already enrolled the sub journey will not ask the user to enroll -->
<OrchestrationStep Order="4" Type="InvokeSubJourney">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>qrChoice</Value>
<Value>pru</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<JourneyList>
<Candidate SubJourneyReferenceId="TotpFactor-Input"/>
</JourneyList>
</OrchestrationStep>
<!-- Call the TOTP validation sub journey-->
<OrchestrationStep Order="5" Type="InvokeSubJourney">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>qrChoice</Value>
<Value>ver</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<JourneyList>
<Candidate SubJourneyReferenceId="TotpFactor-Verify"/>
</JourneyList>
</OrchestrationStep>
<OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer"/>
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb"/>
</UserJourney>
</UserJourneys>
<SubJourneys>
<!-- TOTP enrollment sub journey-->
<SubJourney Id="TotpFactor-Input" Type="Call">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SetTotpDefaultValue" TechnicalProfileReferenceId="SetTotpDefaultValue"/>
</ClaimsExchanges>
</OrchestrationStep>
<!-- If the number of available devices is zero (user hasn't enrolled before),
render the TOTP enrollment page to scan the QR code that starts the enrollment process -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AuthenticatorForSignUp" TechnicalProfileReferenceId="EnableOTPAuthentication"/>
</ClaimsExchanges>
</OrchestrationStep>
<!-- If the number of available devices is zero (user hasn't enrolled before), -->
<!-- render the TOTP verification page. -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AuthenticatorForSignIn" TechnicalProfileReferenceId="OTPVerification"/>
</ClaimsExchanges>
</OrchestrationStep>
<!-- check the number of available devices. -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="CheckAvailableDevices" TechnicalProfileReferenceId="AzureMfa-GetAvailableDevices"/>
</ClaimsExchanges>
</OrchestrationStep>
</OrchestrationSteps>
</SubJourney>
<!-- TOTP verification sub journey-->
<SubJourney Id="TotpFactor-Verify" Type="Call">
<OrchestrationSteps>
<!-- Set the required claims numberOfAvailableDevices -->
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SetTotpDefaultValue" TechnicalProfileReferenceId="SetTotpDefaultValue"/>
</ClaimsExchanges>
</OrchestrationStep>
<!-- If current user is not a new one (this is a sign-in flow, and not sign-up),
check the number of available devices. -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="CheckAvailableDevices" TechnicalProfileReferenceId="AzureMfa-GetAvailableDevices"/>
</ClaimsExchanges>
</OrchestrationStep>
<!-- If the number of available devices isn't zero (user has enrolled before),
render the TOTP verification page -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AuthenticatorForSignIn" TechnicalProfileReferenceId="OTPVerification"/>
</ClaimsExchanges>
</OrchestrationStep>
</OrchestrationSteps>
</SubJourney>
</SubJourneys>
<RelyingParty>
<DefaultUserJourney ReferenceId="Test_QR"/>
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect"/>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="userPrincipalName"/>
<OutputClaim ClaimTypeReferenceId="numberOfAvailableDevices"/>
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
</OutputClaims>
<SubjectNamingInfo ClaimType="sub"/>
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment