Validating the user password selection in Azure AD B2C by invoking Troy Hunt’s “Pwned Passwords” API
I recently gave a presentation on Azure AD B2C custom policies.
The collateral for the demo. is on Github pages.
As part of this, I was looking for a killer demo. to demonstrate a B2C SignInSignUp user journey calling a REST API from custom policies during a sign-up flow.
In Azure AD, if you pick a new password that is suspect because it appears in so many breaches (e.g. “Password123”), you get a message saying:
“We’ve seen this password too many times. Please pick a more secure one”
This feature is not yet on B2C and I realised that I could implement this using “Pwned Passwords”.
This is described in much more detail here.
This is invoked by the API:
Essentially, you hash the password using SHA1 and then use the first five digits as the hash prefix.
This is just a part of it but essentially each line is the rest of the hash (i.e. minus the first five characters) and the number of times each hash has appeared in a breach.
We could use this by having B2C call an Azure webAPI (a REST API) and the REST API could then call api.pwnedpasswords.com.
The TrustFrameworkExtensions.xml custom policy (in the collateral above) looks like:
The “ServiceURL” contains the URL of the web API.
There is no authentication so “AuthenticationType” is “None”.
It’s a GET request so we send the claims in the “QueryString”.
We map “NewPassword” to “password” so the API call looks like:
The user journey calls “LocalAccountSignUpWithLogonEmail”
We extend this technical profile by adding a validation technical profile that calls the “REST-API-PwnedPassword” technical profile and this calls the Azure web API.
The Azure webAPI code (in the collateral above) is:
So we hash the password, send off the first five characters to the API, get the response and then search for the rest of the hash. Once we get the correct line, we get the number of times that password has appeared in a breach.
If it has appeared, we send an error message back to B2C with a “ HttpStatusCode.Conflict” code that tells B2C to display the error and stop the user journey.
The technical profile “LocalAccountSignUpWithLogonEmail” has two claims added to it.
<! — Optional claims, to be collected from the user →
<OutputClaim ClaimTypeReferenceId=”extension_ugName” />
<OutputClaim ClaimTypeReferenceId=”extension_ugVenue” />
As this is a self-asserted technical profile (i.e. the user is expected to provide some input), these fields will appear on the sign-up form.
Let’s see what happens when we run the sign-up journey.
We’ve added some branding so we see:
We click “Sign up now”:
Notice the two new textboxes containing the user group information “ugName” and “ugVenue”.
We use password “Password123”.
And we get the “Pwned Password” error!
If we enter a password that has not appeared in a breach, we get the JWT back with the user group fields.