Page tree
Skip to end of metadata
Go to start of metadata

This is a sample scenario, as covered by TestPolicyDrivenRoleLifecycle class.

Imagine we have the constraints for a role to be met:

IdConstraint
C1Each role must have a risk level.
C2Each role with risk level of high must have a description.
C3Each role must have an approver. High-risk roles must have at least 2 approvers.
C4Each role must have an owner.
C5Each role must have an identifier.

Then there are the following rules:

IdRule
R1No role that does not meet C1-C4 might be activated i.e. switched to lifecycleState of active.
R2Activation of a role must be approved by its owner.
R3Activation of a role without identifier is subject to an approval by Security Administrators
R4Active role without identifier must be recertified regularly by Security Administrator.
R5Validity of an active role without identifier must be limited to 180 days at most.

Reports requested:

IdRequirement
RE1See all draft roles that do not meet constraints C1-C4.
RE2See 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):

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.

Policy rules implementing the scenario
<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:equal>
                        <q:path>riskLevel</q:path>
                    </q:equal>
                </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' &amp;&amp; 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:equal>
                        <q:path>riskLevel</q:path>
                        <q:value>high</q:value>
                    </q:equal>
                </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:not>
                        <q:equal>
                            <q:path>riskLevel</q:path>
                            <q:value>high</q:value>
                        </q:equal>
                    </q:not>
                </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:equal>
                        <q:path>identifier</q:path>
                    </q:equal>
                </filter>
            </objectState>
        </and>
        <and>
            <objectState>
                <name>role-active</name>
                <filter>
                    <q:or>
                        <q:equal>
                            <q:path>lifecycleState</q:path>
                            <q:value>active</q:value>
                        </q:equal>
                        <q:equal>
                            <q:path>lifecycleState</q:path>
                        </q:equal>
                    </q:or>
                </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()) &gt; 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>

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]
  • No labels