Expression Profile Configuration

Last modified 08 Mar 2024 08:26 +01:00
Limited feature

This is a limited midPoint feature. This feature currently supports only some specific use-cases. We are perfectly capable to finish the feature, just the funding for the work is needed. Please consider the possibility for supporting development of this feature by using midPoint Platform subscription. If you are midPoint Platform subscriber and this feature is within the goals of your deployment you may be able to use your subscription to endorse implementation of this feature.

Introduction

See Expression Profiles page for a generic introduction to expression profile concepts.

Expression Profile Specification

Expression profiles are defined in system configuration:

Listing 1. Definition of a sample expression profile with related permission profile
<systemConfiguration>
    ...
    <expressions>
        <expressionProfile>
            <identifier>safe</identifier>
            <decision>deny</decision> <!-- default decision of those evaluators that are not explicitly enumerated. -->
            <evaluator>
                <type>asIs</type>
                <decision>allow</decision>
            </evaluator>
            <evaluator>
                <type>path</type>
                <decision>allow</decision>
            </evaluator>
            ...
            <evaluator>
                <type>script</type>
                <decision>deny</decision> <!-- default decision of those script languages that are not explicitly enumerated. -->
                <script>
                    <language>http://midpoint.evolveum.com/xml/ns/public/expression/language#Groovy</language>
                    <decision>allow</decision>
                    <typeChecking>true</typeChecking>
                    <permissionProfile>script-safe</permissionProfile>
                </script>
            </evaluator>
        </expressionProfile>

        <permissionProfile>
            <identifier>script-safe</identifier>
            <decision>deny</decision> <!-- Default decision for those classes that are not explicitly enumerated. -->
            <package>
                <name>com.evolveum.midpoint.xml.ns._public.common.common_3</name>
                <description>MidPoint common schema - generated bean classes</description>
                <decision>allow</decision>
            </package>
            ...
            <class>
                <name>java.lang.Integer</name>
                <decision>allow</decision>
            </class>
            <class>
                <name>java.lang.String</name>
                <description>String operations are generally safe. But Groovy is adding execute() method which is very dangerous.</description>
                <decision>allow</decision> <!-- Default decision for those methods that are not explicitly enumerated. -->
                <method>
                    <name>execute</name>
                    <decision>deny</decision>
                </method>
            </class>
            ...
        </permissionProfile>
    </expressions>
</systemConfiguration>

Expression profile specifies which expression evaluators are allowed. E.g. the configuration about specifies that asIs, path and script evaluators are allowed. The profile can also parametrize the use of evaluators. For example the profile above is constraining the use of script evaluator only to Groovy language. And that same specification is also setting type-checking evaluation mode and applying permission profile to all evaluated scripts.

Permission profile specifies, which part of the Java platform can the evaluator touch. This is applicable almost exclusively to script evaluators, as other evaluators cannot directly access Java classes and methods. Simply speaking, the permission profile works as an access list that decides which classes and methods can be used and which cannot be used.

Permission profile is separated from expression profile, as it is expected that permission profiles may be long and complex in practice. And it is also expected that the same profile may apply to several scripting languages. The primary purpose of the permission profile is to constrain access to the (Java) platform which is not language-specific. Therefore, it is expected that this will be reusable.

The following table lists all items in an expression profile.

Table 1. Configuration items in an expression profile
Item Description Default value

identifier

Profile identifier. Usually short string, essentially a simple profile name. Custom profiles should consider using URIs instead of simple names to avoid conflicts with built-in profiles that may be provided in later versions.

mandatory

description

Free-form description (comment).

-

decision

Default decision for evaluators in this profile: this is the decision of those evaluators that are not explicitly enumerated within it. Currently, this property does NOT apply for other parts of the profile.

mandatory

evaluator (multivalued)

Profiles for individual evaluators.

see decision

bulkActionsProfile

ID of the bulk actions profile to be used with this expression profile.

"allow all bulk actions"

functionLibrariesProfile

ID of the function libraries profile to be used with this expression profile.

"allow all function libraries"

privilegeElevation

Is the privilege elevation (runAsRef, runPrivileged) feature available in this profile?

allow

Function Library and Bulk Action Profiles

We can specify which function libraries (FunctionLibraryType objects) and their individual functions are available in given expression profile. This is done using functionLibrariesProfile items.

In the following example, we create a trusted-functions-only expression profile that allows only the following:

  • using only the function and path expression evaluators (e.g., no scripting),

  • when using the former, not all functions can be called: only the ones from library 102cda99-2afc-4629-b189-79330f0de821 and function recomputeUser from 17b5b255-c71e-4a67-8e42-349862e295ac can.

