Sunday 14 September 2014

Implementing Captcha on PeopleSoft login page using JCaptcha - Part-2

Continuing from JCaptcha Part-1 we move on to Step-3 of the JCaptcha implementation on the PeopleSoft login page.

You will have to repeat the steps henceforth for each domain (in case of multiple domains)

Step-3:
  • Before customizing the files signin.html, text.properties and error.properties, make a backup for restoration purposes. The files can be found here -
     <%PS_HOME%>webserv\<Domain>\applications\peoplesoft\PORTAL.war\WEB-INF\psftdocs\<Domain>  
    
    Open the signin.html file in a text editor and add the following code after the <HEAD> tag
     <!-- Added by V.Rao to prevent captcha image caching --><META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">  
    
  • In the JavaScript section add the Ajax code below
     <!-- added by V.Rao [Begin] Ajax function to refresh the captcha image -->  
     <script>  
     function chitra()  
     {  
     var xmlhttp;  
     if (window.XMLHttpRequest)  
      {// code for IE7+, Firefox, Chrome, Opera, Safari  
      xmlhttp=new XMLHttpRequest();  
      }  
     else  
      {// code for IE6, IE5  
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");  
      }  
     xmlhttp.onreadystatechange=function()  
      {  
       if (xmlhttp.readyState==4 && xmlhttp.status==200)  
       {  
       document.getElementById("sampige").src="/chitra_durga.jpg?r="+new Date().getTime();  
       }  
      }  
     xmlhttp.open("GET","/chitra_durga.jpg",true);  
     xmlhttp.send();  
     }  
     </script>  
     <!-- added by V.Rao [End] Ajax function to refresh the captcha image -->  
    
  • After this, search for the form tag element and modify/replace the action attribute to call the custom Captcha validation JSP as opposed to the PeopleSoft delivered psp servlet as shown below
     <!-- Commented by V.Rao <form action="?cmd=login&languageCd=<%=languageCd%>" method="post" id="login" name="login" autocomplete="off" onSubmit="signin(document.login)"> -->  
     <!-- Added by V.Rao --><form aaction="<%=psCtxPath%><%=psHome%>/Rao99.jsp" method="post" id="login" name="login" autocomplete="off" onSubmit="<%=psCtxPath%><%=psHome%>/Rao99.jsp">   
    
  • The next piece of customization on the signin html file is to bring in the captcha elements i.e captcha image, refresh icon to refresh the captcha image and a text box to capture the verification code entered by the user. The sample code from my signin page is shown below. Place this code below the "pwd" element.
     <!-- Code added by V.Rao [Begin] Captcha elements-->  
     <tr>  
     <td height="35"><img src="/chitra_durga.jpg" alt="<%=20000%>" id='sampige' width="175" height="65" />&nbsp;</td>  
     <td height="35" align='middle'>  
      <img src="<%=psCtxPath%><%=psHome%>/images/PT_REFRESH_ICN.gif" alt="Refresh" width="16" height="16" onclick="chitra()" />  
      &nbsp;</td>  
     <td height="35"><input type = "text" name="jcaptcha" placeholder="<%=20000%>" class="pslogineditbox" tabindex="4"></td>  
     </tr>  
     <!-- Code added by V.Rao [End] -->  
    
    You would have noticed that I have used scriptlet with the number 20000 in a couple of tags. This is the message number that serves as the alternate text for the captcha image as well as the default message shown in the text box provided for the user to key in the captcha verification code. This message text is defined in the text.properties file. The Ajax function chitra() that is triggered upon clicking the refresh icon in turn triggers the Java servlet "chitra_durga.jpg". The servlet generates and streams a fresh captcha image to the client browser.
  • The last piece of customization on the signin html file is to modify the submit button action. Search for the input tag with type "Submit" and modify the code as given here
     <!-- Commented by V.Rao <td height="35"><input name="Submit" type="submit" class="psloginbutton" tabindex="4" value="<%=137%>" onclick="submitAction(document.login)"></td> -->  
     <!-- Added by V.Rao --> <td height="35"><input name="Submit" type="submit" class="psloginbutton" tabindex="4" value="<%=137%>" onclick="<%=psCtxPath%><%=psHome%>/Rao99.jsp"></td>  
    
  • Open the text.properties file and add the code below at the very bottom
     # V.Rao [1-Sep-2014] Using 20000 and above for custom messages  
     20000=Enter the verification code appearing in the image  
    
  • I also need to display a custom error message if the captcha validation fails. To do this open the error.properties file and add the code below at the very bottom
     # V.Rao [1-Sep-2014] Using 20000 and above for custom messages  
     20001=Verification code is required.  
     20002=Invalid verification code. Please try again.  
     20003=Verification failed.  
    

