Showing posts with label Security. Show all posts
Showing posts with label Security. Show all posts

Monday, February 19, 2018

Oracle JET: Bookmark a secured pages

Problem Description: Oracle JET allows us to create SinglePage application (SPA). It changes url when we navigate between pages. What if application is secured application and pages require login to visit. In such case if we book mark a page and later try to launch it, application should verify if user is already logged in, If not redirect user to login page and once logged in user should be shown same page, which he has requested. In this blog we are trying to achieve it.

Also if user has directly started from login page then if login is successful we need to take him to default page mentioned in router configuration.

Solution:
 To implement this we need to achieve following flow

Here are the steps to achieve above flow

1. User can either launch login page or a secured page (say Page-X). If user launches login page, we can directly show him login page, but if he launches Page-X, we need to verify if user is already logged in.To verify if user has already logged in depends on server side logic.
   Here in this blog I assume there is a REST service available, which returns profile of logged in user (myprofile service). we will call this service, without passing any Authorization header. In such case browser will pass SESSIONID from cookie if user is already logged in. If not logged in then we will get 401 from server. If we get error from server, we can redirect user to login page, but we will add current url in login page url additionally, so that we can use it later to redirect user back to Page-X. Here is the common code checkIfLoginDone function written in appcontroller.js

     function ControllerViewModel() {
        $.ajaxSetup({
          xhrFields: {
            withCredentials: true
          }
        }); 

        var self = this;
        self.baseURL='http://localhost:7101';
        self.serviceContextRoot = '/myapp';
        self.serviceInitialURL = self.baseURL + self.serviceContextRoot + '/resources';

        self.router = oj.Router.rootInstance;
        self.checkIfLoginDone = function checkIfLoginDone(){
          console.log('starting login check');
          
          var promise = $.ajax({
             type: "GET",
             url: self.serviceInitialURL+ "/v1/myprofile",
             contentType: "application/json; charset=utf-8",
             crossDomain: true,
             dataType: "json"});
           
            promise.then(function(response) {
                  
                 

              }, function(error) {
                 // error handler
                 var currenturl = window.location.pathname + window.location.search ;
                window.location.href = '/?root=login&origurl='+currenturl;
              });

            return promise;
         
          
        }

In above code if we get error from server, we will be redirecting user to login page and add url of secured page as a parameter origurl. Login page url will appear like
http://<host>:<port>/?root=login&origurl=<url-path-of-secured-page>

[Assuming that login will be router state for login page]

2. To perform login check we can it checkIfLoginDone from all secured pages's ViewModel as
define(['ojs/ojcore', 'knockout', 'jquery', 'appController'],
 function(oj, ko, $, app) {
      self.handleActivated = function(info) {
        // Implement if needed
        return app.checkIfLoginDone();
      };

3. Create a login page: For this you can follow below steps
      a. Create login.html in js/views directory. Content could be
         

      <div class="oj-hybrid-padding">
        <h1>Login Content Area</h1>
          <div id="sampleDemo" style="" class="demo-container">
            <div id="componentDemoContent" style="width: 1px; min-width: 100%;">
              <div id="form-container" class="oj-form-layout">
                <div class="oj-form">
                  <div class="oj-flex">  
                    <div class="oj-flex-item">
                      <oj-label show-required for="username">User Name</oj-label>
                      <oj-input-text id="username" required value="{{username}}"></oj-input-text>
                    </div>
                  </div>
                  <div class="oj-flex">  
                    <div class="oj-flex-item">
                      <oj-label for="password" show-required>Passward</oj-label>
                      <oj-input-password id="password" required value="{{password}}"></oj-input-password>
                    </div>
                  </div>
                </div>
                <oj-button id='submit' on-click='[[doLogin]]'>Login</oj-button>
              </div>              
            </div>
    </div>
  </div>
   
In above page, we have created two fields username/password and a button Login.
Username and password are bound to ViewModel and Login button click calls doLogin method of ViewModel

    b. Create login.js as a ViewModel in js/viewModels directory. Its code would be

define(['ojs/ojcore', 'knockout', 'jquery', 'appController','ojs/ojknockout','ojs/ojlabel','ojs/ojinputtext', 'ojs/ojcheckboxset'],
 function(oj, ko, $, app) {
  
    function LoginViewModel() {
      var self = this;
      function param(name) {
            return (location.search.split(name + '=')[1] || '').split('&')[0];
        }
      self.username = ko.observable("");
      self.password = ko.observable("");
      self.doLogin = function doLogin(event){
        $("body").css("cursor", "wait");
       //do server login here
       var string = self.username() + ':' + self.password();
      var encodedString = 'Basic ' + btoa(string);
             
      var promise = $.ajax({
              type: "POST",
              url: app.serviceInitialURL + '/v1/auth/login',
              contentType: "application/json; charset=utf-8",
              headers: {
                   "Content-Type": "text/plain",
                    "Authorization": encodedString
              },
              crossDomain: true,
              dataType: "json"});
         
      promise.then(function(response){
              var origurl = param('origurl');
              if(origurl){
                window.location.href = origurl;
              }
              else{
                oj.Router.rootInstance.go('dashboard');
              }

              $("body").css("cursor", "default");
         }, function(response){
             //write logic here to show error message to end user.
         }) ;   

      }
      // Header Config
      self.headerConfig = {'viewName': 'header', 'viewModelFactory': app.getHeaderModel()};

      
     

    return new LoginViewModel();
  }
);

Important piece of above code is 
    i. username/password created as ko observable.
   ii. username password is used to create base 64 encoded authorization string
  iii. server side login using $.ajax POST request
   iv. If login is success then verify if there is any url parameter as origurl present. Navigate to the location whereever origurl points to. If not specified then get default page from router and navigate there. 

c. register login page in router configuration

self.router.configure({
          'login': {label: 'Login'},
         'dashboard': {label: 'Dashboard', isDefault: true},
         'incidents': {label: 'Incidents'},
         'customers': {label: 'Customers'},
         'profile': {label: 'Profile'},
         'about': {label: 'About'}
        });

4. Finally we need a logout button. We can keep it in header.html
<div class="oj-flex-bar-end">
    <oj-button id='button1' on-click="[[logout]]">Logout</oj-button>
</div>

logout implementation is written in appcontroller.js by changing getHeaderModel method.
 self.logout = function(event){
           $.ajax({
                 type: "GET",
                 url: self.serviceInitialURL+ "/v1/auth/logout",
                 contentType: "application/json; charset=utf-8",
                 crossDomain: true,
                 dataType: "json",
                 success: function (data, status, jqXHR) {
                        oj.Router.rootInstance.go('login');
                 },

                 error: function (jqXHR, status) {
                     // error handler
                     
                 }
              });

      }


 self.getHeaderModel = function() {
          var headerFactory = {
            createViewModel: function(params, valueAccessor) {
              var model =  {
                pageTitle: self.router.currentState().label,
                handleBindingsApplied: function(info) {
                  // Adjust content padding after header bindings have been applied
                  self.adjustContentPadding();
                },
                toggleDrawer: self.toggleDrawer,
                logout: self.logout
              };
              return Promise.resolve(model);
            }
          }
          return headerFactory;
        }

Above logout method calls server side logout and then redirect user to login page.



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.