Skip to content

Instantly share code, notes, and snippets.

@Froosh
Created June 3, 2021 06:57
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 Froosh/5c8700e3359cbde473f8ab7e17af7bbc to your computer and use it in GitHub Desktop.
Save Froosh/5c8700e3359cbde473f8ab7e17af7bbc to your computer and use it in GitHub Desktop.
Azure AD B2C Password Reset Demo with Predicate Validation
<?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="__B2CTenantName__"
PolicyId="__BaseFileName__"
DeploymentMode="__deployment_mode__"
PublicPolicyUri="https://__B2CTenantName__/__BaseFileName__">
<!-- https://__B2CTenantHost__/__B2CTenantGUID__/__BaseFileName__/oauth2/v2.0/authorize?client_id=__AppRegistrationGUID__&redirect_uri=https%3A%2F%2Fjwt.ms&scope=openid&response_type=id_token -->
<!-- Needs to have custom HTML hosted somewhere that CORS can be set before a custom domain can be used -->
<BuildingBlocks>
<!-- https://docs.microsoft.com/en-us/azure/active-directory-b2c/claimsschema -->
<ClaimsSchema>
<ClaimType Id="objectId">
<DataType>string</DataType>
<UserInputType>Readonly</UserInputType>
</ClaimType>
<ClaimType Id="newPassword">
<DisplayName>New Password</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your new password.</UserHelpText>
<UserInputType>Password</UserInputType>
<PredicateValidationReference Id="StrongPassword" />
</ClaimType>
<ClaimType Id="reenterPassword">
<DisplayName>Confirm New Password</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your new password, again.</UserHelpText>
<UserInputType>Password</UserInputType>
</ClaimType>
</ClaimsSchema>
<!-- The Predicates element must appear directly following the ClaimsSchema element within the BuildingBlocks element. -->
<!-- https://docs.microsoft.com/en-us/azure/active-directory-b2c/predicates -->
<Predicates>
<Predicate Id="IsLengthBetween8And256"
Method="IsLengthRange"
HelpText="The password must be between 8 and 256 characters.">
<Parameters>
<Parameter Id="Minimum">8</Parameter>
<Parameter Id="Maximum">256</Parameter>
</Parameters>
</Predicate>
<Predicate Id="IsLengthBetween20And256"
Method="IsLengthRange"
HelpText="length of 20 or more characters">
<Parameters>
<Parameter Id="Minimum">20</Parameter>
<Parameter Id="Maximum">256</Parameter>
</Parameters>
</Predicate>
<Predicate Id="Lowercase"
Method="IncludesCharacters"
HelpText="a lowercase letter">
<Parameters>
<Parameter Id="CharacterSet">a-z</Parameter>
</Parameters>
</Predicate>
<Predicate Id="Uppercase"
Method="IncludesCharacters"
HelpText="an uppercase letter">
<Parameters>
<Parameter Id="CharacterSet">A-Z</Parameter>
</Parameters>
</Predicate>
<Predicate Id="Number"
Method="IncludesCharacters"
HelpText="a digit">
<Parameters>
<Parameter Id="CharacterSet">0-9</Parameter>
</Parameters>
</Predicate>
<Predicate Id="Symbol"
Method="IncludesCharacters"
HelpText="a symbol">
<Parameters>
<Parameter Id="CharacterSet">@#$%^&amp;*\-_+=[]{}|\\:',.?/`~"();!</Parameter>
</Parameters>
</Predicate>
<Predicate Id="AllowedAADCharacters"
Method="MatchesRegex"
HelpText="An invalid character was provided.">
<Parameters>
<Parameter Id="RegularExpression">(^([0-9A-Za-z\d@#$%^&amp;*\-_+=[\]{}|\\:',?/`~"();! ]|(\.(?!@)))+$)|(^$)</Parameter>
</Parameters>
</Predicate>
<Predicate Id="DisallowedWhitespace"
Method="MatchesRegex"
HelpText="The password must not begin or end with a whitespace character.">
<Parameters>
<Parameter Id="RegularExpression">(^\S.*\S$)|(^\S+$)|(^$)</Parameter>
</Parameters>
</Predicate>
</Predicates>
<!-- The PredicateValidations element must appear directly following the Predicates element within the BuildingBlocks element. -->
<PredicateValidations>
<PredicateValidation Id="StrongPassword">
<PredicateGroups>
<PredicateGroup Id="DisallowedWhitespaceGroup">
<PredicateReferences>
<PredicateReference Id="DisallowedWhitespace" />
</PredicateReferences>
</PredicateGroup>
<PredicateGroup Id="AllowedAADCharactersGroup">
<PredicateReferences>
<PredicateReference Id="AllowedAADCharacters" />
</PredicateReferences>
</PredicateGroup>
<PredicateGroup Id="LengthGroup">
<PredicateReferences>
<PredicateReference Id="IsLengthBetween8And256" />
</PredicateReferences>
</PredicateGroup>
<PredicateGroup Id="ComplexityClasses">
<UserHelpText>The password must have at least 3 of the following:</UserHelpText>
<PredicateReferences MatchAtLeast="3">
<PredicateReference Id="IsLengthBetween20And256" />
<PredicateReference Id="Lowercase" />
<PredicateReference Id="Uppercase" />
<PredicateReference Id="Number" />
<PredicateReference Id="Symbol" />
</PredicateReferences>
</PredicateGroup>
</PredicateGroups>
</PredicateValidation>
</PredicateValidations>
<ContentDefinitions>
<ContentDefinition Id="demo.localaccount.passwordreset">
<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.6</DataUri>
<Metadata>
<Item Key="DisplayName">Local Account Password Reset</Item>
</Metadata>
<LocalizedResourcesReferences MergeBehavior="Append">
<LocalizedResourcesReference Language="en"
LocalizedResourcesReferenceId="demo.localaccount.passwordreset.en" />
</LocalizedResourcesReferences>
</ContentDefinition>
</ContentDefinitions>
<Localization Enabled="true">
<SupportedLanguages DefaultLanguage="en"
MergeBehavior="Append">
<SupportedLanguage>en</SupportedLanguage>
</SupportedLanguages>
<LocalizedResources Id="demo.localaccount.passwordreset.en">
<LocalizedStrings>
<LocalizedString ElementType="UxElement"
StringId="error_fieldIncorrect">Please try again - your password must include the characters below:</LocalizedString>
</LocalizedStrings>
</LocalizedResources>
</Localization>
</BuildingBlocks>
<ClaimsProviders>
<ClaimsProvider>
<!-- The technical profile(s) defined in this section is **required** by the framework to be included in all policies. -->
<DisplayName>Trust Framework Policy Engine Default Claims Provider</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="TpEngine_c3bd4fe2-1775-4013-b91d-35f16d377d13">
<DisplayName>Trust Framework Policy Engine Default Technical Profile</DisplayName>
<Protocol Name="None" />
<Metadata>
<Item Key="url">{service:te}</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>JWT Token Issuing Claims Provider</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="JwtIssuer">
<DisplayName>JWT Issuer Technical Profile</DisplayName>
<Protocol Name="None" />
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="issuer_refresh_token_user_identity_claim_type">objectId</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret"
StorageReferenceId="__jwt_issuer_secret__" />
<Key Id="issuer_refresh_token_key"
StorageReferenceId="__jwt_issuer_refresh_token_key__" />
</CryptographicKeys>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Password Reset Demo Claims Provider</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="PasswordResetDemoTechnicalProfile">
<DisplayName>Password Reset Demo Technical Profile</DisplayName>
<Protocol Name="Proprietary"
Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">demo.localaccount.passwordreset</Item>
<Item Key="setting.inputVerificationDelayTimeInMilliseconds">750</Item>
<Item Key="setting.showCancelButton">False</Item>
</Metadata>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="newPassword"
Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword"
Required="true" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<UserJourneys>
<UserJourney Id="PasswordResetDemoJourney">
<OrchestrationSteps>
<OrchestrationStep Order="1"
Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="PasswordResetDemoClaimsExchange"
TechnicalProfileReferenceId="PasswordResetDemoTechnicalProfile" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2"
Type="SendClaims"
CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
</UserJourney>
</UserJourneys>
<RelyingParty>
<DefaultUserJourney ReferenceId="PasswordResetDemoJourney" />
<TechnicalProfile Id="PasswordResetDemoPolicyProfile">
<DisplayName>Password Reset Policy Profile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"
PartnerClaimType="sub"
DefaultValue="Default Object ID" />
</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