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.
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!
All content listed on this page is the property of Oracle Corp. Redistribution not allowed without written permission