Expressions

Last modified 14 Mar 2024 12:46 +01:00
Expression feature
This page describes configuration of Expression midPoint feature. Please see the feature page for more details.

Introduction

Expression is a part of midPoint configuration that contains logic. It is used in mappings, Correlation and Confirmation Expressions and may be used in other parts later on. Expressions are very flexible. They need to be flexible as expressions are the primary tool of customizing midPoint behavior. Expressions allow simple and efficient constructions that just pass or generate a value but they also allow invocation of complex scripts.

Simple expression example
<expression>
    <script>
        <code>
            givenName + ' ' + familyName
        </code>
    </script>
</expression>

The expressions are executed by invoking a specific expression evaluator. The evaluator is a piece of code that takes expression inputs (variables) and produces a value. There evaluators range from the very simples ("as is" evaluators) to flexible scripting language engines. Individual evaluators are described below.

Each expression take a set of variables as input. Each variable has a name and values. The values may also be "dynamic", not only specifying what the value is but also how it is being changed (delta). The expression than recomputes the variables to the output value, which may also be "dynamic". MidPoint expressions are designed and built especially to support the model of relative changes.

Expression Evaluators

Expression evaluators are individual clauses that create (or transform) a value. Each value construction needs to have at least one constructor to be useful.

Literal

Literal expression evaluator creates an explicit literal value. Single string value may be specified simply by placing it in the value tag as illustrated by the following two examples.

Single-value string literal expression
<expression>
    <value>Bloody Pirate</value>
</expression>
Multi-value literal expression
<expression>
    <value>Pirate</value>
    <value>Sailor</value>
</expression>

An empty value (combine with tolerant=false and strength=strong in mappings) can be expressed as:

Empty value expression
<expression>
  <value/>
</expression>

Complex values and multiple values must be wrapped in appropriate element for the literal expression to distinguish the value structure. Following example shows definition of two literal values for structured property armament.

Multi-value literal expression (alternative representation)
<expression>
    <value>
        <armament>
            <weapon>Cutlass</weapon>
            <placement>right hand</placement>
        </armament>
        <armament>
            <weapon>Pistol</weapon>
            <placement>belt</placement>
        </armament>
    </value>
</expression>

As Is

"As Is" expression is used if no value transformation is needed and there is a clear definition of what an input value is. The "as is" expression just copies this value to the output. It is usually used in inbound and outbound mappings to synchronize passwords and activation status directly to the resource without any change.

As Is expression
<expression>
    <asIs/>
</expression>

As is expression works only if the expression has exactly one source (input variable). If there is no source then the expression cannot produce any value. If there is more than one source then the expression cannot determine which one to user. Use the path expression in such cases (see below).

The As Is value is functionally almost identical to passing the value of input system variable to the output e.g. by using path expression (see below):

Path expression that simulates As Is expression
<expression>
    <path>$input</path>
</expression>

The As Is expression evaluator is the default evaluator that will be used if no expression is specified at all (e.g. in mappings).

Path

Path expression is the most reliable and most efficient way to reference a property or a variable. The expression simply takes path to the desired value.

Following constructor is referencing the name property in the object stored in focus variable.

Path constructor referencing user’s name property
<expression>
    <path>$focus/name</path>
</expression>
The path constructor is following the path through prism objects directly which is much faster. This also allows the path constructor to follow the modification mode (delta) of the source property which is very useful in some situations. Therefore, as a rule of the thumb the path constructor should always be preferred if it is possible to use it.

Script

Script constructor is the most flexible of all the constructors as it allows to invoke an expression written in an expression or scripting language. There are several script languages to choose from. The script expressions are described in more details in a Script Expression page. This page only provides few examples.

Expression constructor using Groovy script
<expression>
<script>
  <language>http://midpoint.evolveum.com/xml/ns/public/expression/language#Groovy</language>
  <code>
    'uid=' + user.getName() + ',ou=people,dc=example,dc=com'
  </code>
</script>
Expression constructor using ECMAScript (JavaScript) script
<expression>
<script>
  <language>http://midpoint.evolveum.com/xml/ns/public/expression/language#ECMAScript</language>
  <code>
    'uid=' + user.getName() + ',ou=people,dc=example,dc=com'
  </code>
</script>

See Script Expression page for more details.

Generate

The generate constructor is used to generate a random value. The value is generated according to the value policy. If there is a value policy already associated with a target property then it is sufficient to specify just plain <generate/> element. The applicable policy will be automatically determined and used. This usually applies to password policies. If no implicit policy is applicable to the target property or if a different policy is desired the policy may be overridden using valuePolicyRef element as illustrated below.

