IG 2023.2

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, refer to [Change the base location of the IG configuration].

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 IG does a deferred evaluation, by writing the expression with # instead of $.

When the streamingEnabled property in admin.json is true, expressions that consume streamed content must be written with # instead of $.

Examples

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 $:

$ {find(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}"
  }
}
Available Objects

Runtime expressions can refer to the same information as configuration expressions, plus the following objects:

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}

Dynamic bindings

The following dynamic binding is available to configuration and runtime expressions:

now

The time since epoch at the instant an expression is evaluated, where epoch is 1 January 1970 00:00:00 UTC.

The binding makes the following information types available:

  • Milliseconds:

    ${now.epochMillis}
  • Seconds:

    ${now.epochSeconds}
  • Date format for RFC 1123:

    ${now.rfc1123}

One or more of the following time periods can be added to the binding to add or subtract a period of time:

  • plusMillis(integer), minusMillis(integer)

  • plusSeconds(integer), minusSeconds(integer)

  • plusMinutes(integer), minusMinutes(integer)

  • plusHours(integer), minusHours(integer)

  • plusDays(integer), minusDays(integer)

The following example binding accesses the instant in epoch seconds one day, four hours, and 30 minutes from now:

${now.plusDays(1).plusHours(4).plusMinutes(30).epochSeconds}

The following example binding accesses the instant in RFC 1123 date format one day from now:

${now.plusDays(1).rfc1123}

For more examples, see the template property of JwtBuilderFilter and the attribute-name property of SetCookieUpdateFilter.

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 of entity 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"

More information

For more information, refer to Contexts, Functions, Request, and Response.

Copyright © 2010-2023 ForgeRock, all rights reserved.