User-based IP restrictions

The goal of this example is to enforce user-based IP restrictions using a Scriptable Step. The solution has the following properties:

  • The allowed IP address is stored in CIDR format as a context data item for each user individually.
  • This context data item can be set per user in the Profile tab of the Adminapp.
  • The scriptable step will determine if the actual IP address of the user device matches the CIDR provided in the context data item.
  • A failure step is used to terminate the flow if the user's IP address does not match the CIDR in the context data item.
  • The flow will continue normally if no IP restriction is set in the context data item.

Prerequisites

To run the example script on this page, you need to install the additional library cidr.lua in the instance directory. cidr.lua is a Lua library to handle CIDR formatted IP addresses. It can be downloaded from CIDR library on github.

  1. To install the cidr.lua library in the instance directory, execute the following command:
  2. copy
    cp cidr.lua $IAM_instance_dir/scripting/lua/share

Scriptable step

In this example, the Scriptable Step uses a Context Data Map and a HTTP Request Information Map as input to check if the IP address of the user device matches the pattern provided in the context data.

  1. Proceed as follows:
  2. Go to:
    Loginapp >> Application and Authentication >> Default Application >> Authentication Flow
  3. In property Steps, create and edit a Scriptable Step plugin, as follows:
  4. In property Input Map, create a Context Data Map plugin and a HTTP Request Information Map plugin.
  5. In field Script, add the following Lua code:
  6. Show moreShow lesscopy
    -- Example script checks a context data item ipv4_restriction against the current ipv4_address
    function iam_on_step_init ()
        local cidr = require 'cidr'
        local ip_and_range = iam.input_map["ipv4_restriction"]
        if (ip_and_range == nil) then
            iam.log:info("No user-specific restriction on IP address enforced. IP address is considered in range")
            return { ip_in_range = "yes" }
        end
        iam.log:info("Read user-specific IP address restriction: " .. ip_and_range)
        local network = cidr:network(ip_and_range)
        
        local user_ip = iam.input_map["client-ip-v4"]
        if (user_ip == nil) then
           iam.log:info("IAM was not able to determine the IP address of the client. IP address is considered in range")
           return { ip_in_range = "yes" }
        end
        iam.log:info("Checking ip address " .. user_ip)
        local is_in_range = network:match(user_ip)
        if is_in_range then
            iam.log:info("User IP address '" .. user_ip .. "' is in range")
            return { ip_in_range = "yes" }
        end
        iam.log:info("User IP address '" .. user_ip .. "' is NOT in range")
        return { ip_in_range = "no" }
    end
  7. In property Output Map, create a new row:
    • Set ip_in_range as Key, and
    • Add the Script Output Declaration plugin as Plugin, and edit it as follows:
      • In property Output Value Type, enter "STRING".
      • Enable the Required property (this is the default setting).
  8. You have now configured a scriptable step that checks if the actual IP address of the user matches the allowed IP address set for this user.

Failure step

Next, configure a Failure Step. This step uses the script execution result from the above scriptable step to determine whether to stop the authentication flow. It checks if the value of script output/key ip_in_range matches the regex pattern ^yes$. If this is the case, the IP address of the user device matches the CIDR provided in the user's context data. Consequently, the failure step is skipped and the authentication flow can continue normally.

  1. Proceed as follows:
  2. Go to:
    Loginapp >> Application and Authentication >> Default Application >> Authentication Flow
  3. In property Steps, create and edit a Failure Step plugin, as follows:
  4. In section Basic Settings and in property Error Code, enter an error code that specifies the reason for aborting the authentication flow, e.g., FLOW_ABORTED_INTENTIONALLY. The error code will be included in the response.
  5. In section Basic Settings and in property Authentication Method Identifier, enter the identifier of the authentication method, e.g., PASSWORD. The failed attempts counter of this authentication method will be increased when the flow is terminated.
  6. In section Tags/Guards and in property Skip Condition, create and edit a String Regex Condition plugin:
    • In property Value Provider of the String Regex Condition plugin, create and edit a String From Map Value Provider plugin:
      • In property Value Maps, add a Script Execution Result Value Map Provider plugin.
      • In property Key, enter ip_in_range.
    • Return to the String Regex Condition plugin. In property Regex Pattern, enter ^yes$. This is the regex pattern to match with the script output value.
  7. You have now configured a failure step that will be skipped if the script output confirms "ip_in_range = yes". In every other case, the failure step will terminate the authentication flow and the PASSWORD failure counter will be increased.