Generate constructor
<expression>
  <generate>
    <valuePolicyRef oid="d4c010c0-d34d-b3af-fe4d-11241a11101f"/>
  </generate>
</expression>

If no value policy is defined and the expression cannot determine the policy automatically it will use a reasonable default setting to generate random value.

Password policies and generate expression

When a generate expression without any parameters (<generate/>) is used to generate a password it will choose password policy automatically. When such an expression is used in a mapping it will choose password policy appropriate for the mapping target. This makes perfect sense, as the generated value must be a valid value for the target property. Which means that is the generate expression is used in the outbound mapping, it will use resource password policy. But if it is used in the inbound mapping, it will use user password policy. Because in the inbound case the target attribute is user password, not resource account password. The generate expression cannot use resource password policy because a password generate using that policy may not be a valid user password.

In case that you would like to change this behavior please specify the password policy explicitly using the valuePolicyRef parameter.

Mappings and expressions are often used to create assignments. Therefore there is a special-purpose expression evaluator that simplifies the way how assignments are created. The evaluator is using a query to search for an target object in midPoint repository. When such object is found the evaluator creates an assignment for that target. This expression is especially useful in object templates.

Following configuration snippet provides an example of assignment evaluator that looks for an OrgType target:

Assignment expression
<expression>
    <assignmentTargetSearch>
        <targetType>c:OrgType</targetType>
        <filter>
            <q:text>name = $organizationalUnit</q:text>
        </filter>
    </assignmentTargetSearch>
</expression>

This assignment target search expression will look for objects of type OrgType in midPoint repository. It will look up the objects by name property. The name of the object should be the same as the value of organizationalUnit variable. If such an object is found than an appropriate assignment structure is created, the OID of the org object is placed inside it.

Search expression evaluators and includeNullInputs

Search expression evaluators have changed default for includeNullInputs. Null inputs are NOT processed by search expression evaluators by default. The reason is that null inputs are usually insignificant for search expression and skipping them results in fewer search operations. In case that processing of null inputs is needed it has to be explicitly turned on for search expression evaluators. This is usually needed in case that the evaluators should provide "default" values in case that some of the source values is not present. Simply speaking: if the expression is not producing a value that you would expect to be produced, turning on includeNullInputs will make midPoint slightly slower, but it may solve your problem.

Relation parameter

If you wish to assign the organization with relation value (such as "manager") to indicate any non-default relation, you need to specify it:

Assignment expression with relation parameter
<expression>
    <assignmentTargetSearch>
        <targetType>c:OrgType</targetType>
        <filter>
            <q:text>name = $organizationalUnit</q:text>
        </filter>
        <assignmentProperties>
            <relation xmlns:org="http://midpoint.evolveum.com/xml/ns/public/common/org-3">org:manager</relation>
        </assignmentProperties>
    </assignmentTargetSearch>
</expression>

After such assignment, GUI will indicate that user with this assignment is a manager of the organization.

Activation parameters

If you need to create assignment for a user with specific activation settings you can do it with following:

Assignment expression with activation parameters
<expression>
    <assignmentTargetSearch>
        <targetType>c:RoleType</targetType>
        <oid></oid>
        <populate>
            <populateItem>
                <expression>
                    <script>
                        <code>
                            import com.evolveum.midpoint.xml.ns._public.common.common_3.ActivationStatusType
                            return ActivationStatusType.ENABLED
                        </code>
                    </script>
                </expression>
                <target>
                    <path>activation/administrativeStatus</path>
                </target>
            </populateItem>
            <populateItem>
                <expression>
                    <script>
                        <code>
                            return basic.parseDateTime("yyyy-MM-dd'T'HH:mm:ss.SSS", "2016-12-31T23:59:59.000");
                        </code>
                    </script>
                </expression>
                <target>
                    <path>activation/validTo</path>
                </target>
            </populateItem>
        </populate>
    </assignmentTargetSearch>
</expression>

When the example above is user, each role assigned with it has administrativeStatus property set to the ENABLED and validTo date set to the 31.12.2016 EOD. This mechanism provide possibility to create assignment of roles, orgs, services with specific activation settings according to some focus attributes. The same mechanism can be used for defining role parameters and other attributes.

Create on Demand

The evaluator also has additional functionality that allows to create assignment targets on demand. This is a very useful functionality e.g. in case of opportunistic organizational structure synchronization when organizational unit names are only present as account attribute values and midPoint has to create appropriate orgs when it sees a new value. Following configuration sample extends the previous example with an create-on-demand functionality:

