Rules in Object Lifecycle
Introduction
Memority lets you manipulate an object attributes directly while it is being processed, during a CREATE or PATCH operation, using Object Lifecycle Policies. This page describes how the Groovy Rules for those policies must be designed, as well as best practices and attention points.
Overview
Object Lifecycle Policies let one introduce behavior deep in the processing of IDM objects, in performance and failure sensitive operations. For this reason, special care should be taken in writing the associated Groovy Rules. For performance reasons, those policies are not scoped with a search expression. Instead, they are configured for a specific object kind and, optionally, for a set of specific object types. Also, several rules can be configured on a single Policy, to make the most of script reuse and composition.
All Object Lifecycle Policies configured for a given Object Kind and Type are always executed for this kind and type. This means they should be fast and reliable.
I will stress that: reliable
If a Rule fails, the whole object operation transaction will fail. In a bulk scenario, this could be a batch of modifications.
The Rules give a direct access to modifying the well-known ApiObject
that is accessible in the groovy code. There is no patching API and the object's attribute are manipulated directly, in a stage of the object processing that does not perform additional validation or checks on the attributes. This means that, after having been changed, the object must be in a correct, valid state.
Lifecycle Control Stages
Although one do not need to know the details of an object processing pipeline to write an Object Lifecycle Policy rule, it is important to understand where such policies stand in regard to other operations done on the object data, during a create or patch operation.

