com.ibm.sbt.security.authentication.oauth.consumer.HMACOAuth1Handler.java Source code

Java tutorial

Introduction

Here is the source code for com.ibm.sbt.security.authentication.oauth.consumer.HMACOAuth1Handler.java

Source

/****************************************************************************************
 * Copyright 2013 IBM Corp.                                                                   *
 *                                                                                      *
 * Licensed under the Apache License, Version 2.0 (the "License");                      *
 * you may not use this file except in compliance with the License.                     *
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0   *
 *                                                                                      *
 * Unless required by applicable law or agreed to in writing, software                  *
 * distributed under the License is distributed on an "AS IS" BASIS,                    *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.             *
 * See the License for the specific language governing permissions and                  *
 * limitations under the License.                                                       *
 ****************************************************************************************/

package com.ibm.sbt.security.authentication.oauth.consumer;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import com.ibm.commons.runtime.Context;
import com.ibm.commons.util.StringUtil;
import com.ibm.commons.util.io.StreamUtil;
import com.ibm.sbt.core.configuration.Configuration;
import com.ibm.sbt.security.authentication.oauth.OAuthException;
import com.ibm.sbt.security.encryption.HMACEncryptionUtility;
import com.ibm.sbt.services.util.SSLUtil;

/**
 * HMAC OAuth1 Handler
 * 
 * @author Vimal Dhupar
 * @author Manish Kataria
 */

public class HMACOAuth1Handler extends OAuth1Handler implements Serializable {

    protected String applicationAccessToken;

    public HMACOAuth1Handler() {
    }

    public HMACOAuth1Handler(String consumerKey, String consumerSecret, String credentialStore, String appId,
            String serviceName, String requestTokenURL, String authorizationURL, String accessTokenURL,
            String signatureMethod, boolean forceTrustSSLCertificate, String applicationAccessToken) {
        this.consumerKey = consumerKey;
        this.consumerSecret = consumerSecret;
        this.credentialStore = credentialStore;
        this.appId = appId;
        this.serviceName = serviceName;
        this.requestTokenURL = requestTokenURL;
        this.authorizationURL = authorizationURL;
        this.accessTokenURL = accessTokenURL;
        this.signatureMethod = signatureMethod;
        this.forceTrustSSLCertificate = forceTrustSSLCertificate;
        this.applicationAccessToken = applicationAccessToken;
    }

    private static final long serialVersionUID = 1L;

    public String getApplicationAccessToken() {
        return applicationAccessToken;
    }

    public void setApplicationAccessToken(String applicationAccessToken) {
        this.applicationAccessToken = applicationAccessToken;
    }

