org.apache.shindig.social.core.oauth.OAuthAuthenticationHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.shindig.social.core.oauth.OAuthAuthenticationHandler.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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 org.apache.shindig.social.core.oauth;

import com.google.inject.Inject;

import net.oauth.OAuth;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthException;
import net.oauth.OAuthMessage;
import net.oauth.OAuthValidator;
import net.oauth.SimpleOAuthValidator;
import net.oauth.OAuthProblemException;
import net.oauth.server.OAuthServlet;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shindig.auth.AuthenticationHandler;
import org.apache.shindig.auth.OAuthConstants;
import org.apache.shindig.auth.SecurityToken;
import org.apache.shindig.common.util.CharsetUtil;
import org.apache.shindig.social.opensocial.oauth.OAuthDataStore;
import org.apache.shindig.social.opensocial.oauth.OAuthEntry;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.Arrays;

import javax.servlet.http.HttpServletRequest;

/**
 * Handle both 2-legged consumer and full 3-legged OAuth requests.
 */
public class OAuthAuthenticationHandler implements AuthenticationHandler {

    public static final String REQUESTOR_ID_PARAM = "xoauth_requestor_id";

    private final OAuthDataStore store;

    @Inject
    public OAuthAuthenticationHandler(OAuthDataStore store) {
        this.store = store;
    }

    public String getName() {
        return "OAuth";
    }

    public String getWWWAuthenticateHeader(String realm) {
        return String.format("OAuth realm=\"%s\"", realm);
    }

    public SecurityToken getSecurityTokenFromRequest(HttpServletRequest request)
            throws InvalidAuthenticationException {
        OAuthMessage message = OAuthServlet.getMessage(request, null);
        if (StringUtils.isEmpty(getParameter(message, OAuth.OAUTH_SIGNATURE))) {
            // Is not an oauth request
            return null;
        }
        String bodyHash = getParameter(message, OAuthConstants.OAUTH_BODY_HASH);
        if (!StringUtils.isEmpty(bodyHash)) {
            verifyBodyHash(request, bodyHash);
        }
        try {
            return verifyMessage(message);
        } catch (OAuthProblemException oauthException) {
            throw new InvalidAuthenticationException("OAuth Authentication Failure", oauthException);
        }
    }

    protected SecurityToken verifyMessage(OAuthMessage message) throws OAuthProblemException {
        OAuthEntry entry = getOAuthEntry(message);
        OAuthConsumer authConsumer = getConsumer(message);

        OAuthAccessor accessor = new OAuthAccessor(authConsumer);

        if (entry != null) {
            accessor.tokenSecret = entry.getTokenSecret();
            accessor.accessToken = entry.getToken();
        }

        try {
            OAuthValidator validator = new SimpleOAuthValidator();
            validator.validateMessage(message, accessor);
        } catch (OAuthProblemException e) {
            throw e;
        } catch (OAuthException e) {
            OAuthProblemException ope = new OAuthProblemException(OAuth.Problems.SIGNATURE_INVALID);
            ope.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, e.getMessage());
            throw ope;
        } catch (IOException e) {
            OAuthProblemException ope = new OAuthProblemException(OAuth.Problems.SIGNATURE_INVALID);
            ope.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, e.getMessage());
            throw ope;
        } catch (URISyntaxException e) {
            OAuthProblemException ope = new OAuthProblemException(OAuth.Problems.SIGNATURE_INVALID);
            ope.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, e.getMessage());
            throw ope;
        }
        return getTokenFromVerifiedRequest(message, entry, authConsumer);
    }

    protected OAuthEntry getOAuthEntry(OAuthMessage message) throws OAuthProblemException {
        OAuthEntry entry = null;
        String token = getParameter(message, OAuth.OAUTH_TOKEN);
        if (!StringUtils.isEmpty(token)) {
            entry = store.getEntry(token);
            if (entry == null) {
                OAuthProblemException e = new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED);
                e.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, "cannot find token");
                throw e;
            } else if (entry.getType() != OAuthEntry.Type.ACCESS) {
                OAuthProblemException e = new OAuthProblemException(OAuth.Problems.TOKEN_REJECTED);
                e.setParameter(OAuth.Problems.OAUTH_PROBLEM_ADVICE, "token is not an access token");
                throw e;
            } else if (entry.isExpired()) {
                throw new OAuthProblemException(OAuth.Problems.TOKEN_EXPIRED);
            }
        }
        return entry;
    }

    protected OAuthConsumer getConsumer(OAuthMessage message) throws OAuthProblemException {
        String consumerKey = getParameter(message, OAuth.OAUTH_CONSUMER_KEY);
        OAuthConsumer authConsumer = store.getConsumer(consumerKey);
        if (authConsumer == null) {
            throw new OAuthProblemException(OAuth.Problems.CONSUMER_KEY_UNKNOWN);
        }
        return authConsumer;
    }

    protected SecurityToken getTokenFromVerifiedRequest(OAuthMessage message, OAuthEntry entry,
            OAuthConsumer authConsumer) throws OAuthProblemException {
        if (entry != null) {
            return new OAuthSecurityToken(entry.getUserId(), entry.getCallbackUrl(), entry.getAppId(),
                    entry.getDomain(), entry.getContainer(), entry.expiresAt().getTime());
        } else {
            String userId = getParameter(message, REQUESTOR_ID_PARAM);
            return store.getSecurityTokenForConsumerRequest(authConsumer.consumerKey, userId);
        }
    }

    public static byte[] readBody(HttpServletRequest request) throws IOException {
        if (request.getAttribute(AuthenticationHandler.STASHED_BODY) != null) {
            return (byte[]) request.getAttribute(AuthenticationHandler.STASHED_BODY);
        }
        byte[] rawBody = IOUtils.toByteArray(request.getInputStream());
        request.setAttribute(AuthenticationHandler.STASHED_BODY, rawBody);
        return rawBody;
    }

    public static String readBodyString(HttpServletRequest request) throws IOException {
        byte[] rawBody = readBody(request);
        return IOUtils.toString(new ByteArrayInputStream(rawBody), request.getCharacterEncoding());
    }

    public static void verifyBodyHash(HttpServletRequest request, String oauthBodyHash)
            throws InvalidAuthenticationException {
        // we are doing body hash signing which is not permitted for form-encoded data
        if (request.getContentType() != null && request.getContentType().contains(OAuth.FORM_ENCODED)) {
            throw new AuthenticationHandler.InvalidAuthenticationException(
                    "Cannot use oauth_body_hash with a Content-Type of application/x-www-form-urlencoded", null);
        } else {
            try {
                byte[] rawBody = readBody(request);
                byte[] received = Base64.decodeBase64(CharsetUtil.getUtf8Bytes(oauthBodyHash));
                byte[] expected = DigestUtils.sha(rawBody);
                if (!Arrays.equals(received, expected)) {
                    throw new AuthenticationHandler.InvalidAuthenticationException(
                            "oauth_body_hash failed verification", null);
                }
            } catch (IOException ioe) {
                throw new AuthenticationHandler.InvalidAuthenticationException(
                        "Unable to read content body for oauth_body_hash verification", null);
            }
        }
    }

    public static String getParameter(OAuthMessage requestMessage, String key) {
        try {
            return StringUtils.trim(requestMessage.getParameter(key));
        } catch (IOException e) {
            return null;
        }
    }
}