Wednesday, November 25, 2015

Implementing no CAPTCHA reCAPTCHA in PeopleSoft

This post is based on a great discussion concerning security on the OTN forums.

The requirement was to solve the problem of bots/hacker websites hijacking users to their malicious locations (masquerading the legitimate PeopleSoft site), scraping the credentials from the users and then posting the data into the PeopleSoft signin page in a typical phishing attack scenario.

If you read through the discussion, you will notice some very valid questions, concerns and suggestions provided by Greg Kelly from Oracle and others around how to ensure that such phishing emails and attacks can be prevented.

Outside of that discussion, traditionally CAPTCHA has been used in several websites to prevent bot attacks. Now Google's reCAPTCHA project is being used more commonly since its inception in 2009. The latest version (no CAPTCHA reCAPTCHA) has significant user experience improvements. Additionally, the reCAPTCHA API version 2.0 is now a RESTful API which makes server side validation a lot easier. Another great incentive to use Google's no CAPTCHA reCAPTCHA is the fact that it is FREE!

Before going down the path of implementing reCAPTCHA, please consider accessibility and user experience implications and test accordingly. Click here for an article that talks about accessibility features of reCAPTCHA.

Here are the steps to implement Google reCAPTCHA API version 2.0 in PeopleSoft.

Note: I am currently using a HCM 9.2 PUM Image 12 - PeopleTools 8.54.08.
Reference Document: Developer's Guide

Step 1: Sign up for an API key pair

Please click here to sign up on the Goolge reCAPTCHA website. Once you sign up for an API key pair to your site, you will be provided with two keys - secret key and site key.

Step 2: Client side integration

In this case, let us assume that we want to add reCAPTCHA to the PeopleSoft signin page. So the signin page will be our client side content where we would add the reCAPTCHA code.

Here are the instructions from the Google reCAPTCHA documentation:


Let us add the above code snippet to the PeopleSoft signin page (signin.html).

Note: We can locate the signin.html file in the following directory on the web server.
<PIA_HOME>/webserv/<DOMAIN>/applications/peoplesoft/PORTAL.war/WEB-INF/psftdocs/<site_name>/

Add the following script inclusion code just before </HEAD> as shown:
<!-- CSK reCAPTCHA - Start -->
<script src='https://www.google.com/recaptcha/api.js'></script>
<!-- CSK reCAPTCHA - End -->


 Add the following div (reCAPTCHA) in an appropriate location on the content page. I chose to add it right before the submit button which could be referenced by <input name="Submit" type="submit" title="<%=137%>" class="ps-button" value="<%=137%>">.

<!-- CSK reCAPTCHA - Start -->
    <div class="g-recaptcha" data-sitekey="<ENTER_YOUR_SITE_KEY_HERE>" align="center"></div>
    <br/>
<!-- CSK reCAPTCHA - End -->


Note: If you are on PeopleTools 8.54 then you might also want to perform the same customizations to signin_fmode.html file as well. This is due to a known issue that will be fixed in PeopleTools 8.55. Refer: E-FLUID - Fluid HomePage Sign Off Link Calls fmode=1 in URL, Skips Custom signout.html Page (Doc ID 2001761.1).

Please bounce and clear the cache on your web server domains. Let us now see the reCAPTCHA plugin in action on the client side.






We are not done yet! Once verified, the reCAPTCHA integration would additionally add a string with the name "g-recaptcha-response" to the payload when the user submits (form post). This string would be a key that is generated specifically for our site. The string needs to be validated on the server side which we will explore in the next section.

Step 3: Server side integration/validation

This is the step where we verify the string provided by reCAPTCHA for validity by making a REST API call. Instructions from Google reCAPTCHA documentation.


For more details: Refer API documentation.

In this case, since we are trying to validate the reCAPTCHA response string provided by the PeopleSoft signin page, the best place to add the validation logic would be in the SignOn PeopleCode.

Let us now add a new row/entry in the sequence of Signon PeopleCode events as shown in the following screenshot. I am referencing a custom function name which I will explain shortly.


