From f3d0174b68971b96dd2e8f518d81abee1fc87645 Mon Sep 17 00:00:00 2001 From: "sanjeevr@chromium.org" Date: Fri, 7 May 2010 02:53:55 +0000 Subject: Moved GaiaAuthenticator from chrome/browser/sync/engine/net to chrome/common/net/gaia. BUG=None TEST=None, no functional change. Review URL: http://codereview.chromium.org/1998004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46654 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/browser/sync/engine/all_status.cc | 10 +- chrome/browser/sync/engine/all_status.h | 11 +- chrome/browser/sync/engine/auth_watcher.cc | 34 +- chrome/browser/sync/engine/auth_watcher.h | 8 +- .../browser/sync/engine/auth_watcher_unittest.cc | 12 +- chrome/browser/sync/engine/authenticator.cc | 10 +- .../browser/sync/engine/net/gaia_authenticator.cc | 398 -------------------- .../browser/sync/engine/net/gaia_authenticator.h | 328 ----------------- .../sync/engine/net/gaia_authenticator_unittest.cc | 48 --- chrome/browser/sync/engine/net/http_return.h | 16 - .../sync/engine/net/server_connection_manager.cc | 2 +- .../sync/engine/net/server_connection_manager.h | 6 +- .../net/syncapi_server_connection_manager.cc | 4 +- chrome/browser/sync/engine/syncapi.cc | 10 +- chrome/browser/sync/util/signin.h | 15 - chrome/browser/sync/util/user_settings.cc | 10 +- chrome/browser/sync/util/user_settings.h | 7 +- chrome/chrome.gyp | 4 - chrome/chrome_common.gypi | 4 + chrome/chrome_tests.gypi | 2 +- chrome/common/net/gaia/gaia_authenticator.cc | 404 +++++++++++++++++++++ chrome/common/net/gaia/gaia_authenticator.h | 331 +++++++++++++++++ .../common/net/gaia/gaia_authenticator_unittest.cc | 49 +++ chrome/common/net/gaia/signin.h | 18 + chrome/common/net/http_return.h | 17 + chrome/test/sync/engine/mock_gaia_authenticator.cc | 8 +- chrome/test/sync/engine/mock_gaia_authenticator.h | 12 +- .../engine/mock_gaia_authenticator_unittest.cc | 10 +- 28 files changed, 905 insertions(+), 883 deletions(-) delete mode 100644 chrome/browser/sync/engine/net/gaia_authenticator.cc delete mode 100644 chrome/browser/sync/engine/net/gaia_authenticator.h delete mode 100644 chrome/browser/sync/engine/net/gaia_authenticator_unittest.cc delete mode 100644 chrome/browser/sync/engine/net/http_return.h delete mode 100644 chrome/browser/sync/util/signin.h create mode 100644 chrome/common/net/gaia/gaia_authenticator.cc create mode 100644 chrome/common/net/gaia/gaia_authenticator.h create mode 100644 chrome/common/net/gaia/gaia_authenticator_unittest.cc create mode 100644 chrome/common/net/gaia/signin.h create mode 100644 chrome/common/net/http_return.h diff --git a/chrome/browser/sync/engine/all_status.cc b/chrome/browser/sync/engine/all_status.cc index 983833c..abd0e56 100644 --- a/chrome/browser/sync/engine/all_status.cc +++ b/chrome/browser/sync/engine/all_status.cc @@ -10,7 +10,6 @@ #include "base/port.h" #include "base/rand_util.h" #include "chrome/browser/sync/engine/auth_watcher.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" #include "chrome/browser/sync/engine/syncer.h" #include "chrome/browser/sync/engine/syncer_thread.h" @@ -18,6 +17,7 @@ #include "chrome/browser/sync/sessions/session_state.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/common/deprecated/event_sys-inl.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" #include "chrome/common/net/notifier/listener/talk_mediator.h" namespace browser_sync { @@ -59,7 +59,7 @@ void AllStatus::WatchConnectionManager(ServerConnectionManager* conn_mgr) { &AllStatus::HandleServerConnectionEvent)); } -void AllStatus::WatchAuthenticator(GaiaAuthenticator* gaia) { +void AllStatus::WatchAuthenticator(gaia::GaiaAuthenticator* gaia) { gaia_hookup_.reset(NewEventListenerHookup(gaia->channel(), this, &AllStatus::HandleGaiaAuthEvent)); } @@ -171,13 +171,13 @@ int AllStatus::CalcStatusChanges(Status* old_status) { return what_changed; } -void AllStatus::HandleGaiaAuthEvent(const GaiaAuthEvent& gaia_event) { +void AllStatus::HandleGaiaAuthEvent(const gaia::GaiaAuthEvent& gaia_event) { ScopedStatusLockWithNotify lock(this); switch (gaia_event.what_happened) { - case GaiaAuthEvent::GAIA_AUTH_FAILED: + case gaia::GaiaAuthEvent::GAIA_AUTH_FAILED: status_.authenticated = false; break; - case GaiaAuthEvent::GAIA_AUTH_SUCCEEDED: + case gaia::GaiaAuthEvent::GAIA_AUTH_SUCCEEDED: status_.authenticated = true; break; default: diff --git a/chrome/browser/sync/engine/all_status.h b/chrome/browser/sync/engine/all_status.h index 3cd74cc..3e70119 100644 --- a/chrome/browser/sync/engine/all_status.h +++ b/chrome/browser/sync/engine/all_status.h @@ -15,6 +15,11 @@ #include "base/scoped_ptr.h" #include "chrome/common/deprecated/event_sys.h" +namespace gaia { +class GaiaAuthenticator; +struct GaiaAuthEvent; +} + namespace notifier { class TalkMediator; struct TalkMediatorEvent; @@ -23,14 +28,12 @@ struct TalkMediatorEvent; namespace browser_sync { class AuthWatcher; -class GaiaAuthenticator; class ScopedStatusLockWithNotify; class ServerConnectionManager; class Syncer; class SyncerThread; struct AllStatusEvent; struct AuthWatcherEvent; -struct GaiaAuthEvent; struct ServerConnectionEvent; struct SyncerEvent; @@ -106,8 +109,8 @@ class AllStatus { // HandleAuthWatcherEventachieve have the same goal; use only one of the // following two. (The AuthWatcher is watched under Windows; the // GaiaAuthenticator is watched under Mac/Linux.) - void WatchAuthenticator(GaiaAuthenticator* gaia); - void HandleGaiaAuthEvent(const GaiaAuthEvent& event); + void WatchAuthenticator(gaia::GaiaAuthenticator* gaia); + void HandleGaiaAuthEvent(const gaia::GaiaAuthEvent& event); void WatchAuthWatcher(AuthWatcher* auth_watcher); void HandleAuthWatcherEvent(const AuthWatcherEvent& event); diff --git a/chrome/browser/sync/engine/auth_watcher.cc b/chrome/browser/sync/engine/auth_watcher.cc index 7b98439..53c21cf 100644 --- a/chrome/browser/sync/engine/auth_watcher.cc +++ b/chrome/browser/sync/engine/auth_watcher.cc @@ -8,12 +8,12 @@ #include "base/string_util.h" #include "chrome/browser/sync/engine/all_status.h" #include "chrome/browser/sync/engine/authenticator.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/browser/sync/syncable/syncable.h" #include "chrome/browser/sync/util/user_settings.h" #include "chrome/common/deprecated/event_sys-inl.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" #include "chrome/common/net/notifier/listener/talk_mediator.h" // How authentication happens: @@ -45,7 +45,7 @@ AuthWatcher::AuthWatcher(DirectoryManager* dirman, const string& service_id, const string& gaia_url, UserSettings* user_settings, - GaiaAuthenticator* gaia_auth, + gaia::GaiaAuthenticator* gaia_auth, notifier::TalkMediator* talk_mediator) : gaia_(gaia_auth), dirman_(dirman), @@ -71,7 +71,7 @@ AuthWatcher::AuthWatcher(DirectoryManager* dirman, void AuthWatcher::PersistCredentials() { DCHECK_EQ(MessageLoop::current(), message_loop()); - GaiaAuthenticator::AuthResults results = gaia_->results(); + gaia::GaiaAuthenticator::AuthResults results = gaia_->results(); // We just successfully signed in again, let's clear out any residual cached // login data from earlier sessions. @@ -85,7 +85,7 @@ void AuthWatcher::PersistCredentials() { if (!user_settings_->VerifyAgainstStoredHash(results.email, results.password)) user_settings_->StoreHashedPassword(results.email, results.password); - if (PERSIST_TO_DISK == results.credentials_saved) { + if (gaia::PERSIST_TO_DISK == results.credentials_saved) { user_settings_->SetAuthTokenForService(results.email, SYNC_SERVICE_NAME, gaia_->auth_token()); @@ -161,7 +161,7 @@ void AuthWatcher::DoAuthenticateWithToken(const std::string& gaia_email, } AuthWatcherEvent event = {AuthWatcherEvent::ILLEGAL_VALUE , 0}; gaia_->SetUsername(email); - gaia_->SetAuthToken(auth_token, SAVE_IN_MEMORY_ONLY); + gaia_->SetAuthToken(auth_token, gaia::SAVE_IN_MEMORY_ONLY); const bool was_authenticated = NOT_AUTHENTICATED != status_; switch (result) { case Authenticator::SUCCESS: @@ -231,22 +231,23 @@ bool AuthWatcher::AuthenticateLocally(string email, const string& password) { void AuthWatcher::ProcessGaiaAuthFailure() { DCHECK_EQ(MessageLoop::current(), message_loop()); - GaiaAuthenticator::AuthResults results = gaia_->results(); + gaia::GaiaAuthenticator::AuthResults results = gaia_->results(); if (LOCALLY_AUTHENTICATED == status_) { return; // nothing todo } else if (AuthenticateLocally(results.email, results.password)) { // We save the "Remember me" checkbox by putting a non-null auth // token into the last_user table. So if we're offline and the // user checks the box, insert a bogus auth token. - if (PERSIST_TO_DISK == results.credentials_saved) { + if (gaia::PERSIST_TO_DISK == results.credentials_saved) { const string auth_token("bogus"); user_settings_->SetAuthTokenForService(results.email, SYNC_SERVICE_NAME, auth_token); } - const bool unavailable = ConnectionUnavailable == results.auth_error || - Unknown == results.auth_error || - ServiceUnavailable == results.auth_error; + const bool unavailable = + gaia::ConnectionUnavailable == results.auth_error || + gaia::Unknown == results.auth_error || + gaia::ServiceUnavailable == results.auth_error; if (unavailable) return; } @@ -262,10 +263,10 @@ void AuthWatcher::DoAuthenticate(const AuthRequest& request) { current_attempt_trigger_ = request.trigger; - SaveCredentials save = request.persist_creds_to_disk ? - PERSIST_TO_DISK : SAVE_IN_MEMORY_ONLY; - SignIn const signin = user_settings_-> - RecallSigninType(request.email, GMAIL_SIGNIN); + gaia::SaveCredentials save = request.persist_creds_to_disk ? + gaia::PERSIST_TO_DISK : gaia::SAVE_IN_MEMORY_ONLY; + gaia::SignIn const signin = user_settings_-> + RecallSigninType(request.email, gaia::GMAIL_SIGNIN); // We let the caller be lazy and try using the last captcha token seen by // the gaia authenticator if they haven't provided a token but have sent @@ -329,11 +330,12 @@ void AuthWatcher::DoHandleServerConnectionEvent( // the auth failure should trigger UI indications that we're not logged in. // METRIC: If we get a SYNC_AUTH_ERROR, our token expired. - GaiaAuthenticator::AuthResults authresults = gaia_->results(); + gaia::GaiaAuthenticator::AuthResults authresults = gaia_->results(); AuthRequest request = { authresults.email, authresults.password, authresults.auth_token, std::string(), std::string(), - PERSIST_TO_DISK == authresults.credentials_saved, + gaia::PERSIST_TO_DISK == + authresults.credentials_saved, AuthWatcherEvent::EXPIRED_CREDENTIALS }; DoAuthenticate(request); } diff --git a/chrome/browser/sync/engine/auth_watcher.h b/chrome/browser/sync/engine/auth_watcher.h index 149ade3..7ae3f98 100644 --- a/chrome/browser/sync/engine/auth_watcher.h +++ b/chrome/browser/sync/engine/auth_watcher.h @@ -15,10 +15,10 @@ #include "base/ref_counted.h" #include "base/scoped_ptr.h" #include "base/thread.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" #include "chrome/browser/sync/protocol/service_constants.h" #include "chrome/browser/sync/util/sync_types.h" #include "chrome/common/deprecated/event_sys.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" #include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST namespace notifier { @@ -53,7 +53,7 @@ struct AuthWatcherEvent { ILLEGAL_VALUE, }; WhatHappened what_happened; - const GaiaAuthenticator::AuthResults* auth_results; + const gaia::GaiaAuthenticator::AuthResults* auth_results; // use AuthWatcherEvent as its own traits type in hookups. typedef AuthWatcherEvent EventType; static inline bool IsChannelShutdownEvent(const AuthWatcherEvent& event) { @@ -94,7 +94,7 @@ class AuthWatcher : public base::RefCountedThreadSafe { const std::string& service_id, const std::string& gaia_url, UserSettings* user_settings, - GaiaAuthenticator* gaia_auth, + gaia::GaiaAuthenticator* gaia_auth, notifier::TalkMediator* talk_mediator); ~AuthWatcher(); @@ -205,7 +205,7 @@ class AuthWatcher : public base::RefCountedThreadSafe { const ServerConnectionEvent& event, const std::string& auth_token_snapshot); - scoped_ptr const gaia_; + scoped_ptr const gaia_; syncable::DirectoryManager* const dirman_; ServerConnectionManager* const scm_; scoped_ptr connmgr_hookup_; diff --git a/chrome/browser/sync/engine/auth_watcher_unittest.cc b/chrome/browser/sync/engine/auth_watcher_unittest.cc index 601d65f..f314155 100644 --- a/chrome/browser/sync/engine/auth_watcher_unittest.cc +++ b/chrome/browser/sync/engine/auth_watcher_unittest.cc @@ -8,11 +8,11 @@ #include "base/waitable_event.h" #include "chrome/browser/sync/engine/all_status.h" #include "chrome/browser/sync/engine/auth_watcher.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" -#include "chrome/browser/sync/engine/net/http_return.h" #include "chrome/browser/sync/util/user_settings.h" #include "chrome/common/deprecated/event_sys-inl.h" +#include "chrome/common/net/http_return.h" #include "chrome/common/net/notifier/listener/talk_mediator_impl.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" #include "chrome/test/sync/engine/mock_server_connection.h" #include "chrome/test/sync/engine/test_directory_setter_upper.h" #include "testing/gtest/include/gtest/gtest.h" @@ -34,9 +34,9 @@ static const char* kValidAuthToken = "validAuthToken"; namespace browser_sync { -class GaiaAuthMockForAuthWatcher : public browser_sync::GaiaAuthenticator { +class GaiaAuthMockForAuthWatcher : public gaia::GaiaAuthenticator { public: - GaiaAuthMockForAuthWatcher() : browser_sync::GaiaAuthenticator( + GaiaAuthMockForAuthWatcher() : GaiaAuthenticator( kTestUserAgent, kTestServiceId, kTestGaiaURL), use_bad_auth_token_(false) {} virtual ~GaiaAuthMockForAuthWatcher() {} @@ -55,7 +55,7 @@ class GaiaAuthMockForAuthWatcher : public browser_sync::GaiaAuthenticator { protected: bool PerformGaiaRequest(const AuthParams& params, AuthResults* results) { if (params.password == kWrongPassword) { - results->auth_error = browser_sync::BadAuthentication; + results->auth_error = gaia::BadAuthentication; return false; } if (params.password == kCorrectPassword) { @@ -71,7 +71,7 @@ class GaiaAuthMockForAuthWatcher : public browser_sync::GaiaAuthenticator { } bool LookupEmail(AuthResults* results) { - results->signin = GMAIL_SIGNIN; + results->signin = gaia::GMAIL_SIGNIN; return true; } diff --git a/chrome/browser/sync/engine/authenticator.cc b/chrome/browser/sync/engine/authenticator.cc index 48f64fe..f8b3ce1 100644 --- a/chrome/browser/sync/engine/authenticator.cc +++ b/chrome/browser/sync/engine/authenticator.cc @@ -4,12 +4,12 @@ #include "chrome/browser/sync/engine/authenticator.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" #include "chrome/browser/sync/engine/syncproto.h" #include "chrome/browser/sync/protocol/sync.pb.h" #include "chrome/browser/sync/util/user_settings.h" #include "chrome/common/deprecated/event_sys-inl.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" namespace browser_sync { @@ -33,12 +33,12 @@ Authenticator::AuthenticationResult Authenticator::Authenticate( string username, string password, bool save_credentials) { // TODO(sync): need to figure out if this routine is used anywhere other // than the test code. - GaiaAuthenticator auth_service("ChromiumBrowser", "chromiumsync", + gaia::GaiaAuthenticator auth_service("ChromiumBrowser", "chromiumsync", "https://www.google.com:443/accounts/ClientLogin"); auth_service.set_message_loop(MessageLoop::current()); - const SignIn signin_type = - settings_->RecallSigninType(username, GMAIL_SIGNIN); - if (!auth_service.Authenticate(username, password, SAVE_IN_MEMORY_ONLY, + const gaia::SignIn signin_type = + settings_->RecallSigninType(username, gaia::GMAIL_SIGNIN); + if (!auth_service.Authenticate(username, password, gaia::SAVE_IN_MEMORY_ONLY, signin_type)) { return UNSPECIFIC_ERROR_RETURN; } diff --git a/chrome/browser/sync/engine/net/gaia_authenticator.cc b/chrome/browser/sync/engine/net/gaia_authenticator.cc deleted file mode 100644 index 2be47f8..0000000 --- a/chrome/browser/sync/engine/net/gaia_authenticator.cc +++ /dev/null @@ -1,398 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" - -#include -#include -#include - -#include "base/basictypes.h" -#include "base/port.h" -#include "base/string_split.h" -#include "chrome/browser/sync/engine/net/http_return.h" -#include "chrome/common/deprecated/event_sys-inl.h" -#include "googleurl/src/gurl.h" -#include "net/base/escape.h" - -using std::pair; -using std::string; -using std::vector; - -namespace browser_sync { - -static const char kGaiaV1IssueAuthTokenPath[] = "/accounts/IssueAuthToken"; - -static const char kGetUserInfoPath[] = "/accounts/GetUserInfo"; - -// Sole constructor with initializers for all fields. -GaiaAuthenticator::GaiaAuthenticator(const string& user_agent, - const string& service_id, - const string& gaia_url) - : user_agent_(user_agent), - service_id_(service_id), - gaia_url_(gaia_url), - request_count_(0), - delay_(0), - next_allowed_auth_attempt_time_(0), - early_auth_attempt_count_(0), - message_loop_(NULL) { - GaiaAuthEvent done = { GaiaAuthEvent::GAIA_AUTHENTICATOR_DESTROYED, None, - this }; - channel_ = new Channel(done); -} - -GaiaAuthenticator::~GaiaAuthenticator() { - delete channel_; -} - -// mutex_ must be entered before calling this function. -GaiaAuthenticator::AuthParams GaiaAuthenticator::MakeParams( - const string& user_name, - const string& password, - SaveCredentials should_save_credentials, - const string& captcha_token, - const string& captcha_value, - SignIn try_first) { - AuthParams params; - params.request_id = ++request_count_; - params.email = user_name; - params.password = password; - params.should_save_credentials = should_save_credentials; - params.captcha_token = captcha_token; - params.captcha_value = captcha_value; - params.authenticator = this; - params.try_first = try_first; - return params; -} - -bool GaiaAuthenticator::Authenticate(const string& user_name, - const string& password, - SaveCredentials should_save_credentials, - const string& captcha_token, - const string& captcha_value, - SignIn try_first) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - - AuthParams const params = - MakeParams(user_name, password, should_save_credentials, captcha_token, - captcha_value, try_first); - return AuthenticateImpl(params); -} - -bool GaiaAuthenticator::AuthenticateWithLsid(const string& lsid, - bool long_lived) { - auth_results_.lsid = lsid; - // We need to lookup the email associated with this LSID cookie in order to - // update |auth_results_| with the correct values. - if (LookupEmail(&auth_results_)) { - auth_results_.email = auth_results_.primary_email; - return IssueAuthToken(&auth_results_, service_id_, long_lived); - } - return false; -} - - -bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - AuthResults results; - const bool succeeded = AuthenticateImpl(params, &results); - if (params.request_id == request_count_) { - auth_results_ = results; - GaiaAuthEvent event = { succeeded ? GaiaAuthEvent::GAIA_AUTH_SUCCEEDED - : GaiaAuthEvent::GAIA_AUTH_FAILED, - results.auth_error, this }; - channel_->NotifyListeners(event); - } - return succeeded; -} - -// This method makes an HTTP request to the Gaia server, and calls other -// methods to help parse the response. If authentication succeeded, then -// Gaia-issued cookies are available in the respective variables; if -// authentication failed, then the exact error is available as an enum. If the -// client wishes to save the credentials, the last parameter must be true. -// If a subsequent request is made with fresh credentials, the saved credentials -// are wiped out; any subsequent request to the zero-parameter overload of this -// method preserves the saved credentials. -bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params, - AuthResults* results) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - results->credentials_saved = params.should_save_credentials; - results->auth_error = ConnectionUnavailable; - // Save credentials if so requested. - if (params.should_save_credentials != DONT_SAVE_CREDENTIALS) { - results->email = params.email.data(); - results->password = params.password; - } else { // Explicitly clear previously-saved credentials. - results->email = ""; - results->password = ""; - } - - // The aim of this code is to start failing requests if due to a logic error - // in the program we're hammering GAIA. - time_t now = time(0); - if (now > next_allowed_auth_attempt_time_) { - next_allowed_auth_attempt_time_ = now + 1; - // If we're more than 2 minutes past the allowed time we reset the early - // attempt count. - if (now - next_allowed_auth_attempt_time_ > 2 * 60) { - delay_ = 1; - early_auth_attempt_count_ = 0; - } - } else { - ++early_auth_attempt_count_; - // Allow 3 attempts, but then limit. - if (early_auth_attempt_count_ > 3) { - delay_ = GetBackoffDelaySeconds(delay_); - next_allowed_auth_attempt_time_ = now + delay_; - return false; - } - } - - return PerformGaiaRequest(params, results); -} - -bool GaiaAuthenticator::PerformGaiaRequest(const AuthParams& params, - AuthResults* results) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - GURL gaia_auth_url(gaia_url_); - - string post_body; - post_body += "Email=" + EscapeUrlEncodedData(params.email); - post_body += "&Passwd=" + EscapeUrlEncodedData(params.password); - post_body += "&source=" + EscapeUrlEncodedData(user_agent_); - post_body += "&service=" + service_id_; - if (!params.captcha_token.empty() && !params.captcha_value.empty()) { - post_body += "&logintoken=" + EscapeUrlEncodedData(params.captcha_token); - post_body += "&logincaptcha=" + EscapeUrlEncodedData(params.captcha_value); - } - post_body += "&PersistentCookie=true"; - // We set it to GOOGLE (and not HOSTED or HOSTED_OR_GOOGLE) because we only - // allow consumer logins. - post_body += "&accountType=GOOGLE"; - - string message_text; - unsigned long server_response_code; - if (!Post(gaia_auth_url, post_body, &server_response_code, &message_text)) { - results->auth_error = ConnectionUnavailable; - return false; - } - - // Parse reply in two different ways, depending on if request failed or - // succeeded. - if (RC_FORBIDDEN == server_response_code) { - ExtractAuthErrorFrom(message_text, results); - return false; - } else if (RC_REQUEST_OK == server_response_code) { - ExtractTokensFrom(message_text, results); - const bool old_gaia = - results->auth_token.empty() && !results->lsid.empty(); - const bool long_lived_token = - params.should_save_credentials == PERSIST_TO_DISK; - if ((old_gaia || long_lived_token) && - !IssueAuthToken(results, service_id_, long_lived_token)) - return false; - - return LookupEmail(results); - } else { - results->auth_error = Unknown; - return false; - } -} - -bool GaiaAuthenticator::LookupEmail(AuthResults* results) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - // Use the provided Gaia server, but change the path to what V1 expects. - GURL url(gaia_url_); // Gaia server. - GURL::Replacements repl; - // Needs to stay in scope till GURL is out of scope. - string path(kGetUserInfoPath); - repl.SetPathStr(path); - url = url.ReplaceComponents(repl); - - string post_body; - post_body += "LSID="; - post_body += EscapeUrlEncodedData(results->lsid); - - unsigned long server_response_code; - string message_text; - if (!Post(url, post_body, &server_response_code, &message_text)) { - return false; - } - - // Check if we received a valid AuthToken; if not, ignore it. - if (RC_FORBIDDEN == server_response_code) { - // Server says we're not authenticated. - ExtractAuthErrorFrom(message_text, results); - return false; - } else if (RC_REQUEST_OK == server_response_code) { - typedef vector > Tokens; - Tokens tokens; - base::SplitStringIntoKeyValuePairs(message_text, '=', '\n', &tokens); - for (Tokens::iterator i = tokens.begin(); i != tokens.end(); ++i) { - if ("accountType" == i->first) { - // We never authenticate an email as a hosted account. - DCHECK_EQ("GOOGLE", i->second); - results->signin = GMAIL_SIGNIN; - } else if ("email" == i->first) { - results->primary_email = i->second; - } - } - return true; - } - return false; -} - -// We need to call this explicitly when we need to obtain a long-lived session -// token. -bool GaiaAuthenticator::IssueAuthToken(AuthResults* results, - const string& service_id, - bool long_lived) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - // Use the provided Gaia server, but change the path to what V1 expects. - GURL url(gaia_url_); // Gaia server. - GURL::Replacements repl; - // Needs to stay in scope till GURL is out of scope. - string path(kGaiaV1IssueAuthTokenPath); - repl.SetPathStr(path); - url = url.ReplaceComponents(repl); - - string post_body; - post_body += "LSID="; - post_body += EscapeUrlEncodedData(results->lsid); - post_body += "&service=" + service_id; - if (long_lived) { - post_body += "&Session=true"; - } - - unsigned long server_response_code; - string message_text; - if (!Post(url, post_body, &server_response_code, &message_text)) { - return false; - } - - // Check if we received a valid AuthToken; if not, ignore it. - if (RC_FORBIDDEN == server_response_code) { - // Server says we're not authenticated. - ExtractAuthErrorFrom(message_text, results); - return false; - } else if (RC_REQUEST_OK == server_response_code) { - // Note that the format of message_text is different from what is returned - // in the first request, or to the sole request that is made to Gaia V2. - // Specifically, the entire string is the AuthToken, and looks like: - // "" rather than "AuthToken=". Thus, we need not use - // ExtractTokensFrom(...), but simply assign the token. - int last_index = message_text.length() - 1; - if ('\n' == message_text[last_index]) - message_text.erase(last_index); - results->auth_token = message_text; - return true; - } - return false; -} - -// Helper method that extracts tokens from a successful reply, and saves them -// in the right fields. -void GaiaAuthenticator::ExtractTokensFrom(const string& response, - AuthResults* results) { - vector > tokens; - base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); - for (vector >::iterator i = tokens.begin(); - i != tokens.end(); ++i) { - if (i->first == "SID") { - results->sid = i->second; - } else if (i->first == "LSID") { - results->lsid = i->second; - } else if (i->first == "Auth") { - results->auth_token = i->second; - } - } -} - -// Helper method that extracts tokens from a failure response, and saves them -// in the right fields. -void GaiaAuthenticator::ExtractAuthErrorFrom(const string& response, - AuthResults* results) { - vector > tokens; - base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); - for (vector >::iterator i = tokens.begin(); - i != tokens.end(); ++i) { - if (i->first == "Error") { - results->error_msg = i->second; - } else if (i->first == "Url") { - results->auth_error_url = i->second; - } else if (i->first == "CaptchaToken") { - results->captcha_token = i->second; - } else if (i->first == "CaptchaUrl") { - results->captcha_url = i->second; - } - } - - // Convert string error messages to enum values. Each case has two different - // strings; the first one is the most current and the second one is - // deprecated, but available. - const string& error_msg = results->error_msg; - if (error_msg == "BadAuthentication" || error_msg == "badauth") { - results->auth_error = BadAuthentication; - } else if (error_msg == "NotVerified" || error_msg == "nv") { - results->auth_error = NotVerified; - } else if (error_msg == "TermsNotAgreed" || error_msg == "tna") { - results->auth_error = TermsNotAgreed; - } else if (error_msg == "Unknown" || error_msg == "unknown") { - results->auth_error = Unknown; - } else if (error_msg == "AccountDeleted" || error_msg == "adel") { - results->auth_error = AccountDeleted; - } else if (error_msg == "AccountDisabled" || error_msg == "adis") { - results->auth_error = AccountDisabled; - } else if (error_msg == "CaptchaRequired" || error_msg == "cr") { - results->auth_error = CaptchaRequired; - } else if (error_msg == "ServiceUnavailable" || error_msg == "ire") { - results->auth_error = ServiceUnavailable; - } -} - -// Reset all stored credentials, perhaps in preparation for letting a different -// user sign in. -void GaiaAuthenticator::ResetCredentials() { - DCHECK_EQ(MessageLoop::current(), message_loop_); - AuthResults blank; - auth_results_ = blank; -} - -void GaiaAuthenticator::SetUsernamePassword(const string& username, - const string& password) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - auth_results_.password = password; - auth_results_.email = username; -} - -void GaiaAuthenticator::SetUsername(const string& username) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - auth_results_.email = username; -} - -void GaiaAuthenticator::RenewAuthToken(const string& auth_token) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - DCHECK(!this->auth_token().empty()); - auth_results_.auth_token = auth_token; -} -void GaiaAuthenticator::SetAuthToken(const string& auth_token, - SaveCredentials save) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - auth_results_.auth_token = auth_token; - auth_results_.credentials_saved = save; -} - -bool GaiaAuthenticator::Authenticate(const string& user_name, - const string& password, - SaveCredentials should_save_credentials, - SignIn try_first) { - DCHECK_EQ(MessageLoop::current(), message_loop_); - const string empty; - return Authenticate(user_name, password, should_save_credentials, empty, - empty, try_first); -} - -} // namespace browser_sync diff --git a/chrome/browser/sync/engine/net/gaia_authenticator.h b/chrome/browser/sync/engine/net/gaia_authenticator.h deleted file mode 100644 index a489cca..0000000 --- a/chrome/browser/sync/engine/net/gaia_authenticator.h +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// Use this class to authenticate users with Gaia and access cookies sent -// by the Gaia servers. This class lives on the SyncEngine_AuthWatcherThread. -// -// Sample usage: -// GaiaAuthenticator gaia_auth("User-Agent", SYNC_SERVICE_NAME, -// browser_sync::kExternalGaiaUrl); -// if (gaia_auth.Authenticate("email", "passwd", SAVE_IN_MEMORY_ONLY, -// true)) { // Synchronous -// // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(), -// // or gaia_auth.lsid() -// } -// -// Credentials can also be preserved for subsequent requests, though these are -// saved in plain-text in memory, and not very secure on client systems. The -// email address associated with the Gaia account can be read; the password is -// write-only. - -#ifndef CHROME_BROWSER_SYNC_ENGINE_NET_GAIA_AUTHENTICATOR_H_ -#define CHROME_BROWSER_SYNC_ENGINE_NET_GAIA_AUTHENTICATOR_H_ - -#include - -#include "base/basictypes.h" -#include "base/message_loop.h" -#include "chrome/browser/sync/util/signin.h" -#include "chrome/common/deprecated/event_sys.h" -#include "googleurl/src/gurl.h" -#include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST - -namespace browser_sync { - -static const char kGaiaUrl[] = - "https://www.google.com:443/accounts/ClientLogin"; - -// Use of the following enum is odd. GaiaAuthenticator only looks at -// and DONT_SAVE_CREDENTIALS and SAVE_IN_MEMORY_ONLY (PERSIST_TO_DISK is == to -// SAVE_IN_MEMORY_ONLY for GaiaAuthenticator). The sync engine never uses -// DONT_SAVE_CREDENTIALS. AuthWatcher does look in GaiaAuthenticator's results -// object to decide if it should save credentials to disk. This currently -// works so I'm leaving the odd dance alone. - -enum SaveCredentials { - DONT_SAVE_CREDENTIALS, - SAVE_IN_MEMORY_ONLY, - PERSIST_TO_DISK // Saved in both memory and disk -}; - -// Error codes from Gaia. These will be set correctly for both Gaia V1 -// (/ClientAuth) and V2 (/ClientLogin) -enum AuthenticationError { - None = 0, - BadAuthentication = 1, - NotVerified = 2, - TermsNotAgreed = 3, - Unknown = 4, - AccountDeleted = 5, - AccountDisabled = 6, - CaptchaRequired = 7, - ServiceUnavailable = 8, - // Errors generated by this class not Gaia. - CredentialsNotSet = 9, - ConnectionUnavailable = 10 -}; - -class GaiaAuthenticator; - -struct GaiaAuthEvent { - enum { - GAIA_AUTH_FAILED, - GAIA_AUTH_SUCCEEDED, - GAIA_AUTHENTICATOR_DESTROYED - } - what_happened; - AuthenticationError error; - const GaiaAuthenticator* authenticator; - - // Lets us use GaiaAuthEvent as its own traits type in hookups. - typedef GaiaAuthEvent EventType; - static inline bool IsChannelShutdownEvent(const GaiaAuthEvent& event) { - return event.what_happened == GAIA_AUTHENTICATOR_DESTROYED; - } -}; - -// GaiaAuthenticator can be used to pass user credentials to Gaia and obtain -// cookies set by the Gaia servers. -class GaiaAuthenticator { - FRIEND_TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved); - public: - - // Since GaiaAuthenticator can be used for any service, or by any client, you - // must include a user-agent and a service-id when creating one. The - // user_agent is a short string used for simple log analysis. gaia_url is used - // to choose the server to authenticate with (e.g. - // http://www.google.com/accounts/ClientLogin). - GaiaAuthenticator(const std::string& user_agent, - const std::string& service_id, - const std::string& gaia_url); - - virtual ~GaiaAuthenticator(); - - // This object should only be invoked from the AuthWatcherThread message - // loop, which is injected here. - void set_message_loop(const MessageLoop* loop) { - message_loop_ = loop; - } - - // Pass credentials to authenticate with, or use saved credentials via an - // overload. If authentication succeeds, you can retrieve the authentication - // token via the respective accessors. Returns a boolean indicating whether - // authentication succeeded or not. - bool Authenticate(const std::string& user_name, const std::string& password, - SaveCredentials should_save_credentials, - const std::string& captcha_token, - const std::string& captcha_value, - SignIn try_first); - - bool Authenticate(const std::string& user_name, const std::string& password, - SaveCredentials should_save_credentials, - SignIn try_first); - - // Pass the LSID to authenticate with. If the authentication succeeds, you can - // retrieve the authetication token via the respective accessors. Returns a - // boolean indicating whether authentication succeeded or not. - bool AuthenticateWithLsid(const std::string& lsid, bool long_lived_token); - - // Resets all stored cookies to their default values. - void ResetCredentials(); - - void SetUsernamePassword(const std::string& username, - const std::string& password); - - void SetUsername(const std::string& username); - - // Virtual for testing - virtual void RenewAuthToken(const std::string& auth_token); - void SetAuthToken(const std::string& auth_token, SaveCredentials); - - struct AuthResults { - SaveCredentials credentials_saved; - std::string email; - std::string password; - - // Fields that store various cookies. - std::string sid; - std::string lsid; - std::string auth_token; - - std::string primary_email; - - // Fields for items returned when authentication fails. - std::string error_msg; - enum AuthenticationError auth_error; - std::string auth_error_url; - std::string captcha_token; - std::string captcha_url; - SignIn signin; - - // TODO(skrul): When auth fails, the "signin" field of the results - // struct never gets set, which causes valgrind to complain. Give - // this field a value here so the error is suppressed. It turns - // out that the signin field has only one possible value, so the - // correct fix here would be to to remove it entirely. - AuthResults() : credentials_saved(DONT_SAVE_CREDENTIALS), - auth_error(None), - signin(GMAIL_SIGNIN) { } - }; - - protected: - - struct AuthParams { - GaiaAuthenticator* authenticator; - uint32 request_id; - SaveCredentials should_save_credentials; - std::string email; - std::string password; - std::string captcha_token; - std::string captcha_value; - SignIn try_first; - }; - - // mutex_ must be entered before calling this function. - AuthParams MakeParams(const std::string& user_name, - const std::string& password, - SaveCredentials should_save_credentials, - const std::string& captcha_token, - const std::string& captcha_value, - SignIn try_first); - - // The real Authenticate implementations. - bool AuthenticateImpl(const AuthParams& params); - bool AuthenticateImpl(const AuthParams& params, AuthResults* results); - - // virtual for testing purposes. - virtual bool PerformGaiaRequest(const AuthParams& params, - AuthResults* results); - virtual bool Post(const GURL& url, const std::string& post_body, - unsigned long* response_code, std::string* response_body) { - return false; - } - - // Caller should fill in results->LSID before calling. Result in - // results->primary_email. - virtual bool LookupEmail(AuthResults* results); - - // Subclasses must override to provide a backoff delay. It is virtual instead - // of pure virtual for testing purposes. - // TODO(sanjeevr): This should be made pure virtual. But this class is - // currently directly being used in sync/engine/authenticator.cc, which is - // wrong. - virtual int GetBackoffDelaySeconds(int current_backoff_delay) { - NOTREACHED(); - return current_backoff_delay; - } - - public: - // Retrieve email. - inline std::string email() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.email; - } - - // Retrieve password. - inline std::string password() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.password; - } - - // Retrieve AuthToken, if previously authenticated; otherwise returns "". - inline std::string auth_token() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.auth_token; - } - - // Retrieve SID cookie. For details, see the Google Accounts documentation. - inline std::string sid() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.sid; - } - - // Retrieve LSID cookie. For details, see the Google Accounts documentation. - inline std::string lsid() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.lsid; - } - - // Get last authentication error. - inline enum AuthenticationError auth_error() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.auth_error; - } - - inline std::string auth_error_url() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.auth_error_url; - } - - inline std::string captcha_token() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.captcha_token; - } - - inline std::string captcha_url() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_.captcha_url; - } - - inline AuthResults results() const { - DCHECK_EQ(MessageLoop::current(), message_loop_); - return auth_results_; - } - - typedef EventChannel Channel; - - inline Channel* channel() const { - return channel_; - } - - private: - bool IssueAuthToken(AuthResults* results, const std::string& service_id, - bool long_lived_token); - - // Helper method to parse response when authentication succeeds. - void ExtractTokensFrom(const std::string& response, AuthResults* results); - // Helper method to parse response when authentication fails. - void ExtractAuthErrorFrom(const std::string& response, AuthResults* results); - - // Fields for the obvious data items. - const std::string user_agent_; - const std::string service_id_; - const std::string gaia_url_; - - AuthResults auth_results_; - - // When multiple async requests are running, only the one that started most - // recently updates the values. - // - // Note that even though this code was written to handle multiple requests - // simultaneously, the sync code issues auth requests one at a time. - uint32 request_count_; - - Channel* channel_; - - // Used to compute backoff time for next allowed authentication. - int delay_; // In seconds. - // On Windows, time_t is 64-bit by default. Even though we have defined the - // _USE_32BIT_TIME_T preprocessor flag, other libraries including this header - // may not have that preprocessor flag defined resulting in mismatched class - // sizes. So we explicitly define it as 32-bit on Windows. - // TODO(sanjeevr): Change this to to use base::Time -#if defined(OS_WIN) - __time32_t next_allowed_auth_attempt_time_; -#else // defined(OS_WIN) - time_t next_allowed_auth_attempt_time_; -#endif // defined(OS_WIN) - int early_auth_attempt_count_; - - // The message loop all our methods are invoked on. Generally this is the - // SyncEngine_AuthWatcherThread's message loop. - const MessageLoop* message_loop_; -}; - -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_ENGINE_NET_GAIA_AUTHENTICATOR_H_ diff --git a/chrome/browser/sync/engine/net/gaia_authenticator_unittest.cc b/chrome/browser/sync/engine/net/gaia_authenticator_unittest.cc deleted file mode 100644 index 6955a0a..0000000 --- a/chrome/browser/sync/engine/net/gaia_authenticator_unittest.cc +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" - -#include - -#include "chrome/browser/sync/engine/net/http_return.h" -#include "googleurl/src/gurl.h" -#include "testing/gtest/include/gtest/gtest.h" - -using std::string; - -namespace browser_sync { - -class GaiaAuthenticatorTest : public testing::Test { }; - -class GaiaAuthMockForGaiaAuthenticator : public GaiaAuthenticator { - public: - GaiaAuthMockForGaiaAuthenticator() - : GaiaAuthenticator("useragent", "serviceid", "http://gaia_url") {} - ~GaiaAuthMockForGaiaAuthenticator() {} - protected: - bool Post(const GURL& url, const string& post_body, - unsigned long* response_code, string* response_body) { - *response_code = RC_REQUEST_OK; - response_body->assign("body\n"); - return true; - } - - int GetBackoffDelaySeconds( - int current_backoff_delay) { - // Dummy delay value. - return 5; - } -}; - -TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved) { - GaiaAuthMockForGaiaAuthenticator mock_auth; - MessageLoop message_loop; - mock_auth.set_message_loop(&message_loop); - GaiaAuthenticator::AuthResults results; - EXPECT_TRUE(mock_auth.IssueAuthToken(&results, "sid", true)); - EXPECT_EQ(0, results.auth_token.compare("body")); -} - -} // namespace browser_sync diff --git a/chrome/browser/sync/engine/net/http_return.h b/chrome/browser/sync/engine/net/http_return.h deleted file mode 100644 index fd5167b..0000000 --- a/chrome/browser/sync/engine/net/http_return.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SYNC_ENGINE_NET_HTTP_RETURN_H_ -#define CHROME_BROWSER_SYNC_ENGINE_NET_HTTP_RETURN_H_ - -namespace browser_sync { -enum HTTPReturnCode { - RC_REQUEST_OK = 200, - RC_UNAUTHORIZED = 401, - RC_FORBIDDEN = 403, -}; -} // namespace browser_sync - -#endif // CHROME_BROWSER_SYNC_ENGINE_NET_HTTP_RETURN_H_ diff --git a/chrome/browser/sync/engine/net/server_connection_manager.cc b/chrome/browser/sync/engine/net/server_connection_manager.cc index 225e3fb..7fbd9da 100644 --- a/chrome/browser/sync/engine/net/server_connection_manager.cc +++ b/chrome/browser/sync/engine/net/server_connection_manager.cc @@ -11,7 +11,6 @@ #include #include "build/build_config.h" -#include "chrome/browser/sync/engine/net/http_return.h" #include "chrome/browser/sync/engine/net/url_translator.h" #include "chrome/browser/sync/engine/syncapi.h" #include "chrome/browser/sync/engine/syncer.h" @@ -19,6 +18,7 @@ #include "chrome/browser/sync/protocol/sync.pb.h" #include "chrome/browser/sync/syncable/directory_manager.h" #include "chrome/common/deprecated/event_sys-inl.h" +#include "chrome/common/net/http_return.h" #include "googleurl/src/gurl.h" namespace browser_sync { diff --git a/chrome/browser/sync/engine/net/server_connection_manager.h b/chrome/browser/sync/engine/net/server_connection_manager.h index 3681d06..05deddd 100644 --- a/chrome/browser/sync/engine/net/server_connection_manager.h +++ b/chrome/browser/sync/engine/net/server_connection_manager.h @@ -14,11 +14,11 @@ #include "base/logging.h" #include "base/scoped_ptr.h" #include "base/string_util.h" -#include "chrome/browser/sync/engine/net/http_return.h" #include "chrome/browser/sync/syncable/syncable_id.h" -#include "chrome/browser/sync/util/signin.h" #include "chrome/browser/sync/util/sync_types.h" #include "chrome/common/deprecated/event_sys.h" +#include "chrome/common/net/http_return.h" +#include "chrome/common/net/gaia/signin.h" namespace syncable { class WriteTransaction; @@ -258,7 +258,7 @@ class ServerConnectionManager { const std::string client_id() const { return client_id_; } - void SetDomainFromSignIn(SignIn signin_type, const std::string& signin); + void SetDomainFromSignIn(gaia::SignIn signin_type, const std::string& signin); // This changes the server info used by the connection manager. This allows // a single client instance to talk to different backing servers. This is diff --git a/chrome/browser/sync/engine/net/syncapi_server_connection_manager.cc b/chrome/browser/sync/engine/net/syncapi_server_connection_manager.cc index d5b387e..08e5623 100644 --- a/chrome/browser/sync/engine/net/syncapi_server_connection_manager.cc +++ b/chrome/browser/sync/engine/net/syncapi_server_connection_manager.cc @@ -4,8 +4,8 @@ #include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h" -#include "chrome/browser/sync/engine/net/http_return.h" #include "chrome/browser/sync/engine/syncapi.h" +#include "chrome/common/net/http_return.h" using browser_sync::HttpResponse; using std::string; @@ -50,7 +50,7 @@ bool SyncAPIBridgedPost::Init(const char* path, const string& auth_token, static_cast(http->GetResponseContentLength()); if (response->response_code < 400) response->server_status = HttpResponse::SERVER_CONNECTION_OK; - else if (response->response_code == browser_sync::RC_UNAUTHORIZED) + else if (response->response_code == RC_UNAUTHORIZED) response->server_status = HttpResponse::SYNC_AUTH_ERROR; else response->server_status = HttpResponse::SYNC_SERVER_ERROR; diff --git a/chrome/browser/sync/engine/syncapi.cc b/chrome/browser/sync/engine/syncapi.cc index 1469927..20bfc12 100644 --- a/chrome/browser/sync/engine/syncapi.cc +++ b/chrome/browser/sync/engine/syncapi.cc @@ -42,7 +42,6 @@ #include "chrome/browser/sync/engine/auth_watcher.h" #include "chrome/browser/sync/engine/change_reorder_buffer.h" #include "chrome/browser/sync/engine/model_safe_worker.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" #include "chrome/browser/sync/engine/net/server_connection_manager.h" #include "chrome/browser/sync/engine/net/syncapi_server_connection_manager.h" #include "chrome/browser/sync/engine/syncer.h" @@ -63,6 +62,7 @@ #include "chrome/browser/sync/util/user_settings.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/deprecated/event_sys.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" #include "chrome/common/net/notifier/listener/notification_constants.h" #include "chrome/common/net/notifier/listener/talk_mediator.h" #include "chrome/common/net/notifier/listener/talk_mediator_impl.h" @@ -940,7 +940,7 @@ syncable::BaseTransaction* WriteTransaction::GetWrappedTrans() const { } // A GaiaAuthenticator that uses HttpPostProviders instead of CURL. -class BridgedGaiaAuthenticator : public browser_sync::GaiaAuthenticator { +class BridgedGaiaAuthenticator : public gaia::GaiaAuthenticator { public: BridgedGaiaAuthenticator(const string& user_agent, const string& service_id, const string& gaia_url, @@ -1424,7 +1424,7 @@ bool SyncManager::SyncInternal::Init( // Watch various objects for aggregated status. allstatus()->WatchConnectionManager(connection_manager()); - std::string gaia_url = browser_sync::kGaiaUrl; + std::string gaia_url = gaia::kGaiaUrl; const char* service_id = gaia_service_id ? gaia_service_id : SYNC_SERVICE_NAME; @@ -1961,7 +1961,7 @@ void SyncManager::SyncInternal::HandleAuthWatcherEvent( return; // Authentication failures translate to GoogleServiceAuthError events. case AuthWatcherEvent::GAIA_AUTH_FAILED: // Invalid GAIA credentials. - if (event.auth_results->auth_error == browser_sync::CaptchaRequired) { + if (event.auth_results->auth_error == gaia::CaptchaRequired) { auth_problem_ = AuthError::CAPTCHA_REQUIRED; std::string url_string("https://www.google.com/accounts/"); url_string += event.auth_results->captcha_url; @@ -1971,7 +1971,7 @@ void SyncManager::SyncInternal::HandleAuthWatcherEvent( GURL(event.auth_results->auth_error_url))); return; } else if (event.auth_results->auth_error == - browser_sync::ConnectionUnavailable) { + gaia::ConnectionUnavailable) { auth_problem_ = AuthError::CONNECTION_FAILED; } else { auth_problem_ = AuthError::INVALID_GAIA_CREDENTIALS; diff --git a/chrome/browser/sync/util/signin.h b/chrome/browser/sync/util/signin.h deleted file mode 100644 index 0664d38..0000000 --- a/chrome/browser/sync/util/signin.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_SYNC_UTIL_SIGNIN_H_ -#define CHROME_BROWSER_SYNC_UTIL_SIGNIN_H_ - -// This enumeration is here since we used to support hosted and non-hosted -// accounts, but now only the latter is supported. -enum SignIn { - // The account foo@domain is authenticated as a consumer account. - GMAIL_SIGNIN -}; - -#endif // CHROME_BROWSER_SYNC_UTIL_SIGNIN_H_ diff --git a/chrome/browser/sync/util/user_settings.cc b/chrome/browser/sync/util/user_settings.cc index 9c492e1..043d532 100644 --- a/chrome/browser/sync/util/user_settings.cc +++ b/chrome/browser/sync/util/user_settings.cc @@ -429,8 +429,8 @@ void UserSettings::SwitchUser(const string& username) { } } -void UserSettings::RememberSigninType(const string& signin, SignIn signin_type) -{ +void UserSettings::RememberSigninType(const string& signin, + gaia::SignIn signin_type) { ScopedDBHandle dbhandle(this); SQLStatement statement; statement.prepare(dbhandle.get(), @@ -443,8 +443,8 @@ void UserSettings::RememberSigninType(const string& signin, SignIn signin_type) } } -SignIn UserSettings::RecallSigninType(const string& signin, SignIn default_type) -{ +gaia::SignIn UserSettings::RecallSigninType(const string& signin, + gaia::SignIn default_type) { ScopedDBHandle dbhandle(this); SQLStatement statement; statement.prepare(dbhandle.get(), @@ -453,7 +453,7 @@ SignIn UserSettings::RecallSigninType(const string& signin, SignIn default_type) int query_result = statement.step(); if (SQLITE_ROW == query_result) { int signin_type = statement.column_int(0); - return static_cast(signin_type); + return static_cast(signin_type); } return default_type; } diff --git a/chrome/browser/sync/util/user_settings.h b/chrome/browser/sync/util/user_settings.h index 17de505..e379cc0 100644 --- a/chrome/browser/sync/util/user_settings.h +++ b/chrome/browser/sync/util/user_settings.h @@ -12,8 +12,8 @@ #include "base/file_path.h" #include "base/lock.h" #include "build/build_config.h" -#include "chrome/browser/sync/util/signin.h" #include "chrome/browser/sync/util/sync_types.h" +#include "chrome/common/net/gaia/signin.h" extern "C" struct sqlite3; @@ -59,8 +59,9 @@ class UserSettings { std::string* username, std::string* service_token); - void RememberSigninType(const std::string& signin, SignIn signin_type); - SignIn RecallSigninType(const std::string& signin, SignIn default_type); + void RememberSigninType(const std::string& signin, gaia::SignIn signin_type); + gaia::SignIn RecallSigninType(const std::string& signin, + gaia::SignIn default_type); void RemoveAllGuestSettings(); diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 614521c..a622be2 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -842,9 +842,6 @@ 'browser/sync/engine/model_changing_syncer_command.h', 'browser/sync/engine/model_safe_worker.cc', 'browser/sync/engine/model_safe_worker.h', - 'browser/sync/engine/net/gaia_authenticator.cc', - 'browser/sync/engine/net/gaia_authenticator.h', - 'browser/sync/engine/net/http_return.h', 'browser/sync/engine/net/server_connection_manager.cc', 'browser/sync/engine/net/server_connection_manager.h', 'browser/sync/engine/net/syncapi_server_connection_manager.cc', @@ -920,7 +917,6 @@ 'browser/sync/util/nigori.cc', 'browser/sync/util/nigori.h', 'browser/sync/util/row_iterator.h', - 'browser/sync/util/signin.h', 'browser/sync/util/sync_types.h', 'browser/sync/util/user_settings.cc', 'browser/sync/util/user_settings.h', diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index 93728d5..4845f34 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi @@ -306,6 +306,7 @@ 'type': '<(library)', 'sources': [ 'common/net/dns.h', + 'common/net/http_return.h', 'common/net/net_resource_provider.cc', 'common/net/net_resource_provider.h', 'common/net/network_change_notifier_proxy.cc', @@ -316,6 +317,9 @@ 'common/net/socket_stream.h', 'common/net/url_request_intercept_job.cc', 'common/net/url_request_intercept_job.h', + 'common/net/gaia/gaia_authenticator.cc', + 'common/net/gaia/gaia_authenticator.h', + 'common/net/gaia/signin.h', ], 'dependencies': [ 'chrome_resources', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 016af11..17bbb12 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -979,6 +979,7 @@ 'common/extensions/user_script_unittest.cc', 'common/json_value_serializer_unittest.cc', 'common/mru_cache_unittest.cc', + 'common/net/gaia/gaia_authenticator_unittest.cc', 'common/notification_service_unittest.cc', 'common/process_watcher_unittest.cc', 'common/property_bag_unittest.cc', @@ -1773,7 +1774,6 @@ 'browser/sync/engine/auth_watcher_unittest.cc', 'browser/sync/engine/download_updates_command_unittest.cc', 'browser/sync/engine/mock_model_safe_workers.h', - 'browser/sync/engine/net/gaia_authenticator_unittest.cc', 'browser/sync/engine/process_commit_response_command_unittest.cc', 'browser/sync/engine/syncapi_unittest.cc', 'browser/sync/engine/syncer_proto_util_unittest.cc', diff --git a/chrome/common/net/gaia/gaia_authenticator.cc b/chrome/common/net/gaia/gaia_authenticator.cc new file mode 100644 index 0000000..38fc19b --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator.cc @@ -0,0 +1,404 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/net/gaia/gaia_authenticator.h" + +#include +#include +#include + +#include "base/basictypes.h" +#include "base/port.h" +#include "base/string_split.h" +#include "chrome/common/deprecated/event_sys-inl.h" +#include "chrome/common/net/http_return.h" +#include "googleurl/src/gurl.h" +#include "net/base/escape.h" + +using std::pair; +using std::string; +using std::vector; + +namespace gaia { + +static const char kGaiaV1IssueAuthTokenPath[] = "/accounts/IssueAuthToken"; + +static const char kGetUserInfoPath[] = "/accounts/GetUserInfo"; + +// Sole constructor with initializers for all fields. +GaiaAuthenticator::GaiaAuthenticator(const string& user_agent, + const string& service_id, + const string& gaia_url) + : user_agent_(user_agent), + service_id_(service_id), + gaia_url_(gaia_url), + request_count_(0), + delay_(0), + next_allowed_auth_attempt_time_(0), + early_auth_attempt_count_(0), + message_loop_(NULL) { + GaiaAuthEvent done = { GaiaAuthEvent::GAIA_AUTHENTICATOR_DESTROYED, None, + this }; + channel_ = new Channel(done); +} + +GaiaAuthenticator::~GaiaAuthenticator() { + delete channel_; +} + +// mutex_ must be entered before calling this function. +GaiaAuthenticator::AuthParams GaiaAuthenticator::MakeParams( + const string& user_name, + const string& password, + SaveCredentials should_save_credentials, + const string& captcha_token, + const string& captcha_value, + SignIn try_first) { + AuthParams params; + params.request_id = ++request_count_; + params.email = user_name; + params.password = password; + params.should_save_credentials = should_save_credentials; + params.captcha_token = captcha_token; + params.captcha_value = captcha_value; + params.authenticator = this; + params.try_first = try_first; + return params; +} + +bool GaiaAuthenticator::Authenticate(const string& user_name, + const string& password, + SaveCredentials should_save_credentials, + const string& captcha_token, + const string& captcha_value, + SignIn try_first) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + + AuthParams const params = + MakeParams(user_name, password, should_save_credentials, captcha_token, + captcha_value, try_first); + return AuthenticateImpl(params); +} + +bool GaiaAuthenticator::AuthenticateWithLsid(const string& lsid, + bool long_lived) { + auth_results_.lsid = lsid; + // We need to lookup the email associated with this LSID cookie in order to + // update |auth_results_| with the correct values. + if (LookupEmail(&auth_results_)) { + auth_results_.email = auth_results_.primary_email; + return IssueAuthToken(&auth_results_, service_id_, long_lived); + } + return false; +} + + +bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + AuthResults results; + const bool succeeded = AuthenticateImpl(params, &results); + if (params.request_id == request_count_) { + auth_results_ = results; + GaiaAuthEvent event = { succeeded ? GaiaAuthEvent::GAIA_AUTH_SUCCEEDED + : GaiaAuthEvent::GAIA_AUTH_FAILED, + results.auth_error, this }; + channel_->NotifyListeners(event); + } + return succeeded; +} + +// This method makes an HTTP request to the Gaia server, and calls other +// methods to help parse the response. If authentication succeeded, then +// Gaia-issued cookies are available in the respective variables; if +// authentication failed, then the exact error is available as an enum. If the +// client wishes to save the credentials, the last parameter must be true. +// If a subsequent request is made with fresh credentials, the saved credentials +// are wiped out; any subsequent request to the zero-parameter overload of this +// method preserves the saved credentials. +bool GaiaAuthenticator::AuthenticateImpl(const AuthParams& params, + AuthResults* results) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + results->credentials_saved = params.should_save_credentials; + results->auth_error = ConnectionUnavailable; + // Save credentials if so requested. + if (params.should_save_credentials != DONT_SAVE_CREDENTIALS) { + results->email = params.email.data(); + results->password = params.password; + } else { // Explicitly clear previously-saved credentials. + results->email = ""; + results->password = ""; + } + + // The aim of this code is to start failing requests if due to a logic error + // in the program we're hammering GAIA. +#if defined(OS_WIN) + __time32_t now = _time32(0); +#else // defined(OS_WIN) + time_t now = time(0); +#endif // defined(OS_WIN) + + if (now > next_allowed_auth_attempt_time_) { + next_allowed_auth_attempt_time_ = now + 1; + // If we're more than 2 minutes past the allowed time we reset the early + // attempt count. + if (now - next_allowed_auth_attempt_time_ > 2 * 60) { + delay_ = 1; + early_auth_attempt_count_ = 0; + } + } else { + ++early_auth_attempt_count_; + // Allow 3 attempts, but then limit. + if (early_auth_attempt_count_ > 3) { + delay_ = GetBackoffDelaySeconds(delay_); + next_allowed_auth_attempt_time_ = now + delay_; + return false; + } + } + + return PerformGaiaRequest(params, results); +} + +bool GaiaAuthenticator::PerformGaiaRequest(const AuthParams& params, + AuthResults* results) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + GURL gaia_auth_url(gaia_url_); + + string post_body; + post_body += "Email=" + EscapeUrlEncodedData(params.email); + post_body += "&Passwd=" + EscapeUrlEncodedData(params.password); + post_body += "&source=" + EscapeUrlEncodedData(user_agent_); + post_body += "&service=" + service_id_; + if (!params.captcha_token.empty() && !params.captcha_value.empty()) { + post_body += "&logintoken=" + EscapeUrlEncodedData(params.captcha_token); + post_body += "&logincaptcha=" + EscapeUrlEncodedData(params.captcha_value); + } + post_body += "&PersistentCookie=true"; + // We set it to GOOGLE (and not HOSTED or HOSTED_OR_GOOGLE) because we only + // allow consumer logins. + post_body += "&accountType=GOOGLE"; + + string message_text; + unsigned long server_response_code; + if (!Post(gaia_auth_url, post_body, &server_response_code, &message_text)) { + results->auth_error = ConnectionUnavailable; + return false; + } + + // Parse reply in two different ways, depending on if request failed or + // succeeded. + if (RC_FORBIDDEN == server_response_code) { + ExtractAuthErrorFrom(message_text, results); + return false; + } else if (RC_REQUEST_OK == server_response_code) { + ExtractTokensFrom(message_text, results); + const bool old_gaia = + results->auth_token.empty() && !results->lsid.empty(); + const bool long_lived_token = + params.should_save_credentials == PERSIST_TO_DISK; + if ((old_gaia || long_lived_token) && + !IssueAuthToken(results, service_id_, long_lived_token)) + return false; + + return LookupEmail(results); + } else { + results->auth_error = Unknown; + return false; + } +} + +bool GaiaAuthenticator::LookupEmail(AuthResults* results) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + // Use the provided Gaia server, but change the path to what V1 expects. + GURL url(gaia_url_); // Gaia server. + GURL::Replacements repl; + // Needs to stay in scope till GURL is out of scope. + string path(kGetUserInfoPath); + repl.SetPathStr(path); + url = url.ReplaceComponents(repl); + + string post_body; + post_body += "LSID="; + post_body += EscapeUrlEncodedData(results->lsid); + + unsigned long server_response_code; + string message_text; + if (!Post(url, post_body, &server_response_code, &message_text)) { + return false; + } + + // Check if we received a valid AuthToken; if not, ignore it. + if (RC_FORBIDDEN == server_response_code) { + // Server says we're not authenticated. + ExtractAuthErrorFrom(message_text, results); + return false; + } else if (RC_REQUEST_OK == server_response_code) { + typedef vector > Tokens; + Tokens tokens; + base::SplitStringIntoKeyValuePairs(message_text, '=', '\n', &tokens); + for (Tokens::iterator i = tokens.begin(); i != tokens.end(); ++i) { + if ("accountType" == i->first) { + // We never authenticate an email as a hosted account. + DCHECK_EQ("GOOGLE", i->second); + results->signin = GMAIL_SIGNIN; + } else if ("email" == i->first) { + results->primary_email = i->second; + } + } + return true; + } + return false; +} + +// We need to call this explicitly when we need to obtain a long-lived session +// token. +bool GaiaAuthenticator::IssueAuthToken(AuthResults* results, + const string& service_id, + bool long_lived) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + // Use the provided Gaia server, but change the path to what V1 expects. + GURL url(gaia_url_); // Gaia server. + GURL::Replacements repl; + // Needs to stay in scope till GURL is out of scope. + string path(kGaiaV1IssueAuthTokenPath); + repl.SetPathStr(path); + url = url.ReplaceComponents(repl); + + string post_body; + post_body += "LSID="; + post_body += EscapeUrlEncodedData(results->lsid); + post_body += "&service=" + service_id; + if (long_lived) { + post_body += "&Session=true"; + } + + unsigned long server_response_code; + string message_text; + if (!Post(url, post_body, &server_response_code, &message_text)) { + return false; + } + + // Check if we received a valid AuthToken; if not, ignore it. + if (RC_FORBIDDEN == server_response_code) { + // Server says we're not authenticated. + ExtractAuthErrorFrom(message_text, results); + return false; + } else if (RC_REQUEST_OK == server_response_code) { + // Note that the format of message_text is different from what is returned + // in the first request, or to the sole request that is made to Gaia V2. + // Specifically, the entire string is the AuthToken, and looks like: + // "" rather than "AuthToken=". Thus, we need not use + // ExtractTokensFrom(...), but simply assign the token. + int last_index = message_text.length() - 1; + if ('\n' == message_text[last_index]) + message_text.erase(last_index); + results->auth_token = message_text; + return true; + } + return false; +} + +// Helper method that extracts tokens from a successful reply, and saves them +// in the right fields. +void GaiaAuthenticator::ExtractTokensFrom(const string& response, + AuthResults* results) { + vector > tokens; + base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); + for (vector >::iterator i = tokens.begin(); + i != tokens.end(); ++i) { + if (i->first == "SID") { + results->sid = i->second; + } else if (i->first == "LSID") { + results->lsid = i->second; + } else if (i->first == "Auth") { + results->auth_token = i->second; + } + } +} + +// Helper method that extracts tokens from a failure response, and saves them +// in the right fields. +void GaiaAuthenticator::ExtractAuthErrorFrom(const string& response, + AuthResults* results) { + vector > tokens; + base::SplitStringIntoKeyValuePairs(response, '=', '\n', &tokens); + for (vector >::iterator i = tokens.begin(); + i != tokens.end(); ++i) { + if (i->first == "Error") { + results->error_msg = i->second; + } else if (i->first == "Url") { + results->auth_error_url = i->second; + } else if (i->first == "CaptchaToken") { + results->captcha_token = i->second; + } else if (i->first == "CaptchaUrl") { + results->captcha_url = i->second; + } + } + + // Convert string error messages to enum values. Each case has two different + // strings; the first one is the most current and the second one is + // deprecated, but available. + const string& error_msg = results->error_msg; + if (error_msg == "BadAuthentication" || error_msg == "badauth") { + results->auth_error = BadAuthentication; + } else if (error_msg == "NotVerified" || error_msg == "nv") { + results->auth_error = NotVerified; + } else if (error_msg == "TermsNotAgreed" || error_msg == "tna") { + results->auth_error = TermsNotAgreed; + } else if (error_msg == "Unknown" || error_msg == "unknown") { + results->auth_error = Unknown; + } else if (error_msg == "AccountDeleted" || error_msg == "adel") { + results->auth_error = AccountDeleted; + } else if (error_msg == "AccountDisabled" || error_msg == "adis") { + results->auth_error = AccountDisabled; + } else if (error_msg == "CaptchaRequired" || error_msg == "cr") { + results->auth_error = CaptchaRequired; + } else if (error_msg == "ServiceUnavailable" || error_msg == "ire") { + results->auth_error = ServiceUnavailable; + } +} + +// Reset all stored credentials, perhaps in preparation for letting a different +// user sign in. +void GaiaAuthenticator::ResetCredentials() { + DCHECK_EQ(MessageLoop::current(), message_loop_); + AuthResults blank; + auth_results_ = blank; +} + +void GaiaAuthenticator::SetUsernamePassword(const string& username, + const string& password) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + auth_results_.password = password; + auth_results_.email = username; +} + +void GaiaAuthenticator::SetUsername(const string& username) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + auth_results_.email = username; +} + +void GaiaAuthenticator::RenewAuthToken(const string& auth_token) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + DCHECK(!this->auth_token().empty()); + auth_results_.auth_token = auth_token; +} +void GaiaAuthenticator::SetAuthToken(const string& auth_token, + SaveCredentials save) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + auth_results_.auth_token = auth_token; + auth_results_.credentials_saved = save; +} + +bool GaiaAuthenticator::Authenticate(const string& user_name, + const string& password, + SaveCredentials should_save_credentials, + SignIn try_first) { + DCHECK_EQ(MessageLoop::current(), message_loop_); + const string empty; + return Authenticate(user_name, password, should_save_credentials, empty, + empty, try_first); +} + +} // namepace gaia + diff --git a/chrome/common/net/gaia/gaia_authenticator.h b/chrome/common/net/gaia/gaia_authenticator.h new file mode 100644 index 0000000..b165cf6 --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator.h @@ -0,0 +1,331 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// Use this class to authenticate users with Gaia and access cookies sent +// by the Gaia servers. This class cannot be used on its own becaue it relies +// on a subclass to provide the virtual Post and GetBackoffDelaySeconds methods. +// +// Sample usage: +// class ActualGaiaAuthenticator : public gaia::GaiaAuthenticator { +// Provides actual implementation of Post and GetBackoffDelaySeconds. +// }; +// ActualGaiaAuthenticator gaia_auth("User-Agent", SERVICE_NAME, kGaiaUrl); +// if (gaia_auth.Authenticate("email", "passwd", SAVE_IN_MEMORY_ONLY, +// true)) { // Synchronous +// // Do something with: gaia_auth.auth_token(), or gaia_auth.sid(), +// // or gaia_auth.lsid() +// } +// +// Credentials can also be preserved for subsequent requests, though these are +// saved in plain-text in memory, and not very secure on client systems. The +// email address associated with the Gaia account can be read; the password is +// write-only. + +// TODO(sanjeevr): This class has been moved here from the bookmarks sync code. +// While it is a generic class that handles GAIA authentication, there are some +// artifacts of the sync code such as the SaveCredentials enum which needs to +// be cleaned up. +#ifndef CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_ +#define CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_ + +#include + +#include "base/basictypes.h" +#include "base/message_loop.h" +#include "chrome/common/net/gaia/signin.h" +#include "chrome/common/deprecated/event_sys.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest_prod.h" // For FRIEND_TEST + +namespace gaia { + +static const char kGaiaUrl[] = + "https://www.google.com:443/accounts/ClientLogin"; + +// Use of the following enum is odd. GaiaAuthenticator only looks at +// and DONT_SAVE_CREDENTIALS and SAVE_IN_MEMORY_ONLY (PERSIST_TO_DISK is == to +// SAVE_IN_MEMORY_ONLY for GaiaAuthenticator). + +enum SaveCredentials { + DONT_SAVE_CREDENTIALS, + SAVE_IN_MEMORY_ONLY, + PERSIST_TO_DISK // Saved in both memory and disk +}; + +// Error codes from Gaia. These will be set correctly for both Gaia V1 +// (/ClientAuth) and V2 (/ClientLogin) +enum AuthenticationError { + None = 0, + BadAuthentication = 1, + NotVerified = 2, + TermsNotAgreed = 3, + Unknown = 4, + AccountDeleted = 5, + AccountDisabled = 6, + CaptchaRequired = 7, + ServiceUnavailable = 8, + // Errors generated by this class not Gaia. + CredentialsNotSet = 9, + ConnectionUnavailable = 10 +}; + +class GaiaAuthenticator; + +struct GaiaAuthEvent { + enum { + GAIA_AUTH_FAILED, + GAIA_AUTH_SUCCEEDED, + GAIA_AUTHENTICATOR_DESTROYED + } + what_happened; + AuthenticationError error; + const GaiaAuthenticator* authenticator; + + // Lets us use GaiaAuthEvent as its own traits type in hookups. + typedef GaiaAuthEvent EventType; + static inline bool IsChannelShutdownEvent(const GaiaAuthEvent& event) { + return event.what_happened == GAIA_AUTHENTICATOR_DESTROYED; + } +}; + +// GaiaAuthenticator can be used to pass user credentials to Gaia and obtain +// cookies set by the Gaia servers. +class GaiaAuthenticator { + FRIEND_TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved); + public: + + // Since GaiaAuthenticator can be used for any service, or by any client, you + // must include a user-agent and a service-id when creating one. The + // user_agent is a short string used for simple log analysis. gaia_url is used + // to choose the server to authenticate with (e.g. + // http://www.google.com/accounts/ClientLogin). + GaiaAuthenticator(const std::string& user_agent, + const std::string& service_id, + const std::string& gaia_url); + + virtual ~GaiaAuthenticator(); + + // This object should only be invoked from the AuthWatcherThread message + // loop, which is injected here. + void set_message_loop(const MessageLoop* loop) { + message_loop_ = loop; + } + + // Pass credentials to authenticate with, or use saved credentials via an + // overload. If authentication succeeds, you can retrieve the authentication + // token via the respective accessors. Returns a boolean indicating whether + // authentication succeeded or not. + bool Authenticate(const std::string& user_name, const std::string& password, + SaveCredentials should_save_credentials, + const std::string& captcha_token, + const std::string& captcha_value, + SignIn try_first); + + bool Authenticate(const std::string& user_name, const std::string& password, + SaveCredentials should_save_credentials, + SignIn try_first); + + // Pass the LSID to authenticate with. If the authentication succeeds, you can + // retrieve the authetication token via the respective accessors. Returns a + // boolean indicating whether authentication succeeded or not. + bool AuthenticateWithLsid(const std::string& lsid, bool long_lived_token); + + // Resets all stored cookies to their default values. + void ResetCredentials(); + + void SetUsernamePassword(const std::string& username, + const std::string& password); + + void SetUsername(const std::string& username); + + // Virtual for testing + virtual void RenewAuthToken(const std::string& auth_token); + void SetAuthToken(const std::string& auth_token, SaveCredentials); + + struct AuthResults { + SaveCredentials credentials_saved; + std::string email; + std::string password; + + // Fields that store various cookies. + std::string sid; + std::string lsid; + std::string auth_token; + + std::string primary_email; + + // Fields for items returned when authentication fails. + std::string error_msg; + enum AuthenticationError auth_error; + std::string auth_error_url; + std::string captcha_token; + std::string captcha_url; + SignIn signin; + + // TODO(skrul): When auth fails, the "signin" field of the results + // struct never gets set, which causes valgrind to complain. Give + // this field a value here so the error is suppressed. It turns + // out that the signin field has only one possible value, so the + // correct fix here would be to to remove it entirely. + AuthResults() : credentials_saved(DONT_SAVE_CREDENTIALS), + auth_error(None), + signin(GMAIL_SIGNIN) { } + }; + + protected: + + struct AuthParams { + GaiaAuthenticator* authenticator; + uint32 request_id; + SaveCredentials should_save_credentials; + std::string email; + std::string password; + std::string captcha_token; + std::string captcha_value; + SignIn try_first; + }; + + // mutex_ must be entered before calling this function. + AuthParams MakeParams(const std::string& user_name, + const std::string& password, + SaveCredentials should_save_credentials, + const std::string& captcha_token, + const std::string& captcha_value, + SignIn try_first); + + // The real Authenticate implementations. + bool AuthenticateImpl(const AuthParams& params); + bool AuthenticateImpl(const AuthParams& params, AuthResults* results); + + // virtual for testing purposes. + virtual bool PerformGaiaRequest(const AuthParams& params, + AuthResults* results); + virtual bool Post(const GURL& url, const std::string& post_body, + unsigned long* response_code, std::string* response_body) { + return false; + } + + // Caller should fill in results->LSID before calling. Result in + // results->primary_email. + virtual bool LookupEmail(AuthResults* results); + + // Subclasses must override to provide a backoff delay. It is virtual instead + // of pure virtual for testing purposes. + // TODO(sanjeevr): This should be made pure virtual. But this class is + // currently directly being used in sync/engine/authenticator.cc, which is + // wrong. + virtual int GetBackoffDelaySeconds(int current_backoff_delay) { + NOTREACHED(); + return current_backoff_delay; + } + + public: + // Retrieve email. + inline std::string email() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.email; + } + + // Retrieve password. + inline std::string password() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.password; + } + + // Retrieve AuthToken, if previously authenticated; otherwise returns "". + inline std::string auth_token() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.auth_token; + } + + // Retrieve SID cookie. For details, see the Google Accounts documentation. + inline std::string sid() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.sid; + } + + // Retrieve LSID cookie. For details, see the Google Accounts documentation. + inline std::string lsid() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.lsid; + } + + // Get last authentication error. + inline enum AuthenticationError auth_error() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.auth_error; + } + + inline std::string auth_error_url() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.auth_error_url; + } + + inline std::string captcha_token() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.captcha_token; + } + + inline std::string captcha_url() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_.captcha_url; + } + + inline AuthResults results() const { + DCHECK_EQ(MessageLoop::current(), message_loop_); + return auth_results_; + } + + typedef EventChannel Channel; + + inline Channel* channel() const { + return channel_; + } + + private: + bool IssueAuthToken(AuthResults* results, const std::string& service_id, + bool long_lived_token); + + // Helper method to parse response when authentication succeeds. + void ExtractTokensFrom(const std::string& response, AuthResults* results); + // Helper method to parse response when authentication fails. + void ExtractAuthErrorFrom(const std::string& response, AuthResults* results); + + // Fields for the obvious data items. + const std::string user_agent_; + const std::string service_id_; + const std::string gaia_url_; + + AuthResults auth_results_; + + // When multiple async requests are running, only the one that started most + // recently updates the values. + // + // Note that even though this code was written to handle multiple requests + // simultaneously, the sync code issues auth requests one at a time. + uint32 request_count_; + + Channel* channel_; + + // Used to compute backoff time for next allowed authentication. + int delay_; // In seconds. + // On Windows, time_t is 64-bit by default. Even though we have defined the + // _USE_32BIT_TIME_T preprocessor flag, other libraries including this header + // may not have that preprocessor flag defined resulting in mismatched class + // sizes. So we explicitly define it as 32-bit on Windows. + // TODO(sanjeevr): Change this to to use base::Time +#if defined(OS_WIN) + __time32_t next_allowed_auth_attempt_time_; +#else // defined(OS_WIN) + time_t next_allowed_auth_attempt_time_; +#endif // defined(OS_WIN) + int early_auth_attempt_count_; + + // The message loop all our methods are invoked on. + const MessageLoop* message_loop_; +}; + +} // namespace gaia +#endif // CHROME_COMMON_NET_GAIA_GAIA_AUTHENTICATOR_H_ + diff --git a/chrome/common/net/gaia/gaia_authenticator_unittest.cc b/chrome/common/net/gaia/gaia_authenticator_unittest.cc new file mode 100644 index 0000000..1f9813d --- /dev/null +++ b/chrome/common/net/gaia/gaia_authenticator_unittest.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/common/net/gaia/gaia_authenticator.h" + +#include + +#include "chrome/common/net/http_return.h" +#include "googleurl/src/gurl.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::string; + +namespace gaia { + +class GaiaAuthenticatorTest : public testing::Test { }; + +class GaiaAuthMockForGaiaAuthenticator : public GaiaAuthenticator { + public: + GaiaAuthMockForGaiaAuthenticator() + : GaiaAuthenticator("useragent", "serviceid", "http://gaia_url") {} + ~GaiaAuthMockForGaiaAuthenticator() {} + protected: + bool Post(const GURL& url, const string& post_body, + unsigned long* response_code, string* response_body) { + *response_code = RC_REQUEST_OK; + response_body->assign("body\n"); + return true; + } + + int GetBackoffDelaySeconds( + int current_backoff_delay) { + // Dummy delay value. + return 5; + } +}; + +TEST(GaiaAuthenticatorTest, TestNewlineAtEndOfAuthTokenRemoved) { + GaiaAuthMockForGaiaAuthenticator mock_auth; + MessageLoop message_loop; + mock_auth.set_message_loop(&message_loop); + GaiaAuthenticator::AuthResults results; + EXPECT_TRUE(mock_auth.IssueAuthToken(&results, "sid", true)); + EXPECT_EQ(0, results.auth_token.compare("body")); +} + +} // namespace gaia + diff --git a/chrome/common/net/gaia/signin.h b/chrome/common/net/gaia/signin.h new file mode 100644 index 0000000..48f3654 --- /dev/null +++ b/chrome/common/net/gaia/signin.h @@ -0,0 +1,18 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_NET_GAIA_SIGNIN_H_ +#define CHROME_COMMON_NET_GAIA_SIGNIN_H_ + +namespace gaia { +// This enumeration is here since we used to support hosted and non-hosted +// accounts, but now only the latter is supported. +enum SignIn { + // The account foo@domain is authenticated as a consumer account. + GMAIL_SIGNIN +}; + +} // namespace gaia +#endif // CHROME_COMMON_NET_GAIA_SIGNIN_H_ + diff --git a/chrome/common/net/http_return.h b/chrome/common/net/http_return.h new file mode 100644 index 0000000..f47d1bb --- /dev/null +++ b/chrome/common/net/http_return.h @@ -0,0 +1,17 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_NET_HTTP_RETURN_H_ +#define CHROME_COMMON_NET_HTTP_RETURN_H_ + +// TODO(sanjeevr): This has been moved from the sync library so it only +// contains a few HTTP return codes. Add more HTTP return codes. +enum HTTPReturnCode { + RC_REQUEST_OK = 200, + RC_UNAUTHORIZED = 401, + RC_FORBIDDEN = 403, +}; + +#endif // CHROME_COMMON_NET_HTTP_RETURN_H_ + diff --git a/chrome/test/sync/engine/mock_gaia_authenticator.cc b/chrome/test/sync/engine/mock_gaia_authenticator.cc index 867da59..ebcf566 100644 --- a/chrome/test/sync/engine/mock_gaia_authenticator.cc +++ b/chrome/test/sync/engine/mock_gaia_authenticator.cc @@ -29,7 +29,8 @@ void MockGaiaAuthenticator::AddMockUser(MockUser mock_user) { // A convenience method to add a mock user to internal list of users. void MockGaiaAuthenticator::AddMockUser(string email, string passwd, string auth_token, string lsid, - string sid, enum AuthenticationError + string sid, + enum gaia::AuthenticationError auth_error, string error_url, string captcha_token, string captcha_url) { @@ -49,7 +50,8 @@ void MockGaiaAuthenticator::AddMockUser(string email, string passwd, // A convenience method to add a mock user to internal list of users. void MockGaiaAuthenticator::AddMockUser(string email, string passwd, string auth_token, string lsid, - string sid, enum AuthenticationError + string sid, + enum gaia::AuthenticationError auth_error) { MockUser mock_user; mock_user.email = email; @@ -96,7 +98,7 @@ bool MockGaiaAuthenticator::Authenticate(const char* email, // Finding a user does not necessarily imply that the user was logged in OK. // Therefore also check if the AuthenticationError is None. - return (mock_credentials_[current_user_].auth_error == None); + return (mock_credentials_[current_user_].auth_error == gaia::None); } // Remove any stored knowledge about the currently logged-in user, but keep diff --git a/chrome/test/sync/engine/mock_gaia_authenticator.h b/chrome/test/sync/engine/mock_gaia_authenticator.h index 1968200..7eff11a 100644 --- a/chrome/test/sync/engine/mock_gaia_authenticator.h +++ b/chrome/test/sync/engine/mock_gaia_authenticator.h @@ -29,7 +29,7 @@ #include "base/port.h" #include "base/basictypes.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" namespace browser_sync { @@ -42,7 +42,7 @@ typedef struct { std::string auth_token; std::string sid; std::string lsid; - AuthenticationError auth_error; + gaia::AuthenticationError auth_error; std::string captcha_token; std::string captcha_url; std::string error_url; @@ -66,7 +66,7 @@ class MockGaiaAuthenticator { void AddMockUser(std::string email, std::string passwd, std::string auth_token, std::string lsid, std::string sid, - AuthenticationError auth_error, + gaia::AuthenticationError auth_error, std::string error_url, std::string captcha_token, std::string captcha_url); @@ -76,7 +76,7 @@ class MockGaiaAuthenticator { void AddMockUser(std::string email, std::string passwd, std::string auth_token, std::string lsid, std::string sid, - enum AuthenticationError auth_error); + enum gaia::AuthenticationError auth_error); // Removes a mock user from the current list of added users. void RemoveMockUser(const char* email); @@ -115,8 +115,8 @@ class MockGaiaAuthenticator { mock_credentials_[current_user_].lsid; } - AuthenticationError auth_error() { - return (current_user_.length() == 0) ? CredentialsNotSet : + gaia::AuthenticationError auth_error() { + return (current_user_.length() == 0) ? gaia::CredentialsNotSet : mock_credentials_[current_user_].auth_error; } diff --git a/chrome/test/sync/engine/mock_gaia_authenticator_unittest.cc b/chrome/test/sync/engine/mock_gaia_authenticator_unittest.cc index 76c08aa..cf0b994 100644 --- a/chrome/test/sync/engine/mock_gaia_authenticator_unittest.cc +++ b/chrome/test/sync/engine/mock_gaia_authenticator_unittest.cc @@ -6,8 +6,8 @@ #include "base/basictypes.h" #include "base/port.h" -#include "chrome/browser/sync/engine/net/gaia_authenticator.h" #include "chrome/browser/sync/protocol/service_constants.h" +#include "chrome/common/net/gaia/gaia_authenticator.h" #include "chrome/test/sync/engine/mock_gaia_authenticator.h" #include "testing/gtest/include/gtest/gtest.h" @@ -26,7 +26,7 @@ TEST(MockGaiaAuthenticatorTest, TestAuthenticationSuccess) { mock_user.auth_token = "SomeAuthToken"; mock_user.lsid = "SomeLSID"; mock_user.sid = "SomeSID"; - mock_user.auth_error = browser_sync::None; + mock_user.auth_error = gaia::None; mock_gaia_auth.AddMockUser(mock_user); // Assert away ... @@ -63,7 +63,7 @@ TEST(MockGaiaAuthenticatorTest, TestRemoveMockUser) { // Add our mock user mock_gaia_auth.AddMockUser("test", "passwd", "SomeAuthToken", "SomeLSID", - "SomeSID", browser_sync::None); + "SomeSID", gaia::None); // Make sure authentication succeeds. ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd")); @@ -90,7 +90,7 @@ TEST(MockGaiaAuthenticatorTest, TestRemoveAllMockUsers) { // Add our sample mock user. mock_gaia_auth.AddMockUser("test", "passwd", "SomeAuthToken", "SomeLSID", - "SomeSID", browser_sync::None); + "SomeSID", gaia::None); // Make sure authentication succeeds ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd")); @@ -117,7 +117,7 @@ TEST(MockGaiaAuthenticatorTest, TestSavedCredentials) { // Add our sample mock user. mock_gaia_auth.AddMockUser("test", "passwd", "SomeAuthToken", "SomeLSID", - "SomeSID", browser_sync::None); + "SomeSID", gaia::None); // Ask to save credentials. ASSERT_TRUE(mock_gaia_auth.Authenticate("test", "passwd", true)); -- cgit v1.1