Writing Lua scripts for the Scriptable Step

This page explains how to integrate Lua scripts in the Scriptable Step plugin. For more information on Lua itself see The Programming Language Lua.

The following configuration properties/fields are available in the Scriptable Step plugin:

Property

Mandatory

Description

Inputs

optional

List of value map providers that provide input values for the Lua script.

Script

mandatory

Source code of the Lua script.

Outputs

optional

List of keys and data types to return values to Airlock IAM.

Multiple scripting steps can segregate their return values by assigning their results to different namespaces.

Input Secrets

optional

Secrets (that is, sensitive configuration values) can be provided to a script through environment variables. In the script context, secrets only exist in the IAM server. The script developer is responsible for avoiding leaking secrets.

Namespace

optional

Namespace for output values to segregate output from multiple Lua scripts.

Logging

The scripting language is extended with an iam.log directive that logs into the Airlock IAM log.

Output

For a script to return output values to Airlock IAM, you must configure a list of keys and corresponding data types in the Outputs property and specify whether the key is required (mandatory).

The Outputs property exists of two parts:

  • The key of a key-value output pair, set in the Key property.
  • The expected data type(s) of a key-value pair, declared in the Script Output Declaration plugin. This plugin also defines whether the key-value pair is required (mandatory).

To integrate a script correctly, the following conditions must be met:

  • The script must return all mandatory keys.
  • The script cannot return undeclared keys.
  • The data types of the output values must match the declaration.
  • If the Outputs property is not configured, the return statement is optional.

If one of these conditions is not met, an error will result, and the flow will be terminated as failed.

Output data types

IAM supports the following data types for script output values:

  • STRING: Any variable-length UTF-8 character sequence.
  • BOOLEAN: Either true or false. Binary digits are not allowed.
  • NUMBER: An integer (64-bit constraints). Floating point values are currently not supported.
  • DATE_TIME: An integer-type Unix timestamp in milliseconds.
  • DATE: A valid date string in the format yyyy-MM-dd (e.g., 2021-06-04).

Output elements

The script output values can be provided in various output elements. Output elements define the type and structure of the script output, such as lists, maps, or a single output value. You can combine these output elements at will. This allows for highly structured and nested output values, e.g., a list of roles for users.

When specifying the Script Output Declaration plugin, you in fact set the output element of the script.

IAM currently supports the following script output elements:

  • List (List Output Element plugin):
    Defines a list as script output. The size of the list is variable, and each element in the list must match the declared type.
  • Map (Map Output Element plugin):
    Defines a key-value map element as script output. Two mutually exclusive modes are supported:
    • Key-value mode: The key-value pairs of the map are explicitly predefined, but each value may be a different type. Use this mode when keys are known and data types differ.
    • Uniform mode: The map may contain a variable number of output values, but each entry must have the same type. This mode does not require keys. Use this mode when keys are dynamic and/or not known in advance, but data types are the same.
  • Simple (Simple Output Element plugin)
    Defines a simple script output type, such as numbers, strings, dates, or booleans.