Assignment expression with create-on-demand configuration
<expression>
    <assignmentTargetSearch>
        <targetType>c:OrgType</targetType>
        <filter>
            <q:text>name = $organizationalUnit</q:text>
        </filter>
        <createOnDemand>true</createOnDemand>
        <populateObject>
            <populateItem>
                <expression>
                    <path>$organizationalUnit</path>
                </expression>
                <target>
                    <path>name</path>
                </target>
            </populateItem>
        </populateObject>
    </assignmentTargetSearch>
</expression>

New OrgType object will be created if no matching object is found by the query. The new object will be populated by the values specified by inner expressions (in populateItem elements).

Expressions inside expressions

Please note that the assignment expressions are part of the expression and it also usually contains inner expressions. So we have expressions inside expressions. This may look confusing at the first moment but in fact it goes very well in line with midPoint approach of reusability. We do not want to reinvent the same mechanism, we rather try to reuse what we already have. And this also creates a very powerful and flexible customization tool.

The assignment expressions can get very post-modern. E.g. one can have assignment expression inside assignment expression. Something like this:

functionality:

Assignment expression with create-od-demand configuration
<expression>
    <assignmentTargetSearch>
        <targetType>c:OrgType</targetType>
        <filter>
            <q:text>name = $organizationalUnit</q:text>
        </filter>
        <createOnDemand>true</createOnDemand>
        <populateObject>
            <populateItem>
                <expression>
                    <path>$organizationalUnit</path>
                </expression>
                <target>
                    <path>name</path>
                </target>
            </populateItem>
            <populateItem>
                <expression>
                    <assignmentTargetSearch>
                        <targetType>c:OrgType</targetType>
                        <filter>
                            <q:equal>
                                <q:path>c:name</q:path>
                                <expression>
                                    <value>TOP</value>
                                </expression>
                            </q:equal>
                        </filter>
                    </assignmentTargetSearch>
                </expression>
                <target>
                    <path>assignment</path>
                </target>
            </populateItem>
        </populateObject>
    </assignmentTargetSearch>
</expression>

This sample creates a new org on demand and such org will be assigned to the user. However, the new org itself will have an assignment. In this case it is an assignment to some kind of "TOP" organizational unit. This is usually what is required as we do not want to create new top-level organizational units every time (see Organizational Structure for more details).

Concept of mappings is very versatile. Therefore, it is used also to search associated objects on resources that supports multiple object types with association between them.

associationTargetSearch is searching the corresponding object that will be associated with constructed account based on the filter.

search strategy defines where the search can be carried out. Possible values are inRepository, onResource, and onResourceIfNeeded.

Association target search in account construction within a role
<role>
    <inducement>
        <construction>
            <resourceRef oid="0a37121f-d515-4a23-9b6d-554c5ef61272" relation="org:default" type="c:ResourceType" />
            <association>
                <ref>ri:group</ref>
                <outbound>
                    <expression>
                         <associationTargetSearch>
                            <filter>
                                <q:equal>
                                    <q:path>attributes/ri:dn</q:path>
                                    <q:value>cn=library,ou=groups,dc=example,dc=com</q:value>
                                </q:equal>
                            </filter>
                            <searchStrategy>onResourceIfNeeded</searchStrategy>
                        </associationTargetSearch>
                    </expression>
                </outbound>
            </association>
        </construction>
        <order>2</order>
        <focusType>UserType</focusType>
    </inducement>
</role>

Association from link searches association similarly like Association target search. The difference is the association is defined by a linked object insted of a direct search within existing resource objects.

assignmentPathIndex defines which object in assignmentPath should be used for the association. Index 0 correspond to focus object (e.g. a user), 1 corresponds to directly assigned role, 2 corresponds to metarole and so on.

projectionDescriminator defines the kind and intent of associated resource object.

Note that the linked object needs to have the corresponding projection linked on given resource. Otherwise, the association from link won’t be able to work properly.

Association from link in context of a metarole applied to org. unit archetype
<role>
    <!--  Provides LDAP group for the org object -->
    <inducement>
        <construction>
            <resourceRef oid="0a37121f-d515-4a23-9b6d-554c5ef61272" relation="org:default" type="c:ResourceType" />
            <kind>entitlement</kind>
            <intent>group</intent>
        </construction>
        <order>2</order>        <!--  order=2 means the org object: org->archetype->metarole -->
    </inducement>

    <!--  Provides LDAP group membership for the org object members (users) -->
    <inducement>
        <construction>
            <resourceRef oid="0a37121f-d515-4a23-9b6d-554c5ef61272" relation="org:default" type="c:ResourceType" />
            <association>
                <ref>ri:group</ref>
                <outbound>
                    <expression>
                        <associationFromLink>
                            <projectionDiscriminator>
                                <kind>entitlement</kind>
                                <intent>group</intent>
                            </projectionDiscriminator>
                            <assignmentPathIndex>1</assignmentPathIndex>        <!--  derive from the immediately assigned org -->
                        </associationFromLink>
                    </expression>
                </outbound>
            </association>
        </construction>
        <order>3</order>        <!--  order=3 means the user object; user has an assignment to the org: user->org->archetype->metarole -->
    </inducement>
