How to Customize Password Validation

How to Customize Password Validation

tutorials

The Curity Identity Server does not have password strength validation active by default for creating new accounts using the registration feature of the HTML Form authenticator. This article covers how to enable password validation using a Validation Procedure. It also shows how to update the frontend with a strength indicator while typing a password.

The policy that will be enforced requires four out of these five criteria to be true. A password should:

  • have the minimum length of eight (8) characters
  • have at least one lower case character
  • have at least one upper case character
  • have at least two digits
  • have at least one special character

Prerequisites

You will need an installation of the Curity Identity Server with the basic setup completed. Follow the Getting Started Guides to achieve this. Alternatively, if you have a system up and running with your own configuration, you can use that as well. Just be aware that you probably have different names for certain components.

Enabling Backend Validation

The Curity Identity Server uses Validation Procedures for input validation. Validation procedures can be used for many purposes but are typically added during authentication or registration. A procedure is written in JavaScript.

Create Validation Procedure

Create a procedure by using the Admin UI. Click on System->Procedure->New procedure.

Give it the name password-strength and make sure the type is validation-procedure.

Insert the following code:

function result(validationContext) {
    var errors = {};

    var password = validationContext.request.getFormParameter("password");
    
    if (checkStrength(password) < 4) {
        errors.strength = "weakpassword";
    }
    
    return errors;
}

function checkStrength(enteredPassword) {
    var length = /(.{8,})/;
    var upperCase = /(.*[A-Z])/;
    var lowerCase = /(.*[a-z])/;
    var digit = /(.*[0-9].*[0-9])/;
    var specialChar = /([^A-Za-z0-9])/;

    var points = 0;
    if (length.test(enteredPassword)) {
        points++;
    } 
    if (upperCase.test(enteredPassword)) {
        points++;
    } 
    if (lowerCase.test(enteredPassword)) {
        points++
    } 
    if (digit.test(enteredPassword)) {
        points++;
    } 
    if (specialChar.test(enteredPassword)) {
        points++;
    }

    return points;
}

The result() function will be called with a context once the procedure is executed. A validation is considered successful if there are no errors returned. An error returned refers to a message key, in this case, weakpassword. This key is used to present a localized error message which will be declared later.

Assigning the Validation Procedure

Assign the validation procedure to an authenticator to activate password validation during account registration. Click on Authenticators and select the authenticator to update; in this example, username-password. Expand the Advanced configuration section. Under Request Validation, click on Add and enter the following values:

Request SubpathEndpointHTTP MethodValidation Procedure
indexauthentication-service-registrationpostpassword-strength

The password-strength validation procedure will get executed when an HTTP POST request receives the registration endpoint through the username-password authenticator.

Add a New Message

The frontend will display the message corresponding to the message key sent by the validation procedure. Since weakpassword is a new key, the message for each supported language has to be updated. In this example, only English will be updated.

To add a new message, copy the existing messages into the overrides directory.

cp $IDSVR_HOME/usr/share/messages/core/en/messages \
$IDSVR_HOME/usr/share/messages/overrides/en/

Then open $IDSVR_HOME/usr/share/messages/overrides/en/messages and add:

authenticator.html-form.create-account.weakpassword=Password is not complex enough

Update Frontend

With the backend in place, it is only possible to set a password that meets the requirements. Otherwise, the backend throws an error.

The standard registration page already has a progress bar showing password strength, but it does not match the new policy of the validation procedure. This section describes how to control that progress bar and add an extra checkmark when the password is strong enough.

Create a fragment called password-ok.vm in the overrides/fragments directory.

mkdir $IDSVR_HOME/usr/share/templates/overrides/fragments
touch $IDSVR_HOME/usr/share/templates/overrides/fragments/password-ok.vm

In that file, add the following content:

<style $!nonceAttr>
.password-group-ok {
    position: relative;
}
.password-group-ok .progress {
    width: calc(100% - 28px);
}
.password-group-ok::after {
    content: '\f120';
    font-family: 'Ionicons';
    color: #57C75C;
    font-size: 1rem;
    width: 18px;
    height: 18px;
    position: absolute;
    right: 0;
    bottom: -4px;
    z-index: 1;
}
</style>
#parse("fragments/jquery")
<script $!nonceAttr>
$(window).on('load', () => { 
    var passwordField = $("input[type='password']");
    passwordField.off();
    passwordField.on("input", passwordValidation)
});

function passwordValidation() {
    var passwordField = $("input[type='password']");
    var strength = checkStrength(passwordField.val());
    setBar(strength);
}

function checkStrength(enteredPassword) {
    var length = /(.{8,})/;
    var upperCase = /(.*[A-Z])/;
    var lowerCase = /(.*[a-z])/;
    var digit = /(.*[0-9].*[0-9])/;
    var specialChar = /([^A-Za-z0-9])/;

    var points = 0;
    if (length.test(enteredPassword)) {
        points++;
    } 
    if (upperCase.test(enteredPassword)) {
        points++;
    } 
    if (lowerCase.test(enteredPassword)) {
        points++
    } 
    if (digit.test(enteredPassword)) {
        points++;
    } 
    if (specialChar.test(enteredPassword)) {
        points++;
    }

    return points;
}

function setBar(value) {
    var allColors = ("progress-success progress-info progress-warning progress-danger");
    var bar = $("div.progress div[role='progressbar']");
    var passwordGroup = $("div.password-group");
    bar.removeClass(allColors);
    passwordGroup.removeClass("password-group-ok");
    value *= 20;
    if (value < 33) {
        bar.addClass("progress-danger");
    }
    else if (value < 66) {
        bar.addClass("progress-warning");
    }
    else {
        bar.addClass("progress-success");
        passwordGroup.addClass("password-group-ok");
    }

    bar.width(value + "%");
} 
</script>

This fragment contains everything needed, both CSS and JavaScript. The CSS is to create a green checkmark once the password is strong enough. The JavaScript takes care of overriding the progress bar’s existing functionality and applying the new policy to it.

Reuse of code

Notice how checkStrength() is reused from the Validation Procedure.

Include this fragment into the registration template of the HTML form authenticator.

Create a folder structure and copy the original template to the overrides folder.

mkdir -p $IDSVR_HOME/usr/share/templates/overrides/authenticator/html-form/create-account/
cp $IDSVR_HOME/usr/share/templates/core/authenticator/html-form/create-account/get.vm \
$IDSVR_HOME/usr/share/templates/overrides/authenticator/html-form/create-account/

Open get.vm in the overrides folder and add the fragment before the form element.

#define($_body)
#parse("fragments/password-ok")<form method="post" class="login-form">

Try It Out

With both the frontend and backend in place, you can now try out the validation procedure. Click on Create Account when using the username-password authenticator. Observe how the progress bar changes when entering a password. When the password is strong enough, the bar turns green, and the checkmark appears. If you choose to create an account with a weak password, the backend will return an error indicating that the password is not complex enough.

Upgrade

When the Curity Identity Server is upgraded, the files in the overrides folder are copied into the new system directly or added to a custom Docker image. The validation procedure is included in the backed-up configuration data. This makes it straightforward to maintain custom logic over time.

Conclusion

This tutorial covered how to use a custom validation procedure for password validation, but a validation procedure can validate any input. For example, the procedure could check that the user agrees to the terms when creating an account.

The updated UI will indicate when a password is strong, but it does not prevent the user from trying to create an account with a weak password. This could be changed for a better user experience by disabling buttons, for example.

Keep up with our latest articles and how-tos RSS feeds.