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.



Monday, February 9, 2015

How HTTPS works

In this blog I would like to write about 'How HTTPS works'. Let us try to simplify it and assume there is no web in this world. I want to have some transactions with my bank. Bank is in another city and to complete that transaction I need to send some secret documents to bank and also I would receive some secret documents from bank. Let say the only way to send and receive documents is through postal services. Now we know scenario, let us see what are our problems


  1. Identity of Bank: Because bank is in another city and I am not going to bank directly, how would I know bank is genuine. I have to make sure identity of bank is correct before sending documents.
  2. Security in transition: How would I make sure that no body is able to read my documents while they are in transition.

This is too much of task for me to verify identity etc, let me hire a personal assistant PA to help me in this bank transaction.

To solve first problem (Identity of Bank) we need an authority which can say yes 'So and So bank is a genuine bank'. This authority can provide a certificate to bank and bank needs to show that certificate to client (my PA). As a client my PA can check with authority that certificate is actually issued by them and its still valid. If yes, I will be sure that I am working with a genuine bank. It involves following tasks now
  a. Bank needs to get a certificate from authority
  b. Before sending documents to bank, my PA will ask for bank certificate.
  c. Bank will provide certificate
  d. My PA will verify certificate with authority and if found correct, my PA will proceed to next step otherwise it should warn me and also give me option to go-ahead with transaction or decline.

To solve second problem (Security in transition) we can lock our documents in a box and we can create two similar keys to open the box. One key can be used by bank and other key can be used by my PA. That way we are secure that no one can see/steal our documents in between. Let us name this key as Symmetric-key.

But by introducing box we have introduced two more problems
a. There are different types of boxes/locks available in market. We (bank and my PA) should come to an agreement that which kind of box/lock can be used so that we both know how to operate that box/lock.

b. We can not use same symmetric-key permanently for all our transactions. Its unsafe to store it in my home. If anybody gets hold of this key, he will be able to open our box. To avoid this my PA can generate key every time we want to initiate our transaction. But now problem is how would my PA will send key to bank. We can't send it directly using postal services as someone might take it and then later misuse it to steal my documents. To solve this problem we need another lock/key. This lock should have two different types of keys. It can be locked by a key-1 but can only be unlocked by key-2. Key-1 is public key and Key-2 is private key. Ownership of keys lies with bank and bank shares public key with everybody but private key with nobody. It means anybody who has public key can lock the box but only bank can unlock it using private key. Let us call this mechanism asymmetric-box and asymmetric-key. My PA wants to send symmetric-key to bank. He can ask bank to send him public key and then lock symmetric-key in asymmetric box using public key and send it through postal services. Now only bank can open this box using private key and get hold of symmetric key. Now bank is sending public key but there is no need to secure it. Even if anybody gets it, it does not matter as he can't unlock using public key.
To sum up 'To secure documents we are using symmetric key but to secure symmetric key we are using asymmetric key (public/private). There is no need to secure public key.'

Let us conclude our steps

1. Bank needs to generate asymmetric keys (One time activity)
2. Bank needs to get certificate from authority (One time activity)
3. Before starting any conversation my PA needs to ask bank about model of symmetric box/lock that can be used. For that my PA sends information of supported box/lock to Bank and ask which one they also support. There is no secret information here so anybody can read. No issues.
4. Bank agrees to certain box/lock model and sends that information back. There is no secret information here so anybody can read. No issues.
5. My PA asks for bank certificate, which is issued by authority. With certificate bank needs to send public key also. There is no secret information here so anybody can read. No issues.
6. My PA contacts authority and validates bank certificate. If found correct and valid, my PA will start next step. Otherwise he warns me and give me option to go-ahead or decline.
7. Let say certificate is valid or I allow my PA to go-ahead
8. We (My PA and Bank) starts conversation
9. My PA generates a random symmetric key
10. Locks it using public key and send it to bank. We are sending very sensitive symmetric key but that is locked using public key and it can only be opened by private key. No one other than bank can have private key so no one can do anything.
11. Bank unlocks symmetric key using private key and keeps it for our conversation.
12. My PA locks documents using symmetric key and send it to bank. No one other than my PA/bank has symmetric key so no one can see documents in between.
13. Bank unlocks documents using symmetric key.
14. Bank locks documents using symmetric key and sends to my PA. No one other than my PA/bank has symmetric key so no one can see documents in between.
15. My PA unlocks documents using symmetric key.
16. We continue sending documents using symmetric key until I decided to end conversation.
17. I decide to end conversation.
18. Next time when we want to contact bank again we will start with step 3. We will check bank's validity again and we will generate new symmetric key.

