Package com.google.appengine.tools.admin

Source Code of com.google.appengine.tools.admin.ClientLoginServerConnection$ClientLoginException

// Copyright 2011 Google Inc. All Rights Reserved.

package com.google.appengine.tools.admin;

import com.google.appengine.tools.admin.AppAdminFactory.ConnectOptions;
import com.google.appengine.tools.util.ClientCookie;
import com.google.appengine.tools.util.ClientCookieManager;
import com.google.common.annotations.VisibleForTesting;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.prefs.Preferences;

/**
*/
public class ClientLoginServerConnection extends AbstractServerConnection {

  /**
   * Exception type for email/password mismatch failures.
   */
  public class ClientAuthFailException extends ClientLoginException {
    public ClientAuthFailException(String s) {
      super(s);
    }

    public ClientAuthFailException(String s, Throwable t) {
      super(s, t);
    }
  }
  /**
   * Exception type for login failures.
   */
  public class ClientLoginException extends IOException {
    public ClientLoginException(String s) {
      super(s);
    }

    public ClientLoginException(String s, Throwable t) {
      super(s, t);
    }
  }

  protected ClientCookieManager cookies;

  public ClientLoginServerConnection(ConnectOptions options) {
    super(options);
    cookies = options.getCookies();
    if (cookies == null) {
      cookies = new ClientCookieManager();
    }
  }

  /**
   * Authenticates the user.
   *
   * The authentication process works as follows: 1) We get a username and
   * password from the user 2) We use ClientLogin to obtain an AUTH token for
   * the user 3) We pass the auth token to /_ah/login on the server to obtain an
   * authentication cookie. If login was successful, it tries to redirect us to
   * the URL we provided.
   *
   * If we attempt to access the upload API without first obtaining an
   * authentication cookie, it returns a 401 response and directs us to
   * authenticate ourselves with ClientLogin.
   *
   * @param url which require authentication
   * @param account_type
   * @see <a
   *      href="http://code.google.com/apis/accounts/AuthForInstalledApps.html"></a>
   */
  private void authenticate(URL url, String account_type) throws ClientLoginException,
      IOException {
    for (int unused = 1;; ++unused) {
      try {
        String authToken = getAuthToken(url.getHost(), account_type);
        getAuthCookie(authToken);
        break;
      } catch (ClientLoginException e) {
        if (unused >= 3) {
          throw e;
        }
      }
    }
    checkAuthCookie(url);
  }

  @VisibleForTesting
  void checkAuthCookie(URL url) throws ClientLoginException {
    long minExpireTime = System.currentTimeMillis() + 60 * 1000;
    Iterator<ClientCookie> li = cookies.getCookies();
    while (li.hasNext()) {
      final ClientCookie cookie = li.next();
      if (cookie.getExpirationTime() > minExpireTime && cookie.match(url)) {
        return;
      }
    }

    throw new ClientLoginException("This system's clock appears to be set incorrectly. "+
                                   "Check the system time and set it to the correct time " +
                                   "before trying again.");
  }

  @Override
  protected void doHandleSendErrors(int status, URL url, HttpURLConnection conn,
      BufferedReader connReader) throws IOException {
    if (status == 401) {
      authenticate(url, null);
    } else if (status == 403) {
      System.out.println(constructHttpErrorMessage(conn, connReader));
      authenticate(url, null);
    } else if (status >= 500 && status <= 600) {
    } else if (status == 302) {
      Map<String, List<String>> headers = conn.getHeaderFields();
      String location = headers.get("Location").get(0);
      if (location.startsWith("https://www.google.com/accounts/ServiceLogin")) {
        authenticate(url, null);
      } else if (location.matches("https://www.google.com/a/[a-z0-9.-]+/ServiceLogin.*")) {
        authenticate(url, "HOSTED");
      }
    }
  }

  @Override
  protected void doPostConnect(String method, HttpURLConnection conn, DataPoster data)
      throws IOException {
    cookies.readCookies(conn);
    if (options.getUsePersistedCredentials()) {
      saveCookies();
    }
  }

  @Override
  protected void doPreConnect(String method, HttpURLConnection conn, DataPoster data) {
    cookies.writeCookies(conn);
  }

