diff options
-rw-r--r-- | chrome/browser/profiles/profile_manager.cc | 4 | ||||
-rw-r--r-- | chrome/browser/signin/account_reconcilor.cc | 210 | ||||
-rw-r--r-- | chrome/browser/signin/account_reconcilor.h | 59 | ||||
-rw-r--r-- | chrome/browser/signin/account_reconcilor_unittest.cc | 34 | ||||
-rw-r--r-- | chrome/browser/signin/signin_manager.cc | 29 | ||||
-rw-r--r-- | chrome/browser/signin/signin_manager.h | 6 | ||||
-rw-r--r-- | google_apis/gaia/gaia_auth_consumer.h | 3 | ||||
-rw-r--r-- | google_apis/gaia/gaia_auth_fetcher.cc | 26 | ||||
-rw-r--r-- | google_apis/gaia/gaia_auth_fetcher.h | 8 | ||||
-rw-r--r-- | google_apis/gaia/gaia_auth_fetcher_unittest.cc | 15 | ||||
-rw-r--r-- | google_apis/gaia/gaia_urls.cc | 6 | ||||
-rw-r--r-- | google_apis/gaia/gaia_urls.h | 2 |
12 files changed, 343 insertions, 59 deletions
diff --git a/chrome/browser/profiles/profile_manager.cc b/chrome/browser/profiles/profile_manager.cc index c598ee2..d05e25c 100644 --- a/chrome/browser/profiles/profile_manager.cc +++ b/chrome/browser/profiles/profile_manager.cc @@ -33,6 +33,7 @@ #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/profiles/startup_task_runner_service.h" #include "chrome/browser/profiles/startup_task_runner_service_factory.h" +#include "chrome/browser/signin/account_reconcilor_factory.h" #include "chrome/browser/sync/profile_sync_service.h" #include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/ui/browser.h" @@ -818,6 +819,9 @@ void ProfileManager::DoFinalInitForServices(Profile* profile, // Start the deferred task runners once the profile is loaded. StartupTaskRunnerServiceFactory::GetForProfile(profile)-> StartDeferredTaskRunners(); + + if (profiles::IsNewProfileManagementEnabled()) + AccountReconcilorFactory::GetForProfile(profile); } void ProfileManager::DoFinalInitLogging(Profile* profile) { diff --git a/chrome/browser/signin/account_reconcilor.cc b/chrome/browser/signin/account_reconcilor.cc index f54e15d..9dccc40 100644 --- a/chrome/browser/signin/account_reconcilor.cc +++ b/chrome/browser/signin/account_reconcilor.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/json/json_reader.h" #include "base/logging.h" #include "base/time/time.h" #include "chrome/browser/chrome_notification_types.h" @@ -16,21 +17,45 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" +#include "google_apis/gaia/gaia_auth_fetcher.h" +#include "google_apis/gaia/gaia_constants.h" -AccountReconcilor::AccountReconcilor(Profile* profile) : profile_(profile) { +AccountReconcilor::AccountReconcilor(Profile* profile) + : profile_(profile), + are_gaia_accounts_set_(false), + requests_(NULL) { RegisterWithSigninManager(); RegisterWithCookieMonster(); // If this profile is not connected, the reconcilor should do nothing but // wait for the connection. - SigninManagerBase* signin_manager = - SigninManagerFactory::GetForProfile(profile_); - if (!signin_manager->GetAuthenticatedUsername().empty()) { + if (IsProfileConnected()) { RegisterWithTokenService(); StartPeriodicReconciliation(); } } +AccountReconcilor::~AccountReconcilor() { + // Make sure shutdown was called first. + DCHECK(registrar_.IsEmpty()); + DCHECK(!reconciliation_timer_.IsRunning()); + DCHECK(!requests_); +} + +void AccountReconcilor::Shutdown() { + DVLOG(1) << "AccountReconcilor::Shutdown"; + DeleteAccessTokenRequests(); + UnregisterWithSigninManager(); + UnregisterWithTokenService(); + UnregisterWithCookieMonster(); + StopPeriodicReconciliation(); +} + +void AccountReconcilor::DeleteAccessTokenRequests() { + delete[] requests_; + requests_ = NULL; +} + void AccountReconcilor::RegisterWithCookieMonster() { content::Source<Profile> source(profile_); registrar_.Add(this, chrome::NOTIFICATION_COOKIE_CHANGED, source); @@ -66,21 +91,29 @@ void AccountReconcilor::UnregisterWithTokenService() { token_service->RemoveObserver(this); } +bool AccountReconcilor::IsProfileConnected() { + return !SigninManagerFactory::GetForProfile(profile_)-> + GetAuthenticatedUsername().empty(); +} + void AccountReconcilor::StartPeriodicReconciliation() { + DVLOG(1) << "AccountReconcilor::StartPeriodicReconciliation"; // TODO(rogerta): pick appropriate thread and timeout value. reconciliation_timer_.Start( FROM_HERE, - base::TimeDelta::FromMinutes(5), + base::TimeDelta::FromSeconds(300), this, &AccountReconcilor::PeriodicReconciliation); } void AccountReconcilor::StopPeriodicReconciliation() { + DVLOG(1) << "AccountReconcilor::StopPeriodicReconciliation"; reconciliation_timer_.Stop(); } void AccountReconcilor::PeriodicReconciliation() { - PerformReconcileAction(); + DVLOG(1) << "AccountReconcilor::PeriodicReconciliation"; + StartReconcileAction(); } void AccountReconcilor::Observe(int type, @@ -88,10 +121,12 @@ void AccountReconcilor::Observe(int type, const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL: + DVLOG(1) << "AccountReconcilor::Observe: signed in"; RegisterWithTokenService(); StartPeriodicReconciliation(); break; case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: + DVLOG(1) << "AccountReconcilor::Observe: signed out"; UnregisterWithTokenService(); StopPeriodicReconciliation(); break; @@ -106,14 +141,16 @@ void AccountReconcilor::Observe(int type, void AccountReconcilor::OnCookieChanged(ChromeCookieDetails* details) { // TODO(acleung): Filter out cookies by looking at the domain. - // PerformReconcileAction(); + // StartReconcileAction(); } void AccountReconcilor::OnRefreshTokenAvailable(const std::string& account_id) { + DVLOG(1) << "AccountReconcilor::OnRefreshTokenAvailable: " << account_id; PerformMergeAction(account_id); } void AccountReconcilor::OnRefreshTokenRevoked(const std::string& account_id) { + DVLOG(1) << "AccountReconcilor::OnRefreshTokenRevoked: " << account_id; PerformRemoveAction(account_id); } @@ -129,18 +166,157 @@ void AccountReconcilor::PerformRemoveAction(const std::string& account_id) { // TODO(acleung): Implement this: } -void AccountReconcilor::PerformReconcileAction() { - // TODO(acleung): Implement this: +void AccountReconcilor::StartReconcileAction() { + if (!IsProfileConnected()) + return; + + // Reset state for validating gaia cookie. + are_gaia_accounts_set_ = false; + gaia_accounts_.clear(); + GetAccountsFromCookie(); + + // Reset state for validating oauth2 tokens. + primary_account_.clear(); + chrome_accounts_.clear(); + DeleteAccessTokenRequests(); + valid_chrome_accounts_.clear(); + invalid_chrome_accounts_.clear(); + ValidateAccountsFromTokenService(); } -AccountReconcilor::~AccountReconcilor() { - // Make sure shutdown was called first. - DCHECK(registrar_.IsEmpty()); +void AccountReconcilor::GetAccountsFromCookie() { + gaia_fetcher_.reset(new GaiaAuthFetcher(this, GaiaConstants::kChromeSource, + profile_->GetRequestContext())); + gaia_fetcher_->StartListAccounts(); } -void AccountReconcilor::Shutdown() { - UnregisterWithSigninManager(); - UnregisterWithTokenService(); - UnregisterWithCookieMonster(); - StopPeriodicReconciliation(); +void AccountReconcilor::OnListAccountsSuccess(const std::string& data) { + gaia_fetcher_.reset(); + + // Get account information from response data. + gaia_accounts_ = ParseListAccountsData(data); + if (gaia_accounts_.size() > 0) { + DVLOG(1) << "AccountReconcilor::OnListAccountsSuccess: " + << "Gaia " << gaia_accounts_.size() << " accounts, " + << "Primary is '" << gaia_accounts_[0] << "'"; + } else { + DVLOG(1) << "AccountReconcilor::OnListAccountsSuccess: No accounts"; + } + + are_gaia_accounts_set_ = true; + FinishReconcileAction(); +} + +// static +std::vector<std::string> AccountReconcilor::ParseListAccountsData( + const std::string& data) { + std::vector<std::string> account_ids; + + // Parse returned data and make sure we have data. + scoped_ptr<base::Value> value(base::JSONReader::Read(data)); + if (!value) + return account_ids; + + base::ListValue* list; + if (!value->GetAsList(&list) || list->GetSize() < 2) + return account_ids; + + // Get list of account info. + base::ListValue* accounts; + if (!list->GetList(1, &accounts) || accounts == NULL) + return account_ids; + + // Build a vector of accounts from the cookie. Order is important: the first + // account in the list is the primary account. + for (size_t i = 0; i < accounts->GetSize(); ++i) { + base::ListValue* account; + if (accounts->GetList(i, &account) && account != NULL) { + std::string email; + if (account->GetString(3, &email) && !email.empty()) + account_ids.push_back(email); + } + } + + return account_ids; +} + +void AccountReconcilor::OnListAccountsFailure( + const GoogleServiceAuthError& error) { + gaia_fetcher_.reset(); + DVLOG(1) << "AccountReconcilor::OnListAccountsFailure: " << error.ToString(); + + are_gaia_accounts_set_ = true; + FinishReconcileAction(); +} + +void AccountReconcilor::ValidateAccountsFromTokenService() { + primary_account_ = + SigninManagerFactory::GetForProfile(profile_)->GetAuthenticatedUsername(); + DCHECK(!primary_account_.empty()); + + ProfileOAuth2TokenService* token_service = + ProfileOAuth2TokenServiceFactory::GetForProfile(profile_); + chrome_accounts_ = token_service->GetAccounts(); + DCHECK(chrome_accounts_.size() > 0); + + DVLOG(1) << "AccountReconcilor::ValidateAccountsFromTokenService: " + << "Chrome " << chrome_accounts_.size() << " accounts, " + << "Primary is '" << primary_account_ << "'"; + + DCHECK(!requests_); + requests_ = + new scoped_ptr<OAuth2TokenService::Request>[chrome_accounts_.size()]; + for (size_t i = 0; i < chrome_accounts_.size(); ++i) { + requests_[i] = token_service->StartRequest(chrome_accounts_[i], + OAuth2TokenService::ScopeSet(), + this); + } +} + +void AccountReconcilor::OnGetTokenSuccess( + const OAuth2TokenService::Request* request, + const std::string& access_token, + const base::Time& expiration_time) { + DVLOG(1) << "AccountReconcilor::OnGetTokenSuccess: valid " + << request->GetAccountId(); + valid_chrome_accounts_.insert(request->GetAccountId()); + FinishReconcileAction(); +} + +void AccountReconcilor::OnGetTokenFailure( + const OAuth2TokenService::Request* request, + const GoogleServiceAuthError& error) { + DVLOG(1) << "AccountReconcilor::OnGetTokenSuccess: invalid " + << request->GetAccountId(); + invalid_chrome_accounts_.insert(request->GetAccountId()); + FinishReconcileAction(); +} + +void AccountReconcilor::FinishReconcileAction() { + // Make sure that the process of validating the gaia cookie and the oauth2 + // tokens individually is done before proceeding with reconciliation. + if (!are_gaia_accounts_set_ || + (chrome_accounts_.size() != (valid_chrome_accounts_.size() + + invalid_chrome_accounts_.size()))) { + return; + } + + DVLOG(1) << "AccountReconcilor::FinishReconcileAction"; + + bool are_primaries_equal = + gaia_accounts_.size() > 0 && primary_account_ == gaia_accounts_[0]; + bool have_same_accounts = chrome_accounts_.size() == gaia_accounts_.size(); + if (have_same_accounts) { + for (size_t i = 0; i < gaia_accounts_.size(); ++i) { + if (std::find(chrome_accounts_.begin(), chrome_accounts_.end(), + gaia_accounts_[i]) == chrome_accounts_.end()) { + have_same_accounts = false; + break; + } + } + } + + if (!are_primaries_equal || !have_same_accounts) { + // TODO(rogerta): fix things up. + } } diff --git a/chrome/browser/signin/account_reconcilor.h b/chrome/browser/signin/account_reconcilor.h index 7454f36..cf7e9ac 100644 --- a/chrome/browser/signin/account_reconcilor.h +++ b/chrome/browser/signin/account_reconcilor.h @@ -6,16 +6,21 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/memory/scoped_ptr.h" #include "components/browser_context_keyed_service/browser_context_keyed_service.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/oauth2_token_service.h" +class GaiaAuthFetcher; class Profile; struct ChromeCookieDetails; class AccountReconcilor : public BrowserContextKeyedService, content::NotificationObserver, + GaiaAuthConsumer, + OAuth2TokenService::Consumer, OAuth2TokenService::Observer { public: explicit AccountReconcilor(Profile* profile); @@ -31,6 +36,9 @@ class AccountReconcilor : public BrowserContextKeyedService, } private: + class AccountReconcilorTest; + FRIEND_TEST_ALL_PREFIXES(AccountReconcilorTest, ParseListAccountsData); + // Register and unregister with dependent services. void RegisterWithCookieMonster(); void UnregisterWithCookieMonster(); @@ -39,32 +47,69 @@ class AccountReconcilor : public BrowserContextKeyedService, void RegisterWithTokenService(); void UnregisterWithTokenService(); + bool IsProfileConnected(); + + void DeleteAccessTokenRequests(); + + static std::vector<std::string> ParseListAccountsData( + const std::string& data); + // Start and stop the periodic reconciliation. void StartPeriodicReconciliation(); void StopPeriodicReconciliation(); void PeriodicReconciliation(); - // The profile that this reconcilor belongs to. - Profile* profile_; - content::NotificationRegistrar registrar_; - base::RepeatingTimer<AccountReconcilor> reconciliation_timer_; - void PerformMergeAction(const std::string& account_id); void PerformRemoveAction(const std::string& account_id); - void PerformReconcileAction(); + void StartReconcileAction(); + void FinishReconcileAction(); + + void GetAccountsFromCookie(); + void ValidateAccountsFromTokenService(); + + void OnCookieChanged(ChromeCookieDetails* details); // Overriden from content::NotificationObserver virtual void Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; - void OnCookieChanged(ChromeCookieDetails* details); + // Overriden from OAuth2TokenService::Consumer + virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, + const std::string& access_token, + const base::Time& expiration_time) OVERRIDE; + virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, + const GoogleServiceAuthError& error) OVERRIDE; // Overriden from OAuth2TokenService::Observer virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE; virtual void OnRefreshTokenRevoked(const std::string& account_id) OVERRIDE; virtual void OnRefreshTokensLoaded() OVERRIDE; + // Overriden from GaiaAuthConsumer + virtual void OnListAccountsSuccess(const std::string& data) OVERRIDE; + virtual void OnListAccountsFailure( + const GoogleServiceAuthError& error) OVERRIDE; + + // The profile that this reconcilor belongs to. + Profile* profile_; + content::NotificationRegistrar registrar_; + base::RepeatingTimer<AccountReconcilor> reconciliation_timer_; + + // Used during reconcile action. + // These members are used used to validate the gaia cookie. + scoped_ptr<GaiaAuthFetcher> gaia_fetcher_; + bool are_gaia_accounts_set_; + std::vector<std::string> gaia_accounts_; + + // Used during reconcile action. + // These members are used to validate the tokens in OAuth2TokenService. + std::string primary_account_; + std::vector<std::string> chrome_accounts_; + scoped_ptr<OAuth2TokenService::Request>* requests_; + std::set<std::string> valid_chrome_accounts_; + std::set<std::string> invalid_chrome_accounts_; + DISALLOW_COPY_AND_ASSIGN(AccountReconcilor); }; diff --git a/chrome/browser/signin/account_reconcilor_unittest.cc b/chrome/browser/signin/account_reconcilor_unittest.cc index 52cb18a..de70c79 100644 --- a/chrome/browser/signin/account_reconcilor_unittest.cc +++ b/chrome/browser/signin/account_reconcilor_unittest.cc @@ -101,3 +101,37 @@ TEST_F(AccountReconcilorTest, ProfileAlreadyConnected) { ASSERT_TRUE(NULL != reconcilor); ASSERT_TRUE(reconcilor->IsPeriodicReconciliationRunning()); } + +TEST_F(AccountReconcilorTest, ParseListAccountsData) { + std::vector<std::string> accounts; + accounts = AccountReconcilor::ParseListAccountsData(""); + ASSERT_EQ(0u, accounts.size()); + + accounts = AccountReconcilor::ParseListAccountsData("1"); + ASSERT_EQ(0u, accounts.size()); + + accounts = AccountReconcilor::ParseListAccountsData("[]"); + ASSERT_EQ(0u, accounts.size()); + + accounts = AccountReconcilor::ParseListAccountsData("[\"foo\", \"bar\"]"); + ASSERT_EQ(0u, accounts.size()); + + accounts = AccountReconcilor::ParseListAccountsData("[\"foo\", []]"); + ASSERT_EQ(0u, accounts.size()); + + accounts = AccountReconcilor::ParseListAccountsData( + "[\"foo\", [[\"bar\", 0, \"name\", 0, \"photo\", 0, 0, 0]]]"); + ASSERT_EQ(0u, accounts.size()); + + accounts = AccountReconcilor::ParseListAccountsData( + "[\"foo\", [[\"bar\", 0, \"name\", \"email\", \"photo\", 0, 0, 0]]]"); + ASSERT_EQ(1u, accounts.size()); + ASSERT_EQ("email", accounts[0]); + + accounts = AccountReconcilor::ParseListAccountsData( + "[\"foo\", [[\"bar1\", 0, \"name1\", \"email1\", \"photo1\", 0, 0, 0], " + "[\"bar2\", 0, \"name2\", \"email2\", \"photo2\", 0, 0, 0]]]"); + ASSERT_EQ(2u, accounts.size()); + ASSERT_EQ("email1", accounts[0]); + ASSERT_EQ("email2", accounts[1]); +} diff --git a/chrome/browser/signin/signin_manager.cc b/chrome/browser/signin/signin_manager.cc index 2279e46..aed460a 100644 --- a/chrome/browser/signin/signin_manager.cc +++ b/chrome/browser/signin/signin_manager.cc @@ -611,35 +611,6 @@ void SigninManager::OnSignedIn(const std::string& username) { } password_.clear(); // Don't need it anymore. DisableOneClickSignIn(profile_); // Don't ever offer again. - - if (type_ == SIGNIN_TYPE_WITH_OAUTH_CODE && - !temp_oauth_login_tokens_.access_token.empty()) - // Cookie jar may not be set up properly, need to first get an uber token - // and then merge sessions with the token. - client_login_->StartTokenFetchForUberAuthExchange( - temp_oauth_login_tokens_.access_token); -} - -void SigninManager::OnUberAuthTokenSuccess(const std::string& token) { - DVLOG(1) << "SigninManager::OnUberAuthTokenSuccess"; - NotifyDiagnosticsObservers(UBER_TOKEN_STATUS, "Successful"); - client_login_->StartMergeSession(token); -} - -void SigninManager::OnMergeSessionSuccess(const std::string& data) { - DVLOG(1) << "SigninManager::OnMergeSessionSuccess"; - NotifyDiagnosticsObservers(MERGE_SESSION_STATUS, "Successful"); -} - -void SigninManager::OnMergeSessionFailure(const GoogleServiceAuthError& error) { - LOG(ERROR) << "Unable to mereg sessions. Login failed."; - NotifyDiagnosticsObservers(MERGE_SESSION_STATUS, error.ToString()); -} - -void SigninManager::OnUberAuthTokenFailure( - const GoogleServiceAuthError& error) { - LOG(ERROR) << "Unable to retreive the uber token. Login failed."; - NotifyDiagnosticsObservers(UBER_TOKEN_STATUS, error.ToString()); } void SigninManager::OnGetUserInfoFailure(const GoogleServiceAuthError& error) { diff --git a/chrome/browser/signin/signin_manager.h b/chrome/browser/signin/signin_manager.h index 0cafc8d..e78c63b 100644 --- a/chrome/browser/signin/signin_manager.h +++ b/chrome/browser/signin/signin_manager.h @@ -154,12 +154,6 @@ class SigninManager : public SigninManagerBase, virtual void OnGetUserInfoSuccess(const UserInfoMap& data) OVERRIDE; virtual void OnGetUserInfoFailure( const GoogleServiceAuthError& error) OVERRIDE; - virtual void OnUberAuthTokenSuccess(const std::string& token) OVERRIDE; - virtual void OnUberAuthTokenFailure( - const GoogleServiceAuthError& error) OVERRIDE; - virtual void OnMergeSessionSuccess(const std::string& data) OVERRIDE; - virtual void OnMergeSessionFailure( - const GoogleServiceAuthError& error) OVERRIDE; // content::NotificationObserver virtual void Observe(int type, diff --git a/google_apis/gaia/gaia_auth_consumer.h b/google_apis/gaia/gaia_auth_consumer.h index 4030336..d5ab306 100644 --- a/google_apis/gaia/gaia_auth_consumer.h +++ b/google_apis/gaia/gaia_auth_consumer.h @@ -82,6 +82,9 @@ class GaiaAuthConsumer { virtual void OnMergeSessionSuccess(const std::string& data) {} virtual void OnMergeSessionFailure(const GoogleServiceAuthError& error) {} + + virtual void OnListAccountsSuccess(const std::string& data) {} + virtual void OnListAccountsFailure(const GoogleServiceAuthError& error) {} }; #endif // GOOGLE_APIS_GAIA_GAIA_AUTH_CONSUMER_H_ diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc index f0e2644..8c0eb9a 100644 --- a/google_apis/gaia/gaia_auth_fetcher.cc +++ b/google_apis/gaia/gaia_auth_fetcher.cc @@ -182,6 +182,7 @@ GaiaAuthFetcher::GaiaAuthFetcher(GaiaAuthConsumer* consumer, uberauth_token_gurl_(GaiaUrls::GetInstance()->oauth1_login_url().Resolve( base::StringPrintf(kUberAuthTokenURLFormat, source.c_str()))), oauth_login_gurl_(GaiaUrls::GetInstance()->oauth1_login_url()), + list_accounts_gurl_(GaiaUrls::GetInstance()->list_accounts_url()), client_login_to_oauth2_gurl_( GaiaUrls::GetInstance()->client_login_to_oauth2_url()), fetch_pending_(false) {} @@ -659,6 +660,19 @@ void GaiaAuthFetcher::StartOAuthLogin(const std::string& access_token, fetcher_->Start(); } +void GaiaAuthFetcher::StartListAccounts() { + DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; + + fetcher_.reset(CreateGaiaFetcher(getter_, + " ", // To force an HTTP POST. + "Origin: https://www.google.com", + list_accounts_gurl_, + net::LOAD_NORMAL, + this)); + fetch_pending_ = true; + fetcher_->Start(); +} + // static GoogleServiceAuthError GaiaAuthFetcher::GenerateAuthError( const std::string& data, @@ -844,6 +858,16 @@ void GaiaAuthFetcher::OnOAuth2RevokeTokenFetched( consumer_->OnOAuth2RevokeTokenCompleted(); } +void GaiaAuthFetcher::OnListAccountsFetched(const std::string& data, + const net::URLRequestStatus& status, + int response_code) { + if (status.is_success() && response_code == net::HTTP_OK) { + consumer_->OnListAccountsSuccess(data); + } else { + consumer_->OnListAccountsFailure(GenerateAuthError(data, status)); + } +} + void GaiaAuthFetcher::OnGetUserInfoFetched( const std::string& data, const net::URLRequestStatus& status, @@ -937,6 +961,8 @@ void GaiaAuthFetcher::OnURLFetchComplete(const net::URLFetcher* source) { OnOAuthLoginFetched(data, status, response_code); } else if (url == oauth2_revoke_gurl_) { OnOAuth2RevokeTokenFetched(data, status, response_code); + } else if (url == list_accounts_gurl_) { + OnListAccountsFetched(data, status, response_code); } else { NOTREACHED(); } diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h index 5021a53..0864f18 100644 --- a/google_apis/gaia/gaia_auth_fetcher.h +++ b/google_apis/gaia/gaia_auth_fetcher.h @@ -158,6 +158,9 @@ class GaiaAuthFetcher : public net::URLFetcherDelegate { void StartOAuthLogin(const std::string& access_token, const std::string& service); + // Starts a request to list the accounts in the GAIA cookie. + void StartListAccounts(); + // Implementation of net::URLFetcherDelegate virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE; @@ -253,6 +256,10 @@ class GaiaAuthFetcher : public net::URLFetcherDelegate { const net::URLRequestStatus& status, int response_code); + void OnListAccountsFetched(const std::string& data, + const net::URLRequestStatus& status, + int response_code); + void OnGetUserInfoFetched(const std::string& data, const net::URLRequestStatus& status, int response_code); @@ -359,6 +366,7 @@ class GaiaAuthFetcher : public net::URLFetcherDelegate { const GURL merge_session_gurl_; const GURL uberauth_token_gurl_; const GURL oauth_login_gurl_; + const GURL list_accounts_gurl_; // While a fetch is going on: scoped_ptr<net::URLFetcher> fetcher_; diff --git a/google_apis/gaia/gaia_auth_fetcher_unittest.cc b/google_apis/gaia/gaia_auth_fetcher_unittest.cc index 8970691..a12fb97 100644 --- a/google_apis/gaia/gaia_auth_fetcher_unittest.cc +++ b/google_apis/gaia/gaia_auth_fetcher_unittest.cc @@ -187,6 +187,7 @@ class MockGaiaConsumer : public GaiaAuthConsumer { const GoogleServiceAuthError& error)); MOCK_METHOD1(OnUberAuthTokenFailure, void( const GoogleServiceAuthError& error)); + MOCK_METHOD1(OnListAccountsSuccess, void(const std::string& data)); }; #if defined(OS_WIN) @@ -789,3 +790,17 @@ TEST_F(GaiaAuthFetcherTest, StartOAuthLogin) { net::URLFetcher::GET, &auth); auth.OnURLFetchComplete(&mock_fetcher); } + +TEST_F(GaiaAuthFetcherTest, ListAccounts) { + std::string data("[\"gaia.l.a.r\", [" + "[\"gaia.l.a\", 1, \"First Last\", \"user@gmail.com\", " + "\"//googleusercontent.com/A/B/C/D/photo.jpg\", 1, 1, 0]]]"); + MockGaiaConsumer consumer; + EXPECT_CALL(consumer, OnListAccountsSuccess(data)).Times(1); + + GaiaAuthFetcher auth(&consumer, std::string(), GetRequestContext()); + net::URLRequestStatus status(net::URLRequestStatus::SUCCESS, 0); + MockFetcher mock_fetcher(GaiaUrls::GetInstance()->list_accounts_url(), + status, net::HTTP_OK, cookies_, data, net::URLFetcher::GET, &auth); + auth.OnURLFetchComplete(&mock_fetcher); +} diff --git a/google_apis/gaia/gaia_urls.cc b/google_apis/gaia/gaia_urls.cc index 43e4bf9..16bd9d6 100644 --- a/google_apis/gaia/gaia_urls.cc +++ b/google_apis/gaia/gaia_urls.cc @@ -28,6 +28,7 @@ const char kOAuthGetAccessTokenUrlSuffix[] = "OAuthGetAccessToken"; const char kOAuthWrapBridgeUrlSuffix[] = "OAuthWrapBridge"; const char kOAuth1LoginUrlSuffix[] = "OAuthLogin"; const char kOAuthRevokeTokenUrlSuffix[] = "AuthSubRevokeToken"; +const char kListAccountsSuffix[] = "ListAccounts"; // OAuth scopes const char kOAuth1LoginScope[] = "https://www.google.com/accounts/OAuthLogin"; @@ -103,6 +104,7 @@ GaiaUrls::GaiaUrls() { oauth_wrap_bridge_url_ = gaia_url_.Resolve(kOAuthWrapBridgeUrlSuffix); oauth_revoke_token_url_ = gaia_url_.Resolve(kOAuthRevokeTokenUrlSuffix); oauth1_login_url_ = gaia_url_.Resolve(kOAuth1LoginUrlSuffix); + list_accounts_url_ = gaia_url_.Resolve(kListAccountsSuffix); // URLs from accounts.google.com (LSO). get_oauth_token_url_ = lso_origin_url_.Resolve(kGetOAuthTokenUrlSuffix); @@ -198,6 +200,10 @@ const GURL& GaiaUrls::oauth1_login_url() const { return oauth1_login_url_; } +const GURL& GaiaUrls::list_accounts_url() const { + return list_accounts_url_; +} + const std::string& GaiaUrls::oauth1_login_scope() const { return oauth1_login_scope_; } diff --git a/google_apis/gaia/gaia_urls.h b/google_apis/gaia/gaia_urls.h index e06b95d..51addeb 100644 --- a/google_apis/gaia/gaia_urls.h +++ b/google_apis/gaia/gaia_urls.h @@ -32,6 +32,7 @@ class GaiaUrls { const GURL& oauth_user_info_url() const; const GURL& oauth_revoke_token_url() const; const GURL& oauth1_login_url() const; + const GURL& list_accounts_url() const; const std::string& oauth1_login_scope() const; const std::string& oauth_wrap_bridge_user_info_scope() const; @@ -73,6 +74,7 @@ class GaiaUrls { GURL oauth_user_info_url_; GURL oauth_revoke_token_url_; GURL oauth1_login_url_; + GURL list_accounts_url_; std::string oauth1_login_scope_; std::string oauth_wrap_bridge_user_info_scope_; |