Friday, September 26, 2014

Exposing User System Attributes in OIM 11gR2PS2 GUI Customization

Introduction


Recently while working with a customer to help with an upgrade from OIM 11gR1 to 11gR2PS2, one interesting request came up regarding OIM GUI customization.

The requirement was to expose some User System Attributes that in R1 were directly available in the GUI customization data but in R2 are not exposed in the GUI Customization options.

There is a way in R2 to easily expose the data using a custom Managed Bean along with some GUI tweaks.

The process for customizing the OIM UI is easy enough and well documented in the OIM Customization Guide.

The following content takes you through the steps for exposing the User System Attributes.


The Requirement


Like said before, we need to expose some User System Attributes that are not directly available in the GUI.

In this example, we are going to expose:

usr.usr_create:  user creation date;
usr.usr_pwd_expired: if the user password is expired;
usr.usr_update: user update date;

The page where we will expose this data is the User Details in the OIM Identity Self Service and we want to show something like that:


The Solution


To implement our requirement we will have to:

1. Develop a custom Managed Bean, where we will obtain the user that is being inspected in the OIM User Details page and the required attributes;

2. Export our project as a ADF Library Jar File, which will result in a JAR file;

3. Repackage our JAR file into the Custom Library placeholder, oracle.iam.ui.custom-dev-starter-pack.war;

4. Redeploy the customizations to OIM as a Library;

5. Reference the Managed Bean properties (usr_create, usr_pwd_expired and usr_update) in the User Details Page.

Develop a Custom Managed Bean


The OIM guide to Interface Customizations has the complete details on how to set up the JDeveloper ViewController project, configuration and deployment steps.

I will not go over those details here as it is out of the scope of this post, but the important things to have in mind are:

1. Make sure you create a "ADF ViewController Project";

2. Set the correct Library and Classpath dependencies from "IDM_HOME/server/jdev.lib" folder, as described in the Interface Customization guide;

3. Make sure your Managed Bean has scope set as "backingBean";

4. Make sure your project has deployment profile configured as "ADF Library JAR File", as described in the guide.

5. Add a Managed Bean to your project, as described in the guide, and name it as ExposeUserSystemAttributesMBean, for example.

The important implementation details of the Managed Bean are as follows:

Declare the attributes you want to expose (and auxiliary class properties) and generate getters and setters:

    private String usr_create = "";
    private String usr_update = "";
    private String usr_pwd_expired = "";
    private SimpleDateFormat sdf = new SimpleDateFormat("E MMM dd HH:mm:ss z yyyy");
    private static Logger log = Logger.getLogger("oracle.iam.ui.custom");

 • Since it is a Request Bean, and it will be instantiated for every request made to the User Details page, so it makes sense to initialize the attributes in the Bean constructor:

    public ExposeUserSystemAttributesMBean() {
        getUserSystemAttribute();
    }

The actual work:

    private void getUserSystemAttribute() {

        //Evaluates the EL expression, obtaining the user login being inspected in the OIM GUI
        String usr_lgn = FacesUtils.getValueFromELExpression("#{bindings.userLogin.inputValue}").toString();

        //Gets the UserManager object, so we can search for the User object
        UserManager userMgr = OIMClientFactory.getUserManager();

        //Sets which User Attributes will be returned populated in our User object
        HashSet<String> searchAttrs = new java.util.HashSet<String>();
        searchAttrs.add(UserManagerConstants.AttributeName.USRCREATED.getId());
        searchAttrs.add(UserManagerConstants.AttributeName.USRUPDATED.getId());
        searchAttrs.add(UserManagerConstants.AttributeName.PWD_EXPIRED.getId());
        
        try {
            //Obtains the User Object, searching by USER_LOGIN. If USER_LOGIN is not unique (by default it is)
            //OIM API will throw an SearchKeyNotUniqueException
            User usr = userMgr.getDetails(UserManagerConstants.AttributeName.USER_LOGIN.getId(),usr_lgn,searchAttrs);
            
            //Sets the Bean creation_date property from the User Object
            setUsr_create(sdf.format(usr.getCreationDate()));

            //Some system users (xelsysadm, oiminternal) has usr_pwd_expired=null
            //throwing a NumberFormatException when we try to parse it
            try {
                Boolean is_pass_exp = (Integer.parseInt(usr.getPasswordExpired()) != 0);
                //Sets the Bean usr_pwd_expired property from the User Object
                setUsr_pwd_expired(String.valueOf(is_pass_exp));
            } catch (NumberFormatException nfe) {
                //Sets N/A since in those cases usr_pwd_expired=null
                setUsr_pwd_expired("N/A");
            }

            String u_updt = usr.getAttribute(UserManagerConstants.AttributeName.USRUPDATED.getId()).toString();
            //Sets the Bean usr_update property from the User Object
            setUsr_update(u_updt);     
        } catch (NoSuchUserException nsue) {
            log.log(Level.SEVERE, "Error while getting User System Attributes, caused by: "+nsue.getMessage()+". Check the logs for more details");
            nsue.printStackTrace();
        } catch (UserLookupException ule) {
            log.log(Level.SEVERE, "Error while getting User System Attributes, caused by: "+ule.getMessage()+". Check the logs for more details");
            ule.printStackTrace();
        } catch (SearchKeyNotUniqueException sknue) {
            log.log(Level.SEVERE, "Error while getting User System Attributes, caused by: "+sknue.getMessage()+". Check the logs for more details");
            sknue.printStackTrace();
        } 
    }

