Monday, September 9, 2013

OIM Reset Password Customization Example

Out-of-the-box, the OIM reset password functionality is available to system administrators, and to delegated administrators who have administrative privileges on users’ accounts and have the ‘reset password’ privilege assigned to them. The data of the user who is having his/her password reset plays no role on how this functionality is presented to delegated administrators.

This post shows a way of having password reset functionality behaving differently depending on the end user data. This post is another post of the OIM Academy series, to check the series click here.
Before going further, it is important to mention that there is a need to first understand the OIM UI customizations concepts. Apart from the OIM documentation available here, you can also check this example and this post.

 Out-of-the-box, the OIM reset password functionality is available through a pop-up. The behavior of this pop-up is driven by the “XL.ResetWithGeneratedPwd” system property. The following quote from OIM documentation explains it: “If a user's password is to be reset, then this property determines how the password is to be reset by the delegated administrator. If this property is set to true, then the password is always automatically generated. If set to false, then an additional option of setting the password manually is provided.OIM Identity console provides an easy way to reset someone’s password”.

In other words, out-of-the-box, there is only a single way of showing the out-of-the-box reset password pop-up, and such way is driven by the property mentioned above. In one configuration, delegated administrators have the flexibility of either manually provide a password or automatically generate a password; in the other configuration, only the option to automatically reset the password is available.

But customers might have a different requirement: “for external users, help desks can only trigger automatically password generation; for internal users, help desks can either manually provide a password or automatically generate a password”.

The requirement described above can be achieved with a simple UI customization plus a custom managed bean. First, some of the details on this customization:

  • The main idea is to add a custom action button to the user detail page. The button will invoke a custom managed bean to reset a user’s password (automatically generation).
  • The out-of-the-box ‘reset password’ button will be modified and a condition will be added to it. This condition determines whether or not the button will show on the user detail page
  • This blog post uses the ‘user type’ attribute to create the conditional expressions: the user details page will show OOTB ‘Reset Password’ button when a ‘Employee’ user is shown, and it will show a custom reset password button for any other ‘user type’. Any other user attribute can be used to build the expressions
  • A sandbox is needed to accommodate the UI customizations

Implementing

1. Deploying the custom managed bean 

 Below the code that was created as part of this example. This code must be deployed as a custom managed bean. The code is invoked when the delegated administrator confirms that he/she wants to reset the end user’s password. The code uses OIM APIs to generate a random password.

package com.oracle.iam.demo.view.pwd;

import com.oracle.iam.util.FacesUtils;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;

import oracle.adf.view.rich.event.DialogEvent;

import oracle.iam.identity.usermgmt.api.UserManager;
import oracle.iam.ui.platform.model.common.OIMClientFactory;

public class CustomPwdResetBean {
    
    private static Logger logger = Logger.getLogger("IAM.DEMO");

    public CustomPwdResetBean() {}
    
    public void confirmReset(DialogEvent evt){ 
        
        logger.entering(this.getClass().getName(), "confirmReset ","confirm outcome is "+ evt.getOutcome().name());
        
        try {
            if (evt.getOutcome().compareTo(DialogEvent.Outcome.yes) == 0) {
            
                String userLogin  = FacesUtils.getAttributeBindingValue("userLogin",String.class).trim();
                
                UserManager userMgtService = OIMClientFactory.getUserManager();   
                userMgtService.resetPassword(userLogin,true,true);

                this.setFacesMessage("Password for user "+userLogin+" has been reset successfully!");
                
                logger.logp(Level.FINEST, this.getClass().getName(), "confirmReset", "Reset password for user "+userLogin);
            }
        }
        catch (Exception e) {
            this.setFacesMessage("An internal error has occourred: "+e.getLocalizedMessage());
            logger.logp(Level.SEVERE, this.getClass().getName(), "confirmReset", "Error changing user status",e);   
        }
        logger.exiting(this.getClass().getName(), "confirmReset");
    }
    
    private void setFacesMessage(String msg) {
        
        FacesMessage message = new FacesMessage();
        message.setDetail(msg);
        message.setSummary(msg);
        message.setSeverity(FacesMessage.SEVERITY_INFO);

        FacesContext context = FacesContext.getCurrentInstance();
        context.addMessage(null, message);
    }
}

2. Adding a condition in the out-of-the-box ‘Reset Password’ button

The condition is based on an EL expression that evaluates the ‘User Type’ attribute (keep in mind that internally this attribute is called ‘Role’). Such EL is created on the ‘Visible’ property of ‘Reset Password’ button. In this example, the EL is #{bindings.role.inputValue=='Employee'}:




3. Creating custom UI components

Add an af:commandImageLink UI component right after the OOTB ‘Reset Password’ button. You can copy all the properties from the OOTB ‘password reset’ button to this custom button, the only property to be different is ‘Visible’, it will have a different EL #{bindings.role.inputValue!='Employee'}. You may want to add a af:spacer as well and then reorder the components


4. Manually modifying the sandbox

Export the sandox, open the zip file, and then open oracle\iam\ui\manageusers\pages\mdssys\cust\site\site\userdetails.jsff.xml in a text editor. You will see the af:commandImageLink and the af:spacer you added in the previous step. In order to provide a good user experience to the delegated administrator, add a confirm dialog and configure it to invoke the custom managed bean to reset the user’s password. When the delegated administrator clicks on the custom ‘Reset Password’ button, a confirmation dialog will show up, when he/she confirms, the managed bean is invoked and resets the password.

The screenshot below highlights what needs to be manually added to the userdetails.jsff.xml file. You can notice that the dialogListener property is configured with "#{backingBeanScope.customPwdResetBean.confirmReset}", the customPwdResetBean is the custom managed bean deployed in step 1:

5. Importing the sandbox

Zip up the manually edited file back into the sandbox zip file and then import the file back into OIM. Then make the sandbox active and test the reset password.

The screenshots below show how the results:




Disclaimers and observations:

  • The search user page also shows a reset password button. A similar customization can be done or you can simply hide that button, forcing delegated administrators to navigate to the user details page in order to reset someone’s password
  • The content and codes are provided "as is" and without warranties as to performance or merchantability and are just examples and for informational purpose
  • This post does not go deep in details discussing all the technologies involved in the customization, it is more of a ‘how-to’ example
  • Keep in mind that customizations can always bring performance impact, especially in environments with lots of data. This post does NOT cover any tuning, performance impact or anything like and it was not conceived with performance as an objective

No comments:

Post a Comment

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