Listing 2. Definition of a sample expression profile with a function libraries profile
<systemConfiguration>
    ...
    <expressions>
        ...
        <expressionProfile>
            <identifier>trusted-functions-only</identifier>
            <decision>deny</decision> (1)
            <evaluator>
                <type>function</type>
                <decision>allow</decision>
            </evaluator>
            <evaluator>
                <type>path</type>
                <decision>allow</decision>
            </evaluator>
            <functionLibrariesProfile>trusted-functions-only</functionLibrariesProfile>
        </expressionProfile>
        ...
        <functionLibrariesProfile>
            <identifier>trusted-functions-only</identifier>
            <decision>deny</decision> (1)
            <library>
                <ref oid="102cda99-2afc-4629-b189-79330f0de821"/>
                <decision>allow</decision> (2)
            </library>
            <library>
                <ref oid="17b5b255-c71e-4a67-8e42-349862e295ac"/>
                <decision>deny</decision> (1)
                <function>
                    <name>recomputeUser</name>
                    <decision>allow</decision> (3)
                </function>
            </library>
        </functionLibrariesProfile>
        ...
    </expressions>
</systemConfiguration>
1 What is not explicitly allowed, is denied.
2 Access to all functions in this library is allowed.
3 From this library, only the recomputeUser method can be invoked under this profile.

Also, access to individual bulk actions (like add, enable, expression, and so on) can be controlled as well. You can specify these using bulkActionsProfile items.

In the following example, we create a profile that would allow running all bulk actions, except for generate-value. (Does not make much sense, we use it just as an example.)

Listing 2. Definition of a sample expression profile with a bulk actions profile
<systemConfiguration>
    ...
    <expressions>
        ...
        <expressionProfile>
            <identifier>forbidden-generate-value-action</identifier>
            <decision>allow</decision> (1)
            <bulkActionsProfile>forbidden-generate-value-action</bulkActionsProfile>
        </expressionProfile>
        ...
        <bulkActionsProfile>
            <identifier>forbidden-generate-value-action</identifier>
            <decision>allow</decision> (2)
            <action>
                <name>generate-value</name>
                <decision>deny</decision> (3)
            </action>
        </bulkActionsProfile>
        ...
    </expressions>
</systemConfiguration>
1 All expression evaluators are allowed.
2 All actions (except for the one listed) are allowed.
3 The generate-value action is denied.

As for the action names, either legacy (dash-based) or modern (camel-cased) ones can be used. Please see the list of all actions.

The bulk actions are generally considered more-or-less safe, meaning that mere access to them should not provide a security hazard. For instance, if the access to script expression evaluator is forbidden, the execute-script bulk action does not need to be disabled, as it would not execute any script. Anyway, for better security, it may be helpful to restrict access to those that are not covered by model-level authorizations, like discover-connectors.
If functionLibrariesProfile is not set for given expression profile, the "allow all" profile for function libraries is used. The same is true for bulkActionsProfile. TODO we should consider if the default decision should not be applied instead. But this could break backwards compatibility, as the behavior in 4.7 and before (where these items are not available) is to allow all functions and actions. On the other hand, the profiles are experimental in 4.0-4.7 anyway, so maybe we don’t need to take compatibility into account much.

Privilege Elevation Settings

There is an option to evaluate an expression either with elevated privileges, or under a different identity (see Privilege Elevation (runAsRef, runPrivileged)). It can be dangerous if it’s misused. Hence, the expression profile can disable this option by setting privilegeElevation property to deny:

Listing 3. Denying the use of privilege elevation feature
<systemConfiguration>
    ...
    <expressions>
        ...
        <expressionProfile>
            <identifier>no-privilege-elevation</identifier>
            <privilegeElevation>deny</privilegeElevation>
        </expressionProfile>
        ...
    </expressions>
</systemConfiguration>

Note that if not explicitly specified, the privilege elevation feature is enabled. TODO ok?

Expression Profile Usage

Archetypes

The primary usage pattern for expression profiles is in conjunction with archetypes. The idea is that archetype policy will identify expression profiles that should be applied to all the expressions in archetyped objects. (In the future, midPoint may allow to specify different expression profiles for different parts of an object.)

This is how an expression profile is specified for an archetype:

Listing 4. Specification of an expression profile within an archetype
<archetype xmlns="http://midpoint.evolveum.com/xml/ns/public/common/common-3"
    oid="988c28d2-f879-4e07-a3cb-5ea7ad206146">
    <name>trusted-role</name>
    <archetypePolicy>
        <expressionProfile>trusted</expressionProfile> (1)
    </archetypePolicy>
</archetype>
1 ID of the expression profile to be used.

For more comprehensive example, please see Execution of Trusted Bulk Actions by Unprivileged Users.

Default Object Policy Configuration

If archetype(s) for a given object do not point to an expression profile, midPoint looks at defaultObjectPolicyConfiguration in system configuration.

An example:

Listing 5. Specification of an expression profile using object policy configuration
<systemConfiguration>
    ...
    <defaultObjectPolicyConfiguration>
        <type>ReportType</type>
        <expressionProfile>safe</expressionProfile>
    </defaultObjectPolicyConfiguration>
    ...
</systemConfiguration>

This is also the method how to specify default expression profile for a particular type of objects.

Defaults

For Expressions

