Friday Nov 30, 2012

OIM 11g notification framework

OIM 11g has introduced an improved and template based Notifications framework. New release has removed the limitation of sending text based emails (out-of-the-box emails) and enhanced to support html features. New release provides in-built out-of-the-box templates for events like 'Reset Password', 'Create User Self Service' , ‘User Deleted' etc. Also provides new APIs to support custom templates to send notifications out of OIM.

OIM notification framework supports notification mechanism based on events, notification templates and template resolver. They are defined as follows:

Ø Events are defined as XML file and imported as part of MDS database in order to make notification event available for use.

Ø Notification templates are created using OIM advance administration console. The template contains the text and the substitution 'variables' which will be replaced with the data provided by the template resolver. Templates support internationalization and can be defined as HTML or in form of simple text.

Ø Template resolver is a Java class that is responsible to provide attributes and data to be used at runtime and design time. It must be deployed following the OIM plug-in framework. Resolver data provided at design time is to be used by end user to design notification template with available entity variables and it also provides data at runtime to replace the designed variable with value to be displayed to recipients.

Steps to define custom notifications in OIM 11g are:

Steps#

Steps

1.

Define the Notification Event

2.

Create the Custom Template Resolver class

3.

Create Template with notification contents to be sent to recipients

4.

Create Event triggering spots in OIM

1. Notification Event metadata

The Notification Event is defined as XML file which need to be imported into MDS database. An event file must be compliant with the schema defined by the notification engine, which is NotificationEvent.xsd. The event file contains basic information about the event.
XSD location in MDS database: “/metadata/iam-features-notification/NotificationEvent.xsd”
Schema file can be viewed by exporting file from MDS using weblogicExportMetadata.sh script.
Sample Notification event metadata definition:

1: <?xml version="1.0" encoding="UTF-8"?>

2: <Events xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:noNamespaceSchemaLocation="../../../metadata/NotificationEvent.xsd">

3: <EventType name="Sample Notification">

4: <StaticData>

5: <Attribute DataType="X2-Entity" EntityName="User" Name="Granted User"/>

6: </StaticData>

7: <Resolver class="com.iam.oim.demo.notification.DemoNotificationResolver">

8: <Param DataType="91-Entity" EntityName="Resource" Name="ResourceInfo"/>

9: </Resolver>

10: </EventType>

11: </Events>

Line#

Description

1.

XML file notation tag

2.

Events is root tag

3.

EventType tag is to declare a unique event name which will be available for template designing

4.

The StaticData element lists a set of parameters which allow user to add parameters that are not data dependent. In other words, this element defines the static data to be displayed when notification is to be configured. An example of static data is the User entity, which is not dependent on any other data and has the same set of attributes for all event instances and notification templates. Available attributes are used to be defined as substitution tokens in the template.

5.

Attribute tag is child tag for StaticData to declare the entity and its data type with unique reference name. User entity is most commonly used Entity as StaticData.

6.

StaticData closing tag

7.

Resolver tag defines the resolver class. The Resolver class must be defined for each notification. It defines what parameters are available in the notification creation screen and how those parameters are replaced when the notification is to be sent. Resolver class resolves the data dynamically at run time and displays the attributes in the UI.

8.

The Param DataType element lists a set of parameters which allow user to add parameters that are data dependent. An example of the data dependent or a dynamic entity is a resource object which user can select at run time. A notification template is to be configured for the resource object. Corresponding to the resource object field, a lookup is displayed on the UI. When a user selects the event the call goes to the Resolver class provided to fetch the fields that are displayed in the Available Data list, from which user can select the attribute to be used on the template.

Param tag is child tag to declare the entity and its data type with unique reference name.

9.

Resolver closing tag

10

EventType closing tag

11.

Events closing tag

Note: - DataType needs to be declared as “X2-Entity” for User entity and “91-Entity” for Resource or Organization entities. The dynamic entities supported for lookup are user, resource, and organization.

