Showing posts with label OAuth. Show all posts
Showing posts with label OAuth. Show all posts

Saturday, 7 December 2013

Using JSON Web Token (JWT) to get OAuth 2.0 Access Token [Server-Server Interaction]


Use-Case

This blog explains about using the JWT [JSON Web Tokens] to request for Access Tokens from the Service Providers who support JWT.

I will showcase this scenario by using Google API


What is this JWT [JSON Web Tokens] .............?
JWTs represent a set of claims as a JSON object that is encoded in a JWS and/or JWE structure.
The JWT Structure is mainly composed of three parts they are Header.ClaimSet.Signature which are BASE64 Url Encoded.

For Further Information on JWT theory Refer the following Link : http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-13

Scenario

Create an Client ID by registering in the google apis console  and download the keystore file.
Ensure to save this securely as downloading this again will result in the generation of an new file.

Header Claim:
Since Google uses the RS256 Hashing Mechanism to encrypt the keystore, we are setting the alg to RS256 and the type is set as JWT [JSON web Tokens]

{"alg":"RS256","typ":"JWT"}


Claim Set :

{
"iss":" client_id of the application making the access token request@developer.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/userinfo.profile",
"aud":"https://accounts.google.com/o/oauth2/token",
"exp":1328554385,
"iat":1328550785
}
The scope given in the claim set basically gives the profile information of the client registered in the Google Apis console, but you can use the other Google developer Services  like Google Cloud Storage or the Google Prediction API etc.

The fields exp and iat are the expiration and issuance time on when the jwt was created
Here the exp and iat play an major role as giving an invalid/outdated values may result in the Authentication failure.

Creating the Signature :

Use the following java code to generate the signature

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.StringUtils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import java.security.GeneralSecurityException;
import java.security.PrivateKey;

public class BlogJavaCode {
public BlogJavaCode() {
        super();
    }
 
private  String headerClaim="{\"alg\":\"RS256\",\"typ\":\"JWT\"}"; //provide the above mentioned header claim
private  String claimSet="{\n" + 
"\"iss\":\" client_id of the application making the access token request@developer.gserviceaccount.com\",\n" + 
"\"scope\":\"https://www.googleapis.com/auth/userinfo.profile\",\n" + 
"\"aud\":\"https://accounts.google.com/o/oauth2/token\",\n" + 
"\"exp\":"+generateEXP()+",\n" + 
"\"iat\":"+generateIAT()+"\n" + 
"}";

    
private  long generateIAT()
{
    long currentTime = System.currentTimeMillis();
    long iat = (currentTime/1000);
    return iat; 
}

private   long generateEXP()
{
    long currentTime = System.currentTimeMillis();
    long exp = (currentTime/1000+3600);
    return exp;
}

/**
     * This Method constructs the JWT token 
     * @return jwt string
     */

public  String generateJWTToken()
{
    String encodedHeaderClaim =null;
    String encodedClaimset=null;
    String tempStr =null;  
    byte[] signature = null;
    String jwtToken= null;
        try {
            //Base64encoding of the Header Claim Set
            encodedHeaderClaim = base64encoding(headerClaim.getBytes("UTF-8"));
            //Base64encoding of the Claim Set
            encodedClaimset=base64encoding(claimSet.trim().getBytes("UTF-8"));
            //Temporary String needed to create the signature 
            tempStr = encodedHeaderClaim+"."+encodedClaimset;
            //Load the key from the keystore file
            PrivateKey serviceAccountPrivateKey = SecurityUtils.loadPrivateKeyFromKeyStore(SecurityUtils.getPkcs12KeyStore(),
                                                         new FileInputStream(""),
                                                         "notasecret", "privatekey", "notasecret");
            //Get the UTF-based bytes for the tempStr as it needs to be signed
            byte[] tempStrBytes = getbytesbasedforUtf8(tempStr);
            //Constructing the Signature
            signature =   SecurityUtils.sign(SecurityUtils.getSha256WithRsaSignatureAlgorithm(), serviceAccountPrivateKey, tempStrBytes);
            //The Final JWT String
            jwtToken = tempStr + "." + base64encoding(signature);
            
        } catch (UnsupportedEncodingException e) {
        } catch (FileNotFoundException e) {
        } catch (GeneralSecurityException | IOException e) {
        }
    return jwtToken;
    }

 

 public static String base64encoding(byte[] binaryData) {
        return Base64.encodeBase64URLSafeString(binaryData);
      }
    
  public static byte[] getbytesbasedforUtf8(String string) {
       return StringUtils.getBytesUtf8(string);
    }
}



Making the Request :

Open an URL Connection append the following parameter along with the signature and make the post call as shown below

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=<SignatureObtainedFromtheAboveMethod>.




Tuesday, 30 July 2013

Integrating Google Authentication in Oracle ADF Application


