package com.microsoft.bingads.internal; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.bingads.InternalException; import com.microsoft.bingads.OAuthErrorDetails; import com.microsoft.bingads.OAuthTokenRequestException; import com.microsoft.bingads.OAuthTokens; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; /** * Provides method for getting OAuth tokens from the live.com authorization * server using {@link OAuthRequestParameters}. */ public class LiveComOAuthService implements OAuthService { private static final String UTF_8 = "UTF-8"; public static final URL DESKTOP_REDIRECT_URL; private static final URL TOKEN_REQUEST_URL; private static final String CLIENT_ID = "client_id"; private static final String CLIENT_SECRET = "client_secret"; private static final String GRANT_TYPE = "grant_type"; private static final String REDIRECT_URI = "redirect_uri"; private static final String RESPONSE_TYPE = "response_type"; private static final String STATE = "state"; private enum HttpMethods { POST } static { try { DESKTOP_REDIRECT_URL = new URL("https://login.live.com/oauth20_desktop.srf"); } catch (MalformedURLException e) { throw new InternalException(e); } try { TOKEN_REQUEST_URL = new URL("https://login.live.com/oauth20_token.srf"); } catch (MalformedURLException e) { throw new InternalException(e); } } private final WebServiceCaller webServiceCaller; private ObjectMapper mapper; public LiveComOAuthService() { this(new HttpClientWebServiceCaller()); } public LiveComOAuthService(WebServiceCaller caller) { this.webServiceCaller = caller; this.mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); } /** * Calls live.com authorization server with the * {@link OAuthRequestParameters} passed in, deserializes the response * and returns back OAuth tokens. * * @param oAuthParameters OAuth parameters for authorization server call * @return OAuth tokens */ @Override public OAuthTokens getAccessTokens(OAuthRequestParameters oAuthParameters) { try { List<NameValuePair> paramsList = generateParamsList(oAuthParameters); HttpResponse httpResponse = webServiceCaller.post(TOKEN_REQUEST_URL, paramsList); InputStream stream = httpResponse.getEntity().getContent(); if (httpResponse.getStatusLine().getStatusCode() == 200){ OAuthTokensContract oauthResponse = mapper.readValue(stream, OAuthTokensContract.class); return new OAuthTokens(oauthResponse.getAccessToken(), oauthResponse.getAccessTokenExpiresInSeconds(), oauthResponse.getRefreshToken()); } else { OAuthErrorDetailsContract errorResponse = mapper.readValue(stream, OAuthErrorDetailsContract.class); OAuthErrorDetails errorDetails = new OAuthErrorDetails(errorResponse.getError(), errorResponse.getDescription()); throw new OAuthTokenRequestException(ErrorMessages.OAuthError, errorDetails); } } catch (IOException e) { throw new InternalException(e); } finally { webServiceCaller.shutDown(); } } /** * Creates a URL for authorizing a user * * @param parameters OAuth parameters for ensemble authorization endpoint * * @return a {@link URL} which points to the authorization endpoint with all * required parameters * * @throws MalformedURLException * @throws UnsupportedEncodingException */ public static URL getAuthorizationEndpoint(OAuthUrlParameters parameters) { Map<String, String> paramsMap = new HashMap<String, String>(); paramsMap.put(CLIENT_ID, parameters.getClientId()); paramsMap.put(RESPONSE_TYPE, parameters.getResponseType()); paramsMap.put(REDIRECT_URI, parameters.getRedirectionUri().toString()); if (parameters.getState() != null && !parameters.getState().isEmpty()) { paramsMap.put(STATE, parameters.getState()); } try { return new URL(String.format( "https://login.live.com/oauth20_authorize.srf?scope=bingads.manage&%s", mapToQueryString(paramsMap) )); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } catch (UnsupportedEncodingException e) { throw new IllegalArgumentException(e); } } private static List<NameValuePair> generateParamsList(OAuthRequestParameters requestParams) throws UnsupportedEncodingException { List<NameValuePair> params = new ArrayList<NameValuePair>(); params.add(new BasicNameValuePair(CLIENT_ID, requestParams.getClientId())); if (requestParams.getClientSecret() != null && !requestParams.getClientSecret().isEmpty()) { params.add(new BasicNameValuePair(CLIENT_SECRET, requestParams.getClientSecret())); } params.add(new BasicNameValuePair(GRANT_TYPE, requestParams.getGrantType())); params.add(new BasicNameValuePair(requestParams.getGrantParamName(), requestParams.getGrantValue())); params.add(new BasicNameValuePair(REDIRECT_URI, requestParams.getRedirectionUri().toString())); return params; } private static String mapToQueryString(Map<String, String> params) throws UnsupportedEncodingException { StringBuilder sb = new StringBuilder(); for (Entry<String, String> e : params.entrySet()) { if (sb.length() > 0) { sb.append('&'); } sb.append(URLEncoder.encode(e.getKey(), UTF_8)).append('=').append(URLEncoder.encode(e.getValue(), UTF_8)); } return sb.toString(); } }