Enforced password change for breached passwords

This example shows how to enforce a password change in the case of a weak password, by using the Scriptable Step. Upon each end-user login, the script checks via the haveibeenpwned website whether the password has been breached. If yes, the end-user is forced to change their password.

A breached password is a password that has been previously exposed in data breaches. This exposure poses a substantial risk to the end-user's account(s), as the now-known password may be misused in cyber attacks such as credential stuffing or password spraying. Credential stuffing occurs when a malicious person tries out great numbers of breached username/password pairs to fraudulently gain access to a specific user account. Password spraying is a tactic where a hacker attempts to break into multiple target accounts by using the same single breached password.

The script described here prevents the above attacks by forcing the end-user to change their password in the case of a breach. No compromised passwords will be used to access your application, making your system more secure.

  • This is how the script works:
  • Upon end-user login, the script takes the end-user's password and hashes it with SHA1. Thus, the real password is not revealed during the password check.
  • Next, the script sends the first 5 characters of the password hash, i.e., the hash prefix, to the website haveibeenpwned. This website returns the hash suffixes of all known passwords that have the same hash prefix as the end-user's password. The script then checks whether the full hash of the end-user's password matches the full hash of one or more of the returned passwords. If yes, the end-user password has been breached.
  • For more details on how the breach check works, see haveibeenpwned API.

  • If a password breach occurred, an acknowledge message step informs the end-user about the number of breaches, and prompts the end-user to change their password. At the same time, a red flag (step) is raised, which in turn triggers the mandatory password change step.
  • For more information on red flags, see Red flags.

  • If the end-user's password has not been breached, the end-user can log in normally.

Authentication flow

The following graphic shows the authentication flow used in this example.

Scriptable-Step_Enforce-Password-Flow
  1. The authentication flow consists of the following steps:
  2. The flow starts with the default Username Password Authentication Step, where the end-user authenticates with username and password to the application in question.
  3. The script in the Scriptable Step takes the end-user password from the previous step and checks whether the password is insecure and has been breached. The script's output contains two keys: The password_safe Boolean key indicates the secureness of the end-user password. If there has been a breach, the password_breached_count key counts the number of times the password has been breached.
    • If the value of the password_safe key matches the regex pattern ^false$,
      • The Acknowledge Message Step informs the end-user about the number of breaches based on the value of the password_breached_count key, and prompts the user to change their password.
      • Additionally, the Red Flag Raising Step raises a so-called red flag, which triggers the Mandatory Password Change Step.
      • The Mandatory Password Change Step forces the end-user to change their password.
    • If the value of the password_safe key matches the regex pattern ^true$, all three previous steps are skipped.
  4. The authentication flow ends when the end-user either authenticated successfully right away with a secure password (password_safe = true), or when the user successfully changed their password. In both cases, the end-user can access the desired application.
  5. Note that the newly set password is not checked by the script.

See further below how to configure the above mentioned steps (except the Username Password Authentication Step).

Prerequisites

To run the script used in this example, you need to install the following Lua libraries in the IAM instance directory:

  • Lua-cURL: This Lua shared library sends and receives REST requests from a Lua script.
  • Lua sha1: This Lua module computes SHA-1 and HMAC-SHA1 signature computations in Lua.

Both libraries can be installed with the Luarocks package manager, which you can download from here: https://luarocks.org/.

  • To install the Lua-cURL and the Lua sha1 libraries in the instance directory, execute the following commands:
  • copy
    luarocks install --tree $IAM_instance_dir/scripting/lua lua-cURL
    copy
    luarocks install --tree $IAM_instance_dir/scripting/lua sha1

Configuring the Scriptable Step

