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));
} }
......
...@@ -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