org.sofun.core.security.oauth.OAuthSofunProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.sofun.core.security.oauth.OAuthSofunProvider.java

Source

/*
 * Copyright (c)  Sofun Gaming SAS.
 * Copyright (c)  Julien Anguenot <julien@anguenot.org>
 * Copyright (c)  Julien De Preaumont <juliendepreaumont@gmail.com>
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Julien Anguenot <julien@anguenot.org> - initial API and implementation
*/

package org.sofun.core.security.oauth;

import java.net.HttpURLConnection;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.resteasy.auth.oauth.OAuthConsumer;
import org.jboss.resteasy.auth.oauth.OAuthException;
import org.jboss.resteasy.auth.oauth.OAuthProvider;
import org.jboss.resteasy.auth.oauth.OAuthRequestToken;
import org.jboss.resteasy.auth.oauth.OAuthToken;
import org.sofun.core.CoreConstants;
import org.sofun.core.api.OAuthJPAStorage;

/**
 * OAUth provider implementation.
 * 
 * @author <a href="mailto:julien@anguenot.org">Julien Anguenot</a>
 * 
 */
public class OAuthSofunProvider implements OAuthProvider {

    private static Log log = LogFactory.getLog(OAuthSofunProvider.class);

    private final String realm;

    /**
     * Request tokens are only stored in memory. (Access tokens are stored using
     * JPA)
     */
    private final ConcurrentHashMap<String, OAuthRequestToken> requestTokens = new ConcurrentHashMap<String, OAuthRequestToken>();

    /**
     * Access tokens JPA storage.
     */
    private OAuthJPAStorage storage;

    public OAuthSofunProvider() {
        this("OAuth");
    }

    public OAuthSofunProvider(String realm) {
        this.realm = realm;
    }

    /**
     * Returns the OAuth token storage service.
     * 
     * @return a {@link OAuthJPAStorageImpl} instance.
     * @throws OAuthException
     */
    private OAuthJPAStorage getStorage() throws OAuthException {
        if (storage == null) {
            InitialContext ctx;
            try {
                ctx = new InitialContext();
                return (OAuthJPAStorage) ctx.lookup("sofun/OAUthJPAStorageImpl/local");
            } catch (NamingException e) {
                throw new OAuthException(500, e.getMessage());
            }
        }
        return storage;
    }

    private boolean _accessTokenExists(String key) {
        return _getAccessToken(key) != null;
    }

    private OAuthSofunAccessToken _getAccessToken(String key) {
        try {
            return getStorage().getAccessToken(key);
        } catch (OAuthException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    private OAuthSofunAccessToken doMakeAccessTokens(OAuthRequestToken requestToken) throws OAuthException {

        String newToken;
        do {
            newToken = makeRandomString();
        } while (_accessTokenExists(newToken));

        OAuthSofunConsumer consumer = getConsumer(requestToken.getConsumer().getKey());

        return getStorage().addAccessToken(newToken, makeRandomString(), getTokenExpirationFromNow(), consumer);

    }

    private OAuthSofunAccessToken doGetAccessToken(String consumerKey, String accessKey) throws OAuthException {
        // get is atomic
        OAuthSofunAccessToken ret = _getAccessToken(accessKey);
        if (ret == null) {
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "Token is invalid");
        }
        if (!ret.getConsumer().getKey().equals(consumerKey)) {
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "Consumer is invalid");
        }
        return ret;
    }

    private OAuthRequestToken doMakeRequestToken(String consumerKey, String callback, String[] scopes,
            String[] permissions) throws OAuthException {
        OAuthSofunConsumer consumer = _getConsumer(consumerKey);
        String newToken;
        do {
            newToken = makeRandomString();
        } while (requestTokens.containsKey(newToken));
        OAuthRequestToken token = new OAuthRequestToken(newToken, makeRandomString(), callback, scopes, permissions,
                -1, consumer);
        requestTokens.put(token.getToken(), token);
        return token;
    }