This section explains how to configure the Scriptable Step used in our example. This step checks if the password entered by the end-user upon login is secure or if it has been breached, based on a script.

  1. Proceed as follows:
  2. Go to:
    Loginapp >> Application and Authentication >> <application in question> >> Authentication Flow
  3. In section Basic Settings, in property Steps, create and edit a Scriptable Step plugin, as follows:
  4. Specify the plugin's identifier in the Identifier field, e.g., Password-breach-check_Scriptable-Step.
  5. In section Basic Settings, in property Input Map, create a User Passwords Map plugin.
  6. In section Basic Settings, in field Script, add the following Lua script:
  7. Show moreShow lesscopy
    local curl = require('cURL') 
    local sha1 = require("sha1") 
     
    function iam_on_step_init () 
        iam.output_map = {} 
        local fullHash = string.upper(sha1.sha1(iam.input_map["PASSWORD"])) 
        local hashPrefix = string.sub(fullHash, 1, 5) 
     
        -- https://haveibeenpwned.com/API/v3#SearchingPwnedPasswordsByRange 
        local response, responseCode = performPwndCheck(hashPrefix) 
     
        if response == "" and responseCode == 200 then 
            return { password_safe = true, password_breached_count = 0 } 
        else 
            suffixes = parseResponse(response) 
            for i = 1, #suffixes do 
                local currentSuffix = string.sub(suffixes[i], 1, 35) 
                if currentHashEqualsInitialHash(hashPrefix .. currentSuffix, fullHash) then 
                    local currentBreachCount = tonumber(string.sub(suffixes[i], 37)) 
                    return { password_safe = false, password_breached_count = currentBreachCount } 
                end 
            end 
            return { password_safe = true, password_breached_count = 0 } 
        end 
    end 
     
    function performPwndCheck(prefix) 
        local c = curl.easy { url = 'https://api.pwnedpasswords.com/range/' .. prefix } 
        local body = {} 
        c:setopt_writefunction(table.insert, body) 
        c:perform() 
        return table.concat(body), c:getinfo_response_code() 
    end 
     
    function parseResponse(response) 
        hashes = {} 
        for line in response:gmatch("[^\n]+") do 
            table.insert(hashes, line) 
        end 
        return hashes 
    end 
     
    function currentHashEqualsInitialHash(currentHash, initialHash) 
        return string.upper(currentHash) == initialHash 
    end
  8. In section Basic Settings, in property Output Map, configure two Script Output Declaration plugins, as follows:
    • First Script Output Declaration plugin:
    • Specify the plugin's identifier in the Identifier field, e.g., NUMBER-script-output-declaration-plugin.
    • In property Output Value Type, select NUMBER.
    • Enable the Required property (this is the default setting).
    • Return to the Scriptable Step dialog. In property Output Map, field Key, enter password_breached_count as key for the just created Script Output Declaration plugin NUMBER-script-output-declaration-plugin.
    • Second Script Output Declaration plugin:
    • Specify the plugin's identifier in the Identifier field, e.g., BOOLEAN-script-output-declaration-plugin.
    • In property Output Value Type, select BOOLEAN.
    • Enable the Required property (this is the default setting).
    • Return to the Scriptable Step dialog. In property Output Map, field Key, enter password_safe as key for the just created Script Output Declaration plugin BOOLEAN-script-output-declaration-plugin.
  9. You have now configured a scriptable step that checks if the password entered by the end-user upon login is secure or if it has been breached.

Configuring the Acknowledge Message Step

This section explains how to configure the Acknowledge Message Step used in our example. If the execution of the script indicates that the end-user's password is insecure, this step informs the end-user about the number of breaches, and prompts the end-user to change their password.

  1. Proceed as follows:
  2. Go to:
    Loginapp >> Application and Authentication >> <application in question> >> Authentication Flow
  3. In section Basic Settings, in property Steps, create and edit an Acknowledge Message Step plugin, as follows:
  4. Specify the plugin's identifier in the Identifier field, e.g., Password-breach-check_Acknowledge-Message-Step.
  5. In section Basic Settings, property Server Message, create and edit a Template-based String Provider plugin, as follows:
    • Specify the plugin's identifier in the Identifier field, e.g., Password-breach-check_Message-template.
    • In property Value Map Providers, create a Script Execution Result Value Map Provider plugin. This plugin will provide the value for the password_breached_count variable used in the Template field below. The plugin takes the value from the password_breached_count key in the script execution result.
      • Specify an identifier for the Script Execution Result Value Map Provider plugin in the Identifier field, e.g., Password-breach-check_Script-execution-result-value-map-provider.
    • Return to the Template-based String Provider plugin dilalog. In field Template, enter the text that will be shown to the end-user if their password has been breached and thus insecure, and must be changed. In this example, the following text is used:
    • Your password is not secure. It has been breached ${password_breached_count} times. You have to change it.

      In our example, the acknowledge message is in English only. But Airlock IAM also supports multi-language setups. To provide the acknowledge message in another language, enter a suitable message ID in the property Message ID, section Basic Settings of the Acknowledge Message Step plugin dialog. Refer to this message ID in the relevant language .properties file used for UI translations in the Loginapp Design Kit. For more information, see Customizing Loginapp UI texts and changing translations with the Loginapp Design Kit.

  6. Return to the Acknowledge Message Step plugin dialog. In section Tags/Guards, the property Skip Condition defines the condition that must be fulfilled to skip this step. This is the case when the end-user's password is secure, and the script outcome key password_safe has value true. To configure the corresponding condition, create and edit a String Regex Condition plugin in property Skip Condition, as follows:
    • Specify the plugin's identifier in the Identifier field, e.g., Password-is-safe_String-Regex-Condition.
    • The property Value Provider defines the value provider delivering the value for the condition check. Here, create and edit a String From Map Value Provider, as follows:
      • Specify the plugin's identifier in the Identifier field, e.g., Password-breach-check_String-from-map-value-provider.
      • In the dropdown list of property Value Maps, select the Script Execution Result Value Map Provider plugin you created previously (with the name Password-breach-check_Script-execution-result-value-map-provider). This plugin provides the result of the script execution.
      • In property Key, enter password_safe. The value of this key after script execution is used as input for the condition check.
    • Return to the String Regex Condition plugin dialog. In property Regex Pattern, enter ^true$. If the value of the password_safe key matches this pattern, the condition to skip this Acknowledge Message Step is fulfilled.
  7. Return to the Acknowledge Message Step plugin dialog.
  8. You have now configured an acknowledge message step. If the execution of the script indicates that the end-user's password is secure, this step will be skipped. However, if the script execution indicates that the end-user's password has been breached, this step will inform the end-user about the number of breaches, and prompts the end-user to change their password.

