Tuesday, October 28, 2014

Apache Commons HttpClient for REST in PeopleCode - Part I - GetMethod and Basic Authentication Examples

Recently, I used Apache Commons HttpClient for making REST calls in PeopleCode for a project (interacting with a RESTful API of a Document Management System).

I found that using PeopleSoft Integration Broker for REST had the following limitations for my project:
1. Cookies (intended to be part of response messages) were getting lost and not coming through.
2. Dealing with, reading and processing response messages containing raw binary data (document).

Looking for workarounds, I then started exploring Apache Commons HttpClient after reading Chris Malek's blog and some posts in Jim Marion's blog.

The advantage of using Java is that it gives us a lot of flexibility to interact directly at the http layer. The disadvantage is that we would be bypassing Integration Broker (Gateway) which means we need to consider and implement functionality like logging, error handling and other built-in IB features such as authentication, etc.

There is also a distinction between the IB approach versus the Java approach.

IB Approach has the following flow:
App Server -> Web Server (IB Gateway) -> Third Party System

Java Approach has the following flow:
App Server -> Third Party System

I mention the above to point out that if there are any firewalls to be opened or if there are certificates/keys to be loaded then it needs to be done at the App Server level (if we are going with the Java Approach).

Stating the obvious, but another point to note is that this Java Approach is only an option for outbound REST calls.

That said, I would like to share my experiments and implementation experiences using Apache Commons HttpClient with some examples.

In this post, let us explore how to invoke the Get Method and use Basic Authentication. There are two options that I found to use Basic Authentication (Note: Based on OTN discussion).

Option 1 - Adding Authorization Header:

Local JavaObject &jHttp, &jMethod;

/* Initialize HttpClient and set parameters */
&jHttp = CreateJavaObject("org.apache.commons.httpclient.HttpClient");
&jHttp.getHttpConnectionManager().getParams().setConnectionTimeout(20000);

/* Initialize GetMethod */
&sURL = "https://www.test.com/name.v1/get?emplid=12345";
&jMethod = CreateJavaObject("org.apache.commons.httpclient.methods.GetMethod", &sURL);
&jMethod.setFollowRedirects( False);

/* Basic Auth - Adding Authorization Header */
/* &base64EncodeString = username:password encoded in base64 */
/* Note: In Production it is advised to store the base64 encoded string in a configuration table rather than hardcoding */
&base64EncodeString = "ABCD12345TESTBASE64";
&jMethod.setRequestHeader("Authorization", "Basic " | &base64EncodeString);
/* Basic Auth - Adding Authorization Header */

/* Invoke GetMethod */
&return = &jHttp.executeMethod(&jMethod);
&responseStatus = &jMethod.getStatusLine().getStatusCode();

MessageBox(0, "", 0, 0, "Response Status: " | &responseStatus); 
MessageBox(0, "", 0, 0, "Response Message: " | &jMethod.getResponseBodyAsString());

&jMethod.releaseConnection();

Option 2 - Using UsernamePasswordCredentials Class:


Local JavaObject &jHttp, &jMethod, &jCred, &jAuth;

/* Initialize HttpClient and set parameters */
&jHttp = CreateJavaObject("org.apache.commons.httpclient.HttpClient");
&jHttp.getHttpConnectionManager().getParams().setConnectionTimeout(20000);

/* Initialize GetMethod */
&sURL = "https://www.test.com/name.v1/get?emplid=12345";
&jMethod = CreateJavaObject("org.apache.commons.httpclient.methods.GetMethod", &sURL);
&jMethod.setFollowRedirects( False);

/* Basic Auth - Using UsernamePasswordCredentials Class */
&jCred = CreateJavaObject("org.apache.commons.httpclient.UsernamePasswordCredentials", "userid", "password");
&jAuth = CreateJavaObject("org.apache.commons.httpclient.auth.AuthScope", "www.test.com", 443);
/* Note: Use 443 if your host is using https or 80 if your host is using http */

&jHttp.getState().setCredentials(&jAuth, &jCred);
&jMethod.setDoAuthentication( True);
/* Basic Auth - Using UsernamePasswordCredentials Class */

/* Invoke GetMethod */
&return = &jHttp.executeMethod(&jMethod);
&responseStatus = &jMethod.getStatusLine().getStatusCode();

MessageBox(0, "", 0, 0, "Response Status: " | &responseStatus); 
MessageBox(0, "", 0, 0, "Response Message: " | &jMethod.getResponseBodyAsString());

&jMethod.releaseConnection();

Note: Here are the jars that I downloaded and placed on my app server classpath. An app server bounce/restart is required for the new jars to take effect.
- commons-httpclient-3.1.zip
- commons-codec-1.6.zip
- commons-logging-1.1.3.zip
- commons-io-2.4.zip (optional)

Few more examples of "Apache Commons HttpClient for REST in PeopleCode" to follow in Part II.

5 comments:

  1. I am getting timeouts error

    ReplyDelete
    Replies
    1. Most likely your app server is not able to talk to the third party server.

      As I said in the start, Java Approach has the following flow:
      App Server -> Third Party System

      To rule out connectivity issues, logon to your app server using ssh and try to telnet to the third party system host. If you are not familiar with this or don't have appropriate access, then you may have to work with your admins on getting the connectivity sorted. Thanks!

      Delete
  2. How to check this

    "I mention the above to point out that if there are any firewalls to be opened or if there are certificates/keys to be loaded then it needs to be done at the App Server level (if we are going with the Java Approach)."

    ReplyDelete
    Replies
    1. You will have to telnet to the third party server from your app server using ssh. If that fails then there is definitely a connectivity issues. I am not a PS Admin, so I cannot guide you in great detail on how to figure this out.

      Best bet would be to seek help from your admins.

      Delete
  3. Hi Sasank,

    We are trying to invoke 3rd party rest service to peoplesoft. As part the header we need to pass some header values with the rest URL.

    One of the header in that needs to be "HMAC SHA256 digest of the entire HTTP request using auth string as the encrypted key"
    Note: Auth string is computed as Base 64 encoded string as “username:password”

    My question is how I need to pass auth string key value for HMAC SHA256 in peoplesoft pluggable encryption.

    Could you please help me on this.

    ReplyDelete