This post shows an example of a post process event handler in OIM. The example is simple and it shows how the user profile can be updated from the event handler based on the information that is provided by OIM to the event handler.
Use case description: a UDF is created in the user profile and it will hold the user's 'Director'. To simplify the use case, the 'Director' will be the 'manager's manager'. In other words, the UDF will be populated with the information from two levels up in the management chain, the value to be used is the director's login.
The first step is to create the UDF that will hold the data. An authorization policy is also needed, otherwise it will not be possible to update the UDF using the APIs. All the steps below must be done in OIM logged as system administrator.
Creating the UDF:
Set the attribute size to 100:
Review and confirm:
Now it is time to the authorization policy. The authorization policy will give full control of the new attribute to the "System Administrators" group:
In the second step, make sure that the new attribute is selected:
Keep the assignment as it shows:
Make sure you select "System Administrators" in the assignment:
Review and finish:
After creating the authorization policy, you can verify its efectiviness navigating to the user creation page. Scrolling all the way down, you should be able to see the custom attribute:
With the UDF and the authorization policy in place, you can go ahead and deploy the plug-in. The plug-in is the code that will be invoked by OIM when executing the post process event handler. A plugin is basically a ZIP file that contains a XML file with the plug-in definition and the jar file containing the compiled plug-in code.
There are two options for deploying a plug-in: copying the ZIP file to $OIM_HOME/plugins folder and using the $OIM_HOME/plugin_utility/pluginregistration.xml ANT script. For development environments I use the first option, for clustered and production environment the second option is the way to go because it will deploy the plug-in to the database.
Below the XML with the plug-in definition:
And the plug-in code:
package com.oimacademy.eventhandlers;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import oracle.iam.identity.exception.UserSearchException;
import oracle.iam.identity.usermgmt.api.UserManager;
import oracle.iam.identity.usermgmt.api.UserManagerConstants.AttributeName;
import oracle.iam.identity.usermgmt.vo.User;
import oracle.iam.platform.Platform;
import oracle.iam.platform.authz.exception.AccessDeniedException;
import oracle.iam.platform.context.ContextAware;
import oracle.iam.platform.entitymgr.EntityManager;
import oracle.iam.platform.entitymgr.vo.SearchCriteria;
import oracle.iam.platform.kernel.spi.PostProcessHandler;
import oracle.iam.platform.kernel.vo.AbstractGenericOrchestration;
import oracle.iam.platform.kernel.vo.BulkEventResult;
import oracle.iam.platform.kernel.vo.BulkOrchestration;
import oracle.iam.platform.kernel.vo.EventResult;
import oracle.iam.platform.kernel.vo.Orchestration;
public class UserDirectorEventHandler implements PostProcessHandler {
public UserDirectorEventHandler() {}
@Override
public void initialize(HashMap<String, String> arg0) {
}
@Override
public boolean cancel(long arg0, long arg1, AbstractGenericOrchestration arg2) {
return false;
}
@Override
public void compensate(long arg0, long arg1, AbstractGenericOrchestration arg2) {
}
public EventResult execute(long l1, long l2, Orchestration orch) {
System.out.println("Executing CRUD operation ");
HashMap<String, Serializable> parameters = orch.getParameters();
try {
executeEvent(parameters,orch.getTarget().getType(), orch.getTarget().getEntityId());
} catch (Exception e) {
e.printStackTrace();
}
return new EventResult();
}
public BulkEventResult execute(long l1, long l2, BulkOrchestration orch) {
System.out.println("Executing BULK operation ");
HashMap<String, Serializable>[] bulkParameters = orch.getBulkParameters();
String[] entityIds = orch.getTarget().getAllEntityId();
for (int i = 0; i < bulkParameters.length; i++) {
try {
executeEvent(bulkParameters[i],orch.getTarget().getType(), entityIds[i]);
} catch (Exception e) {
e.printStackTrace();
}
}
return new BulkEventResult();
}
private List<User> getUser(String fieldName, String fieldValue, String retAttr) throws AccessDeniedException,
UserSearchException {
System.out.println("Searching users with "+fieldName+"="+fieldValue);
Set <String>retAttributes = new HashSet<String>();
retAttributes.add(retAttr);
SearchCriteria srchCriteria = new SearchCriteria(fieldName,fieldValue, SearchCriteria.Operator.EQUAL);
UserManager mgr = Platform.getService(UserManager.class);
return mgr.search(srchCriteria, retAttributes, null);
}
private void executeEvent(HashMap parameterHashMap, String targetType, String targetId) {
System.out.println(parameterHashMap);
Long managerLogin = (parameterHashMap.get(AttributeName.MANAGER_KEY.getId()) instanceof ContextAware)
? (Long) ((ContextAware) parameterHashMap.get(AttributeName.MANAGER_KEY.getId())).getObjectValue()
: (Long) parameterHashMap.get(AttributeName.MANAGER_KEY.getId());
System.out.println("managerLogin "+managerLogin);
if (managerLogin != null) {
try {
Long directorKey = null;
String directorLogin = null;
List<User> users = this.getUser(AttributeName.USER_KEY.getId(), managerLogin.toString(), AttributeName.MANAGER_KEY.getId());
if (users.size()==1) {
directorKey = (Long) users.get(0).getAttribute(AttributeName.MANAGER_KEY.getId());
users = this.getUser(AttributeName.USER_KEY.getId(), directorKey.toString(), AttributeName.USER_LOGIN.getId());
directorLogin = (String) users.get(0).getAttribute(AttributeName.USER_LOGIN.getId());
}
System.out.println("directorLogin "+directorLogin);
if (directorLogin != null) {
HashMap<String, Object> mapAttrs = new HashMap<String, Object>();
mapAttrs.put("Director", directorLogin);
EntityManager entMgr = Platform.getService(EntityManager.class);
entMgr.modifyEntity(targetType,targetId, mapAttrs);
}
}
catch (Exception e) {
System.out.println("Error updating user director "+e.getMessage());
e.printStackTrace();
}
}
}
}
And finally the event handler XML:
A few comments about this example and event handlers:
Use case description: a UDF is created in the user profile and it will hold the user's 'Director'. To simplify the use case, the 'Director' will be the 'manager's manager'. In other words, the UDF will be populated with the information from two levels up in the management chain, the value to be used is the director's login.
The first step is to create the UDF that will hold the data. An authorization policy is also needed, otherwise it will not be possible to update the UDF using the APIs. All the steps below must be done in OIM logged as system administrator.
Creating the UDF:
Set the attribute size to 100:
Now it is time to the authorization policy. The authorization policy will give full control of the new attribute to the "System Administrators" group:
In the second step, make sure that the new attribute is selected:
Keep the assignment as it shows:
Make sure you select "System Administrators" in the assignment:
Review and finish:
After creating the authorization policy, you can verify its efectiviness navigating to the user creation page. Scrolling all the way down, you should be able to see the custom attribute:
With the UDF and the authorization policy in place, you can go ahead and deploy the plug-in. The plug-in is the code that will be invoked by OIM when executing the post process event handler. A plugin is basically a ZIP file that contains a XML file with the plug-in definition and the jar file containing the compiled plug-in code.
There are two options for deploying a plug-in: copying the ZIP file to $OIM_HOME/plugins folder and using the $OIM_HOME/plugin_utility/pluginregistration.xml ANT script. For development environments I use the first option, for clustered and production environment the second option is the way to go because it will deploy the plug-in to the database.
Below the XML with the plug-in definition:
<?xml version="1.0" encoding="UTF-8"?> <oimplugins xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <plugins pluginpoint="oracle.iam.platform.kernel.spi.EventHandler"> <plugin pluginclass="oracle.iam.demo.eventhandlers.UserDirectorEventHandler" version="1.0" name="UserDirectorEventHandler"/> </plugins> </oimplugins>
And the plug-in code:
package com.oimacademy.eventhandlers;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import oracle.iam.identity.exception.UserSearchException;
import oracle.iam.identity.usermgmt.api.UserManager;
import oracle.iam.identity.usermgmt.api.UserManagerConstants.AttributeName;
import oracle.iam.identity.usermgmt.vo.User;
import oracle.iam.platform.Platform;
import oracle.iam.platform.authz.exception.AccessDeniedException;
import oracle.iam.platform.context.ContextAware;
import oracle.iam.platform.entitymgr.EntityManager;
import oracle.iam.platform.entitymgr.vo.SearchCriteria;
import oracle.iam.platform.kernel.spi.PostProcessHandler;
import oracle.iam.platform.kernel.vo.AbstractGenericOrchestration;
import oracle.iam.platform.kernel.vo.BulkEventResult;
import oracle.iam.platform.kernel.vo.BulkOrchestration;
import oracle.iam.platform.kernel.vo.EventResult;
import oracle.iam.platform.kernel.vo.Orchestration;
public class UserDirectorEventHandler implements PostProcessHandler {
public UserDirectorEventHandler() {}
@Override
public void initialize(HashMap<String, String> arg0) {
}
@Override
public boolean cancel(long arg0, long arg1, AbstractGenericOrchestration arg2) {
return false;
}
@Override
public void compensate(long arg0, long arg1, AbstractGenericOrchestration arg2) {
}
public EventResult execute(long l1, long l2, Orchestration orch) {
System.out.println("Executing CRUD operation ");
HashMap<String, Serializable> parameters = orch.getParameters();
try {
executeEvent(parameters,orch.getTarget().getType(), orch.getTarget().getEntityId());
} catch (Exception e) {
e.printStackTrace();
}
return new EventResult();
}
public BulkEventResult execute(long l1, long l2, BulkOrchestration orch) {
System.out.println("Executing BULK operation ");
HashMap<String, Serializable>[] bulkParameters = orch.getBulkParameters();
String[] entityIds = orch.getTarget().getAllEntityId();
for (int i = 0; i < bulkParameters.length; i++) {
try {
executeEvent(bulkParameters[i],orch.getTarget().getType(), entityIds[i]);
} catch (Exception e) {
e.printStackTrace();
}
}
return new BulkEventResult();
}
private List<User> getUser(String fieldName, String fieldValue, String retAttr) throws AccessDeniedException,
UserSearchException {
System.out.println("Searching users with "+fieldName+"="+fieldValue);
Set <String>retAttributes = new HashSet<String>();
retAttributes.add(retAttr);
SearchCriteria srchCriteria = new SearchCriteria(fieldName,fieldValue, SearchCriteria.Operator.EQUAL);
UserManager mgr = Platform.getService(UserManager.class);
return mgr.search(srchCriteria, retAttributes, null);
}
private void executeEvent(HashMap parameterHashMap, String targetType, String targetId) {
System.out.println(parameterHashMap);
Long managerLogin = (parameterHashMap.get(AttributeName.MANAGER_KEY.getId()) instanceof ContextAware)
? (Long) ((ContextAware) parameterHashMap.get(AttributeName.MANAGER_KEY.getId())).getObjectValue()
: (Long) parameterHashMap.get(AttributeName.MANAGER_KEY.getId());
System.out.println("managerLogin "+managerLogin);
if (managerLogin != null) {
try {
Long directorKey = null;
String directorLogin = null;
List<User> users = this.getUser(AttributeName.USER_KEY.getId(), managerLogin.toString(), AttributeName.MANAGER_KEY.getId());
if (users.size()==1) {
directorKey = (Long) users.get(0).getAttribute(AttributeName.MANAGER_KEY.getId());
users = this.getUser(AttributeName.USER_KEY.getId(), directorKey.toString(), AttributeName.USER_LOGIN.getId());
directorLogin = (String) users.get(0).getAttribute(AttributeName.USER_LOGIN.getId());
}
System.out.println("directorLogin "+directorLogin);
if (directorLogin != null) {
HashMap<String, Object> mapAttrs = new HashMap<String, Object>();
mapAttrs.put("Director", directorLogin);
EntityManager entMgr = Platform.getService(EntityManager.class);
entMgr.modifyEntity(targetType,targetId, mapAttrs);
}
}
catch (Exception e) {
System.out.println("Error updating user director "+e.getMessage());
e.printStackTrace();
}
}
}
}
And finally the event handler XML:
<?xml version="1.0" encoding="UTF-8"?> <eventhandlers xmlns="http://www.oracle.com/schema/oim/platform/kernel" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.oracle.com/schema/oim/platform/kernel orchestration-handlers.xsd"> <action-handler class="oracle.iam.demo.eventhandlers.UserDirectorEventHandler" entity-type="User" operation="CREATE" name="UserDirectorUpdate" stage="postprocess" order="1000" sync="TRUE"/> </eventhandlers>
A few comments about this example and event handlers:
- The event handler is defined for post updates only. It could also be used as post create by modifying the event handler XML definition.
- The use of the class oracle.iam.platform.entitymgr.EntityManager for updating the user profile prevents OIM from triggering a second orchestration event after the user gets updated by. If a second execution is needed, then the oracle.iam.identity.usermgmt.api.UserManager class must be used for updating the user (keep in mind that in this case the event handler code will have to have controls to prevent infinite loops in the event handler invocation).
- OIM sends only the modified data in the Orchestration argument sent to the event handler. The event handler in this example depends on the presence of the 'Manager Key' field in the Orchestration data, and it will update the user only when this field is present.
- Keep in mind that post process event handlers can have impact on overall OIM performance, so try to keep them as 'little' as possible.
- The example in this post works for OIM 11g PS1 (11.1.1.5). In order to deploy the same example to a 11.1.1.3 environment, it is necessary to delete the namespaces tags from the event handler XML.
No comments:
Post a Comment