Friday 20 July 2018

Reverse Engineering on OIM Event Handlers

If someone give me an OIM environment and ask to find out all the event handlers deployed on it and their associated class, it is not that easy process to find out. In this article, I am going to describe how one can find all the event handlers (User, Role etc.) and their qualified class name deployed on OIM (PS3).

Before we start, we need to understand where we generally use event handlers in OIM. It is used normally during any OIM events like create/modify/delete/disable/enable of users or assign/revoke role etc. where create, modify, delete, assign are kind of operation and user, role are entities.

In order to find out how many event handlers are there, follow the below steps:

1. Login to weblogic EM console and expand Identity and Access -> OIM -> oim(11.1.2.0.0)

2. Right click on it and select System MBean Browser.

3. Now naviage to oracle.iam -> server:oim -> Application:oim -> IAMAppDesignMBean

4. Click on ConfigQueryMBeanName

5. From right hand window, click on Operations




6. Click on the getEventHandlers.



7. In the parameter section put the parameter as below:
                  P1 --> Entity Type (user, role etc.)
                  P2 --> Operation (create, modify, delete etc.).

8. Once done click on Invoke.

9. It will display the result in the same page.


10. The output list contains all the event handlers’ doc available in the MDS.

11. It contains validation, pre-process, action, post process along with out of band handlers.

12. Each row contains 5 columns as below
              Stage: whether it is validation, pre-process, action or post process
              Order: Order number of the handlers.
              Name: name of the event handlers
              Location: the document location in MDS
              Conditional: true or false

13. Now pick the appropriate one you need to check further. Normally you can find out from the name.

14. Copy the MDS doc location.

15. Now navigate to oracle.mds.lcm -> Server:oim -> Application: OIMAppMetadata -> MDSAppRuntime

16. Click on MDSAppRuntime and from the right hand panel click on Operations



17. Now click on the first exportMetadata link as mentioned in the picture.


18. In the parameter section we have to provide 2 parameters as below:
              toLocation: Location where file will be downloaded (in the server where OIM is installed)
              docs: name of the MDS doc. In order to enter the doc, click on the pencil icon and add the doc like below. You can add more than one doc at a time. Click OK.



19. Once all the parameters are given click on Invoke.


20. If invoke is successful then success message will be displayed.

21. After this operation, login to the host machine and go to the mentioned output location.

22. You can find the directory structure as per the doc name and the file as below


23. Open the file in editor mode and check the list of event handler defined. You can find the list of event handlers like below:

<action-handler orch-target="oracle.iam.platform.kernel.vo.EntityOrchestration" class="oracle.iam.identity.usermgmt.impl.handlers.custom.CustomPostProcessHandler" entity-type="User" operation="CREATE" name="CustomPostProcessHandler" stage="postprocess" sync="TRUE" order="2000000"/>

24. Now you can get your desired event handler and their associated class name.

Note: if you want to change some of the existing event handlers functionality, simply change the class name and re-import.

Wednesday 18 July 2018

Adding Command Button in OIM PS3 (Managed Bean Concept)

Adding a new command button in oi pages requires UI level customization, where you need to create managed bean. Managed Bean is a regular java bean registered with JSF or in other word, it is a java bean managed by JSF framework. If we create our own managed bean, then we can build our own Expression Language. Let us define a scenario first.

Scenario: Customer requires a button in catalog search page. When clicked, some popup message will be displayed.

In order to develop a custom managed bean, follow the below steps.

Pre-Requisite

Copy the jdev.lib folder from [OIM_HOME]/server directory to you local machine.

Development

1. Open JDeveloper IDE (I am using 11.1.1.7)
2. Click on new and create "Fusion Web Application (ADF)".


3. Follow the steps and click next to complete the creation of new application.
4. You can see there are 2 projects created Model and ViewController
3. Right click on ViewController project and click on New.
4. Choose Java from the left pane and select Java Class from the right pane.



5. click OK and provide the class name (e.g. CustomEventListener)


6. Click OK to create the java file.
7. the entire work space would look like below


8. Right click on the ViewController project and click on Project Properties.
9. In the properties page select Libraries and Classpath
10. Click on Add Library and and select the path of jdev.lib where you copied the shared libraries,
11. Add all three shared libraries from jdev.lib.