Once notification event metadata is defined, need to be imported into MDS database. Fully qualified resolver class name need to be define for XML but do not need to load the class in OIM yet (it can be loaded later).

2. Coding the notification resolver

All event owners have to provide a resolver class which would resolve the data dynamically at run time. Custom resolver class must implement the interface oracle.iam.notification.impl.NotificationEventResolver and override the implemented methods with actual implementation. It has 2 methods:

S#

Methods Descriptions

1.

public List<NotificationAttribute> getAvailableData(String eventType, Map<String, Object> params);

This API will return the list of available data variables. These variables will be available on the UI while creating/modifying the Templates and would let user select the variables so that they can be embedded as a token as part of the Messages on the template. These tokens are replaced by the value passed by the resolver class at run time. Available data is displayed in a list.

The parameter "eventType" specifies the event Name for which template is to be read.
The parameter "params" is the map which has the entity name and the corresponding value for which available data is to be fetched.

Sample code snippet:

List<NotificationAttribute> list = new ArrayList<NotificationAttribute>();

long objKey = (Long) params.get("resource");

//Form Field details based on Resource object key

HashMap<String, Object> formFieldDetail = getObjectFormName(objKey);

for (Iterator<?> itrd = formFieldDetail.entrySet().iterator(); itrd.hasNext(); ) {

NotificationAttribute availableData = new NotificationAttribute();

Map.Entry formDetailEntrySet = (Entry<?, ?>)itrd.next();

String fieldLabel = (String)formDetailEntrySet.getValue();

availableData.setName(fieldLabel);

list.add(availableData);

}

return list;

2.

Public HashMap<String, Object> getReplacedData(String eventType, Map<String, Object> params);

This API would return the resolved value of the variables present on the template at the runtime when notification is being sent.

The parameter "eventType" specifies the event Name for which template is to be read.
The parameter "params" is the map which has the base values such as usr_key, obj_key etc required by the resolver implementation to resolve the rest of the variables in the template.

Sample code snippet:


HashMap<String, Object> resolvedData = new HashMap<String, Object>();
String firstName = getUserFirstname(params.get("usr_key"));
resolvedData.put("fname", firstName);

String lastName = getUserLastName(params.get("usr_key"));
resolvedData.put("lname", lastname);
resolvedData.put("count", "1 million");
return resolvedData;

This code must be deployed as per OIM 11g plug-in framework. The XML file defining the plug-in is as below:

<?xml version="1.0" encoding="UTF-8"?>

<oimplugins xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<plugins pluginpoint="oracle.iam.notification.impl.NotificationEventResolver">

<plugin pluginclass= " com.iam.oim.demo.notification.DemoNotificationResolver" version="1.0" name="Sample Notification Resolver"/>

</plugins>

</oimplugins>

3. Defining the template

To create a notification template:

Log in to the Oracle Identity Administration

Click the System Management tab and then click the Notification tab

From the Actions list on the left pane, select Create

On the Create page, enter values for the following fields under the Template Information section:

Template Name: Demo template

Description Text: Demo template

Under the Event Details section, perform the following:

From the Available Event list, select the event for which the notification template is to be created from a list of available events. Depending on your selection, other fields are displayed in the Event Details section. Note that the template Sample Notification Event created in the previous step being used as the notification event. The contents of the Available Data drop down are based on the event XML StaticData tag, the drop down basically lists all the attributes of the entities defined in that tag. Once you select an element in the drop down, it will show up in the Selected Data text field and then you can just copy it and paste it into either the message subject or the message body fields prefixing $ symbol. Example if list has attribute like First_Name then message body will contains this as $First_Name which resolver will parse and replace it with actual value at runtime.

In the Resource field, select a resource from the lookup. This is the dynamic data defined by the Param DataType element in the XML definition. Based on selected resource getAvailableData method of resolver will be called to fetch the resource object attribute detail, if method is overridden with required implementation. For current scenario, Map<String, Object> params will get populated with object key as value and key as “resource” in the map. This is the only input will be provided to resolver at design time. You need to implement the further logic to fetch the object attributes detail to populate the available Data list. List string should not have space in between, if object attributes has space for attribute name then implement logic to replace the space with ‘_’ before populating the list. Example if attribute name is “First Name” then make it “First_Name” and populate the list. Space is not supported while you try to parse and replace the token at run time with real value.

