Expressions
Expressions that conform to the Universal Expression Language as specified in JSR-245 can be used to specify configuration parameter values.
General Syntax
All expressions follow standard Universal Expression Language syntax:
${expression}
or #{expression}
:
An expression can be a simple reference to a value, a function call, or
arbitrarily complex arithmetic, logical, relational, and conditional
operations. When supplied within a configuration parameter, an expression is
always a string enclosed in quotation marks, for example:
"${request.method}"
.
Configuration and Runtime Expressions
Expressions are evaluated at configuration time (when routes are loaded), or at runtime (when IG is running).
When expressions are evaluated, they access the current environment through the
implicit object openig
. The object has the following properties:
-
baseDirectory
, the path to the base location for IG files. The default location is$HOME/.openig
(appdata\OpenIG
). -
configDirectory
, the path to the IG configuration files. The default location is$HOME/.openig/config
(appdata\OpenIG\config
). -
temporaryDirectory
, the path to the IG temporary files. The default location is$HOME/.openig/tmp
(appdata\OpenIG\OpenIG\tmp
).
For information about how to change the default values, see Change the Default Location of the Configuration Folders.
Configuration Expression
Expression evaluated at configuration time, when routes are loaded.
Configuration expressions can refer to the system heap properties, the built-in
functions listed in Functions,
the ${env['variable']}
, and ${system['property']}
.
Because configuration expressions are evaluated before any requests are made,
they cannot refer to the runtime properties, request
, response
, or
context
.
Runtime Expressions
Expressions evaluated at runtime, for each request and response. IG evaluates runtime expressions as follows:
-
When expressions are written with
$
, IG evaluates them immediately. If the expression consumes streamed content, for example, the content of a request or response, IG blocks the executing thread until all of the content is available. Immediate evaluation of expressions can block the executing thread. -
When expressions are written with
#
, IG defers evaluation until all of the streamed content is available. Deferred evaluation of expressions does not block the executing thread.
For expressions that consume streamed content, make sure that IG
does a deferred evaluation, by writing the expression with #
instead
of $
.
For IG in standalone mode, when the new streaming
property in
admin.json
is true
, expressions that consume streamed content must
be written with #
instead of $
.
The following expressions do not consume streamed content, so it is
safe for IG to do an immediate evaluation. The expressions can
therefore be written with $
:
$ {matches(request.uri.path, '^/foo')}
$ {request.headers['Content-Type'][0] == 'application/json'}
The following example expression is a Route condition. The Route is accessed
if the request contains json with the attribute answer
, whose value is 42
.
IG must defer evaluation of the expression until it receives the
entire body of the reqest, transfoms it to JSON view, and introspects it for
the attribute answer
:
{
"condition": "#{request.entity.json['answer'] == 42}",
"handler": ...
}
The following example expression is a DispatchHandler condition. The
request is dispatched if the request contains a form field with the
attribute answer
, whose value is 42
. IG must defer evaluation of
the expression until it receives the entire body of the reqest, transforms it to
a form view, and introspects it for the attribute answer
:
"bindings": [
{
"condition": "#{request.entity.form['answer'] == 42}",
"handler": ...
}
]
The following example expression is for an AssignmentFilter.
A user ID is captured from a response and stored in the FooBar
header. The
first expression defines the target, and IG evaluates it immediately.
The second expression uses the response entity, so IG must
defer evaluation until it receives the entire body of the response:
"onResponse": [
{
"target": "${response.headers['X-IG-FooBar']}",
"value": "#{toString(response.entity.json['userId'])}"
}
]
The following example expression is for a JwtBuilderFilter. The content of the requests is mapped as a string, so IG must defer evaluation of the expression until it receives the entire body of the request:
{
"template": {
"content": "#{request.entity.string}"
}
}
In standalone mode and web container mode, runtime expressions can refer to the same information as configuration expressions, plus the following objects:
-
attributes
: org.forgerock.services.context.AttributesContext Map<String, Object>, obtained fromAttributesContext.getAttributes()
. For information, see AttributesContext. -
context
: org.forgerock.services.context.Context object. -
contexts
: map<string, context> object. For information, see Contexts. -
request
: org.forgerock.http.protocol.Request object. For information, see Request. -
response
: org.forgerock.http.protocol.Response object, available only when the expression is intended to be evaluated on the response flow. For information, see Response. -
session
: org.forgerock.http.session.Session object, available only when the expression is intended to be evaluated for both request and response flow. For information, see SessionContext.
Value Expressions
A value expression references a value relative to the scope supplied to the
expression. For example, "${request.method}"
references the method of an
incoming HTTP request.
An lvalue-expression
is a specific type of value expression that references a value to be written.
For example, "${session.gotoURL}"
specifies a session attribute named
gotoURL
to write a value to. Attempts to write values to read-only values are
ignored.
Properties whose format is lvalue-expression
cannot consume streamed content.
They must be written with $
instead of #
.
Indexed Properties
Properties of values are accessed using the .
and []
operators, and can
be nested arbitrarily.
The value expressions "${request.method}"
and "${request['method']}"
are
equivalent.
To prevent errors, in property names containing characters that are also
expression operators, use the []
operator instead of the .
operator.
For example, use contexts.amSession.properties['a-b-c']
instead of contexts
.amSession.properties.a-b-c
.
In the case of arrays, the index of an element in the array is expressed as a
number in brackets. For example, "${request.headers['Content-Type'][0]}"
references the first Content-Type
header value in a request. If a property
does not exist, then the index reference yields a null
(empty) value.
Operators
Universal Expression Language provides the following operators:
-
Index property value:
[]
,.
-
Change precedence:
()
-
Arithmetic:
+
(binary),-
(binary),*
,/
,div
,%
,mod
,-
(unary) -
Logical:
and
,&&
,or
,||
,not
,!
-
Relational:
==
,eq
,!=
,ne
,<
,lt
,>
,gt
,⇐
,le
,>=
,ge
-
Empty:
empty
Prefix operation that can be used to determine whether a value is null or empty.
-
Conditional:
?
,:
Operators have the following precedence, from highest to lowest, and from left to right:
-
[]
.
-
()
-
-
(unary)not
!
empty
-
*
/
div
%
mod
-
+
(binary)-
(binary) -
<
>
⇐
>=
lt
gt
le
ge
-
==
!=
eq
ne
-
&&
and
-
||
or
-
?
:
System Properties and Environment Variables
You can use expressions to retrieve Java system properties, and to retrieve nvironment variables.
For system properties, ${system['property']}
yields the
value of property
, or null
if there is no value for
property
. For example, ${system['user.home']}
yields the
home directory of the user running the application server for IG.
For environment variables, ${env['variable']}
yields the
value of variable
, or null
if there is no value for
variable
. For example, ${env['HOME']}
yields the home
directory of the user running the application server for IG.
Token Resolution
Runtime expressions have access to evaluated configuration tokens described
in JSON Evaluation. For
example, the following boolean expression returns true
if the configuration
token my.status.code
resolves to 200
:
${integer(_token.resolve('my.status.code', '404')) == 200}
Functions
A number of built-in functions described in Functions can be called within an expression.
The syntax is ${function(parameter, …)}
, where zero or more parameters
are supplied to the function. For example:
-
"${bool(env['ENABLE_TIMER'])}"
recovers the environment variable"ENABLE_TIMER"
and transforms it into a boolean -
"${toLowerCase(request.method)}"
yields the method of the request, converted to lowercase.
Functions can be operands for operations, and can yield parameters for other function calls.
Escaping Literal Expressions
The character \
is treated as an escape character when it is followed by
${
or \#{
. For example, the expression ${true}
normally
evaluates to true
. To include the string ${true}
in an expression,
write \${true}
When the character \
is followed by any other character sequence, it is not
treated as an escape character.
Embedding Expressions
Consider the following points when embedding expressions:
-
System properties, environment variables, or function expressions can be embedded within expressions.
The following example embeds an environment variable in the argument for a
read()
function. The value ofentity
is set to the contents of the file$HOME/.openig/html/defaultResponse.html
, where$HOME/.openig
is the instance directory:"entity": "${read('&{ig.instance.dir}/html/defaultResponse.html')}"
-
Expressions cannot be embedded inside other expressions, as
${expression}
. -
Embedded elements cannot be enclosed in
${}
.
Extensions
IG offers a plugin interface for extending expressions. See Key Extension Points.
If your deployment uses expression plugins, read the plugin documentation about the additional expressions you can use.
Examples
"${request.uri.path == '/wordpress/wp-login.php'
and request.queryParams['action'][0] != 'logout'}"
"${request.uri.host == 'wiki.example.com'}"
"${request.cookies[keyMatch(request.cookies,'^SESS.*')][0].value}"
"${toString(request.uri)}"
"${request.method == 'POST' and request.uri.path == '/wordpress/wp-login.php'}"
"${request.method != 'GET'}"
"${request.headers['cookie'][0]}"
"${request.uri.scheme == 'http'}"
"${not (response.status.code == 302 and not empty session.gotoURL)}"
"${response.headers['Set-Cookie'][0]}"
"${request.headers['host'][0]}"
"${not empty system['my-variable'] ? system['my-variable'] : '/path/to'}/logs/gateway.log"