Java tutorial
// Copyright 2010, Google Inc. All Rights Reserved. // // Licensed 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 com.google.api.ads.dfp.lib; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpState; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.concurrent.TimeUnit; /** * The AuthToken class creates an authentication token using * the <a href="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html"> * ClientLogin API</a>. * * @author api.arogal@gmail.com (Adam Rogal) */ public class AuthToken { public static final String CLIENT_LOGIN_SERVER = "https://www.google.com/accounts/"; private static final String CLIENT_LOGIN_URL = CLIENT_LOGIN_SERVER + "ClientLogin"; private static final int HTTP_CLIENT_SOCKET_TIMEOUT_IN_MS = (int) TimeUnit.SECONDS.toMillis(20); private static final String AUTH_TOKEN_KEY = "Auth"; private static final String ERROR_KEY = "Error"; private static final String INFO_KEY = "Info"; private static final String URL_KEY = "Url"; private static final String CAPTCHA_TOKEN_KEY = "CaptchaToken"; private static final String CAPTCHA_URL_KEY = "CaptchaUrl"; private static final String CAPTCHA_REQUIRED_ERROR = "CaptchaRequired"; private final String email; private final String password; private final String captchaToken; private final String captchaAnswer; /** * Constructor for email and password request. * * @param email the user's login email address * @param password the user's password */ public AuthToken(String email, String password) { this(email, password, null, null); } /** * Constructor which provides fields for CAPTCHA information. * * @param email the user's login email address * @param password the user's password * @param captchaToken the CAPTCHA token * @param captchaAnswer the CAPTCHA answer */ public AuthToken(String email, String password, String captchaToken, String captchaAnswer) { this.email = email; this.password = password; this.captchaToken = captchaToken; this.captchaAnswer = captchaAnswer; } /** * Constructor used for generating a new {@code AuthToken} from an old one * along with CAPTCHA information. * * @param authToken the {@code AuthToken} object to get the email and password * from * @param captchaToken the CAPTCHA token * @param captchaAnswer the CAPTCHA answer */ public AuthToken(AuthToken authToken, String captchaToken, String captchaAnswer) { this.email = authToken.email; this.password = authToken.password; this.captchaToken = captchaToken; this.captchaAnswer = captchaAnswer; } /** * Retrieves an authentication token using the user's credentials. * * @return a {@code String} authentication token. * @throws AuthTokenException if the status from the Client Login server is * anything but {@code HttpStatus.SC_OK = 200} */ public String getAuthToken() throws AuthTokenException { try { PostMethod postMethod = new PostMethod(CLIENT_LOGIN_URL); int statusCode = postToClientLogin(postMethod); Properties responseProperties = generatePropertiesFromResponse(postMethod.getResponseBodyAsStream()); if (statusCode == HttpStatus.SC_OK) { if (responseProperties.containsKey(AUTH_TOKEN_KEY)) { return responseProperties.getProperty(AUTH_TOKEN_KEY).toString(); } else { throw new IllegalStateException("Unable to get auth token from Client Login server"); } } else { CaptchaInformation captchaInfo = null; String errorCode = null; if (responseProperties.containsKey(ERROR_KEY)) { errorCode = responseProperties.getProperty(ERROR_KEY); if (errorCode != null && errorCode.equals(CAPTCHA_REQUIRED_ERROR)) { captchaInfo = extractCaptchaInfoFromProperties(responseProperties); } if (responseProperties.containsKey(INFO_KEY)) { errorCode += ": " + responseProperties.getProperty(INFO_KEY); } } throw new AuthTokenException(statusCode, postMethod.getResponseBodyAsString(), errorCode, captchaInfo, null); } } catch (IOException e) { throw new AuthTokenException(null, null, null, null, e); } } /** * Makes the POST to the client login API. * * @param postMethod the {@code PostMethod} which encapsulates the URL to * post against * @return an HTTP status code as defined by {@code HttpStatus} * @throws IOException if the HTTP client could not establish a * connection */ private int postToClientLogin(PostMethod postMethod) throws IOException { HttpClient httpClient = new HttpClient(new MultiThreadedHttpConnectionManager()); setProxy(httpClient); HttpConnectionManagerParams connectionManagerParams = httpClient.getHttpConnectionManager().getParams(); connectionManagerParams.setTcpNoDelay(true); connectionManagerParams.setSoTimeout(HTTP_CLIENT_SOCKET_TIMEOUT_IN_MS); postMethod.addParameter("Email", email); postMethod.addParameter("Passwd", password); postMethod.addParameter("accountType", "GOOGLE"); postMethod.addParameter("service", "gam"); postMethod.addParameter("source", "google-dfpapi-java"); if (captchaToken != null) { postMethod.addParameter("logintoken", captchaToken); } if (captchaAnswer != null) { postMethod.addParameter("logincaptcha", captchaAnswer); } return httpClient.executeMethod(postMethod); } /** * Sets the proxy for the HTTP client. * * @param httpClient the HTTP client to set the proxy for */ private void setProxy(HttpClient httpClient) { if (System.getProperty("http.proxyHost") != null && System.getProperty("http.proxyPort") != null) { httpClient.getHostConfiguration().setProxy(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))); if (System.getProperty("http.proxyUser") != null && System.getProperty("http.proxyPassword") != null) { HttpState state = new HttpState(); state.setProxyCredentials( new AuthScope(System.getProperty("http.proxyHost"), Integer.parseInt(System.getProperty("http.proxyPort"))), new UsernamePasswordCredentials(System.getProperty("http.proxyUser"), System.getProperty("http.proxyPassword"))); httpClient.setState(state); } } } /** * Extracts the CAPTCHA information from a response. * * @param authProperties the response from the client login API * @return the CAPTCHA information */ private CaptchaInformation extractCaptchaInfoFromProperties(Properties authProperties) { String captchaUrl = CLIENT_LOGIN_SERVER + authProperties.getProperty(CAPTCHA_URL_KEY); String captchaToken = authProperties.getProperty(CAPTCHA_TOKEN_KEY); String url = authProperties.getProperty(URL_KEY); return new CaptchaInformation(captchaUrl, captchaToken, url); } /** * Generates a {@code Properties} from a client login API response * * @param responseBodyStream the response body as a stream * @return a {@code Properties} generated from the response body * @throws IOException if response body stream could not be read */ private Properties generatePropertiesFromResponse(InputStream responseBodyStream) throws IOException { Properties properties = new Properties(); properties.load(responseBodyStream); return properties; } }