org.infoscoop.request.OAuth2Authenticator.java Source code

Java tutorial

Introduction

Here is the source code for org.infoscoop.request.OAuth2Authenticator.java

Source

/* infoScoop OpenSource
 * Copyright (C) 2010 Beacon IT Inc.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * as published by the Free Software Foundation.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.  If not, see
 * <http://www.gnu.org/licenses/lgpl-3.0-standalone.html>.
 */

package org.infoscoop.request;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import net.oauth.OAuth;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthProblemException;
import net.oauth.OAuthServiceProvider;
import net.oauth.client.OAuthClient;
import net.oauth.client.httpclient3.HttpClient3;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.infoscoop.dao.OAuth2TokenDAO;
import org.infoscoop.dao.OAuthConsumerDAO;
import org.infoscoop.dao.model.OAuth2Token;
import org.infoscoop.dao.model.OAuthConsumerProp;
import org.infoscoop.service.OAuthService;
import org.infoscoop.util.RequestUtil;

public class OAuth2Authenticator implements Authenticator {
    public static final OAuthClient CLIENT = new OAuthClient(new HttpClient3());
    private static String AUTH_CALLBACK_URL2 = "oauth2callback";
    private static Log log = LogFactory.getLog(OAuth2Authenticator.class);
    private static Map<String, OAuthConsumer> consumers = new HashMap<String, OAuthConsumer>();

    public static OAuthConsumer getConsumer(String gadgetUrl, String serviceName) {
        return consumers.get(gadgetUrl + "\t" + serviceName);
    }

    public void doAuthentication(HttpClient client, ProxyRequest request, HttpMethod method, String uid, String pwd)
            throws ProxyAuthenticationException {
        ProxyRequest.OAuth2Config oauthConfig = request.getOauth2Config();
        try {
            OAuthConsumer consumer = newConsumer(oauthConfig.serviceName, oauthConfig, getCallbackURL(request));
            if (oauthConfig.accessToken == null) {
                returnApprovalUrl(request, consumer);
            }

            if (oauthConfig.validityPeriodUTC != null) {
                Calendar cal = Calendar.getInstance();
                cal.setTime(new Date());
                if (cal.getTimeInMillis() > oauthConfig.validityPeriodUTC) {
                    if (oauthConfig.refreshToken == null) {
                        OAuthService.getHandle().deleteOAuth2Token(request.getPortalUid(), oauthConfig.gadgetUrl,
                                oauthConfig.serviceName);
                        returnApprovalUrl(request, consumer);
                    } else {
                        log.error(
                                "AccessToken was expired, try re-get the token. [" + oauthConfig.serviceName + "]");
                        getAccessTokenByRefreshToken(request, consumer);
                        OAuth2Token token2 = OAuth2TokenDAO.newInstance().getAccessToken(request.getPortalUid(),
                                oauthConfig.gadgetUrl, oauthConfig.serviceName);
                        oauthConfig.setAccessToken(token2.getAccessToken());
                        oauthConfig.setRefreshToken(token2.getRefreshToken());
                        oauthConfig.setValidityPeriodUTC(token2.getValidityPeriodUTC());
                    }
                }
            }

            Map<String, String> parameters = null;
            String contentType = request.getRequestHeader("Content-Type");
            if (contentType != null && contentType.startsWith("application/x-www-form-urlencoded")
                    && method.getName().equals("POST")) {
                // TODO analyze charset
                String charset = RequestUtil.getCharset(contentType);
                parameters = RequestUtil.parseRequestBody(request.getRequestBody(), charset);
            }

            if ("Bearer".equalsIgnoreCase(oauthConfig.tokenType)) {
                method.addRequestHeader("Authorization", oauthConfig.tokenType + " " + oauthConfig.accessToken);
            } else {
                method.addRequestHeader("Authorization", "OAuth " + oauthConfig.accessToken);

                String queryString = method.getQueryString();
                queryString = "access_token=" + oauthConfig.accessToken + "&" + queryString;
                method.setQueryString(queryString);
            }
        } catch (URISyntaxException e) {
            throw new ProxyAuthenticationException(e);
        } catch (OAuthException e) {
            throw new ProxyAuthenticationException(e);
        } catch (IOException e) {
            throw new ProxyAuthenticationException(e);
        }
    }

    public int getCredentialType() {
        // TODO Auto-generated method stub
        return 3;
    }

    private void setOauthConfigAfterRefresh() {

    }

    protected OAuthConsumer newConsumer(String name, ProxyRequest.OAuth2Config oauthConfig, String callbackURL)
            throws ProxyAuthenticationException {
        OAuthServiceProvider serviceProvider = new OAuthServiceProvider(null, oauthConfig.userAuthorizationURL,
                oauthConfig.accessTokenURL);
        OAuthConsumerProp consumerProp = OAuthConsumerDAO.newInstance().getConsumer(oauthConfig.getGadgetUrl(),
                name);
        if (consumerProp == null)
            throw new ProxyAuthenticationException(
                    "Consumer key and secret is not set for " + oauthConfig.getGadgetUrl());

        String consumerKey = consumerProp.getConsumerKey();
        String consumerSecret = consumerProp.getConsumerSecret();
        OAuthConsumer consumer = new OAuthConsumer(callbackURL, consumerKey, consumerSecret, serviceProvider);
        consumer.setProperty("name", name);
        consumer.setProperty("request.scope", oauthConfig.scope);
        consumers.put(oauthConfig.getGadgetUrl() + "\t" + name, consumer);
        return consumer;
    }

