Securing your Oracle Rest Data Services module only takes a couple of minutes.
As you can see in the video, this will be a fairly short how-to.
Assumptions
For this post, I’m going to assume:
- You’re able to use SQL Developer.
- You already have an ORDS module created that you want to secure.
- You have at least a basic understanding of Roles, Privileges, Authentication and Authorization.
Test the Existing Service
Before we begin, I’ll test the current service with a curl command.
1 |
curl -i "http://localhost:8080/ords/beacon/beacon/scan" |
This returns a response with a status of “HTTP/1.1 200 OK” and a JSON object with an array of items.
1 2 3 4 5 6 7 |
HTTP/1.1 200 OK Date: Fri, 07 Dec 2018 03:02:15 GMT Content-Type: application/json ETag: "9xNgvloFw1ZfBwQ255WysJ1trS4t9nSdBZUqSdg170X8DfoFDkjBLboruFoXG1TcQRkzWqVx0ptMV6ldt6BU6g==" Transfer-Encoding: chunked {"items":[{"id":641,"scanner_id":5,"beacon_id":"myBeacon","distance":4.72,"created_on":"2017-08-27T22:19:58.082Z"},...... |
Secure Your Service
First up I will create a Role and a Privilege that I’ll use to secure my service.
Create a Role
- Expand the schema connection and REST Data Services, if they are not already expanded.
- Right click on Roles.
- Click New Role…
- Enter a name for the role. I’m using bc-role.
- Click Apply.
Create a Privilege
- Expand the schema connection and REST Data Services, if they are not already expanded.
- Right click on Privileges.
- Click New Privilege…
- Enter a name for the privilege. I’m using bc-priv.
- Select the new role ‘bc-role’.
- Select the ORDS Module. I’m using my Beacon module.
- Click Apply.
Be aware, this will only add security to the specific modules you select in the bottom section. If you were to add a new module later and you want it to be covered with this privilege, you need to remember to edit this privilege and select it in the ‘Protect Modules’ selector.
Alternatively, you can use the ‘Protect Resources’ tab to apply security based on a URI pattern.
For my examples, I’m working from a VirtualBox VM and I have used ‘beacon’ as my schema alias. So the base for all of my REST services in this schema would be
1 |
https://localhost:8080/ords/beacon |
I entered the URI pattern
1 |
/* |
This will protect all ORDS services for this schema. If I wanted to use this method to protect just an admin URI template in my beacon module (the full URI is https://localhost:8080/ords/beacon/beacon/admin), I would use a URI pattern like this
1 |
/beacon/admin/* |
There are many more complex patterns you could use for your services, but for this post, I am only protecting the Beacon module so I am using the first example.
Test
1 |
curl -i "http://localhost:8080/ords/beacon/beacon/scan" |
1 2 3 4 |
HTTP/1.1 401 Unauthorized Content-Type: text/html Content-Length: 13150 ..... |
Access Your Service
I want to set up my ORDS module so it can be accessed by a third party application so I’ll set up OAuth 2.
Create an OAuth 2 Client
Using the OAUTH PL/SQL Package, I will create an OAuth2 client using the privilege I created above.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
-- Create OAUTH client BEGIN OAUTH.create_client( p_name => 'BC Client', p_grant_type => 'client_credentials', p_owner => 'Blaine', p_description => 'A client for Rest Demo', p_support_email => 'blaine.carter@oracle.com', p_privilege_names => 'bc-priv' ); COMMIT; END; / |
Then I will grant the new OAUTH2 client the role I created above.
1 2 3 4 5 6 7 8 9 10 |
-- Grant OAUTH client role BEGIN OAUTH.grant_client_role( p_client_name => 'BC Client', p_role_name => 'bc-role' ); COMMIT; END; / |
Test
In order to generate an access token, I need to get my client id and secret from the user_ords_clients table.
1 2 |
SELECT id, name, client_id, client_secret FROM user_ords_clients; |
1 2 3 |
ID NAME CLIENT_ID CLIENT_SECRET ---------- -------------------- -------------------------------- -------------------------------- 10687 BC Client RTrgeYXmVrA4IjnQtixzLw.. yPljTEn7kXX2ZfdIhPDVow.. |
When you create an OAuth2 client, a REST service ‘/oauth/token’ is created for you that your applications can use to generate a bearer token using the above id and secret.
1 |
curl -i -k --user RTrgeYXmVrA4IjnQtixzLw..:yPljTEn7kXX2ZfdIhPDVow.. --data "grant_type=client_credentials" http://localhost:8080/ords/beacon/oauth/token |
1 2 3 4 5 6 7 |
HTTP/1.1 200 OK Date: Fri, 07 Dec 2018 03:11:58 GMT Content-Type: application/json X-Frame-Options: SAMEORIGIN Transfer-Encoding: chunked {"access_token":"xoJutP9YeUjCqN4mAgDBAw..","token_type":"bearer","expires_in":3600} |
Notice that this token expires in 3600 seconds. Once it expires, you would repeat the above call to generate a new token.
Now that I have an access_token I can include it in the Authorization header to access my secure ORDS service. Notice that since this is a Bearer token I set the Authorization value to ‘Bearer <<my token>>’.
1 |
curl -i -k -H "Authorization: Bearer xoJutP9YeUjCqN4mAgDBAw.." "http://localhost:8080/ords/beacon/beacon/scan" |
1 2 3 4 5 6 7 |
HTTP/1.1 200 OK Date: Fri, 07 Dec 2018 03:22:44 GMT Content-Type: application/json ETag: "9xNgvloFw1ZfBwQ255WysJ1trS4t9nSdBZUqSdg170X8DfoFDkjBLboruFoXG1TcQRkzWqVx0ptMV6ldt6BU6g==" Transfer-Encoding: chunked {"items":[{"id":641,"scanner_id":5,"beacon_id":"myBeacon","distance":4.72,"created_on":"2017-08-27T22:19:58.082Z"},..... |
Example Usage
The following is an example of how to make secure REST calls from an external application after you’ve followed the above steps.
On the application server
Store the client_id and client_secret in environment variables.
In your application
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Function get_token Read the client_id and client_secret from the environment variables. Make a GET request from your ORDS service '.../oauth/token' for a new access_token using your client_id and client_secret. Store the access_token and expiration time. Function get_data If access_token does not exist or is expired. Call get_token. Make a GET request from your ORDS service '.../beacon/scan' using the access_token in a header parameter - "Authorization: Bearer <<Your Token Here>>". If the response status is 401 Unauthorized. If access_token exists and has expired. Call get_token. Retry GET request. Else Raise an error. |
Summary
Setting up security on your ORDS modules is quick and fairly easy.
OAuth2 is just one way to access your secured ORDS modules. If you’d like to setup Basic Auth checkout this post by Jeff Smith.
Console the ORDS documentation for other examples and a much more in-depth explanation.
Hi! Could you provide the code of a PL/SQL process to get the token (if previous one has expired), and use it to consume an APEX restful service?
I really need help to do that.
Thanks!
I haven’t tried to do that before.
Try asking in https://apex.world there are some really smart people over there.