Make a note that the Available Data and Selected Data are used in the substitution tokens definition only, they do not define the final data that will be sent in the notification. OIM will invoke the resolver class to get the data and make the substitutions.

Under the Locale Information section, enter values in the following fields:

To specify a form of encoding, select either UTF-8 or ASCII.

In the Message Subject field, enter a subject for the notification.

From the Type options, select the data type in which you want to send the message. You can choose between HTML and Text/Plain.

In the Short Message field, enter a gist of the message in very few words.

In the Long Message field, enter the message that will be sent as the notification with Available data token which need to be replaced by resolver at runtime.

After you have entered the required values in all the fields, click Save.

A message is displayed confirming the creation of the notification template. Click OK

4. Triggering the event

A notification event can be triggered from different places in OIM. The logic behind the triggering must be coded and plugged into OIM.

Examples of triggering points for notifications:

Event handlers: post process notifications for specific data updates in OIM users

Process tasks: to notify the users that a provisioning task was executed by OIM

Scheduled tasks: to notify something related to the task

The scheduled job has two parameters:

Template Name: defines the notification template to be sent

User Login: defines the user record that will provide the data to be sent in the notification

Sample Code Snippet:

public void execute(String templateName , String userId) {

try {

NotificationService notService = Platform.getService(NotificationService.class);

NotificationEvent eventToSend=this.createNotificationEvent(templateName,userId);

notService.notify(eventToSend);

} catch (Exception e) {

e.printStackTrace();

}

}

private NotificationEvent createNotificationEvent(String poTemplateName, String poUserId) {

NotificationEvent event = new NotificationEvent();

String[] receiverUserIds= { poUserId };

event.setUserIds(receiverUserIds);

event.setTemplateName(poTemplateName);

event.setSender(null);

HashMap<String, Object> templateParams = new HashMap<String, Object>();

templateParams.put("USER_LOGIN",poUserId);

event.setParams(templateParams);

return event;

}

public HashMap getAttributes() {

return null;

}

public void setAttributes() {}

}

Thursday Nov 29, 2012

OIM 11g : Multi-thread approach for writing custom scheduled job

In this post I have shared my experience of designing and developing an OIM schedule job that uses multi threaded approach for updating data in OIM using APIs. I have used thread pool (in particular fixed thread pool) pattern in developing the OIM schedule job. The thread pooling pattern has noted advantages compared to thread per task approach. I have listed few of the advantage here

· Threads are reused
· Creation and tear-down cost of thread is reduced
· Task execution latency is reduced
· Improved performance
· Controlled and efficient management of memory and resources used by threads

More about java thread pool http://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html

The following diagram depicts the high-level architectural diagram of the schedule job that process input from a flat file to update OIM process form data using fixed thread pool approach

The custom scheduled job shared in this post is developed to meet following requirement

1) Need to process a CSV extract that contains identity, account identifying key and list of data to be updated on an existing OIM resource account.

2) CSV file can contain data for multiple resources configured in OIM

3) List of attribute to update and mapping between CSV column to OIM fields may vary between resources

The following are three Java class developed for this requirement (I have given only prototype of the code that explains how to use thread pools in schedule task)

CustomScheduler.java - Implementation of TaskSupport class that reads and passes the parameters configured on the schedule job to Thread Executor class.

package com.oracle.oim.scheduler;

import java.util.HashMap;
import com.oracle.oim.bo.MultiThreadDataRecon;
import oracle.iam.scheduler.vo.TaskSupport;