  private void getAuthCookie(String token) throws IOException {
    Map<String, String> params = new HashMap<String, String>();
    params.put("continue", "http://localhost/");
    params.put("auth", token);
    String query = buildQuery(params);
    URL url = buildURL("/_ah/login?" + query);
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    if (options.getHost() != null) {
      conn.setRequestProperty("Host", options.getHost());
    }

    IOException ioe = connect(POST, conn, null);
    if (conn.getResponseCode() != 302
        || !"http://localhost/".equals(conn.getHeaderField("Location"))) {
      throw new RuntimeException("Bad authentication response: " + conn.getResponseCode() + " "
          + conn.getResponseMessage());
    } else if (ioe != null) {
      throw ioe;
    }

  }

  private String getAuthToken(String host, String accountType) throws IOException,
      ClientLoginException {
    if (accountType == null) {
      if (host.endsWith(".google.com")) {
        accountType = "HOSTED_OR_GOOGLE";
      } else if (options.getHost() != null && options.getHost().endsWith(".google.com")) {
        accountType = "HOSTED_OR_GOOGLE";
      } else {
        accountType = "GOOGLE";
      }
    }
    URL url = new URL("https://www.google.com/accounts/ClientLogin");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();

    String password = options.getPasswordPrompt().getPassword();
    Map<String, String> params = new HashMap<String, String>();
    params.put("Email", options.getUserId());
    params.put("Passwd", password);
    params.put("service", "ah");
    params.put("source", "Google-appcfg-java-unknown");
    params.put("accountType", accountType);
    IOException ioe = connect(POST, conn, new StringPoster(buildQuery(params)));

    BufferedReader reader = getReader(conn);
    HashMap<String, String> response = new HashMap<String, String>();
    String line = null;
    while ((line = reader.readLine()) != null) {
      String[] pair = line.split("=", 2);
      if (pair.length == 2) {
        response.put(pair[0], pair[1]);
      }
    }

    if (conn.getResponseCode() == 200) {
      return response.get("Auth");
    } else if (conn.getResponseCode() == 403) {
      String reason = response.get("Error");
      if ("BadAuthentication".equals(reason)) {
        String info = response.get("Info");
        if ("InvalidSecondFactor".equals(info)) {
          throw new ClientLoginException(""
              + "Use an application-specific password instead of your regular account password. "
              + "See http://www.google.com/support/accounts/bin/answer.py?answer=185833",
              ioe);
        }
        else {
          throw new ClientLoginException("Email \"" + options.getUserId()
              + "\" and password do not match.", ioe);
        }
      } else if ("CaptchaRequired".equals(reason)) {
        throw new ClientLoginException("Please go to "
            + "https://www.google.com/accounts/DisplayUnlockCaptcha "
            + "and verify you are a human. Then try again.");
      } else if ("NotVerified".equals(reason)) {
        throw new ClientLoginException("Your account has not yet been "
            + "verfied. Please check your email to do that, then try again.");
      } else if ("TermsNotAgreed".equals(reason)) {
        throw new ClientLoginException("You have not yet agreed to the "
            + "Terms of Service on your account. Please do that, then try again.");
      } else if ("AccountDeleted".equals(reason)) {
        throw new ClientLoginException("Your user account has been deleted."
            + " If this is an error, contact account support at "
            + "http://www.google.com/support/accounts/");
      } else if ("AccountDisabled".equals(reason)) {
        throw new ClientLoginException("Your user account has been disabled."
            + " If this is an error, contact account support at "
            + "http://www.google.com/support/accounts/");
      } else if ("ServiceUnavailable".equals(reason)) {
        throw new ClientLoginException("The service is currently "
            + "unavailable; try again later.");
      }
      throw new ClientLoginException(response.get("Error"), ioe);
    } else if (conn.getResponseCode() == 401) {
      throw new ClientAuthFailException("Email \"" + options.getUserId()
          + "\" and password do not match.", ioe);
    } else {
      throw new RuntimeException("Bad authentication response: " + conn.getResponseCode() + " "
          + conn.getResponseMessage(), ioe);
    }
  }

  public void saveCookies() throws IOException {
    if (options.getUserId() == null) {
      return;
    }
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    new ObjectOutputStream(out).writeObject(cookies);
    byte[] bytes = out.toByteArray();
    Preferences prefs = Preferences.userNodeForPackage(ServerConnection.class);
    prefs.put("email", options.getUserId());
    prefs.putByteArray("cookies", bytes);
  }
}
TOP

Related Classes of com.google.appengine.tools.admin.ClientLoginServerConnection$ClientLoginException

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.