In the diagram above we consider the "Apply Lifecycle Controls" phase, which is the one during which all automated operations related to an Object lifecycle are performed. This includes handling its enable
state, the authentication methods, computing the Role and Right Assignments on Identities, inheriting the attributes of parent Organizations, and more.
The Lifecycle Controls phase is split in several stages, and the Object Lifecycle Policies can introduce behaviour between those stages. The stages depend on the object kind, and are summarized in the table below:
Stage | Object Kind | Policy Stages (before/after) | Description |
---|---|---|---|
COMMON | all | COMMON_PRE COMMON_POST | Handle the core object lifecycle mechanisms:
|
ASSIGNMENTS | Identity | ASSIGNMENTS_PRE ASSIGNMENTS_POST | Handle the roles and rights hierarchy update, including:
|
AUTH | Identity | AUTH_PRE AUTH_POST | Handles the mechanisms related to Authentication Methods:
|
INHERITANCE | Organization | INHERITANCE_PRE INHERITANCE_POST | Handles the mechanisms related to inheritance in objects that are organized as a hierarchy:
|
REFRESH_ORDERS | Roles | REFRESH_ORDERS_PRE REFRESH_ORDERS_POST | Handles the generation of refresh orders for Roles and Role Assignment Policy changes, when necessary. |
FINALIZE | all | FINALIZE_PRE FINALIZE_POST | Handles last minute operations. This is a placeholder stage, that can also be used by Object Lifecycle Policies to apply behavior at the very last moment. |
Designing Object Lifecycle Policies
Overview
Object Lifecycle Policies should be designed with the following principles in mind:
As few as possible
As targeted as possible
In practice, this means that you should consider:
If you have several behaviors to implement at the same stage, configure a single policy with a single rule that implements all of the behaviors instead of several policies and/or several rules
If the policy applies to only a subset of object types, configure those types on the policy instead of testing for the type in your rule
Also please note that Object Lifecycle Policies are not prioritized, so should several policies exist for the same stage, object kind and object type, they may be executed in any order.
Rules
Basic Principles
Rules in Object Lifecycle Policies are Transform Rules, which means they do not return anything but simply operate on the Rule context (the bound variables).
To manipulate the processed object's attributes, one simply access the OBJECT
bound variable and mutate its content. The OBJECT
properties (attributes) can be directly manipulated using idiomatic Groovy syntax, as in the example below:
OBJECT.commonName = OBJECT.firstName + " " + OBJECT.lastName; // set the value of the 'commonName' attribute
if (OPERATION.operation == ObjectOperation.CREATE && OBJECT.kind == ObjectKind.IDENTITY) {
// always add the 'adm.common-right' right to Identities on creation
OBJECT.rights << RightGrant.of("adm.common-right");
}
Beware, when working with multi-valued attributes: if the object does not have any value for this attribute, the property may be null
, in which case it is necessary to test for nullity before manipulating the list:
if (OBJECT.events == null) {
OBJECT.events = []
}
OBJECT.events << "AWS Summit, April 21st"
It is very important to note that the object's attribute values are considered immutable and must not be modified in place. Instead, an attribute value must be replaced (or added/removed) where necessary. The API always present attribute values as opaque value objects, with facilities to create new, altered versions, where necessary (obviously, for complex attribute values such as Rights or Roles):
OBJECT.roles[0] = RoleAssignment.copying(OBJECT.roles[0]) .status(RoleAssignmentStatus.FROZEN) .build()
OBJECT.roles[0] .setStatus(RoleAssignmentStatus.FROZEN)
ApiObject methods
The ApiObject
also comes with additional methods meant to simplify the manipulation of the attribute values. You can refer to the Javadoc for a complete overview, however here are the most interesting ones:
Method | Usage |
---|---|
CODE
| Return the values for the attribute |
CODE
| Indicates whether or not the object has a value for the attribute |
CODE
| Indicates whether or not the object has the attribute |
CODE
| Add the given value to the multivalued attribute
|
CODE
| Remove the given value from the attribute |
Working with Role Assignments
Role Assignments are complex attribute values, however they must still be considered as immutable value objects that need to be replaced in an Identity's list of roles when they are manipulated.
The RoleAssignment
class provides a builder API that let you quickly create a new Role Assignment from scratch, or from an existing one:
Method | Usage |
---|---|
CODE
| Returns a builder to create a new Role Assignment from scratch. The following defaults are guaranteed:
To obtain a minimum valid Example usage:
CODE
|
CODE
| Returns a builder that is preconfigured to copy the given Example usage:
CODE
|
Best Practices
When implementing an Object Lifecycle Rule, one should keep in mind the following general rules of thumb. Note that they can also be applied to Attribute Compute and Resolve rules.
Rule of thumb | Rationale |
---|---|
Use the earliest stage you can considering your behavior requirement. | This ensures that the changes you make can be used in subsequent stages, and the other lifecycle controls can act on them. |
Only apply necessary computation and use a quick exit pattern. | The control code is executed for each object, so unnecessary computation will slow down all operations needlessly. Instead, your code should test early on if changes must be applied and which changes, and exit quickly as soon as it has been determined that no more computations are needed. |
Do not perform external calls. | Again, external calls (database, web service) are extremely costly and should only be performed as needed. Try to apply strategies to test for it if possible (do not needlessly perform these calls if it is not needed considering the context). For example, an external call that need to be made on creation only should not be performed on PATCH. |
Use Cases
Authentication Method
We want to automatically enable the myMF Aauthentication method on an Identity of type "employee" depending on its location, but only if the Identity is enabled. The authentication methods are managed in the AUTH control stage, but the enabled
status is managed in the COMMON control stage. So our policy must be configured to be applied between the two. We choose COMMON_POST because it is the earliest corresponding to our requirements.
Let's configure the policy:
name | grant_myMFA |
---|---|
objectKind | IDENTITY |
objectTypes | [ "employee" ] |
stages | COMMON_POST |
rules |
GROOVY
The right will only be added if not already granted ( |
Birthright Role
We want to automatically grant a birthright Role to Identities of type "employee" marked 'VIP' whose status is transitioned to "NORMAL". As status checks are performed in the COMMON stage, we decide to do this right after.
Let's configure the policy:
name | assign_birthright |
---|---|
objectKind | IDENTITY |
objectTypes | [ "employee" ] |
stages | COMMON_POST |
rules |
CODE
Here we add as simple Role Assignment with a comment. The default value for the |
Mark for review
We want to mark Identities for review when they have a given set of Roles and have not been reviewed for more than 6 months. To handle this we created two custom attributes:
upForReview
a Boolean attribute that marks the Identity object as needing reviewinglastReviewOn
a Date attribute that provides the last review date, which may benull
Because we base our logic on the Identity's roles, we need the ASSIGNMENTS stage to be run before our rule, so we choose the ASSIGNMENTS_POST stage.
Let's configure the policy:
name | mark_for_review |
---|---|
objectKind | IDENTITY |
objectTypes | [ ] |
stages | ASSIGNMENTS_POST |
rules |
CODE
|