This is all is happening in HTTPS

Let me rephrase it now
I                      = End user
My PA            = Browser (More technically SSL layer of computer conversation)
Bank               = Secured web server
Postal services= Network
documents      = secret data (userid/password, bank accno, personal data etc)
Authority        = CA (Certificate authority as verisign etc)
Box                 = Encryption
Model of box  = Encryption mechanism
Symmetric key= Symmetric key for encryption/decryption
Asymmetric keys = Asymmetric keys for encryption/decryption
Conversation    = browser session



Now let me convert it to technical words
1. Web server which wants to support secret conversation needs to generate asymmetric keys. (One time activity)
2. Web server which wants to support secret conversation needs to get certificate from certifying authority as VeriSign etc. (One time activity) [ I would like to cover step-1 and 2 in separate blog as how to do it using keytool of java]
3. Before starting any conversation browser needs to ask bank about encryption mechanism that can be used. For that browser sends information of supported encryption mechanism (RSA, SSL version etc) to Web-Server and ask which one they also support. There is no secret information here so anybody can read. No issues.
4. Web-Server agrees to certain encryption mechanism and sends that information back. There is no secret information here so anybody can read. No issues.
5. Browser asks for bank certificate, which is issued by authority. With certificate bank needs to send public key also. There is no secret information here so anybody can read. No issues.
6. Browser contacts authority and validates web-server certificate. If found correct and valid, browser will start next step. Otherwise it warns me and give me option to go-ahead or decline. We might have seen such warning in our browser specially while accessing https site over intranet. This is general practice not to involve CA for internal websites and do self sign instead.
7. Let say certificate is valid or I allow browser to go-ahead
8. We (browser and web-server) starts conversation
9. Browser generates a random symmetric key
10. Locks it using public key and sends it to bank. We are sending very sensitive symmetric key but that is locked using public key and it can only be opened by private key. No one other than web-server can have private key so no one can do anything.
11. Web-Server unlocks symmetric key using private key and keeps it for our conversation.
12. Browser locks secret data using symmetric key and send it to web-server. No one other than browser/web-server has symmetric key so no one else can see data in between.
13. Web-server unlocks secret data using symmetric key.
14. Web-server locks secret data using symmetric key and sends to browser. No one other than browser/web-server has symmetric key so no one can see data in between.
15. Browser unlocks secret data using symmetric key.
16. We continue sending secret data using symmetric key until browser decided to end conversation.
17. I decide to end conversation by closing https browser session.
18. Next time when browser wants to contact web-server again it will start with step 3. It will check web-server's validity again and it will generate new symmetric key.

Step 3-4 is called handshake or Hello (Step 3 -- Client Hello, Step 4 -- Server Hello)
Step 5-6-7 is part of certificate exchange
Step 9-10-11-12-13-14-15-16--17 is part of data exchange over https


Few questions before I close this blog
1. Why are we not using asymmetric keys to exchange data?
Ans: Working with asymmetric key is very CPU intensive job and so we would like to avoid it. That is why we have concept of symmetric keys over https

2. Why can't we use same symmetric key every time?
Ans: Its not safe to store symmetric key in your laptop anywhere. It could be a big threat.



In my next blog I will show how we can generate asymmetric keys and get it signed by CA. 

Wednesday, February 4, 2015

Consuming JSR 286 Portlet from WSRP producer in a WebCenter application

In our previous blog (Deploy JSR 286 Portlet) we have created a portlet and deployed it on server. Now in this blog we will consume it on WebCenter application

Our WSDL url from deployed application is http://127.0.0.1:7101/jsr286/portlets/wsrp2?WSDL
We will follow these steps
a. Create a WSRP producer connection
b. Add portlet to a page
c. Run page and see portlet content

Step1:Create a WSRP producer connection: Open ADF application in which you want to add portlets
Navigate to Application Resources > Connection > New Connection > WSRP Producer
Provide registration name, wsdl url, security details (if any) in WSRP Production Connection wizard.
Once connection is done verify if by expanding it. We should be able to see portlets deployed on WSRP producer
You will notice following changes in your project
1. Portlet configuration settings are added in adf-config.xml file
2. If its only ADF project, jdev will add required WebCenter libraries
3. Lots of pxml files got added in <application>\mds\oracle\adf\portlet directory. These files contain information about portlets

