Tuesday, May 7, 2013

OIM 11g R2 Self Registration with CAPTCHA

This post walks you through the fun of customizing OIM and adding a CAPTCHA solution to the self-registration page. Captcha solutions are largely used in web sites to try to prevent automated robots from registering, filling forms, sending messages and many other things.

The captcha solution used is Simple Captcha and it is available here. It is easy to use and easy to hook into applications.

This is another post of the Oracle Identity Manager Academy. To check other tricks, tips and examples you can find the academy post here.

Deploying the captcha solution


Unfortunately, a usually non-recommended step is required to hook the captcha solution into OIM: the capctha servlet must be deployed to the OIM self-service console web application. To do so, you have to:
  1.  Make a backup of $OIM_ORACLE_HOME/server/apps/oracle.iam.console.identity.self-service.ear
  2. Copy the file oracle.iam.console.identity.self-service.ear to a temporary location
  3. Using a ZIP tool like 7zip, open the oracle.iam.console.identity.self-service.ear
  4. Then open oracle.iam.console.identity.self-service.war
  5. Then navigate to WEB-INF folder and add the following to the web.xml file:
    <servlet-name>CaptchaServlet</servlet-name>
    <servlet-class>nl.captcha.servlet.SimpleCaptchaServlet</servlet-class>
    <init-param>
            <param-name>width</param-name>
            <param-value>250</param-value>
    </init-param>
    <init-param>
       <param-name>height</param-name>
       <param-value>75</param-value>
    </init-param>
  </servlet>

You also need to add the captcha jar file (simplecaptcha-1.2.1.jar) into the oracle.iam.console.identity.self-service.war 'lib' folder (if the folder does not exist, just create it).

Then copy the file oracle.iam.console.identity.self-service.ear over the original one and restart WebLogic (you may need to re-deploy the oracle.iam.ui.self-service application in the WebLobig console).

Customizing OIM self registration page


Before starting this section, it is important to mention that the post assumes you have some knowledge of OIM UI customization features. If you don't, you may want to spend some time in the following posts:
There are a couple of tricks to use to customize the self registration page:
  • To direct access the self registration page you can type in the browser url: http://<OIM_HOST>:<OIM_PORT>:/identity/faces/register. This URL works with and without authentication, but OIM will prevent you from submitting a request for self registration if you are authenticated.
  • When on the page, make sure you provide values to the mandatory fields before trying to customize it.

1. The managed bean

There is a need to create and deploy a managed bean. This managed bean must be deployed into the oracle.iam.ui.custom-dev-starter-pack.war placeholder library. In this example, the managed bean is  called 'captchaBean'. The managed bean code:

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

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.validator.ValidatorException;

import nl.captcha.Captcha;

import oracle.adf.view.rich.component.rich.output.RichImage;

public class CaptchaBean {

    private UIComponent rootPanel;
    private UIComponent captchaImage;
    
    public CaptchaBean() {
        super();
    }
    
    public void refreshCaptchaActionListener(ActionEvent e) {

        RichImage image = (RichImage)captchaImage;
        String randomString= String.valueOf(Math.random());
        image.setSource("/captcha?rand="+randomString);           
        
        FacesUtils.partialRender(rootPanel);
    }

    public void verifyCaptchaValue(FacesContext facesContext, UIComponent uiComponent, Object compValue) {
  
        FacesContext fctx = FacesContext.getCurrentInstance();

        ExternalContext ectx = fctx.getExternalContext();

        Captcha captcha = (Captcha)ectx.getSessionMap().get(Captcha.NAME);
        String answer = (String)compValue;
        
        if (!captcha.isCorrect(answer)) {
            throw new ValidatorException(this.getFacesMessage("Please provide a correct answer"));
        }
    }

    private FacesMessage getFacesMessage(String msg) {
            
        FacesMessage message = new FacesMessage();
        message.setDetail(msg);
        message.setSummary(msg);
        message.setSeverity(FacesMessage.SEVERITY_ERROR);

        return message;
    }
    
    public void setRootPanel(UIComponent rootPanel) {
        this.rootPanel = rootPanel;
    }

    public UIComponent getRootPanel() {
        return rootPanel;
    }

    public void setCaptchaImage(UIComponent captchaImage) {
        this.captchaImage = captchaImage;
    }

    public UIComponent getCaptchaImage() {
        return captchaImage;
    }
}