Record: CSK_RECAPTCHA
Field Name: FUNCLIB
Event Name: FieldFormula
Function Name: CSK_RECAPTCHA_CHECK

Note: After making any changes to Signon PeopleCode we must bounce the app servers for them to take effect.

Now let us see how to write some custom code to validate the reCAPTCHA response string. For reference, I pasted the entire peoplecode at the very end of this post.

Click on image to zoom in!


Note: In this case, I am using Apache Commons HttpClient Java Libraries to make the REST API call. Please refer to my previous blog posts that have more details on this topic (Part I and Part II).

Details on custom function validate_reCAPTCHA_JSON is provided below. For the purposes of JSON parsing, I am using a server side scripting technique described by Jim Marion in his blog post

Click on image to zoom in!


Message Catalog Entry that contains the JSON Parsing Script:


Script for reference:

var result = (function() {

     var json = JSON.parse(json_string);

     if (json.success) {
          return "true";
     } else {
          return "false";
     }

}());


This completes our server side integration/validation. Now we are relatively free of bot attacks! :)

Note: The same feature can be applied to any content page within the PeopleSoft application as well. If not easier, the effort should be the same as what we just went through in this post.

PeopleCode Functions for reference:

Function validate_reCAPTCHA_JSON(&json As string) Returns boolean;
  
   Local string &success;
  
   /* Instantiate ScriptEngine Manager and Engine objects */
   Local JavaObject &manager = CreateJavaObject("javax.script.ScriptEngineManager");
   Local JavaObject &engine = &manager.getEngineByName("JavaScript");
  
   /* Pass JSON string */
   &engine.put("json_string", &json);
   /* Get JSON Parse JavaScript from Message Catalog */
   Local string &jsFunction = MsgGetExplainText(26000, 1, "NONE");
  
   If &jsFunction <> "NONE" Then
      &engine.eval(&jsFunction);
      &success = &engine.get("result").toString();
   End-If;
  
   If Upper(&success) = "TRUE" Then
      Return True;
   Else
      Return False;
   End-If;
  
End-Function;

Function CSK_RECAPTCHA_CHECK()
  
   /* Get reCaptcha parameter from the Request */
   Local string &reCAPTCHA = %Request.GetParameter("g-recaptcha-response");
  
   If &reCAPTCHA = "" Then
      /* Fail Authentication */
      SetAuthenticationResult( False, %SignonUserId, "", False);
   Else
      /* Do further validation if required. Refer: https://developers.google.com/recaptcha/docs/verify */
      /* Post user's reCAPTCHA response and server's private key to API: https://www.google.com/recaptcha/api/siteverify */
      try
        
         /* Using Apache HttpClient for REST - Post Method */
         Local JavaObject &jHttp, &jMethod, &filePart, &partArray, &mPartReqEntity;
        
         /* Initialize HttpClient and set parameters */
         &jHttp = CreateJavaObject("org.apache.commons.httpclient.HttpClient");
         &jHttp.getHttpConnectionManager().getParams().setConnectionTimeout(20000);
        
         /* Initialize PostMethod */
         /* !!!!!! Avoid hardcoding !!!!!!!! Replace below URL with a URL definition that is configurable. */
         Local string &sURL = "https://www.google.com/recaptcha/api/siteverify";
         &jMethod = CreateJavaObject("org.apache.commons.httpclient.methods.PostMethod", &sURL);
         &jMethod.setFollowRedirects( False);
        
         /* Add Multi-Part Message - Start */
         /* Create String Part - secret */
         &secretPart = CreateJavaObject("org.apache.commons.httpclient.methods.multipart.StringPart", "secret", "<ENTER_YOUR_SECRET_KEY_HERE>");
         /* Create String Part - response */
         &responsePart = CreateJavaObject("org.apache.commons.httpclient.methods.multipart.StringPart", "response", &reCAPTCHA);
         /* Add Parts to Part Array */
         &partArray = CreateJavaObject("org.apache.commons.httpclient.methods.multipart.Part[]", &secretPart, &responsePart);
         /* Create Multi-Part Request Entity */
         &mPartReqEntity = CreateJavaObject("org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity", &partArray, &jMethod.getParams());
         /* Add Multi-Part Request Entity to the Post Method */
         &jMethod.setRequestEntity(&mPartReqEntity);
         /* Add Multi-Part Message - End */
        
         /* Invoke PostMethod */
         Local integer &return = &jHttp.executeMethod(&jMethod);
         Local string &responseBody = &jMethod.getResponseBodyAsString();
        
         If (validate_reCAPTCHA_JSON(&responseBody)) Then
            /* reCaptcha success: allow user */
            SetAuthenticationResult( True, %SignonUserId, "", False);
         Else
            /* reCaptcha failure: deny */
            SetAuthenticationResult( False, %SignonUserId, "", False);
         End-If;
        
      catch Exception &ex
         /* Unknown Exception */
         SetAuthenticationResult( False, %SignonUserId, "", False);
      end-try;
   End-If;