Step-4
In the HTML for the captcha elements, I had used the PeopleSoft delivered refresh icon - PT_REFRESH_ICN. Unfortunately this image is not available by default on the images folder in the web server. It is fetched from the database and cached in the webserver when a PeopleSoft page references the image. Therefore I decided to always have it available on the webserver. I did that by copying the refresh icon to the image folder located at 
 <%PS_HOME%>\webserv\<Domain>\applications\peoplesoft\PORTAL.war\<domain>\images  

Step-5
Create the JSP file that will intercept the login request and do the validation of the captcha entered by the user. The JSP does one of two things, forwards the login request to the psp servlet if captcha validation is successful or else re-load the login page with the custom captcha error message shown (error code = 20001). The code in my JSP file i.e Rao99.jsp is listed below.

 /**  
  * @author Venkateshwara Rao  
  * @Date  7-Sep-2014  
  */  
 <%@page import="com.octo.captcha.module.servlet.image.SimpleImageCaptchaServlet" %>  
 <%   
   String userCaptchaResponse = request.getParameter("jcaptcha");  
   userCaptchaResponse = userCaptchaResponse.trim();   
   Boolean captchapassed = false;  
   if( userCaptchaResponse.equals("") || userCaptchaResponse == null )  
   {  
 %>  
    <jsp:forward page="/psp/hcm92dmo/?cmd=login&errorCode=20001" >  
    </jsp:forward>  
 <%  
   }  
   else  
   {    // Captcha text is not blank or null  
        try  
        {   
             captchapassed = SimpleImageCaptchaServlet.validateResponse(request, userCaptchaResponse);  
        }  
        catch(Exception e)  
        {  
 %>  
     <jsp:forward page="/psp/hcm92dmo/?cmd=login&errorCode=20003" >  
     </jsp:forward>  
 <%  
        }  
        System.out.println("captcha passed = " + captchapassed ); /* Logging to weblogic console for debugging purpose */  
        if(captchapassed)  
        {  // On captcha validation success redirect to the psp servlet with login command  
 %>  
     <jsp:forward page="/psp/hcm92dmo/?cmd=login" >  
     </jsp:forward>  
 <%  
        }  
        else  
        {// On captcha validation failure redirect to the signon page with error code set to custom# - 20001  
 %>  
     <jsp:forward page="/psp/hcm92dmo/?cmd=login&errorCode=20002" >  
     </jsp:forward>  
 <%  
         }  
   }  
 %>  
The JSP file should be placed at this location on the web server
 <%PS_HOME%>\webserv\<Domain>\applications\peoplesoft\PORTAL.war\<Domain>  

All the modifications done above require a webserver bounce with cache clear before we can proceed to test.

Results
After the webserver bounce, access the PeopleSoft login page and you will see the login page with the Captcha image and the text below the password field  as shown below
Click on the refresh icon to receive a new captcha text/challenge as shown below
If the captcha verification code entered by the user is incorrect the login page is shown again with the custom captcha specific error message (this is the message I added to the error.properties file) as shown below
If the user managed to enter the correct captcha validation code but the PeopleSoft login credentials were incorrect then the login page is displayed back with the usual login id password incorrect message with a fresh captcha challenge as shown below

If the user manages to enter all the three parameters correctly then the servlet forwarding brings them to the homepage as shown below

The captcha validation success is also confirmed in the weblogic logs (with the system.out message I wrote in the JSP code) as shown below

After-thought 
Although it looks simple enough in retrospect, it took me a while to piece together this solution and many a things learnt along the way (things to do and not to do). If only Oracle would incorporate this feature there wouldn't be the need to put in this customized solution. At the end of the day, what I achieved here is more of a workaround than anything because the most logical place for the captcha validation call is within the psp/psc servlet code which validates the PeopleSoft user id and password. This is something customers cannot modify.

Working on this, took me back to my Java/J2EE developer days and made me realize App Designer is such a wonderful tool that simplifies so much of the development and code deployment aspects. With all the talk of JDeveloper replacing PeopleTools/AppDesigner makes me feel we will be going back to cavemen times. It is unlikely however powerful JDeveloper is, for it to replace the Application Designer's simplicity and ease of use.

Note: This solution/source code provided in this post is by no means a production ready one. It was a proof of concept done by me and you will have to make necessary changes at your end before deploying.

No comments:

Post a Comment