PingAM 8.0.0

Custom scripted nodes

With AM’s Node Designer, you can create your own node types to reuse common functionality in journeys. Define node properties and run custom server-side scripts in these nodes to dynamically set values and decide the outcome of authentication journeys.

To write a script for your custom node, you can use any of the next-generation script bindings available to the Scripted Decision node API, including httpClient, idRepository, and openidm.

For example, use the Node Designer to create node types that perform functions such as:

  • Updating email addresses for users based on their location

  • Adding users to a particular group

  • Generating a JWT and stores it in shared state

New node types appear in the Components panel of the tree designer ready for you to include in your authentication journey with a simple drag and drop.

You can also share the functionality by exporting your custom node type and importing it into a different environment.

Library scripts aren’t supported for use with custom scripted nodes. Custom scripted nodes are designed to be self-contained units so that you can import and export them. Import and export functionality isn’t compatible with library scripts.

Design secure nodes

Before you start creating custom scripted nodes, read the following points of best practice to make sure your custom nodes are as secure as possible.

Don’t add sensitive data to shared state

Store sensitive information such as passwords in secrets.

Sanitize input data

Remove sensitive information before using or storing data.

Don’t log sensitive data

Make sure you don’t output sensitive information to logs.

Find more information in Security considerations.

Create a node type

  1. In the AM admin UI, go to Realms > Realm Name > Authentication > Node Designer and click Create Node Type.

    Custom node types are global objects and don’t belong to a realm, so even if you create a node type in one realm, you can still access it from another realm.

  2. On the New Node Type page, enter a unique service name using lowercase letters or numbers only. Also, enter a suitable name for your node type to be displayed in the tree designer.

    For example, setemployeedetails and Set Employee Details, respectively.

    The service name is a fixed reference to the node type, but you can change the display name later.

  3. In the Node Designer editor, set or review the following fields:

    Field Value

    Display Name

    The name displayed in the tree editor. This provides the default name for new nodes of this type. Must be unique.

    Description

    The description for the node type. The description isn’t displayed in the editor.

    Outcomes

    Enter one or more names for the outcome paths of this node. You can’t name an outcome Script Error because that’s reserved for the Error Outcome path.

    For example, true false.

    Node Inputs

    Optionally, list the node state data available to the node.

    For example, username.

    Default: *

    (The node can access all shared and transient state data)

    Node Outputs

    Optionally, list the data the node outputs to shared state.

    Default: *

    (The node sets all state data)

    Properties

    A JSON object that contains the node configuration. The keys can be accessed from your script through the properties binding. The values depend on the journey configuration.

    For example, this configuration defines properties for an employee’s location and group:

    {
      "emp_group": {                                  (1)
        "title": "Employee group",                    (2)
        "description": "Specify all relevant groups", (3)
        "required": true,                             (4)
        "type": "STRING",                             (5)
        "defaultValue": ["Admin", "Sales"],           (6)
        "multivalued": true                           (7)
      },
      "emp_location": {
        "title": "Employee location",
        "description": "Select the primary location",
        "required": true,
        "type": "STRING",
        "defaultValue": "UK",
        "options": {                                  (8)
            "UK": "London",
            "US": "New York"
        }
      }
    }
    1 The key that can be accessed from the script, for example, properties.emp_group.
    2 Required. The title of the property appears as the property name. Must be unique.
    3 The description appears as the tooltip in the tree designer.
    4 Required. Whether it’s mandatory to enter a value for this property.
    5 Required. The input type: STRING, NUMBER, BOOLEAN, or OBJECT.
    6 The initial value(s) for this property that’s displayed in the UI. If you define options, this value must match one of the option keys.
    7 Enables multiple values for a single property for all types except OBJECT. Must be false if options are provided. Default: false.
    8 Define key/value pairs to display options in a drop-down list. The key must only contain alphanumeric characters and underscores and can’t consist only of digits. The values displayed in the list can be any valid string.

    These example properties display in the tree designer view as follows:

    node designer properties

    Script

    Write or paste in a next-generation script that runs when your custom node is processed.

    Use the Node Designer binding, properties, to reference the configured values that you’ve defined in the Properties field. In addition to properties, your script has access to all the Scripted Decision node script bindings. Find examples of scripts and how to use the bindings in Scripted Decision node API.

    For example, this script adds an email address to the user profile and stores employee details in node state:

    var username = nodeState.get("username");
    var identity = idRepository.getIdentity(username);
    
    if (attributes.emp_location == "UK") {
        identity.addAttribute("mail", username + "@example.co.uk");
    }
    else {
        identity.addAttribute("mail", username + "@example.com");
    }
    identity.store();
    
    nodeState.putShared("location", attributes.emp_location);
    nodeState.putShared("group", attributes.emp_group);
    
    action.goTo("true");
    Node Designer scripts only appear in the Node Designer. You can’t manage these scripts under Realms > Realm Name > Scripts.

    Error Outcome

    Enable to add an extra path for scripting errors, for example, if the script references an outcome that’s not defined in the Outcomes field. The outcome appears on the node as Script Error.

    Category

    Select a category from the list. Your node type appears under this section in the tree designer view.

    Tags

    Add tags to organize the node. You can use these to search for a node type in the tree designer.

  4. Save your changes.

