Implementing OAuth 2 with Oracle Access Manager OAuth Services (Part III)

Introduction

This post is part III of a serie of posts about OAM’s OAuth implementation.

Other posts can be found here:

Part I – explains the proposed architecture and how to enable and configure OAM OAuth Services.

Part II – describes a Business to Business use-case (2-legged flow);

Part III  – deals with the Customer to Business use-case (3-legged flow), when the client code is running in the application server;

Part IV – describes the Customer to Business use-case (3-legged flow), when the client application runs on the browser, embedded as Javascript code;

Part V  – provides the source code and additional information for the use case implementation.

This post will cover the C2B (Customer to Business) Use Case, when the Client Application is running on the Server.

In this case, an end user accesses an Application, which needs to fetch data from a Resource Server in behalf of the end user, but without the end user providing his credentials to the Application.

The user has to provide his consent for the client application to access his resources in the Resource Server.

In this use case, all the code resides in the server and it is not visible to the end user.

Oracle recommends that customers install the latest bundle patch available for their specific IdM release. Bundle Patches might include important patches for OAuth implementation. You can find information about Bundle Patch History and Releases in the Support document “OAM Bundle Patch Release History (Doc ID 736372.1)”. Please visit My Oracle Support (https://support.oracle.com) and search for Doc ID 736372.1.

Before You Proceed…

Read this if you’re using OAM R2PS3 (11.1.2.3)

This post was written based on OAM R2PS2 release. Even though most things are still the same on R2PS3 release, there are some subtle differences from one release to the other.
In OAM R2PS3, you need to deploy a webgate in front of your OAM servers in order to use the OAuth 3-legged flow.
The webgate is required to protect the OAuth consent page, otherwise you will get an error when trying to follow the 3-legged OAuth flow.
Review the documentation on how to install a supported webserver and deploy webgate here.

Deploy and register a webserver/webgate and configure the following resources in your application domain:

/ms_oauth/oauth2/oammsui/** – Excluded
/oam/** – Excluded
/ms_oauth/img/* – Excluded
/ms_oauth/style/* – Excluded
/ms_oauth/oauth2/endpoints/** – Excluded
/ms_oauth/oauth2/ui/** – Protected

In your webserver create a new conf file with the following directives

<Location /oam>
SetHandler weblogic-handler
WLProxySSL ON
WLProxySSLPassThrough ON
WLCookieName OAM_JSESSIONID
WebLogicCluster server1:port1, server2:port2
</Location>

<Location /ms_oauth>
SetHandler weblogic-handler
WLProxySSL ON
WLProxySSLPassThrough ON
WLCookieName OAM_JSESSIONID
WebLogicCluster server1:port1, server2:port2
</Location>

Use Case Flow

The following picture shows the flow between the different components

C2B1

 

1. A User Agent, usually a browser, accesses the Application, starting the OAuth flow.

2. The Application detects that the user have not presented an Authorization Code, then it redirects the user to the OAM/OAuth authorization URL.

The redirect is a standard HTTP browser redirect that looks like this:

https://oxygen.mycompany.com:14101/ms_oauth/oauth2/endpoints/oauthservice/authorize?client_id=customerClient&response_type=code&redirect_uri=https://oxygen.mycompany.com:7502/ClientWebApp/CustomerClient&scope=Customer.Info%20UserProfile.me

Some things to note here:

The Application identifies itself with its ID, client_id=customerClient;

The expected response type is the authorization code, response_type=code;

The redirect URI, to where the OAuth server will redirect the request with the authorization code as URL parameter after the user successfully logs in;
And lastly the requested Scope, Customer.Info and UserProfile.me

In this step the OAuth server checks if the requesting client is correctly registered, if it has the correct grant type enabled, in this case Authorization Code, if the redirect_uri is matches the one defined in the client configuration and if it is requesting a scope allowed for this client.

If the conditions above are not met, the OAuth server send and error back and does not proceed to the user authentication.

3. OAuth Server redirects the user to OAM Login Page.

4. User logs in with his credentials.

5. Since the user has started an OAuth flow in step 1, the OAuth server needs the user consent to provide a token to this application which will be used to access the user resource on the Resource Server.

6. OAuth server redirects the user to the consent page so the user can consent or reject the Application access to his resources.

The consent page looks like this:

C2B2

7. The user grants access to the CustomerClient Application

8. The OAuth server returns the Authorization Code the the URI defined in the redirect_uri as an URL parameter.

The response looks like this:

https://oxygen.mycompany.com:7502/ClientWebApp/CustomerClient?code=eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJvcmFjbGUub2F1dGgucmVkaXJlY3QtdXJpIjoiaHR0cHM6Ly9veHlnZW4ubXljb21wYW55LmNvbTo3NTAyL0NsaWVudFdlYkFwcC9DdXN0b21lclNlcnZsZXQiLCJvcmFjbGUub2F1dGgudXNlcl9vcmlnaW5faWRfdHlwZSI6IkxEQVBfVUlEIiwib3JhY2xlLm9hdXRoLnVzZXJfb3JpZ2luX2lkIjoicGF1bG8iLCJpc3MiOiJ3d3cub3JhY2xlLmV4YW1wbGUuY29tIiwib3JhY2xlLm9hdXRoLnN2Y19wX24iOiJPQXV0aFNlcnZpY2VQcm9maWxlIiwiaWF0IjoxNDMxMTAyNjIyMDAwLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6ImF6YyIsImV4cCI6MTQzMTEwMzUyMjAwMCwicHJuIjpudWxsLCJqdGkiOiI2OTkwNDRlZi0zM2IwLTRhNDUtYjI4MS1jYTNjMTc2NzhkNTciLCJvcmFjbGUub2F1dGguY2xpZW50X29yaWdpbl9pZCI6ImN1c3RvbWVyQ2xpZW50Iiwib3JhY2xlLm9hdXRoLnNjb3BlIjoiQ3VzdG9tZXIuSW5mbyIsInVzZXIudGVuYW50Lm5hbWUiOiJEZWZhdWx0RG9tYWluIiwib3JhY2xlLm9hdXRoLmlkX2RfaWQiOiIxMjM0NTY3OC0xMjM0LTEyMzQtMTIzNC0xMjM0NTY3ODkwMTIifQ.Y7fyCqKR6eY95SET9ddXmpCa8acLWSYoRCsZUqMadZ-eUA6GV11zfHJKUUdTcLER3TxjVb8NXLV9Hl_aTFPPxqcf6rVW_yxKrWpW6m18cDeZsmln015AZjJNdGzxrYtOBrrMuLAA58hk1h2CDplagOTDhypT_rAJGD6uDgmRrMM&state=abc

9. The Application then is able to extract the Authorization Code from the URL parameter and request the OAuth Server for an Access Token. The request would look like this in curl:

curl -i -H ‘Authorization: Basic YnJvd3NlckNsaWVudDpnOGFHZ2xaRHJQRGw3ZQ==’ -H “Content-Type: application/x-www-form-urlencoded;charset=UTF-8” –request POST https://oxygen.mycompany.com:14101/ms_oauth/oauth2/endpoints/oauthservice/tokens -d ‘redirect_uri=https://oxygen.mycompany.com:7502/ClientWebApp/CustomerServlet&grant_type=authorization_code&code=eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJvcmFjbGUub2F1dGgucmVkaXJlY3QtdXJpIjoiaHR0cHM6Ly9veHlnZW4ubXljb21wYW55LmNvbTo3NTAyL0NsaWVudFdlYkFwcC9DdXN0b21lclNlcnZsZXQiLCJvcmFjbGUub2F1dGgudXNlcl9vcmlnaW5faWRfdHlwZSI6IkxEQVBfVUlEIiwib3JhY2xlLm9hdXRoLnVzZXJfb3JpZ2luX2lkIjoicGF1bG8iLCJpc3MiOiJ3d3cub3JhY2xlLmV4YW1wbGUuY29tIiwib3JhY2xlLm9hdXRoLnN2Y19wX24iOiJPQXV0aFNlcnZpY2VQcm9maWxlIiwiaWF0IjoxNDMxMTAyNjIyMDAwLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6ImF6YyIsImV4cCI6MTQzMTEwMzUyMjAwMCwicHJuIjpudWxsLCJqdGkiOiI2OTkwNDRlZi0zM2IwLTRhNDUtYjI4MS1jYTNjMTc2NzhkNTciLCJvcmFjbGUub2F1dGguY2xpZW50X29yaWdpbl9pZCI6ImN1c3RvbWVyQ2xpZW50Iiwib3JhY2xlLm9hdXRoLnNjb3BlIjoiQ3VzdG9tZXIuSW5mbyIsInVzZXIudGVuYW50Lm5hbWUiOiJEZWZhdWx0RG9tYWluIiwib3JhY2xlLm9hdXRoLmlkX2RfaWQiOiIxMjM0NTY3OC0xMjM0LTEyMzQtMTIzNC0xMjM0NTY3ODkwMTIifQ.Y7fyCqKR6eY95SET9ddXmpCa8acLWSYoRCsZUqMadZ-eUA6GV11zfHJKUUdTcLER3TxjVb8NXLV9Hl_aTFPPxqcf6rVW_yxKrWpW6m18cDeZsmln015AZjJNdGzxrYtOBrrMuLAA58hk1h2CDplagOTDhypT_rAJGD6uDgmRrMM’ -k

Note that the Application passes its credentials enconded as 64Base in the Authorization header, the redirect URI, the grant type and the Authorization Code.

10. The OAuth Server checks the Authorization Code, if the grant type is enabled for this client and if its credentials are correct before issuing the Access Token.

11. OAuth Server send the Access Token back to the Application in the following format:

{“expires_in”:3600,”token_type”:”Bearer”,”access_token”:”eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJzdWIiOiJwYXVsbyIsIm9yYWNsZS5vYXV0aC51c2VyX29yaWdpbl9pZF90eXBlIjoiTERBUF9VSUQiLCJvcmFjbGUub2F1dGgudXNlcl9vcmlnaW5faWQiOiJwYXVsbyIsImlzcyI6Ind3dy5vcmFjbGUuZXhhbXBsZS5jb20iLCJvcmFjbGUub2F1dGguc3ZjX3BfbiI6Ik9BdXRoU2VydmljZVByb2ZpbGUiLCJpYXQiOjE0MzExMDM5OTgwMDAsIm9yYWNsZS5vYXV0aC5wcm4uaWRfdHlwZSI6IkxEQVBfVUlEIiwib3JhY2xlLm9hdXRoLnRrX2NvbnRleHQiOiJyZXNvdXJjZV9hY2Nlc3NfdGsiLCJleHAiOjE0MzExMDc1OTgwMDAsInBybiI6InBhdWxvIiwianRpIjoiMjQ4YjAyOTgtNWQ1Yy00ZjFkLTkzNjctZTgyYTcwY2ZiOTk5Iiwib3JhY2xlLm9hdXRoLmNsaWVudF9vcmlnaW5faWQiOiJjdXN0b21lckNsaWVudCIsIm9yYWNsZS5vYXV0aC5zY29wZSI6IkN1c3RvbWVyLkluZm8iLCJ1c2VyLnRlbmFudC5uYW1lIjoiRGVmYXVsdERvbWFpbiIsIm9yYWNsZS5vYXV0aC5pZF9kX2lkIjoiMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MDEyIn0.M-OFxBY6XzPRfW295tikNl2rj_M7IqPO1RUOLoj2IyHkcYRxRlFd0kc7le4eAK0oxYSrhhNNbwrzEq25fAdDF9H8nWeMXRec69WRyDi53-BdCB8NPgrYyVcsYVcS5l5XKieMBM7Mnl0AVb3oZ77N0sRQCWkJn2S-wgYoGjHcOOE”}

12. The application is able now to make a call to a remote service – The Resource Server – using the Access Token.

13. As in the same case of the B2B, the Resource Server is another OAuth client, with the particularity that is does not have any grant or scope defined to it.

It just needs to validate the token passed by remote clients. The only detail here is that this client needs to have the option to “Allow Token Attributes Retrieval” enabled, if it wants to perform Token Introspection, that is, return additional values, rather than just receiving a “valid” status from the OAuth Server.

14. The OAuth Server validates the Token and returns additional attributes.

The validation would look like this:

{“successful”:true,”oracle_token_attrs_retrieval”:{“oracle.oauth.tk_context”:”resource_access_tk”,”exp”:1431108481000,”oracle.oauth.user_origin_id_type”:”LDAP_UID”,”oracle.oauth.user_origin_id”:”paulo”,”iss”:”www.oracle.example.com”,”prn”:”paulo”,”oracle.oauth.client_origin_id”:”customerClient”,”oracle.oauth.scope”:”Customer.Info”,”jti”:”78fc3b08-b12a-4fbc-bad8-a7e5b7041332″,”oracle.oauth.svc_p_n”:”OAuthServiceProfile”,”iat”:1431104881000,”oracle.oauth.id_d_id”:”12345678-1234-1234-1234-123456789012″}}

Note that the token, in a C2B use case, represents both the OAuth client (“oracle.oauth.client_origin_id”:”customerClient”) and the end user (“prn”:”paulo”).

15. The Resource Server returns the requested resource to the Client Application

16. The Client Application presents the results to the user agent.

 

C2B Use Case Implementation

To implement the C2B use case, a standard Java Servlet will be used, CustomerClient.java, that is very similar with the B2B use case, but it requires the user consent to allow the client application to access the user resources in its behalf.

This servlet, will obtain an Authorization Token, result of the end user authentication.

If this Servlet is protected by a OAM policy, and the user has already authenticated, the redirect to the authorization end point will provide the authentication token without the user having to login again.

With the Authorizaition Token, the Servlet can obtain and Access Token using the Authorization Code grant type, and will pass this Access Token to the Resource Server, when making the call to the Customer REST endpoint.

The Resource Service is implemented in a plain Java class using the Jersey framework to expose the Customer Service as a RESTful webservice.

The Resource Server also implements a Servlet Filter, that intercepts all incoming requests to validate the incoming Access Token before giving access to the REST Endpoint.

The relevant classes for this use case are:

  • CustomerClient.java
  • TokenProxyService.java
  • CustomerService.java
  • OAuthTokenValidationFilter.java
  • OAuthTokenValidator.java

Comments

  1. Hi ateam,
    OAuth server is not returning a authorization code.

Add Your Comment