12. Click OK to close the window.
13. Now open the CustomEventListener.java and write below code as sample


package view;

import javax.faces.application.FacesMessage;
import javax.faces.event.ActionEvent;
import oracle.iam.ui.platform.utils.FacesUtils;

public class CustomEventListener {
    public CustomEventListener() {
        super();
    }
    
    public void testButtonActionListener(ActionEvent e) {
        
        System.out.println("This is a custom event listener");
        String loggedinUser = FacesUtils.getValueFromELExpression("#{oimcontext.currentUser['User Login']}").toString();
        FacesUtils.addFacesInformationMessage("This is a test message: "+loggedinUser);
        System.out.println("Current Logged In user: "+loggedinUser);
    }
        
}

**** The above code get the current logged in user from the OIM available EL and display a popup message.

9. Save the file. You can write your own logic.
10. Expand Web Content -> Page Flows and open adfc-config.xml
11. Under the Managed Bean section , click on + icon and add a new managed bean like below

Name: CustomELBean
Class: view.CustomEventListener
Scope: backingBean




12. Save the configuration.
13. Now we have to create the deployment profile. To do that, right click on the ViewController project and choose Deployment.

14. Delete the existing profile and click on New to add a new one.
15. From the Archive Type select ADF Library Jar File and in the Name put name of the jar (e.g. adflibTestEventListener1). Click OK to create the profile.


16. Click OK to finish the process.
18. Now right click on the ViewController project and click deploy and select the adflibTestEventListener1 to JAR file.


19. Now your adf library jar is ready for the deployment.

Deploying the Artifacts

1. Copy the oracle.iam.ui.custom-dev-starter-pack.war from OIM_HOME/server/apps directory to your local machine.

2. copy the adflibTestEventListener1.jar from the project deploy folder and move the same to oracle.iam.ui.custom-dev-starter-pack.war\WEB-INF\lib


3. Replace the modified oracle.iam.ui.custom-dev-starter-pack.war to the OIM_HOME/server/apps directory.

4. Stop the OIM managed server.
5. Delete the cache, tmp and stage folders from the [DOMAIN_HOME]/servers/[OIM_MANAGED_SERVER_NAME] directory

6. Start the OIM managed server.


Testing

1. Login into identity self service console using System Administrator privileges.
2. Import the below sandbox.


3. Activate the sandbox.
4. Go to the Self-Service home page and open catalog page.
5. Once the catalog page is opened, you can see an Extra button named Test. Clicking that button display a popup message with the logged-in user ID.




Note: sandbox contain a commandButton with actionListener property added like below

FileName: sandbox_button.zip\oracle\iam\ui\catalog\pages\mdssys\cust\site\site\access-request-train.jspx.xml

<?xml version='1.0' encoding='UTF-8'?>
<mds:customization version="11.1.1.66.73" xmlns:mds="http://xmlns.oracle.com/mds" motype_local_name="root" motype_nsuri="http://java.sun.com/JSP/Page">
   <mds:insert after="pt_pgl3(xmlns(f=http://java.sun.com/jsf/core))/f:facet[@name='separator']" parent="pt_pgl3">
      <af:commandButton xmlns:af="http://xmlns.oracle.com/adf/faces/rich" id="cb1001" text="Test" actionListener="#{backingBeanScope.customELBean.testButtonActionListener}"/>
   </mds:insert>
</mds:customization>

Tuesday 24 April 2018

OIM performance analysis using thread dump

In this article I am going to describe how we can analyse the OIM performance using java thread dump. In many situation we have observed that OIM performance is very poor and response time is quite long. There are many reasons behind this killing slowness and poor server response. Some observed reasons are highlighted below:

1. Re-Try task schedule job is running and queuing huge number of failed tasks.
2. Re-Try failed reconciliation events job running with huge number of failed event.
3. Some event handler is stuck and trying to connect external web service.
4. Some admin role (with huge number of members) taking unexpected time to open and hanged the system etc.

There can many other reason for the poor performance.

