package com.eviware.soapui.impl.rest.actions.oauth; import com.eviware.soapui.SoapUI; import com.eviware.soapui.config.AccessTokenPositionConfig; import com.eviware.soapui.impl.rest.OAuth1Profile; import com.eviware.soapui.support.MessageSupport; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.TimeUtils; import com.google.api.client.auth.oauth.OAuthAuthorizeTemporaryTokenUrl; import com.google.api.client.auth.oauth.OAuthCallbackUrl; import com.google.api.client.auth.oauth.OAuthCredentialsResponse; import com.google.api.client.auth.oauth.OAuthGetAccessToken; import com.google.api.client.auth.oauth.OAuthGetTemporaryToken; import com.google.api.client.auth.oauth.OAuthHmacSigner; import com.google.api.client.auth.oauth.OAuthParameters; import com.google.api.client.auth.oauth.OAuthSigner; import com.google.api.client.http.GenericUrl; import com.google.api.client.http.apache.ApacheHttpTransport; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.utils.URIUtils; import org.apache.oltu.oauth2.common.OAuth; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.security.GeneralSecurityException; public class GoogleOAuth1ClientFacade implements OAuth1ClientFacade { private final static MessageSupport messages = MessageSupport.getMessages(GoogleOAuth1ClientFacade.class); private String tokenSecret; @Override public void requestAccessToken(OAuth1Profile profile) throws OAuth1Exception { try { OAuth1Parameters parameters = new OAuth1Parameters(profile); OAuthParameterValidator.validate(parameters); extractAccessToken(parameters); } catch (MalformedURLException | URISyntaxException e) { SoapUI.logError(e, messages.get("GoogleOAuth1ClientFacade.Error.WrongURL")); throw new OAuth1Exception(e); } } private void extractAccessToken(final OAuth1Parameters parameters) throws URISyntaxException, MalformedURLException, OAuth1Exception { tokenSecret = null; final UserBrowserFacade browserFacade = getBrowserFacade(); browserFacade.addBrowserListener(new BrowserListenerAdapter() { @Override public void locationChanged(String newLocation) { getAccessTokenAndSaveToProfile(browserFacade, parameters, extractVerifierFromForm(newLocation)); } @Override public void browserClosed() { super.browserClosed(); if (!parameters.isAccessTokenRetrievedFromServer()) { setRetrievedCanceledStatus(parameters); } tokenSecret = null; } }); parameters.waitingForAuthorization(); browserFacade.open(new URI(createAuthorizationURL(parameters)).toURL()); } private void setRetrievedCanceledStatus(OAuth1Parameters parameters) { parameters.retrievalCanceled(); } private OAuthCallbackUrl extractVerifierFromForm(String newLocation) { return StringUtils.hasContent(newLocation) ? new OAuthCallbackUrl(newLocation) : null; } private String createAuthorizationURL(OAuth1Parameters parameters) throws OAuth1Exception { OAuthGetTemporaryToken temporaryTokenGetter = new OAuthGetTemporaryToken(parameters.temporaryTokenUri) { @Override public OAuthParameters createParameters() { OAuthParameters result = super.createParameters(); result.version = "1.0"; return result; } }; temporaryTokenGetter.consumerKey = parameters.consumerKey; temporaryTokenGetter.signer = getSigner(parameters.consumerSecret, tokenSecret); temporaryTokenGetter.callback = parameters.redirectUri; temporaryTokenGetter.transport = new ApacheHttpTransport(); OAuthCredentialsResponse response = null; try { response = temporaryTokenGetter.execute(); } catch (IOException e) { throw new OAuth1Exception(e); } OAuthAuthorizeTemporaryTokenUrl authorizeUrl = new OAuthAuthorizeTemporaryTokenUrl(parameters.authorizationUri); authorizeUrl.temporaryToken = response.token; tokenSecret = response.tokenSecret; return authorizeUrl.build(); } private void getAccessTokenAndSaveToProfile(UserBrowserFacade browserFacade, OAuth1Parameters parameters, OAuthCallbackUrl callbackUrl) { if (callbackUrl != null && callbackUrl.token != null && callbackUrl.verifier != null) { try { parameters.receivedAuthorizationCode(); OAuthGetAccessToken accessTokenGetter = new OAuthGetAccessToken(parameters.accessTokenUri); accessTokenGetter.temporaryToken = callbackUrl.token; accessTokenGetter.verifier = callbackUrl.verifier; accessTokenGetter.consumerKey = parameters.consumerKey; accessTokenGetter.signer = getSigner(parameters.consumerSecret, tokenSecret); accessTokenGetter.transport = new ApacheHttpTransport(); OAuthCredentialsResponse response = accessTokenGetter.execute(); if (response.token != null) { parameters.setAccessTokenInProfile(response.token); parameters.setAccessTokenIssuedTimeInProfile(TimeUtils.getCurrentTimeInSeconds()); browserFacade.close(); } parameters.setTokenSecretInProfile(response.tokenSecret); } catch (IOException e) { SoapUI.logError(e); } } } private OAuthSigner getSigner(String clientSharedSecret, String tokenSharedSecret) { OAuthHmacSigner signer = new OAuthHmacSigner(); signer.clientSharedSecret = clientSharedSecret; signer.tokenSharedSecret = tokenSharedSecret; return signer; } protected UserBrowserFacade getBrowserFacade() { WebViewUserBrowserFacade result = new WebViewUserBrowserFacade(); return result; } @Override public void applyAccessToken(OAuth1Profile profile, HttpRequestBase request, String requestContent) { AccessTokenPositionConfig.Enum i = profile.getAccessTokenPosition(); if (i == AccessTokenPositionConfig.QUERY) { appendAccessTokenToQuery(profile, request); } else if (i == AccessTokenPositionConfig.HEADER) { appendAccessTokenToHeader(profile, request); } else { assert false; } } private void appendAccessTokenToQuery(OAuth1Profile profile, HttpRequestBase request) { OAuthParameters oAuthParameters = getOAuthParameters(profile, request); String queryString = makeQueryStringWithOAuthParameters(oAuthParameters); URI oldUri = request.getURI(); String requestQueryString = oldUri.getQuery() != null ? oldUri.getQuery() + "&" + queryString : queryString; try { request.setURI(URIUtils.createURI(oldUri.getScheme(), oldUri.getHost(), oldUri.getPort(), oldUri.getRawPath(), requestQueryString, oldUri.getFragment())); } catch (URISyntaxException e) { SoapUI.logError(e); } } private String makeQueryStringWithOAuthParameters(OAuthParameters oAuthParameters) { StringBuilder buf = new StringBuilder(); appendParameter(buf, "oauth_token", oAuthParameters.token); appendParameter(buf, "oauth_consumer_key", oAuthParameters.consumerKey); appendParameter(buf, "oauth_nonce", oAuthParameters.nonce); appendParameter(buf, "oauth_signature_method", oAuthParameters.signatureMethod); appendParameter(buf, "oauth_signature", oAuthParameters.signature); appendParameter(buf, "oauth_version", oAuthParameters.version); appendParameter(buf, "oauth_timestamp", oAuthParameters.timestamp); // hack: we have to remove the extra '&' at the end return buf.substring(0, buf.length() - 1); } private void appendParameter(StringBuilder buf, String name, String value) { if (value != null) { buf.append(OAuthParameters.escape(name)).append("=").append(OAuthParameters.escape(value)).append("&"); } } private void appendAccessTokenToHeader(OAuth1Profile profile, HttpRequestBase request) { OAuthParameters oAuthParameters = getOAuthParameters(profile, request); request.removeHeaders(OAuth.HeaderType.AUTHORIZATION); request.addHeader(OAuth.HeaderType.AUTHORIZATION, oAuthParameters.getAuthorizationHeader()); } private OAuthParameters getOAuthParameters(OAuth1Profile profile, HttpRequestBase request) { OAuthParameters oAuthParameters = new OAuthParameters(); oAuthParameters.consumerKey = profile.getConsumerKey(); oAuthParameters.token = profile.getAccessToken(); oAuthParameters.signer = getSigner(profile.getConsumerSecret(), profile.getTokenSecret()); oAuthParameters.version = "1.0"; oAuthParameters.computeNonce(); oAuthParameters.computeTimestamp(); try { oAuthParameters.computeSignature(request.getMethod(), new GenericUrl(request.getURI())); } catch (GeneralSecurityException e) { SoapUI.logError(e); } return oAuthParameters; } }