<globalPolicyRule>
<name>basic-constraints-definitions</name>
<description>
This is no-action disabled rule that is used to define basic constraints:
what is an incomplete role (as per C1 to C4), what is a role activation, etc.
To keep constraints in the logical order we must enclose each in separate "and"
element. Otherwise the IDE would issue a lot of XSD validation errors
(because of the ordering prescribed in PolicyConstraintsType definition).
</description>
<policyConstraints>
<and>
<objectState>
<name>c1-no-risk-level</name>
<!-- presentation is not needed, as default key of PolicyConstraint.c1-no-risk-level is used -->
<filter>
<q:text>riskLevel not exists</q:text>
</filter>
</objectState>
</and>
<and>
<objectState>
<!-- could be implemented also as a conjunction of two filter-based objectState constraints -->
<name>c2-no-description-for-high-risk-role</name>
<!-- presentation is not needed, as default key of PolicyConstraint.c2-no-description-for-high-risk-role is used -->
<expression>
<script>
<code>object.riskLevel == 'high' && object.description == null</code>
</script>
</expression>
</objectState>
</and>
<and>
<name>c3-less-than-2-approvers-for-high-risk-role</name>
<!-- message definition is not needed, as default key of PolicyConstraint.c3-less-than-2-approvers-for-high-risk-role is used -->
<presentation>
<final>true</final> <!-- we don't need to show further details -->
</presentation>
<objectState>
<name>high-risk-role</name>
<filter>
<q:text>riskLevel = "high"</q:text>
</filter>
</objectState>
<objectMinAssigneesViolation>
<multiplicity>2</multiplicity>
<relation>approver</relation>
</objectMinAssigneesViolation>
</and>
<and>
<name>c3-less-than-1-approver-for-non-high-risk-role</name>
<!-- message definition is not needed, as default key of PolicyConstraint.c3-less-than-1-approver-for-non-high-risk-role is used -->
<presentation>
<final>true</final>
</presentation>
<objectState>
<name>not-high-risk-role</name>
<filter>
<q:text>riskLevel != "high"</q:text>
</filter>
</objectState>
<objectMinAssigneesViolation>
<multiplicity>1</multiplicity>
<relation>approver</relation>
</objectMinAssigneesViolation>
</and>
<and>
<objectMinAssigneesViolation>
<name>c4-no-role-owner</name>
<!-- PolicyConstraint.c4-no-role-owner is intentionally not defined, to demonstrate the use of the built-in message -->
<multiplicity>1</multiplicity>
<relation>owner</relation>
</objectMinAssigneesViolation>
</and>
<and>
<objectState>
<name>c5-no-identifier</name>
<!-- no message definition is needed: a key of PolicyConstraint.c5-no-identifier is used -->
<!-- situation and expectedUse are set for "active role with no identifier" because that's what we want to certify and report -->
<presentation>
<hidden>true</hidden>
</presentation>
<filter>
<q:text>identifier not exists</q:text>
</filter>
</objectState>
</and>
<and>
<objectState>
<name>role-active</name>
<filter>
<q:text>lifecycleState = "active" or lifecycleState not exists</q:text>
</filter>
</objectState>
</and>
<and>
<objectState>
<name>validity-not-limited</name>
<presentation>
<message>
<keyExpression>
<script>
<code>
import com.evolveum.midpoint.xml.ns._public.common.common_3.*
if (object.activation == null) {
'PolicyConstraint.validity-not-limited.validToNull'
} else if (object.activation.administrativeStatus == ActivationStatusType.ENABLED) {
'PolicyConstraint.validity-not-limited.enabled'
} else if (object.activation.validTo == null) {
'PolicyConstraint.validity-not-limited.validToNull'
} else {
'PolicyConstraint.validity-not-limited.validToNotNull'
}
</code>
</script>
</keyExpression>
<argumentExpression>
<script>
<code>
object.activation?.validTo
</code>
</script>
</argumentExpression>
</message>
</presentation>
<expression>
<script>
<code>
import com.evolveum.midpoint.xml.ns._public.common.common_3.*
import com.evolveum.midpoint.prism.xml.XmlTypeConverter
if (object.activation == null) {
return true
}
def state = object.activation.administrativeStatus
if (state == ActivationStatusType.ENABLED) {
return true
} else if (state != null) {
return false
}
def validTo = object.activation.validTo
if (validTo == null) {
return true
}
def nowPlus180 = XmlTypeConverter.fromNow(XmlTypeConverter.createDuration("P180D"))
return validTo.toGregorianCalendar().compareTo(nowPlus180.toGregorianCalendar()) > 0
</code>
</script>
</expression>
</objectState>
</and>
<and>
<name>active-role-with-no-identifier</name>
<!-- presentation is not needed, as default key of PolicyConstraint.active-role-with-no-identifier is used -->
<presentation>
<final>true</final>
</presentation>
<ref>
<name>role-active</name>
</ref>
<ref>
<name>c5-no-identifier</name>
</ref>
</and>
<and>
<or>
<name>incomplete-role-c1-to-c4</name>
<!-- message definition is not needed, as the default key of PolicyConstraint.incomplete-role-c1-to-c4 is used -->
<presentation>
<hidden>true</hidden>
</presentation>
<ref>
<name>c1-no-risk-level</name>
</ref>
<ref>
<name>c2-no-description-for-high-risk-role</name>
</ref>
<ref>
<name>c3-less-than-1-approver-for-non-high-risk-role</name>
</ref>
<ref>
<name>c3-less-than-2-approvers-for-high-risk-role</name>
</ref>
<ref>
<name>c4-no-role-owner</name>
</ref>
</or>
</and>
<and>
<transition>
<name>role-activation</name>
<presentation>
<final>true</final>
<hidden>true</hidden>
</presentation>
<stateBefore>false</stateBefore>
<stateAfter>true</stateAfter>
<constraints>
<ref>
<name>role-active</name>
</ref>
</constraints>
</transition>
</and>
</policyConstraints>
<condition>
<!-- This rule serves as a container for constraints definitions. It is not to be evaluated directly. -->
<expression>
<value>false</value>
</expression>
</condition>
</globalPolicyRule>
<globalPolicyRule>
<name>r1-no-activation-of-incomplete-roles</name>
<description>R1: No role that does not meet C1-C4 might be activated i.e. switched to lifecycleState of active.</description>
<policyConstraints>
<name>r1-no-activation-of-incomplete-roles</name>
<!-- presentation uses PolicyConstraint.r1-no-activation-of-incomplete-roles -->
<!-- Note: situation is not defined here, as this is a transition-related rule.
Situation marking incomplete rules is defined in incomplete-role-c1-to-c4 constraint. -->
<ref>
<name>incomplete-role-c1-to-c4</name>
</ref>
<ref>
<name>role-activation</name>
</ref>
</policyConstraints>
<policyActions>
<enforcement/>
</policyActions>
<focusSelector>
<type>RoleType</type>
</focusSelector>
</globalPolicyRule>
<globalPolicyRule>
<name>r2-role-activation-approval</name>
<description>R2: Activation of a role must be approved by its owner.</description>
<policyConstraints>
<name>r2-role-activation-approval</name>
<presentation>
<final>true</final>
</presentation>
<ref>
<name>role-activation</name>
</ref>
</policyConstraints>
<policyActions>
<approval>
<compositionStrategy>
<order>10</order>
</compositionStrategy>
<approvalSchema>
<stage>
<approverRelation>owner</approverRelation>
</stage>
</approvalSchema>
</approval>
</policyActions>
<focusSelector>
<type>RoleType</type>
</focusSelector>
</globalPolicyRule>
<globalPolicyRule>
<name>r3-no-identifier-role-activation-approval</name>
<description>R3: Activation of a role without identifier is subject to an approval by Security Administrators.</description>
<policyConstraints>
<name>r3-no-identifier-role-activation-approval</name>
<presentation>
<final>true</final>
</presentation>
<ref>
<name>role-activation</name>
</ref>
<ref>
<name>c5-no-identifier</name>
</ref>
</policyConstraints>
<policyActions>
<approval>
<compositionStrategy>
<order>10</order>
</compositionStrategy>
<approvalSchema>
<stage>
<approverRef oid="a14afc10-e4a2-48a4-abfd-e8a2399f98d3" type="c:OrgType"/> <!-- Security Administrators -->
</stage>
</approvalSchema>
</approval>
</policyActions>
<focusSelector>
<type>RoleType</type>
</focusSelector>
</globalPolicyRule>
<globalPolicyRule>
<name>r5-validity-limitation-for-active-role</name>
<description>R5: Validity of an active role without identifier must be limited to 180 days at most.</description>
<policyConstraints>
<name>r5-validity-limitation-for-active-role</name>
<and>
<presentation>
<final>true</final>
<hidden>true</hidden>
</presentation>
<ref>
<name>active-role-with-no-identifier</name>
</ref>
</and>
<ref>
<name>validity-not-limited</name>
</ref>
</policyConstraints>
<policyActions>
<enforcement/>
</policyActions>
<focusSelector>
<type>RoleType</type>
</focusSelector>
</globalPolicyRule>
<globalPolicyRule>
<name>re1-report-draft-roles-violating-c1-c4</name>
<description>RE1: See all draft roles that do not meet constraints C1-C4.</description>
<policyConstraints>
<ref>
<name>incomplete-role-c1-to-c4</name>
</ref>
</policyConstraints>
<policySituation>http://sample.org/situations#incomplete-role-c1-to-c4</policySituation>
<policyActions>
<record>
<policyRules>full</policyRules> <!-- assuming we want to be able to display details of the problem -->
</record>
</policyActions>
<focusSelector>
<type>RoleType</type>
</focusSelector>
</globalPolicyRule>
<globalPolicyRule>
<name>re2-report-active-roles-violating-c5</name>
<description>RE2: See all active roles that do not meet constraint C5.</description>
<policyConstraints>
<ref>
<name>active-role-with-no-identifier</name>
</ref>
</policyConstraints>
<policySituation>http://sample.org/situations#active-role-with-no-identifier</policySituation>
<policyActions>
<record>
<policyRules>none</policyRules> <!-- assuming we only want the list of roles matching this rule (no details needed) -->
</record>
</policyActions>
<focusSelector>
<type>RoleType</type>
</focusSelector>
</globalPolicyRule>
Sample scenario
This is a sample scenario, as covered by TestPolicyDrivenRoleLifecycle class.
Imagine we have the constraints for a role to be met:
Id | Constraint |
---|---|
C1 |
Each role must have a risk level. |
C2 |
Each role with risk level of high must have a description. |
C3 |
Each role must have an approver. High-risk roles must have at least 2 approvers. |
C4 |
Each role must have an owner. |
C5 |
Each role must have an identifier. |
Then there are the following rules:
Id | Rule |
---|---|
R1 |
No role that does not meet C1-C4 might be activated i.e. switched to lifecycleState of active. |
R2 |
Activation of a role must be approved by its owner. |
R3 |
Activation of a role without identifier is subject to an approval by Security Administrators |
R4 |
Active role without identifier must be recertified regularly by Security Administrator. |
R5 |
Validity of an active role without identifier must be limited to 180 days at most. |
Reports requested:
Id | Requirement |
---|---|
RE1 |
See all draft roles that do not meet constraints C1-C4. |
RE2 |
See all active roles that do not meet constraint C5. |
Rules in action
Let’s say we have a role that breaks almost all constraints: has no risk level defined, no approver, no owner, no identifier, no validity set. After trying to activate such role, the following would appear (currently only for preview changes due to implementation limitations):
[ Image missing ]
The message Role test1234 (OID bbb0d3aa-0b2f-4710-80e0-11360c423c37) requires at least 1 assignees with the relation of 'owner' is intentionally different from the others. It is present just to show how default constraint messages look like, in comparison with custom ones. |
Policy rules used
This is how it could be implemented.
Localization properties:
PolicyConstraint.role-activation=Role is being activated
PolicyConstraint.active-role-with-no-identifier=Active role with no identifier [C5]
PolicyConstraint.incomplete-role-c1-to-c4=Role definition is incomplete as defined in C1-C4
PolicyConstraint.c1-no-risk-level=No risk level defined [C1]
PolicyConstraint.c2-no-description-for-high-risk-role=No description for high risk role [C2]
PolicyConstraint.c3-less-than-2-approvers-for-high-risk-role=Less than 2 approvers for high-risk role [C3]
PolicyConstraint.c3-less-than-1-approver-for-non-high-risk-role=No approver for non-high-risk role [C3]
#PolicyConstraint.c4-no-role-owner=No role owner [C4] # using default presentation instead
PolicyConstraint.c5-no-identifier=No role identifier [C5]
PolicyConstraint.validity-not-limited.status=Validity is not limited (status is set to 'enabled')
PolicyConstraint.validity-not-limited.validToNull=Validity is not limited (validTo is not set)
PolicyConstraint.validity-not-limited.validToNotNull=Validity is not limited (validTo is set to {0})
PolicyConstraint.r1-no-activation-of-incomplete-roles=No role that does not meet C1-C4 might be activated [R1]
PolicyConstraint.r2-role-activation-approval=Activation of a role must be approved by its owner [R2]
PolicyConstraint.r3-no-identifier-role-activation-approval=Activation of a role without identifier is subject to an approval by Security Administrators [R3]
PolicyConstraint.r5-validity-limitation-for-active-role=Validity of an active role without identifier must be limited to 180 days at most [R5]