</role>

Sequential Value

Const

Expression evaluator used to produce value of a constant.

See Configuration and Use of Constants for more details.

Expression Variables

Extra Variables

Expression may define extra variables in addition to those provided by midPoint:

<expression>
    <variable>
        <name>jack</name>
        <objectRef oid="c0c010c0-d34d-b33f-f00d-111111111111" type="UserType"/>
    </variable>
    <path>$jack/givenName</path>
</expression>

Root Node

If value construction is used in a case where it is likely that most of the values will originate from a single object or a data structure such structure is assigned to the root node of the expression. The root node is kind of a default variable for the expression. Some expression languages can take advantage of the root node but most cannot. Currently, the root node only applies to Path expression In Path the root node can be addressed without a variable name. Therefore, the following two expressions are equivalent (assuming that focus is set as a root node).

Expression constructor using explicit variable
<expression>
    <path>$focus/name</path>
</expression>
Expression constructor using root node
<expression>
    <path>name</path>
</expression>

Security

Privilege Elevation (Run As, Run Privileged)

Expressions are normally evaluated using the security principal of the user that initiated the operation. This is the best security practice, as the authorizations go deep into the system and close to the data. By doing this, it is unlikely that an expression would read data or initiate an operation that the user is not authorized for. Therefore, the probability of a security breach is reduced.

However, there are some cases when an expression needs access to data or operations beyond the user’s authorization. Either the expression can be executed with the identity of a different user, or a faster option of elevating the privileges only is available as well.

How to Use Elevated Privileges

The following example shows both options for privilege elevation. Although they can be used at the same time, you normally use only one of them.

An example of the current runAs/runPrivileged syntax
<expression>
    <privileges>
        <runAsRef oid="e5e0f2fe-0aea-11e7-b02b-2b6815aa719e" type="UserType"/> (1)
        <runPrivileged>true</runPrivileged> (2)
    </privileges>
    <script>
        ....
    </script>
</expression>
1 Switches the identity of the principal
2 Keeps the identity, elevates only the privileges

Effects of Privilege Escalation

When runAsRef is used, the expression will be executed with the authorization of the object referenced. In the examples above, it will be the user identified by OID e5e0f2fe-0aea-11e7-b02b-2b6815aa719e.

The variable actor that is present in most expressions still refers to the identity of the user that initiated the operations. This variable is not affected by the runAs configuration.

When runPrivileged is used, the expression will be executed under the identity of the currently logged-in users. Their authorizations will be extended by including "allow all" (http://midpoint.evolveum.com/xml/ns/public/security/authorization-3#all) for the duration of expression evaluation.

Performance Implications

The use of runAsRef involves the login process, which can take considerable time. In some cases, the time needed may be in the range of tens of milliseconds. This may or may not be acceptable, e.g., for the evaluation of frequently used expressions.

The use of runPrivileged should be much faster.

Auditing

Each audit record contains the effectivePrincipalRef item that contains the reference to the identity under which the operation took place. When runAsRef is used, the referenced identity is recorded.

Also, effectivePrivilegesModification property is there, indicating whether privileges were modified with regard to the original ones defined in the repository. When runPrivileged is used, this property has a value of fullElevation.

Please see Privilege Elevation (runAsRef, runPrivileged) for more information.

Security of Script Expressions

Script expressions are a code that runs inside midPoint servers. As such, script expressions are incredibly powerful. But with great powers comes great responsibility. Script expressions can do a lot of useful things, but they can also do a lot of harm. There are just a few simple internal safeguards when it comes to expression evaluation. E.g. midPoint script libraries will properly enforce authorization when executing the functions. However, script languages are powerful and a clever expression can find a way around this safeguards. MidPoint is not placing expressions in a sandbox, therefore expressions are free to do almost anything. The sandbox is not enforced from complexity and performance reasons, but it may be applied in future midPoint versions if necessary. For the time being, please be very careful who can define expressions in midPoint. Do not allow any untrusted user to modify the expressions.

See Script Expression Sandboxing for more details.

Compliance

This feature is related to the following compliance frameworks:

Was this page helpful?
YES NO
Thanks for your feedback