<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 Configuration
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:
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.
Item | Description | Default value |
---|---|---|
|
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 |
|
Free-form description (comment). |
- |
|
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 |
|
Profiles for individual evaluators. |
see |
|
ID of the actions profile to be used with this expression profile. |
"allow all actions" |
|
ID of the function libraries profile to be used with this expression profile. |
"allow all function libraries" |
|
Is the privilege elevation (runAsRef, runPrivileged) feature available in this profile? |
|
Function Library and 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
andpath
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 functionrecomputeUser
from17b5b255-c71e-4a67-8e42-349862e295ac
can.
<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 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 actions, except for generate-value
.
(Does not make much sense, we use it just as an example.)
<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 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 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
:
<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:
<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 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:
<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 Currently, there are the following built-in profiles: |
For Actions
If there is no explicitly provided expression profile ID, midPoint looks for the following system configuration properties present in expressions/defaults
:
Property | Meaning | Default value |
---|---|---|
|
Expression profile for midPoint actions running under an unprivileged principal. |
|
|
Expression profile for midPoint actions running under a privileged principal. |
|
These defaults roughly correspond to pre-4.8 behavior.
The distinction between privileged and unprivileged principal is based on whether it possesses the |
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
-
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.)
-
The whole object has the same expression profile.
-
The coverage by expression profiles is NOT COMPLETE. Please see the current status.
-
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).
-
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.
-
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.
-
See Expression Profiles: Full Implementation for the details about our plans for the future of expression profiles.