Export your project as ADF Library Jar File


If you configured your project deployment profile correctly, all you need to do in JDeveloper is right click your project name, select "Deploy" option, and select your deployment profile:


This will generate the JAR file in the location you configured in your deployment profile.

Repackage our JAR file into the Custom Library placeholder


In order to deploy customizations to OIM GUI, we need to repackage our artifacts into the Library placeholder. 

The library placeholder is a file called oracle.iam.ui.custom-dev-starter-pack.war which can be found in "IDM_HOME/server/apps/" directory.

Make a backup copy of file. Copy the original oracle.iam.ui.custom-dev-starter-pack.war to your workstation. 

Open the file using any ZIP utility, like 7-Zip. Copy your JAR file (in my example it is called "adflibOIMUserSystemAttributes.jar") to "oracle.iam.ui.custom-dev-starter-pack.war\WEB-INF\lib\". 

If the lib folder does not exist into WEB-INF, you will have to create it. The resulting file should look like this:


Copy the modified "oracle.iam.ui.custom-dev-starter-pack.war" back to "IDM_HOME/server/apps/" directory.

Redeploy the customizations to OIM as a Library


Log in to Weblogic Admin Console and go to "Deployments", click "Lock and Edit", select "oracle.iam.ui.custom(11.1.1,11.1.1)" from the list and click "Update" button.


The update process will ask you to select which referencing applications should be updated as well in the process, select both "oracle.iam.console.identity.self-service.ear (V2.0)" and "oracle.iam.console.identity.sysadmin.ear (V2.0)", click Finish then "Activate Changes".


Reference the Managed Bean properties in the User Details Page


To expose our system properties in the User Details page we need to login to OIM Identity Self Service, create and activate a Sandbox first.

Then go to "Administration > Users" and search for a user. 

In the User Details page, click "Customize" then "View > Source". 

This opens a frame on top of the User Details page, where we can add more fields and data to our page.

With your mouse, scroll to the page section where you want to add the managed beans fields, in my case, I chose "Other Attributes", and click the area marked with a blue square:


Select the "panelFormLayout" and click "Add Content"


From the list, select "Web Components" then "Panel with Label and Message", click on the "Add" link and then "Close" button.


A "panelLabelAndMessage" element is added to the "panelFormLayout" we selected before.


Now, select the recently added "panelLabelAndMessage" and click "Edit" button. Set the Label property to one of our properties label, like "User Update Date" and click "OK".


Select the "panelLabelAndMessage" again but now click "Add Content" button. From the list select "Web Components" then "Output Text", click on the "Add" link and then click "Close".

Select the "outputText" we just added and click "Edit" button. 

In the dialog that appears, remove the default Value for the component, and click in the small downward arrow in the right side, to open the Expression Builder.


In the next dialog, select "Type a value or expression" and enter "#{backingBeanScope.exposeUserSystemAttributes.usr_update}", without quotes.

The backingBeanScope part of the EL expression is the standard way ADF references the backing beans (we defined the scope in the adfc-config.xml) in the JSFF/taskflow.

The exposeUserSystemAttributes part is the name we gave to our Managed Bean (also defined in the adfc-config.xml).

Finally, the usr_update part is the bean property we're exposing in our Managed Bean.


Repeat the same procedure for each of the User System attributes fields we're exposing in our Managed Bean.

The location and the way you expose them is a design decision and OIM is flexible enough to allow you a few options, choose what suits you best.

Logging and troubleshooting


If you implement a logger for our custom Managed Bean you can set its log levels in Enterprise Manager once our class in instantiated for the first time. 

For instructions on how to do it, please take a look at my colleague's excellent post on the subject: Logging in OIM Custom Code

You can easily insert log messages for any granularity you wish in your code and check them in the oim_server-diagnostic.log files for troubleshooting or runtime information purposes. 

In case you accidentally published your SandBox or you realized you need to revert back the changes, you can follow the procedure here or follow Support Note "OIM 11gR2: How to Roll back A Published Sandbox (Doc ID 1496179.1)".


No comments:

Post a Comment

Note: Only a member of this blog may post a comment.