package com.bluevia.commons.connector.http.oauth; import java.io.ByteArrayInputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.apache.log4j.Logger; import oauth.signpost.OAuth; import oauth.signpost.OAuthConsumer; import oauth.signpost.OAuthProvider; import oauth.signpost.OAuthProviderListener; import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; import oauth.signpost.exception.OAuthCommunicationException; import oauth.signpost.exception.OAuthExpectationFailedException; import oauth.signpost.exception.OAuthMessageSignerException; import oauth.signpost.exception.OAuthNotAuthorizedException; import oauth.signpost.http.HttpParameters; import com.bluevia.commons.Utils; import com.bluevia.commons.connector.http.HttpConnector; import com.bluevia.commons.connector.http.HttpException; import com.bluevia.commons.exception.BlueviaException; /** * Implementation of HttpConnector to sign requests using OAuth * */ public class OauthHttpConnector extends HttpConnector implements IOAuth { private static Logger log = Logger.getLogger(OauthHttpConnector.class.getName()); protected OAuthConsumer mConsumer; protected OAuthProvider mProvider; /** * OAuthHttpConnector constructor * Creates an OauthHttpConnector 1.0a and instantiates the OauthConsumer and OauthProvider with the * information supplied * * @param consumer the consumer data * @param accessToken the access token * @param authorizationWebsiteUrl */ public OauthHttpConnector(OAuthToken consumer, OAuthToken accessToken){ mConsumer = new CommonsHttpOAuthConsumer(consumer.getToken(), consumer.getSecret()); mConsumer.setTokenWithSecret(accessToken.getToken(), accessToken.getSecret()); } /** * OAuthHttpConnector constructor, 2-legged mode * Creates an OauthHttpConnector 1.0a and instantiates the OauthConsumer and OauthProvider with the * information supplied * * @param consumer the consumer data * @param accessToken the access token * @param authorizationWebsiteUrl */ public OauthHttpConnector(OAuthToken consumer){ mConsumer = new CommonsHttpOAuthConsumer(consumer.getToken(), consumer.getSecret()); } /** * OAuthHttpConnector constructor, 2-legged mode * Creates an OauthHttpConnector 1.0a and instantiates the OauthConsumer and OauthProvider with the * information supplied * * @param consumer the consumer data * @param accessToken the access token * @param requestTokenEndpointUrl * @param accessTokenEndpointUrl * @param authorizationWebsiteUrl */ public OauthHttpConnector(OAuthToken consumer, String requestTokenEndpointUrl, String accessTokenEndpointUrl, String authorizationWebsiteUrl){ mConsumer = new CommonsHttpOAuthConsumer(consumer.getToken(), consumer.getSecret()); mConsumer.setSigningStrategy(new BVAuthorizationHeaderSigningStrategy()); mProvider = new BVCommonsHttpOauthProvider(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl); mProvider.setOAuth10a(true); } /** * OAuthHttpConnector constructor * Creates an OauthHttpConnector 1.0a and instantiates the OauthConsumer and OauthProvider with the * information supplied * * @param consumer the consumer data * @param accessToken the access token * @param cert the path to client certificate * @param certFilePass the password of client certificate * @param authorizationWebsiteUrl */ public OauthHttpConnector(OAuthToken consumer, OAuthToken accessToken, String cert, String certFilePass){ mKeyStorePath = cert; mKeyStorePass = certFilePass; mConsumer = new CommonsHttpOAuthConsumer(consumer.getToken(), consumer.getSecret()); mConsumer.setTokenWithSecret(accessToken.getToken(), accessToken.getSecret()); } /** * OAuthHttpConnector constructor, 2-legged mode * Creates an OauthHttpConnector 1.0a and instantiates the OauthConsumer and OauthProvider with the * information supplied * * @param consumer the consumer data * @param cert the path to client certificate * @param certFilePass the password of client certificate * @param authorizationWebsiteUrl */ public OauthHttpConnector(OAuthToken consumer, String cert, String certFilePass){ mKeyStorePath = cert; mKeyStorePass = certFilePass; mConsumer = new CommonsHttpOAuthConsumer(consumer.getToken(), consumer.getSecret()); } /** * OAuthHttpConnector constructor, 2-legged mode * Creates an OauthHttpConnector 1.0a and instantiates the OauthConsumer and OauthProvider with the * information supplied * * @param consumer the consumer data * @param requestTokenEndpointUrl * @param accessTokenEndpointUrl * @param authorizationWebsiteUrl * @param cert the path to client certificate * @param certFilePass the password of client certificate */ public OauthHttpConnector(OAuthToken consumer, String requestTokenEndpointUrl, String accessTokenEndpointUrl, String authorizationWebsiteUrl, String cert, String certFilePass){ mKeyStorePath = cert; mKeyStorePass = certFilePass; mConsumer = new CommonsHttpOAuthConsumer(consumer.getToken(), consumer.getSecret()); mConsumer.setSigningStrategy(new BVAuthorizationHeaderSigningStrategy()); mProvider = new BVCommonsHttpOauthProvider(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl); mProvider.setOAuth10a(true); } @Override public void authenticate() throws BlueviaException { try { mConsumer.sign(mRequest); } catch (OAuthMessageSignerException e) { log.error("Unable to sign request" + e.getMessage()); throw new BlueviaException("Unable to sign request", e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthExpectationFailedException e) { log.error("Unable to sign request" + e.getMessage()); throw new BlueviaException("Unable to sign request", e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthCommunicationException e) { log.error(e.getLocalizedMessage()); if (e.getResponseBody() != null){ log.error(e.getResponseBody()); ByteArrayInputStream bis = new ByteArrayInputStream(e.getResponseBody().getBytes()); throw new HttpException(HttpException.CONNECTION_ERROR, bis, null); } else throw new BlueviaException(e.getMessage(), e, BlueviaException.CONNECTION_ERROR); } } /** * Retrieves a request token. * * TODO * * HTTP body data is allowed. * @param callback the callback for the get request token. Available values are: * <ul> * <li>An url: if your app can receive callbacks and you want to get informed about the result of the authorization process</li> * <li>A phone number: if you want the user to receive the oauth verifier by sms</li> * <li>NULL: if your app cannot receive callbacks</li> * </ul> * @param data HTTP body data * @param listener * * @return OAuthToken {@link OAuthToken} * @throws BlueviaException */ public RequestToken getRequestToken(String callback, byte[] data, OAuthProviderListener listener) throws BlueviaException { validate(); mProvider.setListener(listener); ((BVCommonsHttpOauthProvider)mProvider).setData(data); try { String url = null; if(!Utils.isEmpty(callback)) url = mProvider.retrieveRequestToken(mConsumer, callback); else url = mProvider.retrieveRequestToken(mConsumer, OAuth.OUT_OF_BAND); RequestToken result = new RequestToken(mConsumer.getToken(), mConsumer.getTokenSecret(), url); return result; } catch (OAuthMessageSignerException e) { log.error("Unable to sign request" + e.getMessage()); throw new BlueviaException("Unable to sign request", e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthNotAuthorizedException e) { log.error(e.getLocalizedMessage()); if (e.getResponseBody() != null){ log.error(e.getResponseBody()); ByteArrayInputStream bis = new ByteArrayInputStream(e.getResponseBody().getBytes()); throw new HttpException(HttpException.UNAUTHORIZED, bis, null); } else throw new BlueviaException(e.getMessage(), e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthExpectationFailedException e) { log.error("Unable to sign request" + e.getMessage()); throw new BlueviaException("Unable to sign request", e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthCommunicationException e) { log.error(e.getLocalizedMessage()); if (e.getResponseBody() != null){ log.error(e.getResponseBody()); ByteArrayInputStream bis = new ByteArrayInputStream(e.getResponseBody().getBytes()); throw new HttpException(HttpException.CONNECTION_ERROR, bis, null); } else throw new BlueviaException(e.getMessage(), e, BlueviaException.CONNECTION_ERROR); } } /** * Retrieves the access token corresponding to request token parameter * * @param requestToken the request token received previously * @param oauthVerifier the OAuth verifier for the token * @return the access token * @throws BlueviaException */ public OAuthToken getAccessToken(OAuthToken requestToken, String oauthVerifier) throws BlueviaException { if (requestToken == null || !requestToken.isValid()) throw new BlueviaException("Bad request: RequestToken cannot be null nor empty", BlueviaException.BAD_REQUEST_EXCEPTION); if (Utils.isEmpty(oauthVerifier)) throw new BlueviaException("Bad request: OAuthVerifier cannot be null nor empty", BlueviaException.BAD_REQUEST_EXCEPTION); validate(); ((BVCommonsHttpOauthProvider)mProvider).setData(null); mConsumer.setTokenWithSecret(requestToken.getToken(), requestToken.getSecret()); mProvider.setOAuth10a(true); try { mProvider.retrieveAccessToken(mConsumer, oauthVerifier); } catch (OAuthMessageSignerException e) { log.error("Unable to sign request" + e.getMessage()); throw new BlueviaException("Unable to sign request", e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthNotAuthorizedException e) { log.error(e.getLocalizedMessage()); if (e.getResponseBody() != null){ log.error(e.getResponseBody()); ByteArrayInputStream bis = new ByteArrayInputStream(e.getResponseBody().getBytes()); throw new HttpException(HttpException.UNAUTHORIZED, bis, null); } else throw new BlueviaException(e.getMessage(), e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthExpectationFailedException e) { log.error("Unable to sign request" + e.getMessage()); throw new BlueviaException("Unable to sign request", e, BlueviaException.INTERNAL_CLIENT_ERROR); } catch (OAuthCommunicationException e) { log.error(e.getLocalizedMessage()); if (e.getResponseBody() != null){ log.error(e.getResponseBody()); ByteArrayInputStream bis = new ByteArrayInputStream(e.getResponseBody().getBytes()); throw new HttpException(HttpException.CONNECTION_ERROR, bis, null); } else throw new BlueviaException(e.getMessage(), e, BlueviaException.CONNECTION_ERROR); } return new OAuthToken(mConsumer.getToken(), mConsumer.getTokenSecret()); } @Override public OAuthToken getOauthToken() { if (mConsumer == null) return null; if (Utils.isEmpty(mConsumer.getToken()) || Utils.isEmpty(mConsumer.getTokenSecret())) return null; return new OAuthToken(mConsumer.getToken(), mConsumer.getTokenSecret()); } @Override public void setOauthToken(OAuthToken token) { if (mConsumer != null && token != null) mConsumer.setTokenWithSecret(token.getToken(), token.getSecret()); } @Override public void setAdditionalParameters(HashMap<String, String> params) { HttpParameters oauthParameters = new HttpParameters(); Iterator<Entry<String, String>> it = params.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> pairs = (Map.Entry<String, String>)it.next(); oauthParameters.put(pairs.getKey(), pairs.getValue()); it.remove(); } mConsumer.setAdditionalParameters(oauthParameters); } /** * Validates the correct instantiation of the client attributes. * */ protected void validate() throws BlueviaException { if (mConsumer == null || mProvider == null || !(mProvider instanceof BVCommonsHttpOauthProvider)) throw new IllegalStateException("Client is not correctly instantiated. This should not happen"); } }