public class CustomScheduler extends TaskSupport {

public void execute(HashMap options) throws Exception {

/* Read Schedule Job Parameters */
String param1 = (String) options.get(“Parameter1”);
.
int noOfThread = (int) options.get(“No of Threads”);
.
String paramn = (int) options.get(“ParamterN”);

/* Provide all the required input configured on schedule job to Thread Pool Executor implementation class like 1) Name of the file, 2) Delimiter 3) Header Row Numer 4) Line Escape character 5) Config and resource map lookup 6) No the thread to create */

new MultiThreadDataRecon(all_required_parameters, noOfThreads).reconcile();

}

public HashMap getAttributes() { return null; }

public void setAttributes() { }

}

 

MultiThreadDataRecon.java – Helper class that reads data from input file, initialize the thread executor and builds the task queue.

package com.oracle.oim.bo;

import <required file IO classes>;
import <required java.util classes>;
import <required OIM API classes>;
import <csv reader api>;

public class MultiThreadDataRecon {

private int noOfThreads;
private ExecutorService threadExecutor = null;

public MetaDataRecon(<required params>, int noOfThreads) {
//Store parameters locally
.
.
this.noOfThread = noOfThread;
}

/**
* Initialize 
*/

private void init() throws Exception {

try {

// Initialize CSV file reader API objects
// Initialize OIM API objects
/* Initialize Fixed Thread Pool Executor class if no of threads 
configured is more than 1 */

if (noOfThreads > 1) {
threadExecutor = Executors.newFixedThreadPool(noOfThreads);
} else {
threadExecutor = Executors.newSingleThreadExecutor();
}

/* Initialize TaskProcess clas s which will be executing task 
from the Queue */

TaskProcessor.initializeConfig(params);
} catch (***Exception e) {
// TO DO
}
}

/**
* Method to reconcile data from CSV to OIM
*/

public void reconcile() throws Exception {
try {
init();
while(<csv file has line>){
processRow(line);
}
/* Initiate thread shutdown */
threadExecutor.shutdown();
while (!threadExecutor.isTerminated()) {
// Wait for all task to complete.
}
} catch (Exception e) {
// TO DO
} finally {
try {
//Close all the file handles
} catch (IOException e) {
//TO DO
}
}
}

/**
* Method to process 
*/

private void processRow(String row) {
// Create task processor instance with the row data 
// Following code push the task to work queue and wait for next
available thread to execute
threadExecutor.execute(new TaskProcessor(rowData));

}

}

 

TaskProcessor.java – Implementation of “Runnable” interface that executes the required business logic to update data in OIM.

package com.oracle.oim.bo;

import <required APIs>

class TaskProcessor implements Runnable {

//Initialize required member variables
/**
* Constructor
       */
public TaskProcessor(<row data>) {
// Initialize and parse csv row
}

/*
* Method to initialize required object for task execution
*/
public static void initializeConfig(<params>) {
// Process param and initialize the required configs and object
}

/*
* (non-Javadoc)

* @see java.lang.Runnable#run()
*/
public void run() {
if (<is csv data valid>){
processData();
}
}

/**
* Process the the received CSV input
*/

private void processData() {

try{

//Find the user in OIM using the identity matching key value from CSV
// Find the account to be update from user’s account based on account identifying key on CSV
// Update the account with data from CSV
}catch(***Exception e){
//TO DO
}

}

}

 

Thursday Nov 22, 2012

Web Application Integration Steps in OAM 11gR2 (High Level)

  1. Install OAM, Webtier (OHS) and WebGate as per the standard installation steps.
  2. Create a WebGate instance (i.e deploy WebGate)

A WebGate instance must be created that will copy required bits of agent from WEBGATE_HOME to WebGate instance location that shares the same INSTANCE_HOME with OHS

./deployWebGateInstance.sh –w /Oracle/Middleware/Oracle_WT1/instances/instance1/config/ohs1 –oh /Oracle/Middleware/Oracle_OAMWebGate1

Note: Here –w flag indicates OHS instance folder and –oh indicates the WebGate Oracle home

  1. Configure WebGate