End-Function;

 

24 comments:

  1. Hi Sasank,

    What is the minimum version of tools/application that we need to be to implement reCaptch and is there any restrictions as such. please let us know. thank you.

    ReplyDelete
    Replies
    1. Hi Raj - I don't think there is any tools/application dependency.

      For making the REST call in the above proof of concept, I used Apache HttpClient which is Tools independent. Although, you might have to load the jar files on the App Server.

      For the JSON parsing, I used Jim Marion's server side scripting technique which you can find here:
      http://jjmpsj.blogspot.com/2015/09/javascript-on-app-server-scripting.html

      Hope this helps!

      Delete
  2. Hi Sasank

    The above example show how Captcha/ReCaptcha can be implemented on the sign-in page. Can we do the same thing on a PeopleSoft Fluid page. We have a requirement where people need to register for an account and we want to put in Captcha on this page.

    Please do let me know.

    Regards
    Arshad

    ReplyDelete
    Replies
    1. Hi Arshad - I don't have a working example of this use case but I am certain that the same can be applied to any PIA page (Classic/Fluid) as well.

      The only differences would be:
      - The signin.html customizations should be done on the page. This includes adding the recaptcha api js source and adding the recaptcha DIV to the page.
      - The server side signon peoplecode function can be placed in an appropriate event that fires before the Save (e.g.: SavePreChange, etc.).

      Thanks!

      Delete
  3. Could you tell me please where I can download a version of reCAPTCHA API version 2.0?
    Regards, Alfredo

    ReplyDelete
    Replies
    1. Hi Alfredo,

      There is no need to download anything. You just need to register for a google recaptcha account by going here:
      https://www.google.com/recaptcha/admin

      Once you complete registration, you will receive two keys (site key and secret key). This completes Step 1 in this blog.

      Then you can proceed with the rest of the steps (starting from step 2) detailed in this post.

      Delete
  4. Hi Sasank,

    Thanks for your response.
    I'm working on a Campus Solution 9.0 with a PeopleTools 8.53.
    I put the snippet code in a HTML area on a pia page, and using function CSK_RECAPTCHA_CHECK and I got the next error message:

    Java Exception: java.lang.NoClassDefFoundError: org/apache/commons/httpclient/HttpClient: finding class org.apache.commons.httpclient.HttpClient (2,725) V_SCC_NUR_WRK.V_HELP1.FieldFormula Name:CSK_RECAPTCHA_CHECK PCPC:1279 Statement:24
    Called from:V_SCC_NUR_REG.GBL.SAD_OLA_WRK.ADM_NEXT_BTN.FieldChange Statement:4

    Regards, Alfredo

    ReplyDelete
    Replies
    1. Hi Alfredo - I am using Apache Commons HttpClient to do a REST call from PeopleCode. This is the step where we send the g-recaptcha-response parameter to Google for verification (https://developers.google.com/recaptcha/docs/verify).

      You don't necessarily have to use Apache HttpClient if you choose to POST the data to Google some other way (using IB, etc.). If you want to use Apache Commons HttpClient then you can refer to these blog (which I have also mentioned in this post).
      https://pe0ples0ft.blogspot.com/2014/10/using-apache-commons-httpclient-for.html
      https://pe0ples0ft.blogspot.com/2014/10/apache-commons-httpclient-for-rest-in.html

      Delete
  5. Hi Sasank, Kindly advice on Implementing no-captcha re-captcha using integration Broker.
    Is there a way to do this without having to place code in the webserver?

    ReplyDelete
    Replies
    1. No. ReCaptcha does not work with web services (Integration Broker).

      ReCaptcha is specifically designed to determine that the end-user is not a bot. It is also designed to work only with website that render HTML. ReCaptha involves the end-user interacting with the page to prove that he/she is not a bot.

      In short, it will not work with Integration Broker. You may want to review the following PeopleBook if you want to learn more about Securing Integration Broker.
      https://docs.oracle.com/cd/E58500_01/pt854pbh1/eng/pt/tiba/concept_UnderstandingSecuringIntegrationEnvironments-fe7ea9.html#topofpage

      Delete
  6. Hi Sasank,

    I have implemented reCAPTCHA on a peoplesoft page and it is working great but the reCAPTCHA plugin is disappearing when the user fails to authenticate the 2nd time(postback). Is there a way to reload the plugin every time the user fails to authenticate?

    Thanks

    ReplyDelete
    Replies
    1. Hi - This may be because the recaptcha js is getting reloaded during the postback.

      Is this implemented on a Classic/Fluid page? Also, what PeopleTools version are you on?

      Delete
    2. Hi Sasank,
      Do you know how to reload the recaptcha javascript every time the authentication fails?

      Thanks

      Delete
    3. Here is a workaround to postback problem:

      https://pe0ples0ft.blogspot.com/2017/11/recaptcha-in-peoplesoft-pia-pages.html

      Let us know if it helps. Very interested in hearing about your reCAPTCHA implementation! :)

      Delete
    4. Hi Sasank,

      This is working great. I truly appreciate your time in helping me resolve this issue.

      Thanks,
      Sai.

      Delete
    5. @Sai - Good to hear that it is working!

      Also, if you don't need to callback function, you can remove it. I added a console.log message to demonstrate the callback functionality. Thanks!

      Delete
    6. Sure. Will do. Thanks again Sasank!

      Delete
  7. Sasank,

    Thank you for responding. I have implemented this on a classic page and we are on PT 8.55.16.

    Thanks

    ReplyDelete
  8. Hi Sasank,

    Is there a way to highlight a date in the peopletools date picker. I do not want the current date to be highlighted but i do want to highlight few dates in the month.

    or is there way to disable some dates in the calendar? I came across the below code in json for disabling it. I wanted to check if the code can be added in javascript, in component branding.

    $("selector").datepicker({
    beforeShowDay: function(date) {
    var day = date.getDate();
    return [day < 25 || day > 29];
    }
    });

    Regards,
    Allen

    ReplyDelete
    Replies
    1. @Allen Kuruvilla - This is a great question. It is one of the topics I want to research further if/when I get time. Unfortunately, i don't know exactly how the PeopleSoft datepicker works, so it will really depend on understanding how it works in the first place and then making changes accordingly.

      I will let you know if I find anything useful. Also, if you find a way to achieving this, let us know! I will be interested to hear your approach. :)

      Delete
  9. Hi Sasank,

    I have implemented captcha as you mentioned in your post. I am able to see the captcha check box on login page. However, it is throwing error "Your User ID and/or Password are invalid." even captcha is checked on with correct user id and password. Kindly advise.

    Sanjay Kumar Abbat

    ReplyDelete
    Replies
    1. Check your signon peoplecode.
      1. See if you are getting the g-recaptcha-response parameter in the request.
      2. If you are gettign the g-recaptcha-response parameter, then see if you are able to successfully verify this value with your site's secret key. Google should send back a success in the JSON response.

      Delete
  10. Hi Sasank. I know this post was in 2015 and it's been a while. Do you know if there has been an update whether reCaptcha v2 can be implemented using PeopleSoft Integration Broker?

    ReplyDelete
  11. Hi Sasank,
    1. To implement this recaptcha, do we need to have internet enable at server.
    2. Can't we implement this IP base url which is not expose to internet ?

    ReplyDelete