    //approvalURL??
    private static void returnApprovalUrl(ProxyRequest request, OAuthConsumer consumer)
            throws OAuthException, IOException, URISyntaxException, ProxyAuthenticationException {
        final String consumerName = request.getOauth2Config().serviceName;
        final String callbackURL = getCallbackURL(request);
        Object scope = consumer.getProperty("request.scope");
        final OAuth2Message msg = new OAuth2Message();
        String gadgetUrl = request.getOauth2Config().getGadgetUrl();

        OAuthService.getHandle().saveOAuth2Token(request.getPortalUid(), gadgetUrl, consumerName, null, null, null,
                null, null);
        String authorizationURL = request.getOauth2Config().userAuthorizationURL;
        String state = msg.buildStateJSON(request, consumerName);
        authorizationURL = OAuth.addParameters(authorizationURL, "client_id", consumer.consumerKey, "redirect_uri",
                callbackURL, "response_type", "code", "state", state);
        if (scope != null) {
            authorizationURL = OAuth.addParameters(authorizationURL, "scope", scope.toString());
        }

        //for Google
        //If other server has some problem by follow parameter, thought corresponding.
        authorizationURL = OAuth.addParameters(authorizationURL, "access_type", "offline");
        authorizationURL = OAuth.addParameters(authorizationURL, "approval_prompt", "force");

        request.putResponseHeader("oauthApprovalUrl", authorizationURL);
        throw new ProxyAuthenticationException("Redirect to authorization url.", false);
    }

    private static String getCallbackURL(ProxyRequest request) throws IOException {
        String hostPrefix = request.getOauth2Config().getHostPrefix();
        URL base = new URL(hostPrefix + "/" + AUTH_CALLBACK_URL2);
        return base.toExternalForm();
    }

    private static void getAccessTokenByRefreshToken(ProxyRequest request, OAuthConsumer consumer)
            throws OAuthException, IOException {
        try {
            ProxyRequest proxy = new ProxyRequest(request.getOauth2Config().accessTokenURL, "NoOperation");
            OAuth2Message msg = new OAuth2Message();
            Map<String, String> params = new HashMap<String, String>();
            params.put("client_id", consumer.consumerKey);
            params.put("client_secret", consumer.consumerSecret);
            params.put("refresh_token", request.getOauth2Config().refreshToken);
            params.put("grant_type", "refresh_token");

            Object scope = consumer.getProperty("request.scope");
            if (scope != null) {
                params.put("scope", scope.toString());
            }
            String postData = msg.buildPostBody(params);
            proxy.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
            proxy.setReqeustBody(new ByteArrayInputStream(postData.getBytes("UTF-8")));
            proxy.executePost();

            final String responseBody = proxy.getResponseBodyAsString("UTF-8");
            final String contentType = proxy.getResponseHeader("Content-Type");
            Long validityPeriodUTC = null;
            if (contentType.startsWith("text/plain")) {
                //for facebook
                msg.parseQuery('?' + responseBody);
            } else if (contentType.startsWith("application/json")) {
                // for google
                msg.parseJSON(responseBody);
            }

            final String expiresIn = msg.getExpiresIn();
            if (expiresIn != null) {
                Long expires = Long.parseLong(expiresIn);
                Calendar cal = Calendar.getInstance();
                cal.setTime(new Date());
                validityPeriodUTC = cal.getTimeInMillis() + (expires * 1000L);
            }

            if (msg.getAccessToken() == null) {
                OAuthProblemException problem = new OAuthProblemException(OAuth.Problems.PARAMETER_ABSENT);
                problem.setParameter(OAuth.Problems.OAUTH_PARAMETERS_ABSENT, "access_token");
                throw problem;
            }

            String refreshToken = msg.getRefreshToken();
            if (refreshToken == null) {
                refreshToken = request.getOauth2Config().refreshToken;
            }

            OAuthService.getHandle().saveOAuth2Token(request.getPortalUid(),
                    request.getOauth2Config().getGadgetUrl(), request.getOauth2Config().serviceName,
                    msg.getTokenType(), request.getOauth2Config().code, msg.getAccessToken(), refreshToken,
                    validityPeriodUTC);
        } catch (Exception e) {
            OAuthService.getHandle().deleteOAuth2Token(request.getPortalUid(),
                    request.getOauth2Config().getGadgetUrl(), request.getOauth2Config().serviceName);
            log.error("unexpected error has occured.", e);
        }
    }
}