Step2: Add portlet on a page:
Create an adf page and drag and drop portlet from connection to page.
You will see an entry in page like

Similarly we can add Employee portlet in second facet of panel splitter to see Department and Employee details side by side

We will notice that everytime we drop a portlet on a page, it creates an instance of portlet, which is referred as portletInstance in binding. Similar directory structure also get created in <application>\mds\oracle\adf\portlet\<Producer>\ap directory.

Step3: Run the page:

Monday, February 2, 2015

BAM: Creating editable report in ADF on top of BAM DOs.

BAM provides a way to create an editable report on top of BAM DOs. You just need to select editable fields but problem is you can only create free text fields. What if you want to have LOV (choice list) for some editable field. There seems to be no option in BAM. 

In this blog we are going to create an ADF page,which allows editing a BAM report.

Effectively we need to do following stuff
  1. Query records from BAM DO and show it in tabular format
  2. Make few fields editable in table.
  3. Edit values and click Save. 
  4. All changes should be saved to BAM DO.


To query data from BAM we have three options
  • Use BAM datacontrol: This is the recommended way of querying data from BAM DOs and create a UI out of it. But when it comes to editable report there seems to be few problems.
    • Problem-1: Due to active data behavior table will get refreshed after few seconds and because of that any changes done will be lost after few seconds. We can disable active data behavior but still if we need to perform a PPR on table it will start showing data from directly from DO and again we will lose changes.
    • Problem-2: I don't think there is any setter for binding attributes. If you edit a value in UI and then try to get same value from bindings you will get DO value not edited value. Actually data is not getting pushed to bindings. Binding is still same and if any PPR happens you will lose data also. 
    • Problem-3: Row selection does not work on a table, which is directly based on BAM datacontrol. In UI it appears like row is selected but if you try to get currently selected row in bean, you will see that binding iterator is still pointing to first row. Because of this if you edit a record you would not know which record is actually edited. 
    • Because of above 3 problems I can say its difficult to use BAM data control for editing data.
  • Use BAM webservice: BAM provides the webservice and DataObjectOperationsByName provide a GET service to get data from BAM DOs. But we can have following problems
    • Problem-1: Service only returns one row at a time. If we want to query all employees of certain department that might not be possible. Service will give only one employee record.
    • Problem-2: I could not find a better way to propagate ADF security while calling BAM webservice. Because of which I need to execute BAM webservice using a predefined username/password. Yes we need not to hardcode username/password, we can use credential store to access username/password. If there is any data security at DO level we may miss that and all users will see same data. 
    • Because of above 2 problems I can say its not possible to use BAM webservice to edit (query) multiple rows. 
  • Use BAM database connection: We can directly create EO/VO etc directly on top of BAM tables. This looks like a feasible solution but we have following problems here
    • Problem-1: We need direct access to database and client may not agree.
    • Problem-2: If there is any data security at DO level we may miss that and all users will see same data. 
    • Because of above 2 problems I can say its not a good solution to directly query database.
So we have kind of discarded all possible solution of data query. Now what?
Here is the approach that we are going to do in this blog

  • Query data (all rows) from DO using datacontrol and push them in programatic VO. 
  • Show data from programatic VO to user. 
  • User can freely update data and data will get posted on VO without any issue. PPR will also show edited data.
  • On Submit call DO webservice to update it


NOTE:

  • Because you are showing data from VO to end user, you can use all VO features like LOV creation, control hints etc.
  • As we are querying data using datacontrol so ADF security can be propagated and DO level security will be taken care. [ We have a checkbox on BAM datacontrol wizard to propagate ADF security.]
  • Only downside I see is if you have huge number of records you need to query them all from DO and push to programmatic VO. It may be a bit performance hit. 
Here are the steps to implement this approach
Create datacontrol based on BAM DO: Follow https://docs.oracle.com/cd/E23943_01/dev.1111/e10224/bam_data_control.htm to create a datacontrol based on a BAM DO.
    In general you need to have SOA extension in your jdev. You need to create a BAM connection. You need to search for your DO under connection and then right click and create data control.

