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