Configuring the Red Flag Raising Step

This section explains how to configure the Red Flag Raising Step used in our example. If the execution of the script indicates that the end-user's password is insecure, this red flag raising step raises a red flag, which triggers the mandatory password change step.

  1. Proceed as follows:
  2. Go to:
    Loginapp >> Application and Authentication >> <application in question> >> Authentication Flow
  3. In section Basic Settings, in property Steps, create and edit a Red Flag Raising Step plugin, as follows:
  4. Specify the plugin's identifier in the Identifier field, e.g., Password-breach-check_Red-Flag-Raising-Step.
  5. In section Basic Settings, the property Condition defines the condition that must be fulfilled to raise the red flag. This is the case when the end-user's password is insecure, and the script outcome key password_safe has value false. To configure the corresponding condition, create and edit a String Regex Condition plugin in property Condition, as follows:
    • Specify the plugin's identifier in the Identifier field, e.g., Password-not-safe_String-Regex-Condition.
    • The property Value Provider defines the value provider delivering the value for the condition check. In the dropdown list, select the String From Map Value Provider you created previously (with the name Password-breach-check_string-from-map-value-provider).
    • In property Regex Pattern, enter ^false$. If the value of the password_safe key matches this pattern, the condition to raise the red flag is fulfilled.
  6. Return to the Red Flag Raising Step plugin dialog. The property Red Flag defines the red flag that must be raised if the above condition is fulfilled. Here, create a Mandatory Password Change Red Flag plugin, as follows:
    • Specify the plugin's identifier in the Identifier field, e.g., MANDATORY_PASSWORD_CHANGE-red-flag.
    • In property Name, keep the default name for the red flag (which is MANDATORY_PASSWORD_CHANGE).
  7. You have now configured a red flag raising step. If the execution of the script indicates that the end-user's password is insecure, this step raises a red flag, which triggers the mandatory password change step.

Configuring the Mandatory Password Change Step

This section explains how to configure the Mandatory Password Change Step used in our example. If the execution of the script indicates that the end-user's password is insecure, this step forces the end-user to change their password.

  1. Proceed as follows:
  2. Go to:
    Loginapp >> Application and Authentication >> <application in question> >> Authentication Flow
  3. In section Basic Settings, in property Steps, create and edit a Mandatory Password Change Step plugin, as follows:
  4. Specify the plugin's identifier in the Identifier field, e.g., Password-breach-check_Mandatory-Password-Change-Step.
  5. The sections Basic Settings and Advanced Settings define the settings of the password change. Proceed as follows:
    • Section Basic Settings, property Password Repository: Select Default Password Repository.
    • Section Basic Settings, property Null Password Policy: Leave the default setting unchanged.
    • Section Basic Settings, property Old Password Attempts: Define the allowed number of failed attempts for the old password before the Mandatory Password Change flow will be aborted. This property is relevant if the Old Password Required property is enabled (see next).
    • Section Basic Settings, property Old Password Required: If enabled (default), the end-user must first enter their old password before they can change it.
    • To improve the end-user experience, you could disable the Old Password Required property. Note that in this case, you must use the same key (PASSWORD) in the Password Attribute Key property for both this Mandatory Password Change Step and the Username Password Authentication Step. The Password Attribute Key property is in the Advanced Settings section.

    • Section Advance Settings, property Authentication Method lD: Leave the default setting (PASSWORD) unchanged.
    • Section Advance Settings, property Password Attribute Key: This property is required if the Old Password Required property is disabled. In this case, ensure using the same key here (PASSWORD) as the one used for the Password Attribute Key property in the Username Password Authentication Step.
  6. In section Tags/Guards, in property Red Flag, select the previously created Mandatory Password Change Red Flag (with the name MANDATORY_PASSWORD_CHANGE-red-flag) from the dropdown list. This red flag will be deactivated ("lowered") when the Mandatory Password Change Step is executed.
  7. You have now configured a mandatory password change step.
  8. Activate your configuration.
  9. You have now configured an authentication flow that enforces a password change in the case of a weak password, by using the Scriptable Step.