Scripting environment
AM supports server-side scripts written in either JavaScript or Groovy. Next-generation scripts and client-side authentication scripts must be written in JavaScript.
Scripting engine
AM implements a configurable scripting engine for each of the context types that are executed on the server.
AM uses the following libraries:
-
Mozilla Rhino version 1.7.14 to run JavaScript.
Rhino has limited support for ES6 / ES2015 (JavaScript version 1.7). Learn more in Rhino ES2015 Support.
-
Groovy version 3.0.10 to support scripting in Groovy.
Access Java classes
To access Java classes in a script, import classes in the following way:
-
JavaScript
-
Groovy
var fr = JavaImporter(
org.forgerock.openam.auth.node.api.Action,
javax.security.auth.callback.NameCallback
);
// Now use fr.Action, fr.NameCallback, and so on.
import org.forgerock.openam.auth.node.api.Action;
import javax.security.auth.callback.NameCallback;
Scripts can only import Java classes on the allowlist. AM defines an allowlist per script type.
Allowlists and denylists contain class names that are allowed or denied execution respectively.
Classes called by the script are checked against the allowlist first and must match at least one pattern in the list. The denylist is applied after the allowlist and classes matching any pattern are disallowed.
- Legacy scripts
-
The legacy scripting engine lets you add classes to allowlists and denylists by specifying the class name or by using regular expressions.
You can also configure the scripting engine to make an additional call to the JVM security manager for each class that is accessed. The security manager throws an exception if a class isn’t allowed to execute.
Learn more about allowlisting and configuring script engine security in the following topics:
To reduce the need to allowlist Java classes, consider migrating your scripts to use the next-generation scripting engine, which includes enhanced built-in script bindings for accessing many common script operations and the ability to include third-party software with library scripts.
- Next-generation scripts
-
To enhance security, the next-generation scripting engine for decision node scripts doesn’t support a configurable allowlist for Java classes.
Instead, check if next-generation bindings provide the functionality you need or implement the functionality as a reusable library script.
For information about next-generation bindings and library scripts, refer to:
In cases where reimplementation isn’t possible, you can request the functionality be included as a secure script binding in a future release.
Security considerations
Consider the following points when configuring the security settings within each script engine:
- Use script bindings where possible
-
The predefined script bindings provide a stable API without the need to allowlist Java classes. Different bindings are available to different script types, or contexts.
Learn more in Script bindings.
- The scripting engine only validates directly accessible classes
-
The security settings only apply to classes that the script directly accesses. If the script calls
Foo.a()
and that method callsBar.b()
, the scripting engine will be unable to prevent it. You must consider the whole chain of accessible classes.Access includes actions such as:
-
Importing or loading a class.
-
Accessing any instance of that class. For example, passed as a parameter to the script.
-
Calling a static method on that class.
-
Calling a method on an instance of that class.
-
Accessing a method or field that returns an instance of that class.
-
- Potentially dangerous Java classes are denylisted by default
-
All Java reflection classes (
java.lang.Class
,java.lang.reflect.*
) are denylisted by default to avoid bypassing the security settings.The
java.security.AccessController
class is also denylisted by default to prevent access to thedoPrivileged()
methods.Don’t remove potentially dangerous Java classes from the denylist. - The allowlists and denylists match class or package names only
-
The allowlist and denylist patterns apply only to the exact class or package names involved. The script engine doesn’t know anything about inheritance, so it’s best to allowlist known, specific classes.
Thread pools
Each script is executed in an individual thread. Each scripting engine starts with an initial number of threads available for executing scripts. If no threads are available for execution, AM creates a new thread to execute the script, until the configured maximum number of threads is reached.
If the maximum number of threads is reached, pending script executions are queued in a number of buffer threads, until a thread becomes available for execution. If a created thread has completed script execution and has been idle for a configured time period, AM terminates the thread, shrinking the pool.
Learn more about configuring script engine thread pools in Scripting service.