106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Copyright (c) 2009 The Chromium Authors. All rights reserved.
206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Use of this source code is governed by a BSD-style license that can be
306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// found in the LICENSE file.
406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/net/gaia/gaia_authenticator.h"
606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <string>
806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <utility>
906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include <vector>
1006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/basictypes.h"
1206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/port.h"
1306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "base/string_split.h"
1406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/deprecated/event_sys-inl.h"
1506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "chrome/common/net/http_return.h"
1606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "googleurl/src/gurl.h"
1706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#include "net/base/escape.h"
1806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
1906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochusing std::pair;
2006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochusing std::string;
2106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochusing std::vector;
2206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochnamespace gaia {
2406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kGaiaV1IssueAuthTokenPath[] = "/accounts/IssueAuthToken";
2606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
2706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochstatic const char kGetUserInfoPath[] = "/accounts/GetUserInfo";
2806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
29731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickGaiaAuthenticator::AuthResults::AuthResults() : auth_error(None) {}
30731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
31731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickGaiaAuthenticator::AuthResults::~AuthResults() {}
32731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
33731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickGaiaAuthenticator::AuthParams::AuthParams() : authenticator(NULL),
34731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick                                              request_id(0) {}
35731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
36731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickGaiaAuthenticator::AuthParams::~AuthParams() {}
37731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick
3806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Sole constructor with initializers for all fields.
3906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochGaiaAuthenticator::GaiaAuthenticator(const string& user_agent,
4006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     const string& service_id,
4106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     const string& gaia_url)
4206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    : user_agent_(user_agent),
4306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      service_id_(service_id),
4406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      gaia_url_(gaia_url),
4506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      request_count_(0),
4606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      delay_(0),
4706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      next_allowed_auth_attempt_time_(0),
4806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      early_auth_attempt_count_(0),
4906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      message_loop_(NULL) {
5006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  GaiaAuthEvent done = { GaiaAuthEvent::GAIA_AUTHENTICATOR_DESTROYED, None,
5106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                         this };
5206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  channel_ = new Channel(done);
5306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
5406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
5506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochGaiaAuthenticator::~GaiaAuthenticator() {
5606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  delete channel_;
5706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
5806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
5906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// mutex_ must be entered before calling this function.
6006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen MurdochGaiaAuthenticator::AuthParams GaiaAuthenticator::MakeParams(
6106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const string& user_name,
6206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const string& password,
6306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const string& captcha_token,
6406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    const string& captcha_value) {
6506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  AuthParams params;
6606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  params.request_id = ++request_count_;
6706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  params.email = user_name;
6806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  params.password = password;
6906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  params.captcha_token = captcha_token;
7006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  params.captcha_value = captcha_value;
7106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  params.authenticator = this;
7206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return params;
7306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
7406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
7506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::Authenticate(const string& user_name,
7606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     const string& password,
7706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     const string& captcha_token,
7806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     const string& captcha_value) {
7906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
8006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
8106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  AuthParams const params =
8206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      MakeParams(user_name, password, captcha_token, captcha_value);
8306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return AuthenticateImpl(params);
8406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
8506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
8606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::AuthenticateWithLsid(const string& lsid) {
8706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  auth_results_.lsid = lsid;
8806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // We need to lookup the email associated with this LSID cookie in order to
8906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // update |auth_results_| with the correct values.
9006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (LookupEmail(&auth_results_)) {
9106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    auth_results_.email = auth_results_.primary_email;
9206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return IssueAuthToken(&auth_results_, service_id_);
9306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
9406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return false;
9506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
9606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
9706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params) {
9806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
9906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  AuthResults results;
10006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  const bool succeeded = AuthenticateImpl(params, &results);
10106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (params.request_id == request_count_) {
10206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    auth_results_ = results;
10306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    GaiaAuthEvent event = { succeeded ? GaiaAuthEvent::GAIA_AUTH_SUCCEEDED
10406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                      : GaiaAuthEvent::GAIA_AUTH_FAILED,
10506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                      results.auth_error, this };
10606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    channel_->NotifyListeners(event);
10706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
10806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return succeeded;
10906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
11006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
11106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// This method makes an HTTP request to the Gaia server, and calls other
11206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// methods to help parse the response. If authentication succeeded, then
11306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Gaia-issued cookies are available in the respective variables; if
11406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// authentication failed, then the exact error is available as an enum. If the
11506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// client wishes to save the credentials, the last parameter must be true.
11606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// If a subsequent request is made with fresh credentials, the saved credentials
11706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// are wiped out; any subsequent request to the zero-parameter overload of this
11806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// method preserves the saved credentials.
11906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params,
12006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                         AuthResults* results) {
12106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
12206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  results->auth_error = ConnectionUnavailable;
12306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  results->email = params.email.data();
12406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  results->password = params.password;
12506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
12606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // The aim of this code is to start failing requests if due to a logic error
12706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // in the program we're hammering GAIA.
12806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#if defined(OS_WIN)
12906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  __time32_t now = _time32(0);
13006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#else  // defined(OS_WIN)
13106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  time_t now = time(0);
13206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch#endif  // defined(OS_WIN)
13306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
13406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (now > next_allowed_auth_attempt_time_) {
13506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    next_allowed_auth_attempt_time_ = now + 1;
13606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // If we're more than 2 minutes past the allowed time we reset the early
13706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // attempt count.
13806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (now - next_allowed_auth_attempt_time_ > 2 * 60) {
13906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      delay_ = 1;
14006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      early_auth_attempt_count_ = 0;
14106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
14206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else {
14306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ++early_auth_attempt_count_;
14406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Allow 3 attempts, but then limit.
14506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (early_auth_attempt_count_ > 3) {
14606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      delay_ = GetBackoffDelaySeconds(delay_);
14706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      next_allowed_auth_attempt_time_ = now + delay_;
14806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      return false;
14906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
15006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
15106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
15206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return PerformGaiaRequest(params, results);
15306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
15406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
15506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::PerformGaiaRequest(const AuthParams& params,
15606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                           AuthResults* results) {
15706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
15806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  GURL gaia_auth_url(gaia_url_);
15906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
16006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string post_body;
16106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "Email=" + EscapeUrlEncodedData(params.email);
16206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "&Passwd=" + EscapeUrlEncodedData(params.password);
16306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "&source=" + EscapeUrlEncodedData(user_agent_);
16406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "&service=" + service_id_;
16506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (!params.captcha_token.empty() && !params.captcha_value.empty()) {
16606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    post_body += "&logintoken=" + EscapeUrlEncodedData(params.captcha_token);
16706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    post_body += "&logincaptcha=" + EscapeUrlEncodedData(params.captcha_value);
16806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
16906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "&PersistentCookie=true";
17006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // We set it to GOOGLE (and not HOSTED or HOSTED_OR_GOOGLE) because we only
17106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // allow consumer logins.
17206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "&accountType=GOOGLE";
17306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
17406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string message_text;
17506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  unsigned long server_response_code;
17606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (!Post(gaia_auth_url, post_body, &server_response_code, &message_text)) {
17706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = ConnectionUnavailable;
17806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
17906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
18006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
18106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Parse reply in two different ways, depending on if request failed or
18206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // succeeded.
18306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (RC_FORBIDDEN == server_response_code) {
18406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ExtractAuthErrorFrom(message_text, results);
18506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
18606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (RC_REQUEST_OK == server_response_code) {
18706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ExtractTokensFrom(message_text, results);
18806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (!IssueAuthToken(results, service_id_)) {
18906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      return false;
19006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
19106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
19206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return LookupEmail(results);
19306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else {
19406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = Unknown;
19506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
19606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
19706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
19806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
19921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool GaiaAuthenticator::Post(const GURL& url,
20021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                             const std::string& post_body,
20121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                             unsigned long* response_code,
20221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen                             std::string* response_body) {
20321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return false;
20421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
20521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
20606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::LookupEmail(AuthResults* results) {
20706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
20806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Use the provided Gaia server, but change the path to what V1 expects.
20906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  GURL url(gaia_url_);  // Gaia server.
21006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  GURL::Replacements repl;
21106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Needs to stay in scope till GURL is out of scope.
21206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string path(kGetUserInfoPath);
21306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  repl.SetPathStr(path);
21406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  url = url.ReplaceComponents(repl);
21506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
21606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string post_body;
21706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "LSID=";
21806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += EscapeUrlEncodedData(results->lsid);
21906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
22006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  unsigned long server_response_code;
22106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string message_text;
22206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (!Post(url, post_body, &server_response_code, &message_text)) {
22306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
22406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
22506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
22606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Check if we received a valid AuthToken; if not, ignore it.
22706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (RC_FORBIDDEN == server_response_code) {
22806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Server says we're not authenticated.
22906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ExtractAuthErrorFrom(message_text, results);
23006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
23106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (RC_REQUEST_OK == server_response_code) {
23206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    typedef vector<pair<string, string> > Tokens;
23306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    Tokens tokens;
23406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    base::SplitStringIntoKeyValuePairs(message_text, '=', '\n', &tokens);
23506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    for (Tokens::iterator i = tokens.begin(); i != tokens.end(); ++i) {
23606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      if ("accountType" == i->first) {
23706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        // We never authenticate an email as a hosted account.
23806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        DCHECK_EQ("GOOGLE", i->second);
23906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      } else if ("email" == i->first) {
24006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch        results->primary_email = i->second;
24106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      }
24206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
24306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return true;
24406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
24506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return false;
24606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
24706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
24821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenint GaiaAuthenticator::GetBackoffDelaySeconds(int current_backoff_delay) {
24921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  NOTREACHED();
25021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return current_backoff_delay;
25121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
25221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
25306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// We need to call this explicitly when we need to obtain a long-lived session
25406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// token.
25506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::IssueAuthToken(AuthResults* results,
25606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                       const string& service_id) {
25706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
25806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Use the provided Gaia server, but change the path to what V1 expects.
25906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  GURL url(gaia_url_);  // Gaia server.
26006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  GURL::Replacements repl;
26106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Needs to stay in scope till GURL is out of scope.
26206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string path(kGaiaV1IssueAuthTokenPath);
26306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  repl.SetPathStr(path);
26406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  url = url.ReplaceComponents(repl);
26506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
26606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string post_body;
26706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "LSID=";
26806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += EscapeUrlEncodedData(results->lsid);
26906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "&service=" + service_id;
27006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  post_body += "&Session=true";
27106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
27206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  unsigned long server_response_code;
27306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  string message_text;
27406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (!Post(url, post_body, &server_response_code, &message_text)) {
27506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
27606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
27706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
27806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Check if we received a valid AuthToken; if not, ignore it.
27906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (RC_FORBIDDEN == server_response_code) {
28006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Server says we're not authenticated.
28106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    ExtractAuthErrorFrom(message_text, results);
28206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return false;
28306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (RC_REQUEST_OK == server_response_code) {
28406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Note that the format of message_text is different from what is returned
28506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // in the first request, or to the sole request that is made to Gaia V2.
28606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // Specifically, the entire string is the AuthToken, and looks like:
28706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // "<token>" rather than "AuthToken=<token>". Thus, we need not use
28806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    // ExtractTokensFrom(...), but simply assign the token.
28906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    int last_index = message_text.length() - 1;
29006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if ('\n' == message_text[last_index])
29106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      message_text.erase(last_index);
29206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_token = message_text;
29306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    return true;
29406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
29506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return false;
29606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
29706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
29806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Helper method that extracts tokens from a successful reply, and saves them
29906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// in the right fields.
30006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid GaiaAuthenticator::ExtractTokensFrom(const string& response,
30106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                          AuthResults* results) {
30206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  vector<pair<string, string> > tokens;
30306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens);
30406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  for (vector<pair<string, string> >::iterator i = tokens.begin();
30506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      i != tokens.end(); ++i) {
30606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (i->first == "SID") {
30706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      results->sid = i->second;
30806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    } else if (i->first == "LSID") {
30906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      results->lsid = i->second;
31006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    } else if (i->first == "Auth") {
31106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      results->auth_token = i->second;
31206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
31306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
31406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
31506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
31606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Helper method that extracts tokens from a failure response, and saves them
31706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// in the right fields.
31806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid GaiaAuthenticator::ExtractAuthErrorFrom(const string& response,
31906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                             AuthResults* results) {
32006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  vector<pair<string, string> > tokens;
32106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens);
32206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  for (vector<pair<string, string> >::iterator i = tokens.begin();
32306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      i != tokens.end(); ++i) {
32406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    if (i->first == "Error") {
32506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      results->error_msg = i->second;
32606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    } else if (i->first == "Url") {
32706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      results->auth_error_url = i->second;
32806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    } else if (i->first == "CaptchaToken") {
32906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      results->captcha_token = i->second;
33006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    } else if (i->first == "CaptchaUrl") {
33106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch      results->captcha_url = i->second;
33206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    }
33306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
33406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
33506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // Convert string error messages to enum values. Each case has two different
33606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // strings; the first one is the most current and the second one is
33706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  // deprecated, but available.
33806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  const string& error_msg = results->error_msg;
33906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  if (error_msg == "BadAuthentication" || error_msg == "badauth") {
34006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = BadAuthentication;
34106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (error_msg == "NotVerified" || error_msg == "nv") {
34206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = NotVerified;
34306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (error_msg == "TermsNotAgreed" || error_msg == "tna") {
34406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = TermsNotAgreed;
34506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (error_msg == "Unknown" || error_msg == "unknown") {
34606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = Unknown;
34706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (error_msg == "AccountDeleted" || error_msg == "adel") {
34806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = AccountDeleted;
34906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (error_msg == "AccountDisabled" || error_msg == "adis") {
35006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = AccountDisabled;
35106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (error_msg == "CaptchaRequired" || error_msg == "cr") {
35206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = CaptchaRequired;
35306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  } else if (error_msg == "ServiceUnavailable" || error_msg == "ire") {
35406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch    results->auth_error = ServiceUnavailable;
35506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  }
35606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
35706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
35806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// Reset all stored credentials, perhaps in preparation for letting a different
35906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch// user sign in.
36006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid GaiaAuthenticator::ResetCredentials() {
36106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
36206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  AuthResults blank;
36306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  auth_results_ = blank;
36406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
36506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
36606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid GaiaAuthenticator::SetUsernamePassword(const string& username,
36706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                            const string& password) {
36806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
36906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  auth_results_.password = password;
37006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  auth_results_.email = username;
37106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
37206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
37306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid GaiaAuthenticator::SetUsername(const string& username) {
37406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
37506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  auth_results_.email = username;
37606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
37706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
37806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid GaiaAuthenticator::RenewAuthToken(const string& auth_token) {
37906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
38006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK(!this->auth_token().empty());
38106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  auth_results_.auth_token = auth_token;
38206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
38306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochvoid GaiaAuthenticator::SetAuthToken(const string& auth_token) {
38406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
38506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  auth_results_.auth_token = auth_token;
38606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
38706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
38806741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdochbool GaiaAuthenticator::Authenticate(const string& user_name,
38906741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                                     const string& password) {
39006741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  DCHECK_EQ(MessageLoop::current(), message_loop_);
39106741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  const string empty;
39206741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch  return Authenticate(user_name, password, empty,
39306741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch                      empty);
39406741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}
39506741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
39606741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch}  // namepace gaia
39706741cbc25cd4227a9fba40dfd0273bfcc1a587aBen Murdoch
398