Some output examples:

  • Output 1: A list of roles, where each role is defined as a STRING output type:
  • roles = {“roleA”, “roleB”, “roleC”}

  • This output corresponds with the following settings in the Outputs property of the Scriptable Step plugin:

    • Key: roles
    • Script Output Declaration plugin:
      • Output Type: List Output Element
      • Type: Simple Output Element, with data type STRING.
  • Output 2: A uniform map, where each value pair provides an NUMBER output value:
  • uniform_map_example = {valueA = 1, valueB = 2, valueC = 3}

  • This output corresponds with the following settings in the Outputs property of the Scriptable Step plugin:

    • Key: uniform_map_example
    • Script Output Declaration plugin:
      • Output Type: Map Output Element
      • Uniform Declaration: Simple Output Element, with data type NUMBER.
  • Output 3: A key-value map, with predefined key-value pairs whose output values are of different types, for example, an NUMBER value and a list of roles (see below):
  • explicit_map_example = {firstEntry = 1, secondEntry = {“roleA”, “roleB”, “roleC”}

  • This output corresponds with the following settings in the Outputs property of the Scriptable Step plugin:

    • Key: explicit_map_example
    • Script Output Declaration plugin:
      • Output Type: Map Output Element
      • Key Value Declaration:
      • Row 1

        • Key: firstEntry
        • Script Output Declaration plugin: Simple Output Element as Output Type, and NUMBER as data type.
      • Row 2

        • Key: secondEntry
        • Script Output Declaration plugin: List Output Element as Output Type, then Simple Output Element es Type and STRING as data type.
 
Notice

For the examples following below, configure the Outputs property as follows:

  • Key: full_name
  • Script Output Declaration plugin:
    • Output Type: Simple Output Element, with
    • Type: STRING

Script

To successfully run a script in the scriptable step plugin, at least the following function must be defined in the script property:

 
Example
function iam_on_step_init ()
    <your code>
    return iam.output_map
end

The iam_on_step_init() function is called by IAM when starting the execution of a script.

Input

Input values are configured in the scriptable step plugin through value map providers. For this purpose, Airlock IAM provides a large number of plugins. Refer to the plugin documentation for further information on a particular value map provider.

All the examples in this text configure the Inputs property with a Context Data Map plugin. To read a context data item, the iam.input_map[<key>] table must be used in the script code.

The following example shows how a user's givenname and surname are concatenated into a property full_name. This property is then logged and finally returned to IAM for further use.

 
Example
function iam_on_step_init ()
    iam.output_map = {}
    iam.output_map["full_name"] = iam.input_map["givenname"] .. " " .. iam.input_map["surname"]
    iam.log:info("User with full name: " .. iam.output_map["full_name"])
    return iam.output_map
end

If multiple value map providers contain a key with the same name, the value from the last value map provider will overwrite previous values.

Optional input values

When configuring value provider maps with optional values, it is the script's responsibility to check whether a particular value is present. In case of a missing value, the iam.input_map[<key>] will return the value nil.

The following code example will check if the key givenname is present or not:

 
Example
if (iam.input_map["givenname"] ~= nil) then
   <logic if given name is present>
else
   <logic if given name is absent>
end

List all values provided to the script

The following code snippet will iterate over the table of input values provided to the script and output them to the IAM logfile:

 
Example
for k, v in pairs(iam.input_map) do
    iam.log:info("key : " .. k .. ", value: " .. v)
end 

The following code snippet will achieve the same result, with less formatting:

 
Example
 iam.log:info("Complete input map of GET request step: " .. iam.cjson.encode(iam.input_map))

Input Secrets

Use the Input Secrets property to provide sensitive values to a Lua script. Sensitive values are transferred to the Lua script as environment variables. In the script, these values can be accessed through the IAM API function local secret = iam.secrets:get(<secretId>).

Once made available within the Lua script, secrets are retrieved as plaintext. The script developer is responsible for ensuring that secrets are not leaked (e.g., not logged).

The secretId can only consist of alphanumeric and underscore characters.

Namespaces

Namespaces are optional. They are used to assign a name to the value map from the output of a script. This may be necessary if multiple scripts in the same flow can return an output value with the same key.

If no namespace is configured, the default namespace is used. If several steps return the same key into the default namespace, the value of the scripting step executed last will overwrite the previous value.

Lua API functions

The Lua scripting language provides several built-in functions and types.

The ​print() function has been modified for Airlock IAM. It now writes messages to the appropriate Airlock IAM logfile with severity DEBUG.

All other built-in functions and types remain as implemented and documented by Lua.

Care should be taken when using the os object or functions like load(), loadfile(), or dofile(). These functions may have security-relevant side effects as they are run with the IAM user's permissions and can access processes and file system objects.

IAM API functions

Airlock IAM provides additional and IAM-specific functions for scripting with Lua:

Function

Description

iam.input_map[<key>]

This table contains all the key-value pairs provided to the script by configuring the Input Value Providers. Use the iam.input_map[<key>] key to access the value within the table.

Date-time values include the precise time of day and are represented as a Unix timestamp with millisecond precision. Date values exclude the time, and are specified as strings in the format yyyy-MM-dd.

Note: If no value is present, “nil” is returned.

iam.log:debug(message)

iam.log:info(message)

iam.log:warn(message)

iam.log:error(message)

Use these functions to write messages to the Airlock IAM Log4J log files. The severity of the log message is determined by the function used in the script.

All log message output of a Lua script will be prefixed with LuaScriptInterpreter:

The iam.log function will convert values of data types other than a string to the closest representation of a string value. Tables will be converted to JSON. If a conversion is not possible, type and memory address will be logged (e.g. function: 0x55c4f3eeb220).

Logging uses the standard error output stream. If the script or a library used in the script directly writes to standard error, this will be interpreted as an error message with severity ERROR.

Data written to standard output will be ignored.

iam.secrets:get(<secretId>)

This function retrieves a value from secret storage and returns it as plaintext to the script.

The key and value of secrets are defined in the IAM configuration.

If the value is not present, “nil” is returned.

iam.cjson

This is an alias for the bundled lua-cjson library, which transforms lua tables into JSON strings.

It is used implicitly by other IAM API functions.

See Lua CJSON 2.1.0 Manual for more details.

Error handling

The Config Editor does not verify the correctness of the Lua script syntax or semantics during configuration activation.

The following behavior is to be expected:

Syntax error

Syntax errors will be reported before the scriptable step is executed. The step will fail, and an error will be reported in the IAM log.

Runtime error

Runtime errors will be reported if the error occurs during the execution of the scriptable step. The step will fail, and an error will be reported the IAM log.

We recommended testing custom scripts before they are deployed with Airlock IAM.

The scriptable step supports the following error codes:

Error code

Description

20

A syntax error is present in the script source.

21

A runtime error occurred.

This type of error is printed together with a Lua stack trace, showing the cause and location of the error.

22

The value returned by the iam_on_step_init() has an incorrect data type.

iam_on_step_init() always expects a result of data type table.

24

The value returned by the iam_on_step_init() function cannot be written to the IAM value map.

This error occurs when data (e.g., a function reference) inside the expected output cannot be converted to a string.

27

An error occurred when using the IAM API functions (e.g. trying to access a secret using an identifier that isn't a string).

126

This error occurs if the ​operating system cannot execute the lua executable or if one of the shared libraries cannot be used.

-

If a script does not terminate within 30 seconds, the script is aborted, and the following message is written with severity ERROR to the logfile:

ScriptableStep: Scriptable Step failed: The process was interrupted due to timeout of the script.

Further information and links

External links: