PingOne Advanced Identity Cloud

Next-generation scripts

The next-generation scripting engine offers the following benefits:

Stability
  • A stable set of enhanced bindings that reduces the need to allowlist Java classes to access common functionality.

Ease of use
  • Simplifying your scripts with fewer imports and more intuitive return types that require less code.

  • Easier debugging through clear log messages and a simple logging interface based on SLF4J.

  • Making requests to other APIs from within scripts is easier with a more intuitive HTTP client.

Reduced complexity
  • Simplify and modularize your scripts with library scripts by reusing commonly used code snippets as CommonJS modules.

    Reference library scripts from a next-generation script.

  • Access identity management information seamlessly through the openidm binding.

Availability

The following script types use the next-generation scripting engine:

These are the only script types that can use library scripts and next-generation bindings.

Migrate to next-generation scripts

To use next-generation bindings, you must migrate eligible legacy scripts.

The next-generation engine can’t use legacy scripts.

Where possible, you should migrate legacy scripts to take advantage of next-generation stability.

You can’t change the script engine version after you have created a script.

To migrate existing scripts, create a new script and convert your legacy code:

  1. Create a script and select Next Generation on the Choose Script Engine page.

  2. Copy and paste the legacy version of your script into the JavaScript field.

  3. Review any Java classes that you needed to allowlist to use in your legacy script.

    You can’t add Java classes to the next-generation allowlist.

    Instead, check if any next-generation bindings provide similar functionality, or reimplement the class as a library script. Library scripts let you add third-party code as reusable JavaScript modules that can be referenced from other scripts.

    If this isn’t possible, you can request the functionality to be included as a supported script binding in a future release.

  4. Update your bindings according to the API documentation for the specific script type.

    The following table provides links to examples of how to migrate common bindings to next-generation scripts.

    Binding Next-generation change

    Uses native JavaScript objects, similar to the Fetch API.

    Logger is now based on org.slf4j.Logger, instead of com.sun.identity.shared.debug.Debug.

    Use this binding to access the openidm scripting functions supported in IDM.

    Reference secrets and credentials from scripts.

    Use this utility binding to base64 encode/decode strings and to generate random UUIDs.

httpClient

Call HTTP services with the httpClient.send method. HTTP client requests are asynchronous, unless the get() method is invoked on the returned object.

For more information, refer to Access HTTP services.

  • Legacy

  • Next-generation

var fr = JavaImporter(
    org.forgerock.openam.auth.node.api.Action);

var requestURL =
    "https://example.com/authenticate";
var request = new
    org.forgerock.http.protocol.Request();

request.setUri(requestURL);                 2
request.setMethod("POST");
request.getHeaders().add("Content-Type",    3
    "application/json;");
request.getHeaders().add("Authorization",
    "Bearer abcd-1234");                    4
request.setEntity(JSON.stringify(
    {"username": "demo"}));

var response =
    httpClient.send(request).get();         5

var responseCode =
    response.getStatus().getCode();         6

if (responseCode === 200) {
    action = fr.Action.goTo("true").build();
} else {
    action = fr.Action.goTo("false").build();
}
 // import an external library to get token
var authLib = require('authLib');           1
var bearerToken =
    authLib.generateBearer(nodeState);

var options = {                             2
  method: "POST",
  headers: {
    "Content-Type": "application/json"      3
  },
  token: bearerToken,                       4
  body: {
    username: "demo"
  }
}

var requestURL =
    "https://example.com/authenticate";
var response = httpClient.send(
    requestURL, options).get();             5

if (response.status === 200) {              6
    action.goTo("true");
} else {
    action.goTo("false");
}

1 The example assumes you’ve created a custom library script (authLib) that handles authentication.
2 Set the request options as a native JavaScript object, instead of setting parameters on a Request object.
3 To send a form request, you don’t need to set Content-Type to url-encode parameters. Use the form attribute instead. For details, refer to Access HTTP services.
4 Use Library scripts to reuse common pieces of code; for example, to get an authentication token.
5 Call httpClient.send with the request URL and options as separate arguments, instead of a Request object.
6 Access response data directly using the methods and properties of the returned response object.

logger

The com.sun.identity.shared.debug.Debug logger class is deprecated and replaced by org.forgerock.openam.scripting.logging.ScriptedLoggerWrapper.

ScriptedLoggerWrapper provides a subset of the methods offered by SLF4J.

For more information, refer to Log script messages.

  • Legacy

  • Next-generation

var messageEnabled = logger.messageEnabled();
logger.message("Message with arg {}", arg);

var warnEnabled = logger.warningEnabled();
logger.warning("Warn with arg {}", arg);

var errorEnabled = logger.errorEnabled();
logger.error("Error with arg {}", arg);
var traceEnabled = logger.isTraceEnabled();
logger.trace("Trace with arg {}", arg);

var debugEnabled = logger.isDebugEnabled();
logger.debug("Debug with arg {}", arg);

var infoEnabled = logger.isInfoEnabled();
logger.info("Info with arg {}", arg);

var warnEnabled = logger.isWarnEnabled();
logger.warn("Warn with arg {}", arg);

var errorEnabled = logger.isErrorEnabled();
logger.error("Error with arg {}", arg);

openidm

The openidm binding lets you manage an IDM resource by calling scripting functions directly from a next-generation script.

The following CRUDPAQ functions are supported:

  • create

  • read

  • update

  • delete

  • patch

  • action

  • query

The following example shows the extensive code required in a legacy script to query the existence of a user by their email address in IDM, compared to the ease of using the openidm binding.

For further examples of how to use the openidm binding in your next-generation scripts, refer to Access IDM scripting functions.

For details of other supported functions, refer to Scripting functions.

The openidm binding provides administrative access to IDM functions. Use it with caution to prevent the exposure of sensitive data.

  • Legacy

  • Next-generation

function lookupUser (email) {
  try {
    var idmUserEndpoint =
         + '/openidm/managed/alpha_user?
        _queryFilter=userName+eq+%22'
        + email + '%22';
    var request = new
        org.forgerock.http.protocol.Request();
    var accessToken =
        transientState.get("idmAccessToken");     1

    request.setMethod('GET');
    request.setUri(idmUserEndpoint);              1
    request.getHeaders().add('Authorization',
        'Bearer ' + accessToken);
    request.getHeaders().add('Content-Type',
        'application/json');
    request.getHeaders().add('Accept-API-Version',
        'resource=1.0');

    var httpResponse =
        httpClient.send(request).get();           1
    var responseCode =
        httpResponse.getStatus().getCode();
    if (responseCode === 200) {
      var response = JSON.parse(
          httpResponse.getEntity().getString());
      if (response && response.result &&
            response.result.length > 0) {
        // User found
        return {
          success: true,
          user: response.result[0]};
      } else {
        // User NOT found
        return { success: true, user: null };
      }
    } else {
      return {
        success: false,
        error: 'Error looking up user: ' + responseCode
      };
    }
  } catch (e) {
    return {
      success: false,
      error: 'Error querying user: ' + e.toString()
    };
  }
}
openidm.query("managed/user", {        1
    "_queryFilter":`/userName eq '${email}'`
  }
);

1 Replace code that gets an idmAccessToken and uses the HTTP client object to invoke a request on an /openidm/* endpoint, with the direct use of the openidm binding.

secrets

The secrets binding is available to all next-generation scripts.

Learn more about the secrets binding in Access secrets and credentials.

Legacy Next-generation
var fr = JavaImporter(
    org.forgerock.openam.auth.node.api.Action);

var pw = secrets.getGenericSecret(          1
           "scripted.node.mysecret").getAsUtf8();

var auth =                                  2
  java.util.Base64.getEncoder().encodeToString(
      java.lang.String().getBytes("demo:" + pw));

nodeState.putTransient("authString", auth);
action = fr.Action.goTo("true").build();
var pw = secrets.getGenericSecret(          1
           "scripted.node.mysecret").getAsUtf8();

var auth =                                  2
    utils.base64.encode("demo:" + pw);

nodeState.putTransient("authString", auth);
action.goTo("true");

1 Access the secret from the Advanced Identity Cloud secret store in the same way as the legacy binding.
2 To encode sensitive information, the utils binding replaces the need to allowlist the java.util.Base64 and java.util.Base64$Encoder Java classes.