Saturday, March 5, 2016

Oracle JET and ADF BC REST Basic Authentication

You might be interested to check my previous sample about CRUD implementation in JET - Handling ADF BC 12.2.1 REST Validation in Oracle JET. I'm going to describe how to access secure ADF BC REST service from JET, based on the CRUD sample app. We need to pass authorization header on each REST request, this way server can authenticate user and authorize access to the REST resource. There are couple of other tips applied on ADF BC REST service side, all described below.

Blog reader rjahn shared a link in this blog comment - Oracle JET - Rendering Table from ADF BC REST Service, he describes how to pass authorization header using oauth property, while executing GET and fetching collection in JET. I'm using same approach for GET, but for PATCH, POST and DELETE authorization header is set in slightly different way.

First of all we need to take a look into ADF BC REST security implementation. Each time when custom header is attached in JET, it executes OPTIONS method without appending authorization header. I have disabled security check for OPTIONS in web.xml:


Important tip - by default security operations granted to ADF BC resource are all assigned through single permission (in jazn-data.xml):


I have found this doesn't work, even from Postman - only first operation from the list is authorized. This must be a bug in ADF BC REST security. Workaround is to separate each operation into different permission group manually:


GET executed from JET is authorized and data is coming through:


We can see in network monitor recorded GET execution from JET - authorization header is submitted along with request:


Authorization header is encoded with JavaScript btoa function. Obviously it must run on HTTPS to be completely secure, otherwise someone can intercept and decode the password. Authorization header is being constructed in JET (you would fetch username/password from HTML form, etc.) and is attached to the collection (this way it gets included into request header executed by GET). It doesn't work to attach it to collection through header property (as it works for POST, PATCH and DELETE), but it works with oauth:


Authorization header can be set for PATCH. Data can be updated through secure service:


Authorization header is present in PATCH request:


Authorization header is injected through property - headers (differently than for collection and GET). It didn't work to use oauth here:


Create case is executed through POST, security is enforced through authorization header here also:


We can see header is present in the request:


Authorization header is attached in the same way as for PATCH:


Delete case is executed through DELETE, same authorization header is applied:


Header info:


Authorization header is attached to JET destroy operation:


Download sample application (JET and ADF BC code) - JETCRUDApp_v5.zip. You should include JET code into JET toolkit distribution.

7 comments:

  1. You state that using HTTPS is secure (which is true for the headers) but you need to store the credentials client side because you need them for every request.
    As far as I know this can't be done in a secure way ?

    ReplyDelete
  2. Check update related to your question: http://andrejusb.blogspot.lt/2016/07/adf-bc-rest-authentication-with.html

    ReplyDelete
  3. Hi Andrejus,

    I have downloaded your JETCRUDAPP_v5. It is working fine with authentication. However, For Salary Validation occurs for update operation, I am getting the following error:

    main.js:128 Uncaught TypeError: self.collection.refresh is not a function
    at Model.error (http://localhost:8383/JETCRUDApp/js/main.js:128:49)

    Note: If I comment //self.collection.refresh then the salary validation message shown, but the collection is not refreshed.

    Could you please help me to resolve this issue.

    Thanks

    Ashok

    ReplyDelete
  4. Hi Andrejus,

    I have resolved the issue. The parenthesis missing in the code:

    Wrong: self.collection.refresh();

    Correct: self.collection().refresh();

    It is working fine after putting the parenthesis.

    Thanks

    Ashok

    ReplyDelete
  5. Probably API was changed in newer JET version. It worked before. Thanks.

    Andrejus

    ReplyDelete
  6. Hi Andrejus,
    I would like to pass an Authorization JWT token in all my REST calls.
    I tried the following code and it works fine but when I call collection.refresh, I get 403 error again.
    this.empCollection.fetch({headers: {"Authorization": 'Bearer XXXXXXXXXXXXX'}});
    Can you tell me how to add Authorization header in oj.Collection so that all operations pass this Authorization token?

    Regards,
    Sarah

    ReplyDelete