Commit b29b6884 authored by Xiyuan Xia's avatar Xiyuan Xia Committed by Commit Bot

cros: AuthSyncObserver observes SigninErrorController

- Make AuthSyncObserver observe SigninErrorController in addition
  to sync service so that auth errors caused by other services
  are caught as well.
- Fix an edge case that OAuth2LoginManager marks valid oauth2
  token when it thinks /MergeSession succeeds regardless of
  whether there is any auth error;

Bug: 760610
Test: OAuth2Test.SetInvalidTokenStatus

Change-Id: Idbaee9f7faa1aa2aff939a1540bfcfdd9f49c96c
Reviewed-on: https://chromium-review.googlesource.com/658378
Commit-Queue: Xiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarAchuith Bhandarkar <achuith@chromium.org>
Cr-Commit-Position: refs/heads/master@{#504391}
parent a9e945d7
...@@ -75,6 +75,7 @@ ...@@ -75,6 +75,7 @@
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/account_tracker_service_factory.h"
#include "chrome/browser/signin/easy_unlock_service.h" #include "chrome/browser/signin/easy_unlock_service.h"
#include "chrome/browser/signin/signin_error_controller_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/supervised_user/child_accounts/child_account_service.h" #include "chrome/browser/supervised_user/child_accounts/child_account_service.h"
#include "chrome/browser/supervised_user/child_accounts/child_account_service_factory.h" #include "chrome/browser/supervised_user/child_accounts/child_account_service_factory.h"
...@@ -105,6 +106,7 @@ ...@@ -105,6 +106,7 @@
#include "components/session_manager/core/session_manager.h" #include "components/session_manager/core/session_manager.h"
#include "components/signin/core/account_id/account_id.h" #include "components/signin/core/account_id/account_id.h"
#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/core/browser/signin_manager_base.h" #include "components/signin/core/browser/signin_manager_base.h"
#include "components/user_manager/known_user.h" #include "components/user_manager/known_user.h"
#include "components/user_manager/user.h" #include "components/user_manager/user.h"
...@@ -845,7 +847,15 @@ void UserSessionManager::OnSessionRestoreStateChanged( ...@@ -845,7 +847,15 @@ void UserSessionManager::OnSessionRestoreStateChanged(
bool connection_error = false; bool connection_error = false;
switch (state) { switch (state) {
case OAuth2LoginManager::SESSION_RESTORE_DONE: case OAuth2LoginManager::SESSION_RESTORE_DONE:
user_status = user_manager::User::OAUTH2_TOKEN_STATUS_VALID; // Session restore done does not always mean valid token because the
// merge session operation could be skipped when the first account in
// Gaia cookies matches the primary account in TokenService. However
// the token could still be invalid in some edge cases. See
// http://crbug.com/760610
user_status =
SigninErrorControllerFactory::GetForProfile(user_profile)->HasError()
? user_manager::User::OAUTH2_TOKEN_STATUS_INVALID
: user_manager::User::OAUTH2_TOKEN_STATUS_VALID;
break; break;
case OAuth2LoginManager::SESSION_RESTORE_FAILED: case OAuth2LoginManager::SESSION_RESTORE_FAILED:
user_status = user_manager::User::OAUTH2_TOKEN_STATUS_INVALID; user_status = user_manager::User::OAUTH2_TOKEN_STATUS_INVALID;
......
...@@ -10,65 +10,97 @@ ...@@ -10,65 +10,97 @@
#include "chrome/browser/chromeos/login/users/chrome_user_manager.h" #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
#include "chrome/browser/chromeos/login/users/supervised_user_manager.h" #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/signin/signin_error_controller_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h"
#include "components/browser_sync/profile_sync_service.h" #include "components/browser_sync/profile_sync_service.h"
#include "components/prefs/pref_service.h" #include "components/signin/core/browser/signin_manager_base.h"
#include "components/user_manager/user_manager.h" #include "components/user_manager/user_manager.h"
#include "components/user_manager/user_type.h" #include "components/user_manager/user_type.h"
#include "google_apis/gaia/gaia_auth_util.h"
class Profile;
namespace browser_sync {
class ProfileSyncService;
} // namespace browser_sync
namespace chromeos { namespace chromeos {
AuthSyncObserver::AuthSyncObserver(Profile* profile) // static
: profile_(profile) { bool AuthSyncObserver::ShouldObserve(Profile* profile) {
const user_manager::User* const user =
ProfileHelper::Get()->GetUserByProfile(profile);
return user && (user->HasGaiaAccount() ||
user->GetType() == user_manager::USER_TYPE_SUPERVISED);
} }
AuthSyncObserver::~AuthSyncObserver() { AuthSyncObserver::AuthSyncObserver(Profile* profile) : profile_(profile) {
DCHECK(ShouldObserve(profile));
} }
AuthSyncObserver::~AuthSyncObserver() {}
void AuthSyncObserver::StartObserving() { void AuthSyncObserver::StartObserving() {
browser_sync::ProfileSyncService* sync_service = browser_sync::ProfileSyncService* const sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
if (sync_service) if (sync_service)
sync_service->AddObserver(this); sync_service->AddObserver(this);
SigninErrorController* const error_controller =
SigninErrorControllerFactory::GetForProfile(profile_);
if (error_controller) {
error_controller->AddObserver(this);
OnErrorChanged();
}
} }
void AuthSyncObserver::Shutdown() { void AuthSyncObserver::Shutdown() {
browser_sync::ProfileSyncService* sync_service = browser_sync::ProfileSyncService* const sync_service =
ProfileSyncServiceFactory::GetForProfile(profile_); ProfileSyncServiceFactory::GetForProfile(profile_);
if (sync_service) if (sync_service)
sync_service->RemoveObserver(this); sync_service->RemoveObserver(this);
SigninErrorController* const error_controller =
SigninErrorControllerFactory::GetForProfile(profile_);
if (error_controller)
error_controller->RemoveObserver(this);
} }
void AuthSyncObserver::OnStateChanged(syncer::SyncService* sync) { void AuthSyncObserver::OnStateChanged(syncer::SyncService* sync) {
DCHECK(user_manager::UserManager::Get()->IsLoggedInAsUserWithGaiaAccount() || HandleAuthError(sync->GetAuthError());
user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser()); }
const user_manager::User* user =
void AuthSyncObserver::OnErrorChanged() {
SigninErrorController* const error_controller =
SigninErrorControllerFactory::GetForProfile(profile_);
const std::string error_account_id = error_controller->error_account_id();
const std::string primary_account_id =
SigninManagerFactory::GetForProfile(profile_)
->GetAuthenticatedAccountId();
// Bail if there is an error account id and it is not the primary account id.
if (!error_account_id.empty() && error_account_id != primary_account_id)
return;
HandleAuthError(error_controller->auth_error());
}
void AuthSyncObserver::HandleAuthError(
const GoogleServiceAuthError& auth_error) {
const user_manager::User* const user =
ProfileHelper::Get()->GetUserByProfile(profile_); ProfileHelper::Get()->GetUserByProfile(profile_);
GoogleServiceAuthError::State state = sync->GetAuthError().state(); DCHECK(user->HasGaiaAccount() ||
if (state != GoogleServiceAuthError::NONE && user->GetType() == user_manager::USER_TYPE_SUPERVISED);
state != GoogleServiceAuthError::CONNECTION_FAILED &&
state != GoogleServiceAuthError::SERVICE_UNAVAILABLE && if (auth_error.IsPersistentError()) {
state != GoogleServiceAuthError::REQUEST_CANCELED) {
// Invalidate OAuth2 refresh token to force Gaia sign-in flow. This is // Invalidate OAuth2 refresh token to force Gaia sign-in flow. This is
// needed because sign-out/sign-in solution is suggested to the user. // needed because sign-out/sign-in solution is suggested to the user.
// TODO(nkostylev): Remove after crosbug.com/25978 is implemented. LOG(WARNING) << "Invalidate OAuth token because of an auth error: "
LOG(WARNING) << "Invalidate OAuth token because of a sync error: " << auth_error.ToString();
<< sync->GetAuthError().ToString();
const AccountId& account_id = user->GetAccountId(); const AccountId& account_id = user->GetAccountId();
DCHECK(account_id.is_valid()); DCHECK(account_id.is_valid());
// TODO(nkostyelv): Change observer after active user has changed.
user_manager::User::OAuthTokenStatus old_status = user_manager::User::OAuthTokenStatus old_status =
user->oauth_token_status(); user->oauth_token_status();
user_manager::UserManager::Get()->SaveUserOAuthStatus( user_manager::UserManager::Get()->SaveUserOAuthStatus(
account_id, user_manager::User::OAUTH2_TOKEN_STATUS_INVALID); account_id, user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
RecordReauthReason(account_id, ReauthReason::SYNC_FAILED); RecordReauthReason(account_id, ReauthReason::SYNC_FAILED);
if (user->GetType() == user_manager::USER_TYPE_SUPERVISED && if (user->GetType() == user_manager::USER_TYPE_SUPERVISED &&
old_status != user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) { old_status != user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) {
// Attempt to restore token from file. // Attempt to restore token from file.
...@@ -81,7 +113,7 @@ void AuthSyncObserver::OnStateChanged(syncer::SyncService* sync) { ...@@ -81,7 +113,7 @@ void AuthSyncObserver::OnStateChanged(syncer::SyncService* sync) {
base::RecordAction( base::RecordAction(
base::UserMetricsAction("ManagedUsers_Chromeos_Sync_Invalidated")); base::UserMetricsAction("ManagedUsers_Chromeos_Sync_Invalidated"));
} }
} else if (state == GoogleServiceAuthError::NONE) { } else if (auth_error.state() == GoogleServiceAuthError::NONE) {
if (user->GetType() == user_manager::USER_TYPE_SUPERVISED && if (user->GetType() == user_manager::USER_TYPE_SUPERVISED &&
user->oauth_token_status() == user->oauth_token_status() ==
user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) { user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) {
......
...@@ -7,23 +7,30 @@ ...@@ -7,23 +7,30 @@
#include <string> #include <string>
#include "base/compiler_specific.h"
#include "base/macros.h" #include "base/macros.h"
#include "components/keyed_service/core/keyed_service.h" #include "components/keyed_service/core/keyed_service.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/sync/driver/sync_service_observer.h" #include "components/sync/driver/sync_service_observer.h"
class GoogleServiceAuthError;
class Profile; class Profile;
namespace chromeos { namespace chromeos {
// This class is responsible for detecting authentication problems reported // This class is responsible for detecting authentication problems reported
// by sync service and // by sync service and SigninErrorController on a user profile.
class AuthSyncObserver : public KeyedService, class AuthSyncObserver : public KeyedService,
public syncer::SyncServiceObserver { public syncer::SyncServiceObserver,
public SigninErrorController::Observer {
public: public:
explicit AuthSyncObserver(Profile* user_profile); // Whether |profile| should be observed. Currently, this returns true only
// when |profile| is a user profile of a gaia user or a supervised user.
static bool ShouldObserve(Profile* profile);
explicit AuthSyncObserver(Profile* profile);
~AuthSyncObserver() override; ~AuthSyncObserver() override;
// Starts to observe SyncService and SigninErrorController.
void StartObserving(); void StartObserving();
private: private:
...@@ -35,10 +42,16 @@ class AuthSyncObserver : public KeyedService, ...@@ -35,10 +42,16 @@ class AuthSyncObserver : public KeyedService,
// syncer::SyncServiceObserver implementation. // syncer::SyncServiceObserver implementation.
void OnStateChanged(syncer::SyncService* sync) override; void OnStateChanged(syncer::SyncService* sync) override;
// SigninErrorController::Observer implementation.
void OnErrorChanged() override;
// Handles an auth error.
void HandleAuthError(const GoogleServiceAuthError& auth_error);
// Called on attempt to restore supervised user token. // Called on attempt to restore supervised user token.
void OnSupervisedTokenLoaded(const std::string& token); void OnSupervisedTokenLoaded(const std::string& token);
Profile* profile_; Profile* const profile_;
DISALLOW_COPY_AND_ASSIGN(AuthSyncObserver); DISALLOW_COPY_AND_ASSIGN(AuthSyncObserver);
}; };
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "chrome/browser/chromeos/login/signin/auth_sync_observer.h" #include "chrome/browser/chromeos/login/signin/auth_sync_observer.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_error_controller_factory.h"
#include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/sync/profile_sync_service_factory.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_dependency_manager.h"
...@@ -16,6 +17,7 @@ AuthSyncObserverFactory::AuthSyncObserverFactory() ...@@ -16,6 +17,7 @@ AuthSyncObserverFactory::AuthSyncObserverFactory()
"AuthSyncObserver", "AuthSyncObserver",
BrowserContextDependencyManager::GetInstance()) { BrowserContextDependencyManager::GetInstance()) {
DependsOn(ProfileSyncServiceFactory::GetInstance()); DependsOn(ProfileSyncServiceFactory::GetInstance());
DependsOn(SigninErrorControllerFactory::GetInstance());
} }
AuthSyncObserverFactory::~AuthSyncObserverFactory() { AuthSyncObserverFactory::~AuthSyncObserverFactory() {
...@@ -24,6 +26,9 @@ AuthSyncObserverFactory::~AuthSyncObserverFactory() { ...@@ -24,6 +26,9 @@ AuthSyncObserverFactory::~AuthSyncObserverFactory() {
// static // static
AuthSyncObserver* AuthSyncObserverFactory::GetForProfile( AuthSyncObserver* AuthSyncObserverFactory::GetForProfile(
Profile* profile) { Profile* profile) {
if (!AuthSyncObserver::ShouldObserve(profile))
return nullptr;
return static_cast<AuthSyncObserver*>( return static_cast<AuthSyncObserver*>(
GetInstance()->GetServiceForBrowserContext(profile, true)); GetInstance()->GetServiceForBrowserContext(profile, true));
} }
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include <map>
#include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
...@@ -23,6 +25,7 @@ ...@@ -23,6 +25,7 @@
#include "chrome/browser/extensions/chrome_extension_test_notification_observer.h" #include "chrome/browser/extensions/chrome_extension_test_notification_observer.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
#include "chrome/browser/signin/signin_error_controller_factory.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h" #include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h" #include "chrome/browser/ui/javascript_dialogs/javascript_dialog_tab_helper.h"
...@@ -37,7 +40,9 @@ ...@@ -37,7 +40,9 @@
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/signin/core/account_id/account_id.h" #include "components/signin/core/account_id/account_id.h"
#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_auth_status_provider.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/profile_oauth2_token_service.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/user_manager/user.h" #include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h" #include "components/user_manager/user_manager.h"
#include "content/public/browser/notification_service.h" #include "content/public/browser/notification_service.h"
...@@ -110,8 +115,8 @@ class OAuth2LoginManagerStateWaiter : public OAuth2LoginManager::Observer { ...@@ -110,8 +115,8 @@ class OAuth2LoginManagerStateWaiter : public OAuth2LoginManager::Observer {
waiting_for_state_ = true; waiting_for_state_ = true;
login_manager->AddObserver(this); login_manager->AddObserver(this);
runner_ = new content::MessageLoopRunner; run_loop_ = std::make_unique<base::RunLoop>();
runner_->Run(); run_loop_->Run();
login_manager->RemoveObserver(this); login_manager->RemoveObserver(this);
} }
...@@ -130,14 +135,14 @@ class OAuth2LoginManagerStateWaiter : public OAuth2LoginManager::Observer { ...@@ -130,14 +135,14 @@ class OAuth2LoginManagerStateWaiter : public OAuth2LoginManager::Observer {
final_state_ = state; final_state_ = state;
waiting_for_state_ = false; waiting_for_state_ = false;
runner_->Quit(); run_loop_->Quit();
} }
Profile* profile_; Profile* profile_;
std::set<OAuth2LoginManager::SessionRestoreState> states_; std::set<OAuth2LoginManager::SessionRestoreState> states_;
bool waiting_for_state_; bool waiting_for_state_;
OAuth2LoginManager::SessionRestoreState final_state_; OAuth2LoginManager::SessionRestoreState final_state_;
scoped_refptr<content::MessageLoopRunner> runner_; std::unique_ptr<base::RunLoop> run_loop_;
DISALLOW_COPY_AND_ASSIGN(OAuth2LoginManagerStateWaiter); DISALLOW_COPY_AND_ASSIGN(OAuth2LoginManagerStateWaiter);
}; };
...@@ -166,12 +171,56 @@ class ThreadBlocker { ...@@ -166,12 +171,56 @@ class ThreadBlocker {
DISALLOW_COPY_AND_ASSIGN(ThreadBlocker); DISALLOW_COPY_AND_ASSIGN(ThreadBlocker);
}; };
// Helper class that is added as a RequestMonitor of embedded test server to
// wait for a request to happen and defer it until Unblock is called.
class RequestDeferrer {
public:
RequestDeferrer()
: blocking_event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
start_event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
void UnblockRequest() { blocking_event_.Signal(); }
void WaitForRequestToStart() {
// If we have already served the request, bail out.
if (start_event_.IsSignaled())
return;
run_loop_ = std::make_unique<base::RunLoop>();
run_loop_->Run();
}
void InterceptRequest(const HttpRequest& request) {
start_event_.Signal();
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&RequestDeferrer::QuitRunnerOnUIThread,
base::Unretained(this)));
blocking_event_.Wait();
}
private:
void QuitRunnerOnUIThread() {
if (run_loop_)
run_loop_->Quit();
}
base::WaitableEvent blocking_event_;
base::WaitableEvent start_event_;
std::unique_ptr<base::RunLoop> run_loop_;
DISALLOW_COPY_AND_ASSIGN(RequestDeferrer);
};
} // namespace } // namespace
class OAuth2Test : public OobeBaseTest { class OAuth2Test : public OobeBaseTest {
protected: protected:
OAuth2Test() {} OAuth2Test() {}
// OobeBaseTest overrides.
void SetUpCommandLine(base::CommandLine* command_line) override { void SetUpCommandLine(base::CommandLine* command_line) override {
OobeBaseTest::SetUpCommandLine(command_line); OobeBaseTest::SetUpCommandLine(command_line);
...@@ -180,6 +229,11 @@ class OAuth2Test : public OobeBaseTest { ...@@ -180,6 +229,11 @@ class OAuth2Test : public OobeBaseTest {
command_line->AppendSwitch(switches::kDisableSync); command_line->AppendSwitch(switches::kDisableSync);
} }
void RegisterAdditionalRequestHandlers() override {
embedded_test_server()->RegisterRequestMonitor(
base::Bind(&OAuth2Test::InterceptRequest, base::Unretained(this)));
}
void SetupGaiaServerForNewAccount() { void SetupGaiaServerForNewAccount() {
FakeGaia::MergeSessionParams params; FakeGaia::MergeSessionParams params;
params.auth_sid_cookie = kTestAuthSIDCookie; params.auth_sid_cookie = kTestAuthSIDCookie;
...@@ -396,7 +450,25 @@ class OAuth2Test : public OobeBaseTest { ...@@ -396,7 +450,25 @@ class OAuth2Test : public OobeBaseTest {
return login_manager->restore_strategy_; return login_manager->restore_strategy_;
} }
void InterceptRequest(const HttpRequest& request) {
const GURL request_url =
GURL("http://localhost").Resolve(request.relative_url);
auto it = request_deferers_.find(request_url.path());
if (it == request_deferers_.end())
return;
it->second->InterceptRequest(request);
}
void AddRequestDeferer(const std::string& path,
RequestDeferrer* request_deferer) {
DCHECK(request_deferers_.find(path) == request_deferers_.end());
request_deferers_[path] = request_deferer;
}
private: private:
std::map<std::string, RequestDeferrer*> request_deferers_;
DISALLOW_COPY_AND_ASSIGN(OAuth2Test); DISALLOW_COPY_AND_ASSIGN(OAuth2Test);
}; };
...@@ -410,8 +482,8 @@ class CookieReader : public base::RefCountedThreadSafe<CookieReader> { ...@@ -410,8 +482,8 @@ class CookieReader : public base::RefCountedThreadSafe<CookieReader> {
content::BrowserThread::PostTask( content::BrowserThread::PostTask(
content::BrowserThread::IO, FROM_HERE, content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&CookieReader::ReadCookiesOnIOThread, this)); base::BindOnce(&CookieReader::ReadCookiesOnIOThread, this));
runner_ = new content::MessageLoopRunner; run_loop_ = std::make_unique<base::RunLoop>();
runner_->Run(); run_loop_->Run();
} }
std::string GetCookieValue(const std::string& name) { std::string GetCookieValue(const std::string& name) {
...@@ -444,13 +516,11 @@ class CookieReader : public base::RefCountedThreadSafe<CookieReader> { ...@@ -444,13 +516,11 @@ class CookieReader : public base::RefCountedThreadSafe<CookieReader> {
base::BindOnce(&CookieReader::OnCookiesReadyOnUIThread, this)); base::BindOnce(&CookieReader::OnCookiesReadyOnUIThread, this));
} }
void OnCookiesReadyOnUIThread() { void OnCookiesReadyOnUIThread() { run_loop_->Quit(); }
runner_->Quit();
}
scoped_refptr<net::URLRequestContextGetter> context_; scoped_refptr<net::URLRequestContextGetter> context_;
net::CookieList cookie_list_; net::CookieList cookie_list_;
scoped_refptr<content::MessageLoopRunner> runner_; std::unique_ptr<base::RunLoop> run_loop_;
DISALLOW_COPY_AND_ASSIGN(CookieReader); DISALLOW_COPY_AND_ASSIGN(CookieReader);
}; };
...@@ -616,14 +686,72 @@ IN_PROC_BROWSER_TEST_F(OAuth2Test, TerminateOnBadMergeSessionAfterOnlineAuth) { ...@@ -616,14 +686,72 @@ IN_PROC_BROWSER_TEST_F(OAuth2Test, TerminateOnBadMergeSessionAfterOnlineAuth) {
WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_FAILED); WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_FAILED);
} }
const char kGooglePageContent[] = // Sets up a new user with stored refresh token.
IN_PROC_BROWSER_TEST_F(OAuth2Test, PRE_SetInvalidTokenStatus) {
StartNewUserSession(true);
}
// Tests that an auth error reported by SigninErrorController marks invalid auth
// token status despite OAuth2LoginManager thinks merge session is done
// successfully
IN_PROC_BROWSER_TEST_F(OAuth2Test, SetInvalidTokenStatus) {
RequestDeferrer list_accounts_request_deferer;
AddRequestDeferer("/ListAccounts", &list_accounts_request_deferer);
SetupGaiaServerForUnexpiredAccount();
SimulateNetworkOnline();
// Waits for login screen to be ready.
content::WindowedNotificationObserver(
chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
content::NotificationService::AllSources())
.Wait();
// Signs in as the existing user created in pre test.
ExistingUserController* const controller =
ExistingUserController::current_controller();
UserContext user_context(
AccountId::FromUserEmailGaiaId(kTestEmail, kTestGaiaId));
user_context.SetKey(Key(kTestAccountPassword));
controller->Login(user_context, SigninSpecifics());
// Wait until /ListAccounts request happens so that an auth error can be
// generated after user profile is available but before merge session
// finishes.
list_accounts_request_deferer.WaitForRequestToStart();
// Make sure that merge session is not finished.
OAuth2LoginManager* const login_manager =
OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile());
ASSERT_NE(OAuth2LoginManager::SESSION_RESTORE_DONE, login_manager->state());
// Generate an auth error.
SigninErrorController* const error_controller =
SigninErrorControllerFactory::GetForProfile(profile());
FakeAuthStatusProvider auth_provider(error_controller);
auth_provider.SetAuthError(
kTestEmail, GoogleServiceAuthError(
GoogleServiceAuthError::State::INVALID_GAIA_CREDENTIALS));
// Let go /ListAccounts request.
list_accounts_request_deferer.UnblockRequest();
// Wait for the session merge to finish with success.
WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
// User oauth2 token status should be marked as invalid because of auth error
// and regardless of the merge session outcome.
EXPECT_EQ(GetOAuthStatusFromLocalState(kTestEmail),
user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
}
constexpr char kGooglePageContent[] =
"<html><title>Hello!</title><script>alert('hello');</script>" "<html><title>Hello!</title><script>alert('hello');</script>"
"<body>Hello Google!</body></html>"; "<body>Hello Google!</body></html>";
const char kRandomPageContent[] = constexpr char kRandomPageContent[] =
"<html><title>SomthingElse</title><body>I am SomethingElse</body></html>"; "<html><title>SomthingElse</title><body>I am SomethingElse</body></html>";
const char kHelloPagePath[] = "/hello_google"; constexpr char kHelloPagePath[] = "/hello_google";
const char kRandomPagePath[] = "/non_google_page"; constexpr char kRandomPagePath[] = "/non_google_page";
// FakeGoogle serves content of http://www.google.com/hello_google page for // FakeGoogle serves content of http://www.google.com/hello_google page for
// merge session tests. // merge session tests.
...@@ -672,78 +800,29 @@ class FakeGoogle { ...@@ -672,78 +800,29 @@ class FakeGoogle {
if (start_event_.IsSignaled()) if (start_event_.IsSignaled())
return; return;
runner_ = new content::MessageLoopRunner; run_loop_ = std::make_unique<base::RunLoop>();
runner_->Run(); run_loop_->Run();
} }
private: private:
void QuitRunnerOnUIThread() { void QuitRunnerOnUIThread() {
if (runner_.get()) if (run_loop_)
runner_->Quit(); run_loop_->Quit();
} }
// This event will tell us when we actually see HTTP request on the server // This event will tell us when we actually see HTTP request on the server
// side. It should be signalled only after the page/XHR throttle had been // side. It should be signalled only after the page/XHR throttle had been
// removed (after merge session completes). // removed (after merge session completes).
base::WaitableEvent start_event_; base::WaitableEvent start_event_;
scoped_refptr<content::MessageLoopRunner> runner_; std::unique_ptr<base::RunLoop> run_loop_;
DISALLOW_COPY_AND_ASSIGN(FakeGoogle); DISALLOW_COPY_AND_ASSIGN(FakeGoogle);
}; };
// FakeGaia specialization that can delay /MergeSession handler until
// we explicitly call DelayedFakeGaia::UnblockMergeSession().
class DelayedFakeGaia : public FakeGaia {
public:
DelayedFakeGaia()
: blocking_event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED),
start_event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) {}
void UnblockMergeSession() {
blocking_event_.Signal();
}
void WaitForMergeSessionToStart() {
// If we have already served the request, bail out.
if (start_event_.IsSignaled())
return;
runner_ = new content::MessageLoopRunner;
runner_->Run();
}
private:
// FakeGaia overrides.
void HandleMergeSession(const HttpRequest& request,
BasicHttpResponse* http_response) override {
start_event_.Signal();
content::BrowserThread::PostTask(
content::BrowserThread::UI, FROM_HERE,
base::BindOnce(&DelayedFakeGaia::QuitRunnerOnUIThread,
base::Unretained(this)));
blocking_event_.Wait();
FakeGaia::HandleMergeSession(request, http_response);
}
void QuitRunnerOnUIThread() {
if (runner_.get())
runner_->Quit();
}
base::WaitableEvent blocking_event_;
base::WaitableEvent start_event_;
scoped_refptr<content::MessageLoopRunner> runner_;
DISALLOW_COPY_AND_ASSIGN(DelayedFakeGaia);
};
class MergeSessionTest : public OAuth2Test { class MergeSessionTest : public OAuth2Test {
protected: protected:
MergeSessionTest() : delayed_fake_gaia_(new DelayedFakeGaia()) { MergeSessionTest() = default;
fake_gaia_.reset(delayed_fake_gaia_);
}
// OAuth2Test overrides.
void SetUpCommandLine(base::CommandLine* command_line) override { void SetUpCommandLine(base::CommandLine* command_line) override {
OAuth2Test::SetUpCommandLine(command_line); OAuth2Test::SetUpCommandLine(command_line);
...@@ -760,19 +839,19 @@ class MergeSessionTest : public OAuth2Test { ...@@ -760,19 +839,19 @@ class MergeSessionTest : public OAuth2Test {
non_google_page_url_ = non_google_url.Resolve(kRandomPagePath); non_google_page_url_ = non_google_url.Resolve(kRandomPagePath);
} }
void SetUp() override { void RegisterAdditionalRequestHandlers() override {
OAuth2Test::RegisterAdditionalRequestHandlers();
AddRequestDeferer("/MergeSession", &merge_session_deferer_);
embedded_test_server()->RegisterRequestHandler(base::Bind( embedded_test_server()->RegisterRequestHandler(base::Bind(
&FakeGoogle::HandleRequest, base::Unretained(&fake_google_))); &FakeGoogle::HandleRequest, base::Unretained(&fake_google_)));
OAuth2Test::SetUp();
} }
protected: protected:
void UnblockMergeSession() { void UnblockMergeSession() { merge_session_deferer_.UnblockRequest(); }
delayed_fake_gaia_->UnblockMergeSession();
}
void WaitForMergeSessionToStart() { void WaitForMergeSessionToStart() {
delayed_fake_gaia_->WaitForMergeSessionToStart(); merge_session_deferer_.WaitForRequestToStart();
} }
void JsExpect(content::WebContents* contents, void JsExpect(content::WebContents* contents,
...@@ -809,7 +888,7 @@ class MergeSessionTest : public OAuth2Test { ...@@ -809,7 +888,7 @@ class MergeSessionTest : public OAuth2Test {
} }
FakeGoogle fake_google_; FakeGoogle fake_google_;
DelayedFakeGaia* delayed_fake_gaia_; RequestDeferrer merge_session_deferer_;
GURL fake_google_page_url_; GURL fake_google_page_url_;
GURL non_google_page_url_; GURL non_google_page_url_;
......
...@@ -496,9 +496,11 @@ void ChromeUserManagerImpl::Observe( ...@@ -496,9 +496,11 @@ void ChromeUserManagerImpl::Observe(
ManagerPasswordServiceFactory::GetForProfile(profile); ManagerPasswordServiceFactory::GetForProfile(profile);
if (!profile->IsOffTheRecord()) { if (!profile->IsOffTheRecord()) {
AuthSyncObserver* sync_observer = if (AuthSyncObserver::ShouldObserve(profile)) {
AuthSyncObserverFactory::GetInstance()->GetForProfile(profile); AuthSyncObserver* sync_observer =
sync_observer->StartObserving(); AuthSyncObserverFactory::GetInstance()->GetForProfile(profile);
sync_observer->StartObserving();
}
multi_profile_user_controller_->StartObserving(profile); multi_profile_user_controller_->StartObserving(profile);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment