summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/profiles/profile_manager.cc4
-rw-r--r--chrome/browser/signin/account_reconcilor.cc210
-rw-r--r--chrome/browser/signin/account_reconcilor.h59
-rw-r--r--chrome/browser/signin/account_reconcilor_unittest.cc34
-rw-r--r--chrome/browser/signin/signin_manager.cc29
-rw-r--r--chrome/browser/signin/signin_manager.h6
-rw-r--r--google_apis/gaia/gaia_auth_consumer.h3
-rw-r--r--google_apis/gaia/gaia_auth_fetcher.cc26
-rw-r--r--google_apis/gaia/gaia_auth_fetcher.h8
-rw-r--r--google_apis/gaia/gaia_auth_fetcher_unittest.cc15
-rw-r--r--google_apis/gaia/gaia_urls.cc6
-rw-r--r--google_apis/gaia/gaia_urls.h2
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_;