I'm trying to configure a B2C tenant using policies instead of user flows. For that, I'm using the SocialAndLocalAccount template as start base.
In the sign up page, I added a custom claim to ask the user about his/her birth date. If the user provides a date which make him/her an under age (+18), I would like to display a verification failed message (like the one you can set by using predicates) and prevent the user to be able to sign up by the create button being disabled.
So far, this is what I've got:
-I created two new claims to store a boolean value that would tell me if the user is under age or not and a second one to store the current time.
<ClaimType Id="systemDateTime">
<DisplayName>Today's date</DisplayName>
<DataType>dateTime</DataType>
</ClaimType>
<ClaimType Id="isNotUnderAge">
<DisplayName>Indicates whether user being under age or not</DisplayName>
<DataType>boolean</DataType>
<AdminHelpText>User must be over 18</AdminHelpText>
</ClaimType>
I added to ClaimsTransformation to get the current date and compare it to the selected one (date comparison):
<!-- Check user under age -->
<ClaimsTransformation Id="GetSystemDateTime" TransformationMethod="GetCurrentDateTime">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="systemDateTime" TransformationClaimType="currentDateTime" />
</OutputClaims>
</ClaimsTransformation>
<ClaimsTransformation Id="CheckBirthDateIsNotUnderAge" TransformationMethod="DateTimeComparison">
<InputClaims>
<InputClaim ClaimTypeReferenceId="birthDate" TransformationClaimType="firstDateTime" />
<InputClaim ClaimTypeReferenceId="systemDateTime" TransformationClaimType="secondDateTime" />
</InputClaims>
<InputParameters>
<InputParameter Id="operator" DataType="string" Value="later than" />
<InputParameter Id="timeSpanInSeconds" DataType="int" Value="568025136" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="isNotUnderAge" TransformationClaimType="result" />
</OutputClaims>
</ClaimsTransformation>
Until this point, I think I'might be able to tell if the user is under age or not. From here on, I'm not sure how to continue in order to achieve my goal. I've been reading documentation but didn't come to a solution and I'm unsure that this would be the best approach.
Have you ever came across a similar restriction? If so, which is the best way to achieve this and where can I find any tips that help me resolve my issue?
Thank you very much!
EDIT 1:
I've found this question which explains a similar problem if not the same and it make me ask myself, is it possible to achieve this by using ClaimsTransformations and Predicates or is the REST API the only way to get the expected result?
It looks like you have the right idea as long as you want to blanket ban all users under 18. One option is you can use a validation technical profile to call AssertBooleanClaimIsEqualToValue transformation, which will display a custom error message on the sign-in page if the user is under 18 and won't let them continue. See Microsoft Documentation: Boolean Claim Transformations for example.
If you really want the Continue button to grey out, you could display isNotUnderage as a readonly claim and hide it with CSS, and then use JS to grey out the button based on its value.
The third option is to add an OrchestrationStep before presenting the user with your signup options with a precondition to skip if user is over 18 that will display a new Self-Asserted Technical Profile you can set up to display an error message (just a paragraph claim) and remove the continue button from. The downside here is that it requires you collect the user's age before offering them sign-up options which can complicate things.
Related
First of all, thanks much for sample. Easy to follow and I was able to successfully try it out.
This question related to ClaimsTransformation "ComparePasswordResetOnWithCurrentDateTime" where it is determined if a password reset is required .
On line 77, would it be possible to pass a claim value for the Value attribute in the InputParameter tag ?
Please see screen shot attached
If that's not possible, any ideas on how to accomplish the 'earlier than' operation, where the timeSpanInSeconds is based on a runtime value ?
• Since you are passing an input parameter value which is defined as an element for passing a constant value to a transformation which has two attributes, viz., Value that is the actual constant value to be passed and the ID that is used to give a unique name to the input as in which must match the expected inputs for the transformation method. As you have already given the input parameter as ‘timespaninseconds’ and data type as ‘int’ with a value of ‘80’ which is in line with the input parameter transformation method.
• Thus, if you want to use a claim value instead of the hard coded value passed in that parameter string, then you use them as below example and modify them as per your requirement: -
‘ <ClaimsTransformation Id="ComparePasswordResetOnWithCurrentDateTime"
TransformationMethod="AssertDateTimeIsLessThan">
<InputClaims>
<InputClaim ClaimTypeReferenceId="approvedDateTime"
TransformationClaimType="leftOperand" />
<InputClaim ClaimTypeReferenceId="currentDateTime"
TransformationClaimType="rightOperand" />
</InputClaims>
<InputParameters>
<InputParameter Id="AssertIfEqualTo" DataType="boolean" Value="false" />
<InputParameter Id="AssertIfRightOperandIsNotPresent" DataType="boolean" Value="true" />
<InputParameter Id="TimeSpanInSeconds" DataType="int" Value="-90" />
</InputParameters>
</ClaimsTransformation> ‘
In this claims transformation, if the value of current date and time is earlier than 90 and the approved date and time is equal to the current date and time, then the operation will be carried out to reset the password if the date and time are equal to or greater than 90 days.
Please refer the below links for more information: -
https://learn.microsoft.com/en-us/azure/active-directory-b2c/date-transformations
https://learn.microsoft.com/en-us/azure/active-directory/develop/reference-claims-mapping-policy-type
To my sign up screen, I added 2 built-in fields: First Name and Last Name. In the Users | All users
list, a new user appears with the Name of "unknown". That is because I did not add the "Display Name" attribute. I don't want to make the user fill this additional field. Is it possible to set the Display Name to be populated on the back end as First Name + " " + Last Name?
I believe your two options are:
Enable Custom HTML/JavaScript for your User Interface that will effectively hide the Display Name field, and combine the First Name and Last Name, respectively.
Use the more complex, but powerful Identity Experience Framework and leverage a ClaimsTransformation:
Example:
<ClaimsTransformation Id="Generate-DisplayName" TransformationMethod="FormatStringMultipleClaims">
<InputClaims>
<InputClaim ClaimTypeReferenceId="givenname" TransformationClaimType="inputClaim1"/>
<InputClaim ClaimTypeReferenceId="surname" TransformationClaimType="inputClaim2"/>
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0} {1}"/>
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" TransformationClaimType="outputClaim"/>
</OutputClaims>
</ClaimsTransformation>
I'm creating a custom policy that must do the following:
1. If the user clicks to Sign up, show a screen with three input fields that are:
a. A key (string)
b. date of birth (I would like to display a calendar)
c. another key (string)
However, after reading all the documentation Add claims and customize user input using custom policies in Azure Active Directory B2C and searching in Google, I couldn't find a way to create a "Datepicker" input field in Azure B2C.
How can I accomplish that?
Thank you
<ClaimType Id="dateOfBirth">
<DisplayName>Date of Birth</DisplayName>
<DataType>date</DataType>
<AdminHelpText>The user's date of birth.</AdminHelpText>
<UserHelpText>Your date of birth.</UserHelpText>
<UserInputType>DateTimeDropdown</UserInputType>
<PredicateValidationReference Id="CustomDateRange" />
</ClaimType>
Use DateTimeDropdown.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/claimsschema
Complementing #Jonny answer, you canconfigure the custom data range validation like so:
<BuildingBlocks>
<ClaimsSchema>
<ClaimType Id="dateOfBirth">
<DisplayName>Date of Birth</DisplayName>
<DataType>date</DataType>
<AdminHelpText>The user's date of birth.</AdminHelpText>
<UserHelpText>Your date of birth.</UserHelpText>
<UserInputType>DateTimeDropdown</UserInputType>
<PredicateValidationReference Id="CustomDateRange" />
</ClaimType>
<Predicates>
<Predicate Id="DateRange" Method="IsDateRange" HelpText="The date must be between 01-01-1980 and today.">
<Parameters>
<Parameter Id="Minimum">1980-01-01</Parameter>
<Parameter Id="Maximum">Today</Parameter>
</Parameters>
</Predicate>
</Predicates>
<PredicateValidations>
<PredicateValidation Id="CustomDateRange">
<PredicateGroups>
<PredicateGroup Id="DateRangeGroup">
<PredicateReferences>
<PredicateReference Id="DateRange" />
</PredicateReferences>
</PredicateGroup>
</PredicateGroups>
</PredicateValidation>
</PredicateValidations>
</ClaimsSchema>
</BuildingBlocks>
Helpful links:
BuildingBlocks
Predicates and PredicateValidations
I am having some trouble using the Paragraph UserInput Type available to Azure B2C IEF. I would like to use the Paragraph element because it would make localization a lot easier. However, no matter what I have tried, I am unable to get the Paragraph element to display any text.
I have tried to follow the documentation: https://learn.microsoft.com/en-us/azure/active-directory-b2c/claimsschema#paragraph and I have also contacted the B2C Team via GitHub and was recommended I assign default values.
ClaimType
<ClaimType Id="UserExistsErrorMessage">
<DisplayName>Error Message</DisplayName>
<DataType>string</DataType>
<UserInputType>Paragraph</UserInputType>
</ClaimType>
In my technical profile I am assigning a default value
<OutputClaim ClaimTypeReferenceId="UserExistsErrorMessage" DefaultValue="Test">
I am expecting the paragraph to display the text that I have assigned. Instead all I am getting is a blank < p>< /p> HTML tags when reviewing the source during testing.
To set the value of Paragraph UserInputType, please set default value using input claim.
<InputClaims>
<InputClaim ClaimTypeReferenceId="UserExistsErrorMessage" DefaultValue="Test"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="UserExistsErrorMessage"/>
</OutputClaims>
I believe it's the Enumeration value that must be set to the display value:
<ClaimType Id="UserExistsErrorMessage">
<DisplayName>Error Message</DisplayName>
<DataType>string</DataType>
<UserInputType>Paragraph</UserInputType>
<Restriction>
<Enumeration Text="Test" Value="This is a test message." />
</Restriction>
</ClaimType>
I am trying to structure my base & ext policies so that base remains pretty static. To do this I am overriding claims, etc in the ext policy - which works well. However, when trying to override a Validation Technical profile, it appears that the new items are being added at the beginning of the collection and not the end as I would have expected.
So if I have this:
base.xml
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail-NoVerify">
<DisplayName>Email signup</DisplayName>
… <!-- stuff removed for brevity -->
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>
and this
ext.xml
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail-NoVerify">
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="API-UpdateUser" />
<ValidationTechnicalProfile ReferenceId="API-GetUser" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
They execute in the order of
API-UpdateUser
API-GetUser
AAD-UserWriteUsingLogonEmail
Is there anyway to control this order as I need the user to be created before the API stuff executes? i.e. Execute in order 3, 1, 2
From what I have learned, if the override adds an element with the same elementname and ID, it replaces that element from the base policy.
So, if the extension policy contains:
````
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail-NoVerify">
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="API-UpdateUser" />
<ValidationTechnicalProfile ReferenceId="API-GetUser" />
<ValidationTechnicalProfile ReferenceId="AAD-UserWriteUsingLogonEmail" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
````
then "AAD-UserWriteUsingLogonEmail" won't be invoked 2 times, it will be invoked once, as third validation profile, because the referenceId="AAD-UserWriteUsingLogonEmail" overrides the declaration of that element in the base policy file.
The documentation is not very clear about this, and the closest doc I have found is in https://github.com/Azure-Samples/active-directory-b2c-advanced-policies/blob/master/Documentation/Features%20part%206.md, where it says:
Same element in the child policy and parent policy implies, child
policy is overriding that element of the parent policy
That documentation doesn't make clear what "same element" means, it seems to me to be the same XPath and same ID (with the ID being whatever attribute is the unique id of the element).
You need to overwrite all of them in the correct order in the extension policy. For example, if your base policy has following validation technical profile AAD-UserWriteUsingLogonEmail
In the extension policy, you add AAD-UserWriteUsingLogonEmail again, in the correct order:
API-UpdateUser
API-GetUser
AAD-UserWriteUsingLogonEmail