Import a node type

To reuse node types in other environments, you can import a JSON file containing one or more node types.

  1. In the AM admin UI, go to Node Designer and click Import.

  2. On the Import Nodes page, drag the JSON file into the Import File box or click in the box to open a file browser and select the JSON file.

  3. Click Import.

    AM displays an error if a node of that type already exists or the JSON is invalid.

Export a node type

To reuse node types in other environments, you can export them to a JSON file.

  1. In the AM admin UI, go to Node Designer and select one or more node types from the list to export.

  2. Click Export.

  3. The node types are downloaded to a JSON file.

Exporting node types doesn’t include external dependencies. To make sure exported node types work as expected, record dependencies such as those relied on by bindings that interact with external services and configuration, for example, openidm, secrets, and httpClient.

You can then use these notes to replicate the dependencies when importing the node types into a different environment.

Use your custom node type

Create a journey that references your new node type and configure values appropriate for that journey.

  1. In the AM admin UI, go to Realms > Realm Name > Authentication > Trees and create a tree.

  2. Search for your custom node type in the Components panel using the tags, the name, or the category of your node.

  3. Add the node to your tree and set its properties to values that are appropriate for your authentication journey.

  4. If you need to make changes to your node type, edit its configuration in the Node Designer and return to the tree designer.

    You might need to delete the node from your journey and select a new instance to view updates.

The following example includes the custom node type, Set Employee Details in a journey that sets user-specific information based on node configuration after a successful authentication.

node designer tree example

The node is configured with the following values:

Employee location

New York

Employee group

Admin Sales

For a user, bjensen, the node adds the email address bjensen@example.com to the mail identity profile attribute and the debug node outputs the following updates to nodeState:

  ...
  "location": "New York",
  "group": [
      "Admin",
      "Sales"
  ]
  ...
}

Delete a node type

Deleting a custom node type is a permanent operation. You won’t be able to retrieve it after it’s deleted.

  1. In the AM admin UI, go to Realms > Realm Name > Authentication > Node Designer.

  2. Select the checkbox next to one or more node types. Click x Delete.

You can’t delete a custom node type if a journey uses a node of that type.

Example: Generate JWT node

This example generates a signed JWT using the HMAC SHA-256 algorithm based on tree configuration and the username. It then sets the generated key in shared state.

  1. Create a custom node type with the following settings:

    Field Value

    Display Name

    Generate JWT

    Description

    Select an algorithm to generate a key for encryption / decryption purposes.

    Outcomes

    true false

    Node Inputs

    *

    Node Outputs

    *

    Properties

    {
      "issuer": {
        "title": "Issuer",
        "type": "STRING",
        "description": "The issuer (iss) claim",
        "required": true
      },
      "audience": {
        "title": "Audience",
        "type": "STRING",
        "description": "The audience (aud) claim",
        "required": true
      },
      "signingkey": {
        "title": "HMAC Signing Key",
        "type": "STRING",
        "description": "The secret label for the HMAC signing key",
        "defaultValue": "scripted.node.secret",
        "required": true
      },
      "validity": {
        "title": "Validity (minutes)",
        "type": "NUMBER",
        "required": true,
        "defaultValue": 5
      }
    }

    Script

    var aud = properties.audience;
    var iss = properties.issuer;
    var validity = properties.validity;
    var secret = properties.signingkey;
    
    var signingkey = secrets.getGenericSecret(secret).getAsUtf8();
    
    var username = nodeState.get("username");
    
    var data = {
      jwtType:"SIGNED",
      jwsAlgorithm: "HS256",
      issuer: iss,
      subject: username,
      audience: aud,
      type: "JWT",
      validityMinutes: validity,
      signingKey: signingkey
    };
    
    var jwt = jwtAssertion.generateJwt(data);
    
    if (jwt !== null && jwt.length > 0) {
      nodeState.putShared("assertionJwt" , jwt);
      action.goTo("true");
    } else {
      action.goTo("false");
    }

    Error Outcome

    Enabled

    Tags

    Utilities

  2. Create a journey that includes an instance of the new node type.

    For example:

    Generate JWT node example tree
  3. Configure the node with a secret label mapped to an HMAC signing secret and values for the issuer and audience JWT claims.

    node designer jwt properties
  4. Test the journey. The JWT is added to shared state:

    {
        "realm": "/alpha",
        "assertionJwt": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUz...rXNQ4QhFeIBC2LiH-Sr72Q4",
        ...
    }