A few comments about the code:
  • The method 'verifyCaptchaValue' will be invoked by ADF when the self-registration form is submitted. The property 'validator' in an input text filed indicates which method ADF will invoked. If the method raises the 'ValidatorException', ADF will catch it and show the 'Please provide a correct answer" message on the page.
  •  The method 'refreshCaptchaActionListener' will be invoked when the user clicks on a button to refresh the captcha image. It actually changes the image URL by adding a random string to the end, this is required to make sure that the image gets refreshed. 
  • This code uses the class 'FacesUtils', such class can be found here
The managed bean declaration is done in the adfc-config.xml file:
<?xml version="1.0" encoding="windows-1252" ?>
<adfc-config xmlns="http://xmlns.oracle.com/adf/controller" version="1.2">
  <managed-bean id="__222">
    <managed-bean-name id="__4">captchaBean</managed-bean-name>
    <managed-bean-class id="__1">com.oracle.demo.iam.captcha.view.CaptchaBean</managed-bean-class>
    <managed-bean-scope id="__3">backingBean</managed-bean-scope>
  </managed-bean>
</adfc-config>

The managed bean must be deployed before proceeding with the UI customizations because the methods will be referenced from the custom UI components.

2. Adding the UI components

There are two main UI components to be added through UI customization using the composer: a texfield where end users will enter the captch value, and a button to refresh the captcha image. There is also a need for a couple of layout components to organize the button and the textfield in the self registration page.

2.1 The first step is to create and activate a sandbox that will hold the UI customizations.

2.2 With the sandbox created and actived, hit the customize OIM link on the top right. Then on your browser enter the self registration URL mentioned above.

2.3 Customize the page by adding the following elements under the 'panelHeader: User Registration' component
  • 'Web Components' - 'Show Detail Header'
  • 'Web Components' - 'Spacer'
2.4  Edit the 'Spacer' and set 'Height' to 10 and clean up the 'Width' value

2.5 Edit the 'showDetailHeader:Header' component and set the 'Text' property to 'Are you Human?'

2.6 Edit the 'panelHeader: User Registration' and re-order the child components, the order should be as the one shown in the picture below:


2.7 Click on ''showDetailHeader:Header'' and add a 'Web Components' - 'Panel Form Layout' to it

2.8 Edit the 'panelFormLayout' and set the 'Binding' property to '#{backingBeanScope.captchaBean.rootPanel}'.

2.9 Still with the 'panelFormLayout' selected, add a 'Web Components' - 'Input Text' and a 'Web Components' - 'Command Toolbar Button'

2.10 Edit the 'inputText: Label', set the 'Label' to 'Enter the code above', and click on the 'Required' checkbox. The 'Required' flag tells ADF to validate the field before the form is submitted.

2.11 Edit the 'commandToolbarButton', set the 'Text' to 'Cannot see? Refresh Image' and click on the 'Immediate' checkbox. The 'Immediate' flag tells that a partial form submit is allowed.

At this point, the page should be like the one below:


2.12 Close the customization by clicking on the link on the top right and navigate back to the identity self service console

3. Manually customizing UI components

OIM UI customization features does not expose all ADF components attributes, so there is a need to do some manual intervention to get the components configured.

3.1 De-activate the sandbox and export it

3.2 Open the sandbox zip file and locate the following file: oracle\iam\ui\unauthenticated\selfregistration\pages\mdssys\cust\site\site\user-self-registration.jsff.xml. Open it in a text editor, it should show similar to the one below:



3.3 The first thing to be added to the file above, is the actual captcha image. You can do this by adding the following under the 'af:panelFormLayout' component:
<af:image xmlns:af="http://xmlns.oracle.com/adf/faces/rich" 
             source="/captcha" 
             id="icaptcha1" 
             inlineStyle="width:250px; height:75.0px;"
             binding="#{backingBeanScope.captchaBean.captchaImage}"/>

3.4 Add the action listener property to the 'af:commandToolbarButton': actionListener="#{backingBeanScope.captchaBean.refreshCaptchaActionListener}"

3.5 Add the 'validator' property to the 'af:inputText': validator="#{backingBeanScope.captchaBean.verifyCaptchaValue}

3.6 Add the 'disclosed' property to 'af:showDetailHeader': disclosed="true"

At this point the file should be similar to the image below:


3.7 Repack the sandox zip file and import it back to OIM

4. Testing

Once the managed bean is deployed and the sandbox published (or active), OIM self registration page should like the one below:


Have fun!

No comments:

Post a Comment

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