Thursday, February 19, 2015

MAF (ADF Mobile): Calling an HTTP basic secured REST service

We can follow MAF tutorial http://docs.oracle.com/cd/E53569_01/tutorials/tut_jdev_maf_json/tut_jdev_maf_json.html to invoke a REST service using MAF infrastructure.

In this blog I am just trying to add how we can call SECURED REST service, which requires HTTP Basic authentication.

Before going for actual blog, few lines about tutorial api to execute REST.
Basic approach in tutorial is
a. MAF page will invoke a datacontrol method
b. Create URL for REST request
c. Call REST service
d. Populate POJO objects using REST response
e. Return POJO objects



Main code to invoke REST service looks like
private String invokeRestRequest(String httpMethod, String requestURI, String payload){
   
   String restPayload = "";
   RestServiceAdapter restServiceAdapter = Model.createRestServiceAdapter();
   restServiceAdapter.clearRequestProperties();
   restServiceAdapter.setConnectionName("REST-Public"); //Change it as per your connection name
       
   //set GET, POST, DELETE, PUT
   restServiceAdapter.setRequestType(httpMethod);
       
   //this sample uses JSON only. Thus the media type can be hard-coded in this class
   //the content-type tells the server what format the incoming payload has
   restServiceAdapter.addRequestProperty("Content-Type", "application/json");
   //the accept header indicates the expected payload fromat to the server
   restServiceAdapter.addRequestProperty("Accept", "application/json; charset=UTF-8");
   restServiceAdapter.setRequestURI(requestURI);       
   restServiceAdapter.setRetryLimit(0);   
       
   //variable holding the response
   String response = "";
       
   //set payload if there is payload passed with the request
   if(payload != null){  
             //send with empty payload
             restPayload  = payload;
   }

   try {
       response = (String)restServiceAdapter.send(restPayload);
    } catch (Exception e) {
        //log error
        Trace.log("REST_JSON",Level.SEVERE, this.getClass(),"invokeRestRequest", "Invoke of REST Resource failed for "+httpMethod+" to "+requestURI);
        Trace.log("REST_JSON",Level.SEVERE, this.getClass(),"invokeRestRequest", e.getLocalizedMessage());
        }
  return response;

};

OK, now what if service is secured and needs HTTP authentication.

When a REST service needs authentication we need to add 'Authrization' entry in http header.

Authorization: Basic a3Zlcm1hQGtiYWNlLmNvbTpLYmFjZUAwMDE=
It means if we know username and password we can concatenate them as username:password and then somehow get base64 encoding. Once we have that we can append it with word 'Basic' and set complete string as a value for 'Authorization'. Simple

Only tricky part is getting base64 encoding. We have multiple ways to get base64 encoded string.

Solution 1: Using Java API:

We can use below lines of code to add 'Authorization' in request


String base64 = null;
String cred = "sanjeev" + ":" + "myPassword";
try {
           
    base64 = Base64.getEncoder().encodeToString(cred.getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            //Handle your exception
        }
                restServiceAdapter.addRequestProperty("Authorization", "Basic " + base64);



After this you should be able to call HTTP basic secured REST service. You will require to import java.util.Base64 class.

I think this class is added in java8 so it may not work if have older version of java installed in your mobile.


Solution 2: Using JavaScript api

Another solution could be to use javascript api to get base64 encoding. We have javascript api btoa available that can encode a string. For this approach we need to following these steps
a. Create js file: Create a javascript file and add following lines in it
        base64encode = function (){
             var input = arguments[0];
             return window.btoa(input);
        }

b. Register js against a feature: In feature.xml file add js file against the feature which needs base64 encoding

c. Call js from java code


String cred = "sanjeev" + ":" + "myPassword";
String base64 = (String)AdfmfContainerUtilities.invokeContainerJavaScriptFunction("Test",
                 "base64encode", new Object[] {cred});
        restServiceAdapter.addRequestProperty("Authorization", "Basic " + base64);



For simplicity I have hard coded username/password within method but you can accept them as a parameter to make method more generic.



1 comment:

  1. Perfectly described the topic. This is the perfect way to clear the question by using screen shots along with the text. Imprssive.
    NZT Solutions Pvt. Ltd.

    ReplyDelete