    /*
     * (non-Javadoc)
     * @see com.ibm.sbt.security.authentication.oauth.consumer.OAuth1Handler#getRequestTokenFromServer()
     */
    @Override
    public void getRequestTokenFromServer() throws OAuthException {

        int responseCode = HttpStatus.SC_OK;
        Context context = Context.get();
        String responseBody = "";
        try {
            HttpClient client = new DefaultHttpClient();
            if (getForceTrustSSLCertificate()) {
                client = SSLUtil.wrapHttpClient((DefaultHttpClient) client);
            }

            // In case of Twitter, this callback URL registered can be different from the URL specified below.
            String callbackUrl = getCallbackUrl(context);
            String consumerKey = getConsumerKey();
            String nonce = getNonce();
            String timeStamp = getTimestamp();

            // HMAC requires parameter to be alphabetically sorted, using LinkedHashMap below to preserve
            // ordering
            LinkedHashMap<String, String> signatureParamsMap = new LinkedHashMap<String, String>();
            signatureParamsMap.put(Configuration.CALLBACK, callbackUrl);
            signatureParamsMap.put(Configuration.CONSUMER_KEY, consumerKey);
            signatureParamsMap.put(Configuration.NONCE, nonce);
            signatureParamsMap.put(Configuration.SIGNATURE_METHOD, getSignatureMethod());
            signatureParamsMap.put(Configuration.TIMESTAMP, timeStamp);
            signatureParamsMap.put(Configuration.VERSION, Configuration.OAUTH_VERSION1);

            String consumerSecret = getConsumerSecret();
            String requestPostUrl = getRequestTokenURL();
            HttpPost method = new HttpPost(requestPostUrl);
            String signature = HMACEncryptionUtility.generateHMACSignature(requestPostUrl, method.getMethod(),
                    consumerSecret, "", signatureParamsMap);

            StringBuilder headerStr = new StringBuilder();
            headerStr.append("OAuth ").append(Configuration.CALLBACK).append("=\"").append(callbackUrl)
                    .append("\"");
            headerStr.append(",").append(Configuration.CONSUMER_KEY).append("=\"").append(consumerKey).append("\"");
            headerStr.append(",").append(Configuration.SIGNATURE_METHOD).append("=\"").append(getSignatureMethod())
                    .append("\"");
            headerStr.append(",").append(Configuration.TIMESTAMP).append("=\"").append(timeStamp).append("\"");
            headerStr.append(",").append(Configuration.NONCE).append("=\"").append(nonce).append("\"");
            headerStr.append(",").append(Configuration.VERSION).append("=\"").append(Configuration.OAUTH_VERSION1)
                    .append("\"");
            headerStr.append(",").append(Configuration.SIGNATURE).append("=\"")
                    .append(URLEncoder.encode(signature, "UTF-8")).append("\"");
            method.setHeader("Authorization", headerStr.toString());

            HttpResponse httpResponse = client.execute(method);
            responseCode = httpResponse.getStatusLine().getStatusCode();
            InputStream content = httpResponse.getEntity().getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(content));
            try {
                responseBody = StreamUtil.readString(reader);
            } finally {
                StreamUtil.close(reader);
            }

        } catch (Exception e) {
            throw new OAuthException(e, "Internal error - getRequestToken failed Exception: ");
        }
        if (responseCode != HttpStatus.SC_OK) {
            String exceptionDetail = buildErrorMessage(responseCode, responseBody);
            if (StringUtil.isNotEmpty(exceptionDetail)) {
                throw new OAuthException(null,
                        "HMACOAuth1Handler.java : getRequestTokenFromServer failed." + exceptionDetail);
            }
        } else {
            /*
             * The Response from Twitter contains OAuth request token, OAuth request token secret, and a
             * boolean oauth_callback_confirmed with value set as true or false.
             */
            setRequestToken(getTokenValue(responseBody, Configuration.OAUTH_TOKEN));
            setRequestTokenSecret(getTokenValue(responseBody, Configuration.OAUTH_TOKEN_SECRET));
            /*
             * OAUTH_CALLBACK_CONFIRMED : This property can be used for debugging applications which have not
             * provided the Callback URL while registering the Application. If OAUTH_CALLBACK_CONFIRMED is
             * returned as false, then the application needs to be modified to set a callback url. However,
             * when the Application has specified the Callback Url, and is different from the callback Url we
             * are passing, this property value is returned as true.
             */
            setOAuthCallbackConfirmed(getTokenValue(responseBody, Configuration.OAUTH_CALLBACK_CONFIRMED));
        }

    }

    /*
     * (non-Javadoc)
     * @see com.ibm.sbt.security.authentication.oauth.consumer.OAuth1Handler#getAccessTokenFromServer()
     */
    @Override
    public void getAccessTokenFromServer() throws OAuthException {

        int responseCode = HttpStatus.SC_OK;
        String responseBody = null;
        try {
            HttpClient client = new DefaultHttpClient();
            if (getForceTrustSSLCertificate()) {
                client = SSLUtil.wrapHttpClient((DefaultHttpClient) client);
            }

            StringBuilder requestPostUrl = new StringBuilder(getAccessTokenURL());
            // adding the oauth_verifier to the request.
            requestPostUrl.append("?");
            requestPostUrl.append(Configuration.OAUTH_VERIFIER).append('=')
                    .append(URLEncoder.encode(verifierCode, "UTF-8"));
            HttpPost method = new HttpPost(requestPostUrl.toString());
            // Collecting parameters for preparing the Signature
            String consumerKey = getConsumerKey();
            String requestToken = getRequestToken();
            String nonce = getNonce();
            String timeStamp = getTimestamp();
            /*
             * Generate a map of parameters which are required for creating signature. We are using a Linked
             * HashMap to preserver the order in which parameters are added to the Map, as the parameters need
             * to be sorted for Twitter Signature generation.
             */
            LinkedHashMap<String, String> signatureParamsMap = new LinkedHashMap<String, String>();
            signatureParamsMap.put(Configuration.CONSUMER_KEY, consumerKey);
            signatureParamsMap.put(Configuration.NONCE, nonce);
            signatureParamsMap.put(Configuration.OAUTH_TOKEN, requestToken);
            signatureParamsMap.put(Configuration.SIGNATURE_METHOD, getSignatureMethod());
            signatureParamsMap.put(Configuration.TIMESTAMP, timeStamp);
            signatureParamsMap.put(Configuration.VERSION, Configuration.OAUTH_VERSION1);

            String requestTokenSecret = getRequestTokenSecret();
            String consumerSecret = getConsumerSecret();
            String signature = HMACEncryptionUtility.generateHMACSignature(requestPostUrl.toString(),
                    method.getMethod(), consumerSecret, requestTokenSecret, signatureParamsMap);

            // Preparing the Header for getting access token
            StringBuilder headerStr = new StringBuilder();

            headerStr.append("OAuth ").append(Configuration.CONSUMER_KEY).append("=\"").append(consumerKey)
                    .append("\"");
            headerStr.append(",").append(Configuration.SIGNATURE_METHOD).append("=\"").append(getSignatureMethod())
                    .append("\"");
            headerStr.append(",").append(Configuration.TIMESTAMP).append("=\"").append(timeStamp).append("\"");
            headerStr.append(",").append(Configuration.NONCE).append("=\"").append(nonce).append("\"");
            headerStr.append(",").append(Configuration.VERSION).append("=\"").append(Configuration.OAUTH_VERSION1)
                    .append("\"");
            // This is the request token which is obtained from getRequestTokenFromServer() method.
            headerStr.append(",").append(Configuration.OAUTH_TOKEN).append("=\"").append(requestToken).append("\"");
            headerStr.append(",").append(Configuration.SIGNATURE).append("=\"")
                    .append(URLEncoder.encode(signature, "UTF-8")).append("\"");
            method.setHeader("Authorization", headerStr.toString());

            method.setHeader("Authorization", headerStr.toString());

            HttpResponse httpResponse = client.execute(method);
            responseCode = httpResponse.getStatusLine().getStatusCode();
            InputStream content = httpResponse.getEntity().getContent();
            BufferedReader reader = new BufferedReader(new InputStreamReader(content));
            try {
                responseBody = StreamUtil.readString(reader);
            } finally {
                StreamUtil.close(reader);
            }

        } catch (Exception e) {
            throw new OAuthException(e, "Internal error - getAccessToken failed Exception: ");
        }
        if (responseCode != HttpStatus.SC_OK) {
            String exceptionDetail = buildErrorMessage(responseCode, responseBody);
            if (exceptionDetail != null) {
                throw new OAuthException(null,
                        "HMACOAuth1Handler.java : getAccessTokenFromServer failed. " + exceptionDetail);
            }
        } else {
            /*
             * Response from twitter contains Access Token, Access Token Secret, User Id and Screen Name of
             * the Application.
             */
            setAccessToken(getTokenValue(responseBody, Configuration.OAUTH_TOKEN));
            setAccessTokenSecret(getTokenValue(responseBody, Configuration.OAUTH_TOKEN_SECRET));
        }
    }

    /**
     * createAuthorizationHeader
     * 
     * @param url
     * @param params
     * @return
     */
    public String createAuthorizationHeader(String url, Map<String, String> params) throws OAuthException {

        String nonce = getNonce();
        String timeStamp = getTimestamp();
        String consumerKey = getConsumerKey();
        String consumerSecret = getConsumerSecret();
        String method = Context.get().getHttpRequest().getMethod();
        /*
         * This is the Access Token which is obtained from the Application, while registering the App. User
         * will have to create these tokens, in the application, if not generated already. This Access Token
         * if required for executing APIs on Twitter.
         */
        /* This is the Access Token Secret which is obtained from the getAccessTokenFromServer() method. */
        String tokenSecret = getAccessTokenSecret();
        /*
         * Generate a map of parameters which are required for creating signature. We are using a TreeMap here
         * instead of Linked HashMap, since the authorization header creates a signature using the parameters
         * passed by the User for API Execution. And all these parameters need to be sorted for Twitter
         * Signature generation.
         */
        TreeMap<String, String> treeMap = new TreeMap<String, String>();
        treeMap.put(Configuration.CONSUMER_KEY, consumerKey);
        treeMap.put(Configuration.NONCE, nonce);
        treeMap.put(Configuration.SIGNATURE_METHOD, getSignatureMethod());
        treeMap.put(Configuration.VERSION, Configuration.OAUTH_VERSION1);
        treeMap.put(Configuration.TIMESTAMP, timeStamp);
        treeMap.put(Configuration.OAUTH_TOKEN, applicationAccessToken);

        for (Map.Entry<String, String> entry : params.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            treeMap.put(key, value);
        }
        String signature = "";
        try {
            // generate the complete URL first
            signature = HMACEncryptionUtility.generateHMACSignature(url, method, consumerSecret, tokenSecret,
                    treeMap);
        } catch (Exception e) {
            throw new OAuthException(e, "createAuthorizationHeader failed with Exception");
        }

        StringBuilder headerStr = new StringBuilder();
        headerStr.append("OAuth ").append(Configuration.CONSUMER_KEY).append("=\"").append(consumerKey)
                .append("\"");
        headerStr.append(",").append(Configuration.NONCE).append("=\"").append(nonce).append("\"");
        try {
            headerStr.append(",").append(Configuration.SIGNATURE).append("=\"")
                    .append(URLEncoder.encode(signature, "UTF-8")).append("\"");
        } catch (UnsupportedEncodingException e1) {
            throw new OAuthException(e1, "createAuthorizationHeader failed with UnsupportedEncodingException");
        }
        headerStr.append(",").append(Configuration.SIGNATURE_METHOD).append("=\"").append(getSignatureMethod())
                .append("\"");
        headerStr.append(",").append(Configuration.TIMESTAMP).append("=\"").append(timeStamp).append("\"");
        headerStr.append(",").append(Configuration.OAUTH_TOKEN).append("=\"").append(applicationAccessToken)
                .append("\"");
        headerStr.append(",").append(Configuration.VERSION).append("=\"").append(Configuration.OAUTH_VERSION1)
                .append("\"");

        return headerStr.toString();
    }
}