X

Best Practices from Oracle Development's A‑Team

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

Introduction

This post is part 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 previous posts explained how to configure OAM OAuth Server and how the different use-cases work.

This last post will discuss the Access Tokens and Refresh Tokens usage and Tokens Validation strategy on the Resource Server side.

Both topics are directly related to the client application design, security and overall system performance.

And last, but not least, source code will be provided so that it can be used as a starting point to understand the OAM's OAuth basic implementation.

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>

Access Token and Refresh Token Usage

In the examples provided in this post series, there is no Access Token reutilization or Refresh Token usage.

In a real application scenario, once the client application obtains the Access Token, it would probably make several calls using the same token, as long as it remains valid.

If the Access Token has expired -  and the client application should be able to check its validity before making a call - the client application can request another Access Token using the Refresh Token and its client credentials.

This way, the Client Application avoids making an additional call to the OAuth server every time it needs to call a service in the Resource Server.

In real world scenarios, it would really hurt the system performance, as under real load it is not practical to request a new token each time a call to the Resource Service is made.

There is also a security reason behind Refresh Tokens.

Because Access Tokens are short-lived (in contrast to long-lived Refresh Tokens), if they are compromised or the end user wishes to revoke the client application access, it can be done by revoking the Client Application Tokens (Access and Refresh tokens) and denying its access to all user resources.

This way, even if the application still has a valid Access Token or Refresh Token cached it cannot be used anymore to request access to resources or to request additional Access Tokens.

Remember, Refresh Tokens are obtained exchanging the client credentials with the Authorization Server, thus, by revoking the Client Application access (and all its tokens) the user can deny access to his resources at any time, without compromising security and other Client Applications access.

Token Validation

The token validation in the examples provided on this post rely on an additional call to the OAuth server.

This can degrade the OAuth server and Resource Service performance as these calls adds an additional chunk of time and processing to system when under load.

A good approach is to validate the token locally, using the OAuth server signing key to validate the signature and the Access Token payload.

By default, OAM uses the public certificate under the alias "oracert" to sign the OAuth tokens.

This certificate can be found in <DOMAIN_HOME>/config/fmwconfig/default-keystore.jks keystore.

To export the certificate run the following keytool command:

keytool -exportcert -alias "oracert" -keystore /u02/oracle/domains/OAMDomain/config/fmwconfig/default-keystore.jks -file oracert.der -storepass <STORE_PASS>

In a vanilla installation, the default-keystore password should be the same as OAM keystore password, which ca be found using the following WLST command:

listCred(map="OAM_STORE", key="jks")

There are lots of OAuth toolkits out there that can be used to validate tokens locally.

A simple code implementation using one of the available toolkits would look like this:

public boolean validateJWT(String token, String scope) {     boolean isValid = false;     try {         JWSObject jwsObject = JWSObject.parse(token);         JWSVerifier verifier = new RSASSAVerifier(getPublicKey("oracert.der"));         boolean isValid = jwsObject.verify(verifier);         if(isValid) {             String tk_payload = jwsObject.getPayload().toString();             JSONObject obj = new JSONObject(tk_payload);             String userID = obj.getString("prn");             String tokenScope = obj.getString("oracle.oauth.scope");             if(tokenScope != null && !tokenScope.contains(scope)){                 isValid = false;             }         }     } catch (Exception e) {         isValid = false;         e.printStackTrace();     }     return isValid; } private RSAPublicKey getPublicKey(String filename) throws Exception {     InputStream inStream = null;     try {         inStream = getClass().getClassLoader().getResourceAsStream("certs/"+filename);         CertificateFactory cf = CertificateFactory.getInstance("X.509");         X509Certificate cert = (X509Certificate)cf.generateCertificate(inStream);         return (RSAPublicKey)cert.getPublicKey();     } finally {         if (inStream != null) {             inStream.close();         }     } }

Source Code

The source code is provided "AS IS" with no express or implied warranty for accuracy or accessibility.

The code is indented to demonstrate the basic OAuth/OAM features and does not represent, by any means, the recommended approach or is intended to be used in development or productions environments.

That being said, download the source_code.

The examples are divided into two applications "ClientWebApp" and "ResourceService".

ClientWebApp contains the code for the client part, which will obtain a OAuth Token from OAM and make calls to the REST endpoints in the ResourceService application.

ResourceService will expose REST endpoints, which will receive calls from the ClientWebApp.

The ResourceService application will validate the OAuth Token and make a decision if to reply back with the requested data or not.

The source code is self explanatory and commented so one can follow up with the implementation.

Once the OAM configuration for the OAuth artifacts is done, as explained in Part I of this post series, one can adjust the URLs in the source code, compile, and deploy both applications to any servlet container, and test the complete scenario.

I hope the posts series could be of help to understand the basics of OAM's OAuth implementation, enjoy!

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