In the webgate configuration the EditHttpdConf utility will copy OUI instantiated apache_webgate.template from WEBGATE_HOME to webgate instance location (renamed to webgate.conf), and update httpd.conf with one additional line to include webgate.conf.

export LD_LIBRARY_PATH=$ LD_LIBRARY_PATH:/Oracle/Middleware/Oracle_WT1/lib

Navigate to /Oracle/Middleware/Oracle_OAMWebGate1/webgate/ohs/tools/setup/InstallTools

./EditHttpdConf –w /Oracle/Middleware/Oracle_WT1/instances/instace1/config/OHS/ohs1 –oh /Oracle/Middleware/Oracle_OAMWebGate1 –o webgate.conf

  1. Register WebGate

Use RREG tool to register the OAM 11G WebGate


Navigate to /Oracle/Middleware/Oracle_IDM1/oam/server/rreg/input

Edit OAM11Grequest.xml. Change the specific xml content to include the weblogic admin URL, agentBaseURL, host identifier etc..

Navigate to /Oracle/Middleware/Oracle_IDM1/oam/server/rreg/bin

Set permissions to oamreg.sh à chmod 777 oamreg.sh

Edit oamreg.sh and set OAM_REG_HOME=/Oracle/Middleware/Oracle_IDM1/oam/server/rreg

./oamreg.sh inband input/OAM11Grequest.xml

Enter the WebLogic admin credentials when prompted.

After performing the above steps, there will be two artifcats created under Oracle/Middleware/Oracle_IDM1/oam/server/rreg/output, namely ObAccessClient.xml (Stroing webgate config parameters) and cwallet.sso (storing the agent key). These files must be copied to WebGate instance config folder (/Oracle/Middleware/Oracle_WT1/instances/instance1/config/ohs1/webgate/config)

Restart OHS

  1. Deploy the web application (myApp) in WebLogic application server
  2. Proxy Configuration in OHS

The mod_wl_ohs module enables requests to be proxied from Oracle HTTP Server 11g to Oracle WebLogic Server.

Navigate to /Oracle/Middleware/Oracle_WT1/instances/instance1/config/OHS/ohs1

Edit mod_wl_ohs.conf file to include the following:

<IfModule weblogic_module>

WebLogicHost <WEBLOGIC_HOST>

WebLogicPort <WEBLOGIC_PORT>

# Debug ON

# WLLogFile /tmp/weblogic.log

MatchExpression *.jsp

</IfModule>

<Location /myApp>

SetHandler weblogic-handler

# PathTrim /weblogic

# ErrorPage http:/WEBLOGIC_HOME:WEBLOGIC_PORT/

</Location>

Note: Here WEBLOGIC_HOST and WEBLOGIC_PORT are the WebLogic admin server host and port respectively

Restart OHS. Now if we access the web application URL with OHS host and port

(Ex: http://OHS_HOST:<OHS_PORT>/myApp) so that the requests will be proxied to WebLogic server.

  1. Create a new application domain

Login to OAM Admin Console

Navigate to Shared Componentsà Authentication Schemesà Create Authentication Scheme (Ex: LDAP Auth Scheme. Here the scheme is assoicated with LDAP Authentication Module)

Navigate to Policy Configuration à Application Domain à Create Application Domain

Enter the Application Domain Name and Click Apply.

Navigate to Resources tab and add the resource urls

(Web Application URLs that needs to be protected)

Navigate to Authentication Policy tab à Create a new authentication ploicy by providing the Resource URLs (The sample Web Application URLs) and Authentication Scheme.

Navigate to Authorization Policy tab à Create a new authorization policy à Enter authorization policy name and navigate to Resource Tab à Attach the Reource URL, Host Identifiers here.

Navigate to Conditions tab à Add the conditions like whom to allow and whom to deny access.

Navigate to Rules tab à Crate the Allow Rule and Deny Rule with the available conditions from the previous step so that the Authorization Policy may authorize the logins.

Navigate to Resources tab and attach the Authentication and Authorization plocies created in the above steps.

  1. Test the Web Application Integration.

Monday Nov 19, 2012

How do you test an ICF based connector using Connector Facade Standalone?

The following code helps in writing a standalone java program to test an ICF based connector. The sample code in this example takes into account an ICF based flatfile connector. It is possible to test various operations like create, update, delete, search etc... It is also possible to set values to the connector configuration parameters, add/remove attributes and their values.

public class FlatFile {

private static final java.lang.String BUNDLE_NAME = "<PACKAGE_NAME>";

//Ex: org.info.icf.flatfile

private static final java.lang.String BUNDLE_VERSION = "1.0.0";

private static final java.lang.String CONNECTOR_NAME = "org.info.icf.flatfile.FlatFileConnector";

// Name of connector class i.e. the class implemting the connector SPI operations

public ConnectorFacade getFacade() throws IOException {

ConnectorInfoManagerFactory fact = ConnectorInfoManagerFactory

.getInstance();

File bundleDirectory = new File("<BUNDLE_LOCATION>");

//Ex: /usr/oracle/connector_bundles/

URL url = IOUtil.makeURL(bundleDirectory,

"org.info.icf.flatfile-1.0.0.jar");

ConnectorInfoManager manager = fact.getLocalManager(url);

ConnectorKey key = new ConnectorKey(BUNDLE_NAME, BUNDLE_VERSION,

CONNECTOR_NAME);

ConnectorInfo info = manager.findConnectorInfo(key);

// From the ConnectorInfo object, create the default APIConfiguration.

APIConfiguration apiConfig = info.createDefaultAPIConfiguration();

// From the default APIConfiguration, retrieve the

// ConfigurationProperties.

ConfigurationProperties properties = apiConfig

.getConfigurationProperties();

// Print out what the properties are (not necessary)

List propertyNames = properties.getPropertyNames();

for (String propName : propertyNames) {

ConfigurationProperty prop = properties.getProperty(propName);

System.out.println("Property Name: " + prop.getName()

+ "\tProperty Type: " + prop.getType());

}

properties

.setPropertyValue("fileLocation",

"/usr/oracle/accounts.csv");

// Set all of the ConfigurationProperties needed by the connector.

// properties.setPropertyValue("host", FOOBAR_HOST);

// properties.setPropertyValue("adminName", FOOBAR_ADMIN);

// properties.setPropertyValue("adminPassword", FOOBAR_PASSWORD);

// properties.setPropertyValue("useSSL", false);

// Use the ConnectorFacadeFactory's newInstance() method to get a new

// connector.

ConnectorFacade connFacade = ConnectorFacadeFactory.getInstance()

.newInstance(apiConfig);

// Make sure we have set up the Configuration properly

connFacade.validate();

return connFacade;

}

public static void main(String[] args) throws IOException {

FlatFile file = new FlatFile();

ConnectorFacade cfac = file.getFacade();

Set attrSet = new HashSet();

attrSet.add(AttributeBuilder.build(Name.NAME, "Test01"));

attrSet.add(AttributeBuilder.build("FIRST_NAME", "Test_First"));

attrSet.add(AttributeBuilder.build("LAST_NAME", "Test_Last"));

//Create

Uid uid = cfac.create(ObjectClass.ACCOUNT, attrSet, null);

//Delete

Uid uidP = new Uid("Test01");

cfac.delete(ObjectClass.ACCOUNT, uidP, null);

}

}

Thursday Nov 15, 2012

Introducing weblog IDM 11g

Contributions to this blog are made by NA-TAG Offshore- Security team. This weblog brings to you various articles on Oracle I&AM 11g R1, R2. The articles include OIM11g, OAM 11g, OIA 11g new features, Various ‘How To’ with examples, Solutions/ workarounds for frequently occurring issues, APIs, code samples, Installations, patches etc…
About

OIM11gR2 Blog by NA-TAG Offshore IDAM team

Search

Categories
Archives
November 2012 »
SunMonTueWedThuFriSat
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
16
17
18
20
21
23
24
25
26
27
28
 
       
Today