    private OAuthRequestToken doGetRequestToken(String customerKey, String requestKey) throws OAuthException {
        // get is atomic
        OAuthRequestToken ret = requestTokens.get(requestKey);
        checkCustomerKey(ret, customerKey);
        if (ret == null)
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "No such request key " + requestKey);
        return ret;
    }

    public OAuthRequestToken verifyAndRemoveRequestToken(String customerKey, String requestToken, String verifier)
            throws OAuthException {
        OAuthRequestToken request = getRequestToken(requestToken);
        checkCustomerKey(request, customerKey);

        // We don't need to check for verifier here because user can NEVER
        // interact with the application and therefore get a
        // oauth verification id. Only allowed applications with credentials and
        // allowed routing can interact directly with a
        // given instance of the the sofun platform. A user will always interact
        // with a Sofun platfrom through an application.

        /*
         * if (verifier == null || !verifier.equals(request.getVerifier()))
         * throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED,
         * "Invalid verifier code for token " + requestToken);
         */

        // then let's go through and exchange this for an access token
        return requestTokens.remove(requestToken);
    }

    private static String makeRandomString() {
        return UUID.randomUUID().toString();
    }

    private void checkCustomerKey(OAuthToken token, String customerKey) throws OAuthException {
        if (customerKey != null && !customerKey.equals(token.getConsumer().getKey())) {
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "Invalid customer key");
        }
    }

    //
    // For subclassers
    //

    protected void addConsumer(String consumerKey, String consumerSecret) {
        OAuthSofunConsumer consumer = new OAuthSofunConsumer(consumerKey, consumerSecret, null, null);
        try {
            getStorage().addConsumer(consumer);
        } catch (OAuthException e) {
            log.error(e.getMessage());
        }
    }

    protected void addRequestKey(String consumerKey, String requestToken, String requestSecret, String callback,
            String[] scopes) throws OAuthException {
        OAuthConsumer consumer = _getConsumer(consumerKey);
        OAuthRequestToken token = new OAuthRequestToken(requestToken, requestSecret, callback, scopes, null, -1,
                consumer);
        requestTokens.put(requestToken, token);
    }

    protected void addAccessKey(String consumerKey, String accessToken, String accessSecret, String[] permissions)
            throws OAuthException {
        OAuthSofunConsumer consumer = _getConsumer(consumerKey);
        OAuthSofunAccessToken token = new OAuthSofunAccessToken(accessToken, accessSecret, consumer.getScopes(),
                permissions, getTokenExpirationFromNow(), consumer);

        getStorage().addAccessToken(token);
    }

    protected void authoriseRequestToken(String consumerKey, String requestToken, String verifier)
            throws OAuthException {
        doGetRequestToken(consumerKey, requestToken).setVerifier(verifier);
    }

    protected OAuthSofunConsumer _getConsumer(String consumerKey) throws OAuthException {

        OAuthSofunConsumer ret = getStorage().getConsumer(consumerKey);

        if (ret == null)
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "No such consumer key " + consumerKey);
        return ret;
    }

    //
    // OAuthProvider interface

    @Override
    public String getRealm() {
        return realm;
    }

    @Override
    public String authoriseRequestToken(String consumerKey, String requestToken) throws OAuthException {
        String verifier = makeRandomString();
        doGetRequestToken(consumerKey, requestToken).setVerifier(verifier);
        return verifier;
    }

    @Override
    public OAuthConsumer registerConsumer(String consumerKey, String displayName, String connectURI)
            throws OAuthException {
        OAuthConsumer consumer = getConsumer(consumerKey);
        if (consumer == null) {
            return consumer;
        }
        consumer = new OAuthSofunConsumer(consumerKey, "therealfrog", displayName, connectURI);
        getStorage().addConsumer((OAuthSofunConsumer) consumer);
        return consumer;

    }

    @Override
    public OAuthSofunConsumer getConsumer(String consumerKey) throws OAuthException {
        return _getConsumer(consumerKey);
    }

    @Override
    public OAuthRequestToken getRequestToken(String consumerKey, String requestToken) throws OAuthException {
        OAuthRequestToken token = getRequestToken(requestToken);
        if (consumerKey != null && !token.getConsumer().getKey().equals(consumerKey)) {
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "No such consumer key " + consumerKey);
        }
        return token;
    }

    @Override
    public OAuthToken getAccessToken(String consumerKey, String accessToken) throws OAuthException {
        return doGetAccessToken(consumerKey, accessToken);
    }

    @Override
    public void checkTimestamp(OAuthToken token, long timestamp) throws OAuthException {
        if (token.getTimestamp() > timestamp)
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "Invalid timestamp " + timestamp);
    }

    @Override
    public OAuthToken makeAccessToken(String consumerKey, String requestToken, String verifier)
            throws OAuthException {
        OAuthRequestToken token = verifyAndRemoveRequestToken(consumerKey, requestToken, verifier);
        return doMakeAccessTokens(token);
    }

    @Override
    public OAuthRequestToken makeRequestToken(String consumerKey, String callback, String[] scopes,
            String[] permissions) throws OAuthException {
        OAuthRequestToken token = doMakeRequestToken(consumerKey, callback, scopes, permissions);
        requestTokens.put(token.getToken(), token);
        return token;
    }

    public OAuthRequestToken getRequestToken(String requestToken) throws OAuthException {
        OAuthRequestToken token = requestTokens.get(requestToken);
        if (token == null) {
            throw new OAuthException(HttpURLConnection.HTTP_UNAUTHORIZED, "No such request token " + requestToken);
        }
        return token;
    }

    @Override
    public void registerConsumerScopes(String consumerKey, String[] scopes) throws OAuthException {
        OAuthConsumer consumer = _getConsumer(consumerKey);
        consumer.setScopes(scopes);
    }

    @Override
    public void registerConsumerPermissions(String consumerKey, String[] permissions) throws OAuthException {
        // XXX register consumer permissions here. Done from the filter at the
        // moment
    }

    @Override
    public Set<String> convertPermissionsToRoles(String[] permissions) {
        // XXX convert permissons to roles here. Done from the filter at the
        // moment
        return null;
    }

    /**
     * Returns token expiration timestamp.
     * 
     * @return a timestamp in millisesonds
     */
    private long getTokenExpirationFromNow() {
        return CoreConstants.TOKEN_TIMEOUT * 1000;
    }

}