This blog explains about securing an ADF application using the Google Sign in Functionality which uses the OAuth 2.0 security framework

Prerequisites
package view;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Arrays;
public class MyGoogleHelperClass {

 
  private static final String CLIENT_ID = "YOUR CLIENT ID";
    private static final String CLIENT_SECRET = "YOUR CLIENT SECRET";
    private static final String CALLBACK_URI = "YOUR CALL BACK URI";
    private static final Iterable SCOPE = Arrays.asList("https://www.googleapis.com/auth/userinfo.profile;https://www.googleapis.com/auth/userinfo.email".split(";"));
    private static final String USER_INFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo";
    private static final JsonFactory JSON_FACTORY = new JacksonFactory();
    private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    private String stateToken;
    private final GoogleAuthorizationCodeFlow flow;
    
    public MyGoogleHelperClass() {
        super();
        flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT,
                        JSON_FACTORY, CLIENT_ID, CLIENT_SECRET, SCOPE).build();
        generateStateToken();
    }
    
    public String buildLoginUrl() {
            final GoogleAuthorizationCodeRequestUrl url = flow.newAuthorizationUrl();                   
            return url.setRedirectUri(CALLBACK_URI).setState(stateToken).build();
    }
    
    private void generateStateToken(){
            SecureRandom sr1 = new SecureRandom();
            stateToken = "google;"+sr1.nextInt();
    }
    public void setStateToken(String stateToken) {
        this.stateToken = stateToken;
    }

    public String getStateToken() {
        return stateToken;
    }
    public String getUserInfoJson(final String authCode) throws IOException {                           
            final GoogleTokenResponse response = flow.newTokenRequest(authCode).setRedirectUri(CALLBACK_URI).execute();
            final Credential credential = flow.createAndStoreCredential(response, null);
            final HttpRequestFactory requestFactory = HTTP_TRANSPORT.createRequestFactory(credential);
            // Make an authenticated request
            final GenericUrl url = new GenericUrl(USER_INFO_URL);
            final HttpRequest request = requestFactory.buildGetRequest(url);
            request.getHeaders().setContentType("application/json");
            final String jsonIdentity = request.execute().parseAsString(); 
            return jsonIdentity;

    }
}

Implementation Steps
1. Create a Fusion Application. In the Model create a WSDC of a WS which returns an complex employee Object
2. In the View Controller, create a jspx page i.e DCPage
3. Drag and Drop the Return type node of the method onto the page as ADF Table
4. Create another index.jspx page with a backing bean, then create a command menu button/link and then bind to the method in the backing Bean which contains code as shown below
public void verifytheUser(ActionEvent awt)
    {
     FacesContext context = FacesContext.getCurrentInstance();
     MyGoogleHelperClass ghc = new MyGoogleHelperClass();
     String urlPath     =        ghc.buildLoginUrl();       
try {
            context.getExternalContext().getSessionMap().put("StateToken",ghc.getStateToken());
           context.getExternalContext().redirect(urlPath);
        } catch (IOException e) {
        System.out.println(e);
        }
    }

5. Run the index.jspx page and click on the action button/link, we can see that the page is navigated to the Google Sign-In Page where the user is prompted to login with his credentials
6. If Login is successful, the user is asked to allow the application to access his resource, once accepted the page will be redirected back to the Callback URI
7. In the CallBack Page, get the following request parameters from the redirect uri. here we should check that the state which we sent while making the request matches with the state sent as query param along with the redirect uri. This Security is needed to avoid CSRF Hacking.
public void gettheUserdata()
{
FacesContext context = FacesContext.getCurrentInstance();
Map hm =   context.getExternalContext().getRequestParameterMap();
GoogleHelperClass ghc = new GoogleHelperClass();
// This needs to be verified to Avoid CSRF(Cross-Site Request Forgery)
String sentState = (String)context.getExternalContext().getSessionMap().get("StateToken ");
try {
if(hm.containsKey("code")&&(sentState.equalsIgnoreCase(hm.get("state"))))
{
String userInfo = ghc.getUserInfoJson((String)hm.get("code"));
context.getExternalContext().getSessionMap().put("USERNAME",extracttheName(userInfo));
context.getExternalContext().redirect("DC PAGE URL");            
} else{
context.getExternalContext().redirect("ACCESS DENIED URL");
}
}catch (IOException e) {

                    }
}


 public String extracttheName(String jsonStr)
    {
        String nmeoftheUser=null;
        try {
            JSONArray array = new JSONArray("["+jsonStr+"]");
            for (int i = 0; i < array.length(); i++) {
            JSONObject element = array.getJSONObject(0);
            NmeoftheUser = element.get("name");
            }      
        } catch (JSONException e) {
            System.out.println(e);
        }
        return nmeoftheUser;
    }
  • Code
  • State
8.  Use the Value set in the Session to display the name of the user on the page with the resource