Monday, November 19, 2012

Adding CAPTCHA to WebCenter/ ADF web application

CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) is type of challenge-response test used in computing as attempt to ensure that response is generated by human being. This is requirement for several web sites, especially on registration forms

Sample CAPTCHA is shown below
Figure 1

1. Download Simplecaptcha-1.2.1.jar. This is available for download for free on Internet. This is also available under MyWebApplicationWithCaptcha\Portal\public_html\WEB-INF\lib in application provided for download

2. Create new WebCenter Portal - Framework Application at C:\JDeveloper\mywork

3.  Create lib folder as follows
C:\JDeveloper\mywork\MyWebApplicationWithCaptcha\Portal\public_html\WEB-INF\lib

4. Paste Simplecaptcha-1.2.1.jar under lib folder

5. In JDeveloper, select View → Application Navigator, add Simplecaptcha-1.2.1.jar by right clicking Portal, Project Properties… → Libraries and Classpath → Add JAR/ Directory… Browse to
C:\JDeveloper\mywork\MyWebApplicationWithCaptcha\Portal\public_html\WEB-INF\lib

6. Add following to web.xml of application between <web-app></web-app>

<servlet>
  <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>


<servlet-mapping>
  <servlet-name>CaptchaServlet</servlet-name>
  <url-pattern>/captchaservlet</url-pattern>
</servlet-mapping> 


7. Add following code in MyRegistrationForm.jspx file that needs to have CAPTCHA

<?xml version='1.0' encoding='windows-1252'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
          xmlns:f="http://java.sun.com/jsf/core"
          xmlns:af="http://xmlns.oracle.com/adf/faces/rich">
  <jsp:directive.page contentType="text/html;charset=windows-1252"/>
  <f:view>
    <af:document id="d1" title="My Registration Form">
      <af:form id="f1">
        <af:panelFormLayout id="pfl1">
          <af:panelGroupLayout id="pgl" layout="vertical">
            <af:image source="/captchaservlet" id="i1" clientComponent="true"
                      inlineStyle="width:251px; height:76.0px;"/>
            <af:commandButton text="Refresh CAPTCHA" id="cb2" immediate="true">
              <af:clientListener method="refreshCaptcha" type="action"/>
            </af:commandButton>
          </af:panelGroupLayout>
          <af:panelGroupLayout id="pgl1" layout="horizontal" halign="left">
            <af:inputText id="it1" label="Enter text as seen in above image: "
                          value="#{requestScope.bestGuess}"/>
            <af:commandButton text="Go" id="cb1"
                              actionListener="#{MyRegistrationFormBean.verifyAnswer}"></af:commandButton>
          </af:panelGroupLayout>
          <af:message id="m1" messageType="info" for="it1"/>
        </af:panelFormLayout>
      </af:form>
      <af:resource type="javascript">
        function refreshCaptcha(evt) {
            try {
                var component = evt.getSource();
                var i1 = component.findComponent("i1");
                i1.setSource(i1.getSource() + "?force=" + new Date().getMilliseconds());
                evt.cancel();
                return false;
            }
            catch (err) {
                alert(err);
            }
            return false;
        }
      </af:resource>
    </af:document>
  </f:view>
</jsp:root>



8. Open pages.xml. Drag drop MyRegistrationForm.jspx under Root. Select Delegate Security radio button. Ensure anonymous-role has View permission check box checked

9. Add a package mypackage under Portal and MyRegistrationFormBean in 
request scope as follows. Open MyCapthcaPage.jspx in Design mode. Double click Go button. Enter values as shown below
Figure 2
Click New...

Figure 3
Click OK

Figure 4
Click OK


10. Implementation of MyRegistrationFormClass.java class is as follows


package myPackage;

import java.io.UnsupportedEncodingException;

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.servlet.http.HttpServletRequest;

import nl.captcha.Captcha;

import oracle.adf.view.rich.context.AdfFacesContext;

public class MyRegistrationFormClass {
    public MyRegistrationFormClass() {
    }

    public void verifyAnswer(ActionEvent actionEvent) {
        FacesContext fctx = FacesContext.getCurrentInstance();
        ExternalContext ectx = fctx.getExternalContext();
        HttpServletRequest request = (HttpServletRequest)ectx.getRequest();
        Captcha captcha = (Captcha)ectx.getSessionMap().get(Captcha.NAME);
        try {
            request.setCharacterEncoding("UTF-8");
        } catch (UnsupportedEncodingException e) {
            System.out.println("UTF not supported!");
        }
        String myAnswer = (String)ectx.getRequestMap().get("bestGuess");
        if (myAnswer != null && captcha.isCorrect(myAnswer)) {
            getMessage("Congratulations! You are human");
        } else {
            getMessage("Sorry! You could be a computer!");
            UIComponent panelLabelAndMessage =
                ((UIComponent)actionEvent.getSource()).getParent().getParent();
            UIComponent panelFormlayout = panelLabelAndMessage.getParent();
            AdfFacesContext.getCurrentInstance().addPartialTarget(panelFormlayout);
        }
    }

    private void getMessage(String myMessage) {
        FacesContext fctx = FacesContext.getCurrentInstance();
        fctx.addMessage("it1",
                        new FacesMessage(FacesMessage.SEVERITY_INFO, null,
                                         myMessage));
    }
}


11. To test application, download it by clicking on 'Download Application' below, unzip it, right click MyRegistrationForm.jspx in Application Navigator and click Run
Download application