For this blog we assume that we have created a data control based on 
Create an ADF page to show data from BAM datacontrol: For this we just need to create a page and drag-drop datacontrol on it. Create a table out of it. Run the page. You should see BAM report in tabular format.
Disable active data behavior: To remove active behavior open page definition and set  ChangeEventPolicy and ChangeEventRate for bindings as shown below
Also keep fetchSize very high so that all rows of DO gets fetched at page load itself.

Fetch all records of DO and Push them to programatic VO:
This is an important step. We want to query BAM DO and push its data to programmatic VO. Our approach is to have bean method which will get data using bindings created in previous step and then call an AM method which will populate VO. We can follow these steps
    a. Create programmatic VO and add it in application module
          
                               Add appropriate attribute to VO
     



    b. Add following method in AM and expose it to client
    public void initEmployeePG(List<Map> employeeList){
      
        ViewObjectImpl vo = this.getEmployeeVO();
        Iterator it = employeeList.iterator();
        while(it.hasNext()){
           Map empMap = (Map) it.next();
          
            Row row = vo.createRow();
            vo.insertRow(row);
            row.setAttribute("id", empMap.get("id"));
            row.setAttribute("Salesperson", empMap.get("Salesperson"));
            row.setAttribute("SalesArea", empMap.get("SalesArea"));
            row.setAttribute("SalesNumber", empMap.get("SalesNumber"));
           
           row.setAttribute("ChangeFlag", "N");
        }
       
        vo.setSortBy("Salesperson");
        vo.setQueryMode(ViewObject.QUERY_MODE_SCAN_VIEW_ROWS);
        vo.executeQuery();
    }


above method accepts a list of map, which is used to initialize programmatic VO. Our aim is to somehow create query data from DO using datacontrol and create a list of map based on that data and pass that to this method. This method will insert that data into VO and later we will show UI based on this VO.

To construct a list of map based on DO data we can do following.

    a. Add AM method in pageDef file

    b. Create bean class. Register it in backing bean scope and write following method
     public void initializeEmployeePG(){
        AdfFacesContext facesCtx=  AdfFacesContext.getCurrentInstance();
        Map pageFlow = facesCtx.getPageFlowScope();
        String pageInitialized = (String)pageFlow.get("pPageInitialized");
        if(!"Y".equals(pageInitialized)){
            List<Map> emps = new ArrayList<Map>();
            DCBindingContainer dcBindings = (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
            DCIteratorBinding treeData =    (DCIteratorBinding)dcBindings.get("QueryIterator");
            Row[] rows = treeData.getAllRowsInRange();

            for (Row row1 : rows) {
                BAMDataControlDataRow row = (BAMDataControlDataRow)row1;
                Map pn = (HashMap)row.getDataProvider();
                Map empMap = new HashMap();
                empMap.put("id",pn.get("ID"));
                empMap.put("Salesperson",pn.get("_Salesperson"));
                empMap.put("SalesArea",pn.get("_Sales_Area"));
                empMap.put("SalesNumber",pn.get("_Sales_Number"));
                emps.add(empMap);
            }         
          
            Map params = new HashMap();
            params.put("employeeList",emps);
            ADFUtil.executeOperationBinding("initEmployeePG", params);
                  
            pageFlow.put("pPageInitialized", "Y");
        }
    }

    c. Create a new java class (EmployeeDC.java)and put following method in it.
    public void initializeEmployeePage() {
          
            EmployeePGBean bean =
                (EmployeePGBean)ADFUtil.evaluateEL("#{backingBeanScope.EmployeePGBean}");
            bean.initializeEmployeePG();
          
        }

    d. Expose  EmployeeDC.java as datacontrol
    e. Add initializeEmployeePage method of EmployeeDC in pagedef file. Also add an executable to invoke this method automatically on page load.
           
Below diagram shows complete diagram of page initialization

Remove database connection and make AM non database dependent:
As we only want to access BAM server using BAM datacontrol there is no need to have a database connection in our application. We can follow blog http://andrejusb.blogspot.in/2012/03/use-case-for-adf-bc-with-no-database.html to make AM non database dependent.

Create editable table and show data from programmatic VO:
Now you can comment existing af:table entry in on page and and drop new VO datacontrol on page to create a new table. Remember when you are removing existing af:table bindings should not get removed. In new table you can add inputText, LOV whatever you want as you are only working with programmatic VO

Save data using BAM webservices:
Once user clicks on Save button we may need to call BAM webservice to post data. We can follow blog: http://sanjeev-technology.blogspot.in/2014/11/executing-bam-webservices-using-adf.html