1.9.30 sync.
[gae.git] / java / src / main / com / google / appengine / tools / remoteapi / ClientLogin.java
blob3f0cf58defad2f53823aac1f6f8f701abc3fa2ba
1 // Copyright 2010 Google Inc. All Rights Reserved.
3 package com.google.appengine.tools.remoteapi;
5 import org.apache.commons.httpclient.Cookie;
7 import java.io.IOException;
8 import java.net.URLEncoder;
9 import java.util.Arrays;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.Map;
14 /**
15 * Handles logging into App Engine using
16 * <a href="http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html"
17 * >ClientLogin</a>. This class does not rely on any particular mechanism for
18 * sending HTTP requests to ClientLogin. It instead exposes template methods
19 * for subclasses to implement using different mechanisms.
22 abstract class ClientLogin {
24 /**
25 * Authenticates the user using ClientLogin. This requires two HTTP requests,
26 * one to get a token from Google and one to exchange it for cookies from App Engine.
28 * @deprecated ClientLogin authentication is deprecated and will soon be shut down.
29 * Use OAuth2.0 instead to obtain credentials.
31 @Deprecated
32 public List<Cookie> login(String host, String email, String password) throws IOException {
33 if (email == null || email.isEmpty()) {
34 throw new IllegalArgumentException("email not set");
36 if (password == null || password.isEmpty()) {
37 throw new IllegalArgumentException("password not set");
39 List<String[]> postParams = getClientLoginPostParams(email, password);
40 PostResponse authResponse = executePost(
41 "https://www.google.com/accounts/ClientLogin", postParams);
42 String token = processAuthResponse(authResponse, email);
43 String url = "https://" + host + "/_ah/login"
44 + "?auth=" + URLEncoder.encode(token, "UTF-8")
45 + "&continue=http://localhost/";
46 return getAppEngineLoginCookies(url);
49 /**
50 * Provides the parameter names and values that need to be posted to the
51 * ClientLogin url. Each element of the returned {@link List} is an array of
52 * size 2 where the String at index 0 is the parameter name and the String at
53 * index 1 is the parameter value.
55 private static List<String[]> getClientLoginPostParams(String email, String password) {
56 return Arrays.asList(
57 new String[] {"Email", email},
58 new String[] {"Passwd", password},
59 new String[] {"service", "ah"},
60 new String[] {"source", "Google-remote_api-java-1.0"},
61 new String[] {"accountType", "HOSTED_OR_GOOGLE"});
64 private String processAuthResponse(PostResponse authResponse, String email)
65 throws LoginException {
66 if (authResponse.statusCode == 200 || authResponse.statusCode == 403) {
67 Map<String, String> responseMap = parseClientLoginResponse(authResponse.body);
68 if (authResponse.statusCode == 200) {
69 return responseMap.get("Auth");
70 } else {
71 String reason = responseMap.get("Error");
72 if ("BadAuthentication".equals(reason)) {
73 String info = responseMap.get("Info");
74 if (info != null && !info.isEmpty()) {
75 reason = reason + " " + info;
78 throw new LoginException("Login failed. Reason: " + reason);
80 } else if (authResponse.statusCode == 401) {
81 throw new LoginException("Email \"" + email + "\" and password do not match.");
82 } else {
83 throw new LoginException("Bad authentication response: " + authResponse.statusCode);
87 /**
88 * Parses the key-value pairs in the ClientLogin response.
90 private static Map<String, String> parseClientLoginResponse(String body) {
91 Map<String, String> response = new HashMap<String, String>();
92 for (String line : body.split("\n")) {
93 int eqIndex = line.indexOf("=");
94 if (eqIndex > 0) {
95 response.put(line.substring(0, eqIndex), line.substring(eqIndex + 1));
98 return response;
102 * Executes an HTTP Post to the provided url with the provided params.
104 abstract PostResponse executePost(String url, List<String[]> postParams) throws IOException;
107 * Logs into App Engine and returns the cookies needed to make authenticated requests.
109 abstract List<Cookie> getAppEngineLoginCookies(String url) throws IOException;
112 * Represents a post response.
114 static class PostResponse {
115 final int statusCode;
116 final String body;
117 PostResponse(int statusCode, String body) {
118 this.statusCode = statusCode;
119 this.body = body;