I am trying to use https://github.com/azure-ad-b2c/samples/blob/master/policies/force-password-reset-first-logon to implement the Password reset on initial login for local accounts. I have followed all the steps in https://docs.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-get-started except creating a Facebook secret key since I need to sign in using only local accounts. While testing the policy, when I sign-in using my email address, I am able to successfully login to my application instead of getting re-directed to the password reset page and the custom attribute is not cleared.
I am using Graph API to set the custom attribute "Extenstion_000000000000000000000000000000000_mustResetPassword" with user creation and ForceChangePasswordNextSignIn property is set to false. Can you please direct me where I am doing this wrong?
I would like the user to sign in for the first time and get redirected to reset the password and clear the custom attribute. Please Help!
I am creating user using Graph API
var result = await graphClient.Users
.Request()
.AddAsync(new User
{
GivenName = user.FirstName,
Surname = user.LastName,
DisplayName = user.UserName,
Identities = new List<ObjectIdentity>
{
new ObjectIdentity()
{
SignInType = SignInType.emailAddress.ToDescription(),
Issuer = config.TenantId,
IssuerAssignedId = user.Email
}
},
PasswordProfile = new PasswordProfile()
{
Password = password,
ForceChangePasswordNextSignIn =false
},
PasswordPolicies = "DisablePasswordExpiration",
AdditionalData = extensionInstance
});
**TrustFrameworkExtensions.xml code**
<?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="tenantId.onmicrosoft.com"
PolicyId="B2C_1A_TrustFrameworkExtensions"
PublicPolicyUri="http://tenantId.onmicrosoft.com/B2C_1A_TrustFrameworkExtensions">
<BasePolicy>
<TenantId>tenantId.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
</BasePolicy>
<BuildingBlocks>
<ClaimsSchema>
<!--Demo: Specifies whether user must reset the password-->
<ClaimType Id="extension_mustResetPassword">
<DisplayName>Must reset password</DisplayName>
<DataType>boolean</DataType>
<UserHelpText>Specifies whether user must reset the password</UserHelpText>
</ClaimType>
</ClaimsSchema>
</BuildingBlocks>
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<Metadata>
<Item Key="client_id">00000000-0000-0000-0000-000000000000</Item>
<Item Key="IdTokenAudience">00000000-0000-0000-0000-000000000000</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="00000000-0000-0000-0000-000000000000" />
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="00000000-0000-0000-0000-000000000000" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<!-- Demo action required: Provide objectId and appId before using extension properties.
For more information: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-create-custom-attributes-profile-edit-custom
Action required: Insert objectId and appId here -->
<Metadata>
<Item Key="ApplicationObjectId">00000000-0000-0000-0000-000000000000</Item>
<Item Key="ClientId">00000000-0000-0000-0000-000000000000</Item>
</Metadata>
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<OutputClaims>
<!--Demo: Read the 'must reset password' extension attribute -->
<OutputClaim ClaimTypeReferenceId="extension_mustResetPassword" />
</OutputClaims>
</TechnicalProfile>
<TechnicalProfile Id="AAD-UserRemoveMustResetPasswordUsingObjectId">
<Metadata>
<Item Key="Operation">DeleteClaims</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="extension_mustResetPassword" />
</PersistedClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
<!--Demo: to create the extension attribute extension_mustResetPassword, you should upload the policy
and create one account. Then ***comment out this technical profile***.
-->
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="extension_mustResetPassword" DefaultValue="true" />
</PersistedClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<UserJourneys>
<UserJourney Id="SignUpOrSignInWithForcePasswordReset">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<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>
<!-- This step reads any user attributes that we may not have received when authenticating using ESTS so they can be sent
in the token. -->
<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="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<!--Demo: check if change password is required. If yes, ask the user to reset the password-->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>extension_mustResetPassword</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>extension_mustResetPassword</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<!--Demo: check if change password is required. If yes remove the value of the extension attribute.
So, on the next time user dons' t need to update the password-->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>extension_mustResetPassword</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
<Precondition Type="ClaimEquals" ExecuteActionsIf="false">
<Value>extension_mustResetPassword</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserRemoveMustResetPasswordUsingObjectId" TechnicalProfileReferenceId="AAD-UserRemoveMustResetPasswordUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="6" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
</UserJourneys>
</TrustFrameworkPolicy>
Object details in Azure
[
{
"accountEnabled": true,
"assignedLicenses": [],
"assignedPlans": [],
"businessPhones": [],
"createdDateTime": "2020-12-17T08:22:17+00:00",
"creationType": "LocalAccount",
"deviceKeys": [],
"displayName": "DevM8",
"givenName": "Dev",
"identities": [
{
"signInType": "emailAddress",
"issuer": "tenantId.onmicrosoft.com",
"issuerAssignedId": "[email protected]",
"@odata.type": "microsoft.graph.objectIdentity"
},
{
"signInType": "userPrincipalName",
"issuer": "tenantId.onmicrosoft.com",
"issuerAssignedId": "[email protected]",
"@odata.type": "microsoft.graph.objectIdentity"
}
],
"imAddresses": [],
"mailNickname": "a2a5dbe2-7ba7-42a4-bd9a-67eb41c05d7e",
"onPremisesExtensionAttributes": {
"@odata.type": "microsoft.graph.onPremisesExtensionAttributes",
"extensionAttribute1": null,
"extensionAttribute2": null,
"extensionAttribute3": null,
"extensionAttribute4": null,
"extensionAttribute5": null,
"extensionAttribute6": null,
"extensionAttribute7": null,
"extensionAttribute8": null,
"extensionAttribute9": null,
"extensionAttribute10": null,
"extensionAttribute11": null,
"extensionAttribute12": null,
"extensionAttribute13": null,
"extensionAttribute14": null,
"extensionAttribute15": null
},
"onPremisesProvisioningErrors": [],
"otherMails": [],
"passwordPolicies": "DisablePasswordExpiration",
"provisionedPlans": [],
"proxyAddresses": [],
"refreshTokensValidFromDateTime": "2020-12-17T08:22:16+00:00",
"signInSessionsValidFromDateTime": "2020-12-17T08:22:16+00:00",
"surname": "M",
"userPrincipalName": "[email protected]",
"userType": "Member",
"id": "a2a5dbe2-7ba7-42a4-bd9a-67eb41c05d7e",
"@odata.type": "microsoft.graph.user",
"deletedDateTime": null,
"ageGroup": null,
"city": null,
"companyName": null,
"consentProvidedForMinor": null,
"country": null,
"department": null,
"employeeId": null,
"employeeHireDate": null,
"employeeOrgData": null,
"employeeType": null,
"faxNumber": null,
"infoCatalogs": [],
"isManagementRestricted": null,
"isResourceAccount": null,
"jobTitle": null,
"legalAgeGroupClassification": null,
"mail": null,
"mobilePhone": null,
"onPremisesDistinguishedName": null,
"officeLocation": null,
"onPremisesDomainName": null,
"onPremisesImmutableId": null,
"onPremisesLastSyncDateTime": null,
"onPremisesSecurityIdentifier": null,
"onPremisesSamAccountName": null,
"onPremisesSyncEnabled": null,
"onPremisesUserPrincipalName": null,
"passwordProfile": null,
"postalCode": null,
"preferredDataLocation": null,
"preferredLanguage": null,
"showInAddressList": null,
"state": null,
"streetAddress": null,
"usageLocation": null,
"externalUserState": null,
"externalUserStateChangeDateTime": null,
"extension_185724b7875d4374904106f92b4b951e_FavouriteSeason": "summer",
"extension_185724b7875d4374904106f92b4b951e_mustResetPassword": true,
"extension_185724b7875d4374904106f92b4b951e_LovesPets": true
}
]
AAD-Common Technical profile
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<!-- Demo action required: Provide objectId and appId before using extension properties.
For more information: https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-create-custom-attributes-profile-edit-custom
Action required: Insert objectId and appId here -->
<Metadata>
<Item Key="ApplicationObjectId">90aab09b-721e-4c95-b1e5-52266eb727a4</Item>
<Item Key="ClientId">96e21f60-871b-48a0-867c-404c4ebfa6de</Item>
</Metadata>
</TechnicalProfile>