For backwards compatibility reasons, default profile for expressions is built-in "full access" profile. (Identified as ##full.)

Identifiers for built-in profiles start with #. Please do not use this character as the first one in your profile identifiers. Also, it is not possible to reference built-in profiles from within your configuration. So, if you need to create a "full access" profile, you need to create your own.

Currently, there are the following built-in profiles: ##full (full access), ##none (no access), ##legacyUnprivilegedBulkActions (see below).

For Bulk Actions

If there is no explicitly provided expression profile ID, midPoint looks for the following system configuration properties present in expressions/defaults:

Table 2. Default expression profiles for bulk actions
Property Meaning Default value

bulkActions

Expression profile for midPoint bulk actions running under an unprivileged principal.

##legacyUnprivilegedBulkActions: no expressions (including scripts) are allowed

privilegedBulkActions

Expression profile for midPoint bulk actions running under a privileged principal.

##full: full access

These defaults roughly correspond to pre-4.8 behavior. The distinction between privileged and unprivileged principal is based on whether it possesses the #all authorization. Before 4.8, this authorization was checked before execution of script bulk action and before execution of notify action with the custom event handler. In 4.8, it disallows execution of any expressions (including scripts). It roughly corresponds to the pre-4.7 behavior, but e.g. allows executing notify action with custom event handler that avoids any custom expressions or scripts. (Note that before 4.8 there was no bulk action that evaluated arbitrary expression.)

Security Considerations

Expression profiles are inherently sensitive from information security point of view. However, the problem that expression profiles are trying to solve is not a simple one. Especially constraining scripting languages is a huge task. Scripting languages are designed to be flexible and security considerations are often not very important for scripting languages. Therefore please be very cautious when dealing with scripts, expression and permission profiles. The best recommendation is still not to allow any untrusted party to set up any expressions. But in case that this is not feasible, expression profiles may be useful.

Please exercise extreme caution especially when dealing with permission profiles. Those profiles may get quite complex when it comes to Java platform itself. For example, many methods in java.lang.System object are very dangerous (e.g. exit() method). However, the same class contains methods that are reasonably safe and that are also quite frequently used (e.g.currentTimeMillis()). Therefore it often needed to cherry-pick the methods on a very fine level. And the situation is made worse by the script languages themselves, as they often extend the platform to make it more convenient for a user. For example, Groovy adds execute(…​) method to String class that can be used to execute arbitrary process. While this is very convenient from Groovy programmer’s point of view, it is an utter security disaster. Yet another dangerous thing is a dynamic invocation based on Java Reflection framework. This may even be tightly integrated into some scripting languages. Therefore be very careful and analyse the situation properly. Do not rely on default configuration that comes with midPoint. This configuration is not meant to be completely secure. The setup may vary in various environments, some scripts need to be less powerful, some must be more powerful, some environments are more tolerant to risk and would prefer more flexibility while other environments will heavily constrain flexibility to eliminate the risk. One size does not fit all.

Currently, Groovy is the only language that can be constrained by a permission profile. And even in the case of Groovy, this constraining is quite shallow. There is no sandboxing yet. Groovy scripts are constrained only on compilation level. I.e. the compiler of Groovy scripts will allow or deny a use of specific class or a method. For this method to work, the compiler needs to know types of all the variables and parameters used by the script. Therefore in this case a special type checking mode of Groovy script evaluation must be used. Otherwise the script can assign the System object to a dynamic (untyped) variable and then invoke exit() method on that variable. This is not possible in a type checking mode, as in that case Groovy compiler will determine types for all variables. The script is checked for proper access to classes and methods or the scripts will not compile. Either way, some level of security is assured. However, this protection is still not perfect. The compiler-based protection only examines the script on the surface. Therefore the script cannot execute System.exit() directly. But somewhere in the system there may be a method which can be tricked to executing System.exit() under some circumstances. If such method is used, the compiler does not know that invoking that method may bring the system down. This can only be achieved by a run-time sandboxing of the script execution. While Java platform supports this concept, it is not implemented into midPoint script evaluator yet. Please see Expression Profiles: Full Implementation for the details.

Limitations

  1. Although the expression profile can be specified in any type of archetype (structural or auxiliary), for a given object, at most one expression profile can be specified. If conflicting expression profile identifiers are found, an exception is raised. The reason is that we do not have a reasonable way for merging independently defined expression profiles yet. (This does not apply to super-archetypes. Here, the usual "child-overrides-parent-value" approach applies, i.e. if an expression profile is defined in super-archetype, the child can override that setting.)

  2. The whole object has the same expression profile.

  3. The coverage by expression profiles is NOT COMPLETE. Please see the current status.

  4. For scripting evaluators, the only scripting language that can be constrained by a permission profile is Groovy. Other languages do not have this ability yet. And even Groovy is only constrained on a "compilation level" (see security considerations above).

  5. There may be performance issues when using expression profiles, especially when used with big and complex permission profiles. The code is not yet optimized for performance.

  6. We provide the expression profiles in "AS IS" form. We do not make any claims about security or insecurity of expression profiles. I.e. we do not claim that expression profiles are completely secure. If you are using expression profiles you are doing that completely on your own risk. Proper security testing is more than recommended in such case.

  7. See Expression Profiles: Full Implementation for the details about our plans for the future of expression profiles.

Was this page helpful?
YES NO
Thanks for your feedback