In Unix machine, when we run any service (like OIM, SOA etc), a process gets generated. That process ID contains lot of information that we can use to identify reason for poor performance. Me and my colleague Nicola (https://www.linkedin.com/in/nicola-scendoni) together we did some experiment and found a way to detect which processes are causing the issue.

Here I am explaining the steps we performed:

1. first we run ps -ef|grep wls to get the PID of OIM
2. Once we get the PID, we ran below command to get all the threads of OIM.

          top -H -p <PID>




as you can see, the command top displaying all the threads of OIM PID. From these individual threads, identify those which are taking more CPU and Memory. Copy the thread ids into a notepad.

3. Now we need to convert these thread IDs to its corresponding HEX value. In order to convert the decimal PID values to HEX run the below command

                      printf "%x\n" <THREAD ID>


4. Now we will get the thread dump of entire OIM process using JStack

                [JAVA_HOME]/bin/jstack [OIM PID] > /tmp/jstack_dump.txt

5. Open the thread dump /tmp/jstack_dump.txt and search the HEX value of the thread. This will give you the thread which is consuming lots of CPUs and MEMs.



6. Analyse the thread and its classes, and identify the process of OIM which is causing issue. Take the necessary action based on the identified process.


Hope, this blog will help you to identify causes of poor response time of OIM.

Cheers !!!!!!!!!!!!!!!

Wednesday 4 April 2018

OIM Certification Entity Details using SQL

Using SQL query you can find the details of certification entity by providing certification id as input. There are 3 different queries for Application Instance, Entitlement and Role.

OIM does have certification APIs for getting the entity details from certification id like:

CertificationService -> getIDCEntitlementsByBatch
CertificationService -> getIDCRolesByBatch
CertificationService -> getIDCApplicationInstancesByBatch

But many occasion, these APIs create problem during execution.

Below are the sample queries, which can easily replace the above APIs:

----------------------------------- Entitlement Certification --------------------------------------
SELECT
cert_certs.id AS certification_id,
cert_certs.cert_name AS certificationname,
certs_ent_defn.attr_value AS attribute_value,
certd_ent_defn.glossary_def AS name,
          certd_ent_defn.entity_id AS entitlement_entity_id
FROM
certd_ent_defn certd_ent_defn
INNER JOIN cert_certs cert_certs
ON certd_ent_defn.cert_id = cert_certs.id
INNER JOIN certs_ent_defn certs_ent_defn
ON certd_ent_defn.attr_val_id = certs_ent_defn.id
WHERE
         cert_certs.id = [CERT_ID]

------------------------------------ Application Instance Certification ------------------------
SELECT
certd_app_inst.cert_id AS certification_id,
certs_app_inst.iam_endpoint_id AS applicationid,
certs_app_inst.endpoint_name AS application_name
FROM
certs_app_inst, certd_app_inst,
cert_certs 
WHERE
cert_certs.id = certd_app_inst.cert_id 
AND certs_app_inst.id = certd_app_inst.endpoint_id 
        AND cert_certs.id=[CERT_ID]

------------------------------------------ Role Certification --------------------------------------
SELECT
cert_certs.id AS certification_id,
certs_role.rolename,
certs_role.entity_display_name
FROM
certs_role, certd_role,
cert_certs 
WHERE
cert_certs.id = certd_role.cert_id 
AND certd_role.role_id = certs_role.id
AND  cert_certs.id = [CERT_ID]

Thursday 22 March 2018

Developing SOA custom escalation task

In this blog I am going the describe how to write a custom escalation task for SOA human Task.

Normally SOA human task does have predefined escalation process to Manager, Director and CEO. Where escalation task will be automatically assigned to the one of the specified Role.

In case of OIM workflow, only Manager role is defined. Some time we have requirements to escalate workflow task to any other user or role and the same is not supported by the composite. So we have to write our own custom escalation task.

Below are the steps to create a new escalation task.

1. In JDeveloper, create a new Generic Project CustomEscalator.
2. Create a java class named CustomEscalator under the below package

           oracle.bpel.services.workflow.assignment.dynamic

     Note: use the above package only.

3. Add the below library to the project classpath
                    BPEL Runtime
                    BPEL Services
                    BPM Workflow

4. Open the CustomEscalator class and implements IDynamicTaskEscalationPattern.



5. Override the method getTaskEscalationUser(Task task) with your own logic and return the escalation manager's user login.


6. Once the code is complete, compile and create a jar file (simple jar file).
7. transfer the jar file to [SOA_HOME]/soa/modules/oracle.soa.ext_11.1.1 directory.
8. set CLASSPATH=$CLASSPATH:[MW_HOME]/modules/net.sf.antcontrib_1.1.0.0_1-0b2/lib/ant-contrib.jar
9. set PATH=$PATH:[MW_HOME]/modules/org.apache.ant_1.7.1/bin
10. set ANT_HOME=[MW_HOME]/modules/org.apache.ant_1.7.1
11. run "ant -buildfile build.xml" *


12. Open the EM console.
13. Right click on soa-infra and select SOA Administration -> Workflow Properties




14. Click on  and Add a new function.
15. Provide the below parameters:

        Function Name: CustomEscalator
        Classpath: oracle.bpel.services.workflow.assignment.dynamic.CustomEscalator



16. Click Ok and Apply.
17. In the SOA composite, open the HumanTask .task file.
18. Go to the Deadlines.
19. Clear the Highest Approver Title field.
20. Update "CustomEscalator" to the Custom Escalation Java Class.
21. Provide the duration of the escalation as required. (for testing i used 1 min).


22. Save and Deploy the composite.
23. Restart the SOA managed servers.
24. Test the functionality.


-------------------------------------------------------------------------------------------------------------
*While ANT building if you face the below error message, then perform the activity as mentioned:

Error: 
        oracle.soa.ext_11.1.1\build.xml:41: Problem: failed to create task or type if

Solution:
Modify the build.xml as below

 locate this line:
    <if>
        <equals arg1="${Extension-Name}" arg2="oracle.soa.workflow.wc" />

and replace it with:
    <!--
    <if>
        <equals arg1="${Extension-Name}" arg2="oracle.soa.workflow.wc" />

Locate this line:
      <else>
      <jar destfile="${library.path}"
                update="yes" >

and modify it to
      <else>
      -->
      <jar destfile="${library.path}"
                update="yes" >

Locate this line:
        </else>
    </if>

and modify it to:
        <!--
        </else>
    </if>        
        -->

OIM Plugins auto registration

In OIM, we register plugins for event handler, request data validator etc. We generally copy the plugin zip file contains the jar and plugin.xml, and then we register it manually.

OIM also provided a feature to register the plugin automatically after copying the OIM_HOME/server/plugin folder.

Here are the details of auto-registration process of plugin.


Export the oim-config.xml file.

1. login to weblogic EM console
2. Go to Identity and Access -> OIM -> oim(11.1.2.0.0)
3. Right click on it and click System MBean Browser.
4. Now go the below location





5. Click on the MDSAppRuntime.
6. provide toLocation as /tmp
7. provide docs as /db/oim-config.xml


8. once done click on Invoke
9. check on the /tmp location of the respective server (if select oim server1 then check on the oim1 unix server).

10. a directory named db created, under which you will find oim-config.xml


Modify the oim-config.xml

1. open the oim-config.xml in edit mode.
2. Search for the tag pluginConfig



3. Modify the the value of reloadEnabled and relodaInterval accordingly.
                    reloadEnabled=true means auto registration allowed.
                    reloadInterval=20 means auto registration will occured every 20 sec.

4. After changing the value save the change and close the editor.


Import the modified oim-config.xml

1. 1. login to weblogic EM console
2. Go to Identity and Access -> OIM -> oim(11.1.2.0.0)
3. Right click on it and click System MBean Browser.
4. Now go the same location as export.
5. Select importMetadata, and provide fromLocation and docs as below (same as export).


6. Once done click on Invoke.
7. Restart the oim managed servers.

Wednesday 21 February 2018

Using GuardedString in OIM custom code.

It was observed in several cases, where we write custom java code for OIM (adapter, event handler, UI code , scheduler etc) with password as string value. If we store the password as java.lang.String, it is kept in memory as a clear text password and stays in memory at least until it is garbage collected. Code reviewer will always reject such code, if they find any password as java.lang.String.

GuardedString class can eliminate this problem by storing the password as characters in memory in an encrypted form. The encryption key will be a randomly-generated key. In their serialized form, Guarded String will be encrypted using a known default key. This is to provide a minimum level of protection regardless of the transport. For communications with the Remote Connector Framework it is recommended that deployments enable SSL for true encryption.

In this example I will explained how you can use Guarded String in OIM custom code.

GuardedString class is the member of  org.identityconnectors.common.security package and can be found in framework-1.3.2.jar. That means in your java project you have to import framework-1.3.2.jar as a library.


Below code sample describe how to store string password in GuardedString.

import org.identityconnectors.common.security.GuardedString;

String password = "abcd1234";
char[] passwordToChar = password.toCharArray();
GuardedString guardedPassword = new GuardedString(passwordToChar);


Below code sample describe how to get the password from GuardedString

          guardedPassword.access(new GuardedString.Accessor() {
                        @Override
                        public void access(char[] clearChars) {
                            System.out.println( "String password::::::::::::::::::::::::"+new String(clearChars)); //print the password.
                            
                        }
                    });
            retrivePassword.dispose(); // dispose the GuardedString after use.


it is always better to dispose the GuardedString after authentication operation is done using dispose() method.



Friday 9 February 2018

Read OIM ITResource parameter using API

In this blog I am going to explain how to read the OIM IT Resource parameter using API. Here is the code sample you can use to fetch any available IT resource parameter in your java code.


public void getITResourceParameter(String ITResourceName) throws NumberFormatException, tcAPIException, Exception {

final String methodName = "::getITResourceParameter::";
System.out.println("start execution of CallStoredProcedureForDBAT::"+methodName);

Map phAttributeList = new HashMap();
phAttributeList.put("IT Resources.Name", ITResourceName);

HashMap paramMap = new HashMap();

tcITResourceInstanceOperationsIntf ITResourceAPI = (tcITResourceInstanceOperationsIntf)oimClientObj.getService(tcITResourceInstanceOperationsIntf.class);
tcResultSet itresSet = ITResourceAPI.findITResourceInstances(phAttributeList);
itresSet.goToRow(0);
String ITResourceKey = itresSet.getStringValue("IT Resources.Key");
System.out.println("ITResourceKey::"+ITResourceKey);
tcResultSet paramValuesRS = ITResourceAPI.getITResourceInstanceParameters(Long.parseLong(ITResourceKey));

for(int j=0;j<paramValuesRS.getTotalRowCount();j++){

paramValuesRS.goToRow(j);

paramMap.put(paramValuesRS.getStringValue("IT Resources Type Parameter.Name"), paramValuesRS.getStringValue("IT Resources Type Parameter Value.Value"));

}

adminName = (String) paramMap.get("principal"); // "principal" is the IT Resource attribute name
adminPassword = (String) paramMap.get("credentials"); // "credentials" is the IT Resource attribute name
ldapPort = (String) paramMap.get("port"); //"port" is the IT Resource attribute name
HostName = (String) paramMap.get("host"); //"host" is the IT Resource attribute name
searchBase = (String) paramMap.get("baseContexts"); //"baseContexts" is the IT Resource attribute name

System.out.println("adminName ::"+adminName);
System.out.println("adminPassword ::"+adminPassword);
System.out.println("HostName ::"+HostName);
System.out.println("ldapPort ::"+ldapPort);
System.out.println("searchBase ::"+searchBase);

}

Friday 26 January 2018

Trigger SOA workflow from java

In this blog I am going to explain how SOA workflow can be triggered from Java application. SOA workflow contains BPEL process and Human Task. BPEL process initiate the workflow and complete the workflow, where as Human Task represent the action of the workflow like assigning task for approval. From java based application, we can call the BPLE process to initiate the workflow. While calling the BPEL process, we have to provide input as payload. In this example, I am explaining the one way calling of SOA composite, where Java will only call the workflow, but will not expect any return.

Before proceed with the development work, some constraints need to be followed.

1. Usually BPEL process is linked with WebService binding exposed service. If we need to call the composite from java, we need to add Direct Binding service. But we also have to make sure that Direct Binding service is not feeding the payload data to BPEL process. Here is the section we need to add in composite.xml

1. Click on the Exposed Service and click on Insert
2. Select Direct Binding


3. Give a name (e.g. DService1).
4. Select the WSDL same as the web service binding (e.g. ManualAction.wsdl in my example).
5. Choose the port type as the non-callback service (e.g. ManualAction in my example).
6. Choose the Callback Port Type as callback service (e.g. ManualActionCallback.wsdl in my example).
7. Click ok to create the binding.


8. Once the Direct Binding is created, it will look something like below:


9. Now, you have to make the wiring so that Direct binding will point to the Web Service binding. Below xml tag needs to be added in the composite.xml

   <wire>
    <source.uri>DService1</source.uri>
    <target.uri>ManualAction/manualaction_client</target.uri>
  </wire>



   After adding the wire, it should looks like below
 10. Now you can modify the BPEL file according to your business case. Here in this example I have added a Human Task named ManualActionUser.



11. Now the SOA composite is ready. We have to create a java call for this composite.
12. Create a simple java project and below libs to the classpath

Febric-common.jar
Soa-infra-mgmt.jar
Wsclient-extended.jar
Wlfulclient.jar
Common-logging.jar


13. Use the below code to a new class file.

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.naming.Context;
import oracle.soa.api.JNDIDirectConnectionFactory;
import oracle.soa.api.PayloadFactory;
import oracle.soa.api.XMLMessageFactory;
import oracle.soa.api.invocation.DirectConnection;
import oracle.soa.api.invocation.DirectConnectionFactory;
import oracle.soa.api.message.Message;
import oracle.soa.api.message.Payload;
import oracle.xml.parser.v2.XMLPrintDriver;
import org.xml.sax.InputSource;

public class TestWF1 {
    public TestWF1() {
        super();
    }
    
    public static void main(String[] args) throws Exception {
        String operation = "process";

        // This is the request message XML
        String ns = "http://xmlns.oracle.com/TestWLWS/ManualAction/ManualAction";
        String payloadXML = "<process anualaction="" estwlws="" http:="" xmlns.oracle.com="" xmlns="\">" +
                            "<oldvalue>1</oldvalue>" +
                            "<newvalue>Testing</newvalue>" +
                            "<approverusername>REQUAP9</approverusername>" +
                            "<approverrolename>2</approverrolename>" +
                            "<workflowrequired>3</workflowrequired>" +
                            "<processinstancekey>4</processinstancekey>" +
                            "<targetprocesstaskname>5</targetprocesstaskname>" +
                            "<currentprocesstaskinstancekey>6</currentprocesstaskinstancekey>" +
                            "<applicationname>7</applicationname>" +
                            "<beneficiaryuserlogin>8</beneficiaryuserlogin>" +
                            "<beneficiaryuserkey>123654789</beneficiaryuserkey>" +
                            "<processformfieldname>10</processformfieldname>" +
                            "</process>"; 

        String serviceAddress = "soadirect:/default/ManualAction!1.0/DService1";

        // Specify the direct binding connection properties
        Map<string object=""> props = new HashMap<string object="">();
        props.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
        props.put(Context.PROVIDER_URL, "t3://" + "localhost" + ':' + "8001");
        props.put(Context.SECURITY_PRINCIPAL,"weblogic");
        props.put(Context.SECURITY_CREDENTIALS, "Welcome1");

        // Create the direct binding connection, using those context properties
        DirectConnectionFactory factory = JNDIDirectConnectionFactory.newInstance();
        DirectConnection dc = null;
        try {
           dc = factory.createConnection(serviceAddress, props);
            
            oracle.xml.parser.v2.DOMParser op = new oracle.xml.parser.v2.DOMParser();
            op.parse(new InputSource(new StringReader(payloadXML)));
            XMLPrintDriver pd = new XMLPrintDriver(System.out);
            pd.setFormatPrettyPrint(true);
            pd.printDocument(op.getDocument());
            
            Map partData = new HashMap();
            partData.put("payload", op.getDocument().getDocumentElement());
            Payload payload = PayloadFactory.createXMLPayload(partData); 
            
            Message request = XMLMessageFactory.getInstance().createMessage();
            request.setPayload(payload); 
            
            String uuid = "uuid:" + UUID.randomUUID(); 
            System.out.println("uuid = "+ uuid); 
            request.setProperty(request.CONVERSATION_ID, uuid); 
            dc.post("process", request); 

        } catch(Exception e){
            e.printStackTrace();
        }finally {
            dc.close();
        }
    }

}

14. After running the code check from the Weblogic EM console, by checking in instance of the composite


Followers

OIM API for adding process task and retry failed task

 In this blog you can find how to add new process task and retry any failed/rejected tasks using API. Adding new process task: /************...