X

Best Practices from Oracle Development's A‑Team

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

Introduction

This post is part II of a series 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.

The B2B (or Business to Business) use-case, usually represents an application that calls another application or service, without end user intervention.

In this example, the BusinessClient application (in OAuth spec, called a client) will make a call to a service, BusinessService (in OAuth spec, a Resource Server), and request some Business Information, passing the Access Token.

Since there is no end user intervention, the client is pre authorized to have access to the resource, making this use case one of the simplest to implement.

In this implementation, a Java Servlet will be used to simulate the BusinessClient, so that the flow can be started at will, and a Java RESTful web service will be used to represent the Resource Server.

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.

B2B Use Case - New Page

 

Steps details:

1. BusinessClient requests an OAuth Token from OAuth Server using “Client Credentials” grant type.

The BusinessClient application must be registered with OAM OAuth Server as an OAuth client and it must send its credentials in a Base64 encoded string in the Authorization Header.

The application also declares the scope for which it is requesting the token.

The call would look like this in curl:

curl -i -H "Authorization: Basic YnVzaW5lc3NDbGllbnQ6M1dGTHVkVEZ5Qms=" -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 'grant_type=client_credentials&scope=Business.Info'

2. The OAuth Server checks the client credentials, the grant type and if it is authorized to request the scope.

Note that in Part I of this post, the BusinessClient was defined to request tokens using “Client Credentials” grant type and authorized to request “Business.Info” scopes only.

If a client tries to request tokens using a grant type or a scope it is not authorized to, it will receive an error.

 

3. The OAuth Server also checks if the user has granted permission to the client to request a token in its behalf.

In the B2B use case, there is no user intervention, this client is already allowed to request tokens without representing an end user identity. Remember that in Part I, in the BusinessClient configuration, “Bypass User Consent” is checked.

 

4. OAuth Server returns the Access Token for the BusinessClient.

The OAuth Server response for an Access Token request would look like this:

{"expires_in":3600,"token_type":"Bearer","access_token":"eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJzdWIiOiJidXNpbmVzc0NsaWVudCIsImlzcyI6Ind3dy5vcmFjbGUuZXhhbXBsZS5jb20iLCJvcmFjbGUub2F1dGguc3ZjX3BfbiI6Ik9BdXRoU2VydmljZVByb2ZpbGUiLCJpYXQiOjE0MzY0NzUwODgwMDAsIm9yYWNsZS5vYXV0aC5wcm4uaWRfdHlwZSI6IkNsaWVudElEIiwiZXhwIjoxNDM2NDc4Njg4MDAwLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6InJlc291cmNlX2FjY2Vzc190ayIsInBybiI6ImJ1c2luZXNzQ2xpZW50IiwianRpIjoiNjQwNzEwOTQtOGQyNS00Y2I3LWI5NmMtNDQxZDJmNDI2MjJkIiwib3JhY2xlLm9hdXRoLmNsaWVudF9vcmlnaW5faWQiOiJidXNpbmVzc0NsaWVudCIsIm9yYWNsZS5vYXV0aC5zY29wZSI6IkJ1c2luZXNzLkluZm8iLCJ1c2VyLnRlbmFudC5uYW1lIjoiRGVmYXVsdERvbWFpbiIsIm9yYWNsZS5vYXV0aC5pZF9kX2lkIjoiMTIzNDU2NzgtMTIzNC0xMjM0LTEyMzQtMTIzNDU2Nzg5MDEyIn0.GXcQ3sjFyxcwO85x50zRfZCXf-YEUgFerudOoRVky5a334p3GmlKl147OarZs-h0uGl5okrp0Ivfx7ed2Y7jR0nbTTye6TxiSgCyHrJXjp5_blwRH6hj05KI6RxWdzJJqeC95Kgfh-m2FOqbffQOC1XhHvoWQ8KkG9ub5ZgmhPo"}

This token is not associated with a end-user, it contains the OAuth client application information only.

We will see the difference between this kind of token and the token from a 3-legged OAuth flow.

When decoded, the following revelant information can be extracted from the token:

{
"sub": "businessClient",
"iss": "www.oracle.example.com",
"oracle.oauth.svc_p_n": "OAuthServiceProfile",
"iat": 1436475088000,
"oracle.oauth.prn.id_type": "ClientID",
"exp": 1436478688000,
"oracle.oauth.tk_context": "resource_access_tk",
"prn": "businessClient",
"jti": "64071094-8d25-4cb7-b96c-441d2f42622d",
"oracle.oauth.client_origin_id": "businessClient",
"oracle.oauth.scope": "Business.Info",
"user.tenant.name": "DefaultDomain",
"oracle.oauth.id_d_id": "12345678-1234-1234-1234-123456789012"
}

 

5. Now, with the Access Token, the BusinessClient makes a remote call to the ResourceServer passing the token in the POST parameters.

 

6. The ResourceServer receives the token and makes a call to the OAuth Server to validate the token.

The OAuth server will assert if the token has not expired, has not been tampered with, if it has not been revoked and if the scope is valid.

To make this call, the Resource Server must also be registered as an OAuth client, the Service Token Validator, explained in Part I of this post.

Note below that this client has no scopes or is allowed any grants, it is only used to validate tokens.

The validation can be a simple one or can be a token instrospection, which retrives additional attributes.

Validation calls would look like this:

Simple Validation request:

curl -i -H 'Authorization: Basic YnVzaW5lc3NDbGllbnQ6M1dGTHVkVEZ5Qms=' --request POST http://oxygen.mycompany.com:14100/ms_oauth/oauth2/endpoints/oauthservice/tokens -d 'grant_type=oracle-idm%3A%2Foauth%2Fgrant-type%2Fresource-access-token%2Fjwt&oracle_token_action=validate&scope=UserProfile.me&assertion=eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJzdWIiOiJidXNpbmVzc0NsaWVudCIsImlzcyI6Ind3dy5vcmFjbGUuZXhhbXBsZS5jb20iLCJvcmFjbGUub2F1dGguc3ZjX3BfbiI6Ik9BdXRoU2VydmljZVByb2ZpbGUiLCJpYXQiOjE0MzA4MjczMzAwMDAsIm9yYWNsZS5vYXV0aC5wcm4uaWRfdHlwZSI6IkNsaWVudElEIiwiZXhwIjoxNDMwODMwOTMwMDAwLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6InJlc291cmNlX2FjY2Vzc190ayIsInBybiI6ImJ1c2luZXNzQ2xpZW50IiwianRpIjoiNzBiZTRjOTItZWNmNi00YWM0LWEzOGEtZjUyMzUwMzUzNDJjIiwib3JhY2xlLm9hdXRoLmNsaWVudF9vcmlnaW5faWQiOiJidXNpbmVzc0NsaWVudCIsIm9yYWNsZS5vYXV0aC5zY29wZSI6IlVzZXJQcm9maWxlLm1lIiwidXNlci50ZW5hbnQubmFtZSI6IkRlZmF1bHREb21haW4iLCJvcmFjbGUub2F1dGguaWRfZF9pZCI6IjEyMzQ1Njc4LTEyMzQtMTIzNC0xMjM0LTEyMzQ1Njc4OTAxMiJ9.omYuR3KOsg5QbzYSq98aqtBUb37mpEeSKu-8U5-RVfZ16XceFcDRiDZ8upJcVoRyolpl52RFqjBdIDKRJQK6C21ZBkVhHKUvSyrJCD1AVATihq8Xm2mr0zZuRg6iqbalZEXfuIKd8hU4Q863aMwmo-W9j2Ep63ebTeXpHPkkWcI'

Token Introspection request:

curl -i -H 'Authorization: Basic YnVzaW5lc3NDbGllbnQ6M1dGTHVkVEZ5Qms=' --request POST http://oxygen.mycompany.com:14100/ms_oauth/oauth2/endpoints/oauthservice/tokens -d 'grant_type=oracle-idm%3A%2Foauth%2Fgrant-type%2Fresource-access-token%2Fjwt&oracle_token_action=validate&scope=UserProfile.me&oracle_token_attrs_retrieval=iss%20aud%20exp%20prn%20jti%20exp%20iat%20oracle.oauth.scope%20oracle.oauth.client_origin_id%20oracle.oauth.user_origin_id%20oracle.oauth.user_origin_id_type%20oracle.oauth.tk_context%20oracle.oauth.id_d_id%20oracle.oauth.svc_p_n&assertion=eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCIsImtpZCI6Im9yYWtleSJ9.eyJzdWIiOiJidXNpbmVzc0NsaWVudCIsImlzcyI6Ind3dy5vcmFjbGUuZXhhbXBsZS5jb20iLCJvcmFjbGUub2F1dGguc3ZjX3BfbiI6Ik9BdXRoU2VydmljZVByb2ZpbGUiLCJpYXQiOjE0MzA4MjczMzAwMDAsIm9yYWNsZS5vYXV0aC5wcm4uaWRfdHlwZSI6IkNsaWVudElEIiwiZXhwIjoxNDMwODMwOTMwMDAwLCJvcmFjbGUub2F1dGgudGtfY29udGV4dCI6InJlc291cmNlX2FjY2Vzc190ayIsInBybiI6ImJ1c2luZXNzQ2xpZW50IiwianRpIjoiNzBiZTRjOTItZWNmNi00YWM0LWEzOGEtZjUyMzUwMzUzNDJjIiwib3JhY2xlLm9hdXRoLmNsaWVudF9vcmlnaW5faWQiOiJidXNpbmVzc0NsaWVudCIsIm9yYWNsZS5vYXV0aC5zY29wZSI6IlVzZXJQcm9maWxlLm1lIiwidXNlci50ZW5hbnQubmFtZSI6IkRlZmF1bHREb21haW4iLCJvcmFjbGUub2F1dGguaWRfZF9pZCI6IjEyMzQ1Njc4LTEyMzQtMTIzNC0xMjM0LTEyMzQ1Njc4OTAxMiJ9.omYuR3KOsg5QbzYSq98aqtBUb37mpEeSKu-8U5-RVfZ16XceFcDRiDZ8upJcVoRyolpl52RFqjBdIDKRJQK6C21ZBkVhHKUvSyrJCD1AVATihq8Xm2mr0zZuRg6iqbalZEXfuIKd8hU4Q863aMwmo-W9j2Ep63ebTeXpHPkkWcI'

 

7. The OAuth server responds with the results of the token validation, that would look like this:

The simple validation response:

{"successful":true}

The Token introspection response:

{"successful":true,"oracle_token_attrs_retrieval":{"oracle.oauth.tk_context":"resource_access_tk","exp":1430830930000,"iss":"www.oracle.example.com","prn":"businessClient","oracle.oauth.client_origin_id":"businessClient","oracle.oauth.scope":"UserProfile.me","jti":"70be4c92-ecf6-4ac4-a38a-f5235035342c","oracle.oauth.svc_p_n":"OAuthServiceProfile","iat":1430827330000,"oracle.oauth.id_d_id":"12345678-1234-1234-1234-123456789012"}}

Note that the token for a B2B use case represents just the identity of the OAuth client (“prn”:”businessClient” and “oracle.oauth.client_origin.id”:”businessClient”), it does not contain any reference to an end user because the BusinessClient is pre-authorized and haven’t gone through a user authentication or user consent.

 

8. The resource server is responsible for the implementation of the authorization logic itself, therefore it is up to the ResourceServer to make the decision if the scope for which the token was issued is valid or any other reason it might consider to give access for the requesting application.

If all checks are satisfied, the ResourceServer returns the requested data back to the client.

 

B2B Use Case Implementation

To implement the B2B use case, a standard Java Servlet will be used, BusinessClient.java, so that the use case can be triggered at will.

In a real world situation, it could well be any piece of code running on the server in a scheduled timer, without user intervention.

This servlet, will obtain an Access Token from the OAuth Server, using the Client Credentials grant type, and will pass the Access Token to the Resource Server, when making the call to the Business RESTful endpoint.

The Resource Service will be implemented in a annotated plain Java class using the Jersey framework to expose the Business 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 RESTful WS implementation, BusinessService.java is completely independent from the OAuth implementation.

In a real world case, it might be a good practice to implement Filters, or any other way to intercept the incoming request, and validate the token or other decisions, like scope, before passing the request along to the endpoint.

The complete source code will be provided in the Part VI of this post.

The relevant classes for this use case are:

  • BusinessClient.java
  • OAuthTokenValidationFilter.java
  • OAuthTokenValidator.java
  • BusinessService.java

In the next post we will cover the Customer to Business Use case, when the client application runs on the application server.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha