1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)// found in the LICENSE file.
4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/signin/auth_sync_observer.h"
6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/user_metrics.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/metrics/user_metrics_action.h"
94e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "base/prefs/pref_service.h"
106e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/chromeos/profiles/profile_helper.h"
13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/sync/profile_sync_service.h"
14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/sync/profile_sync_service_factory.h"
154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "chrome/common/pref_names.h"
166e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/user_manager/user_manager.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/user_manager/user_type.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
19d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_util.h"
20d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
21d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class Profile;
22d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class ProfileSyncService;
23d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
24d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)namespace chromeos {
25d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
26d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)AuthSyncObserver::AuthSyncObserver(Profile* profile)
27d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    : profile_(profile) {
28d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)AuthSyncObserver::~AuthSyncObserver() {
31d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
32d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
33d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void AuthSyncObserver::StartObserving() {
34d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ProfileSyncService* sync_service =
35d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ProfileSyncServiceFactory::GetForProfile(profile_);
36d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (sync_service)
37d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    sync_service->AddObserver(this);
38d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
39d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
40d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void AuthSyncObserver::Shutdown() {
41d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ProfileSyncService* sync_service =
42d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ProfileSyncServiceFactory::GetForProfile(profile_);
43d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (sync_service)
44d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    sync_service->RemoveObserver(this);
45d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
46d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
47d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)void AuthSyncObserver::OnStateChanged() {
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  DCHECK(user_manager::UserManager::Get()->IsLoggedInAsRegularUser() ||
496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)         user_manager::UserManager::Get()->IsLoggedInAsSupervisedUser());
50d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ProfileSyncService* sync_service =
51d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      ProfileSyncServiceFactory::GetForProfile(profile_);
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile_);
53d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  GoogleServiceAuthError::State state =
54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      sync_service->GetAuthError().state();
55d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  if (state != GoogleServiceAuthError::NONE &&
56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      state != GoogleServiceAuthError::CONNECTION_FAILED &&
57d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      state != GoogleServiceAuthError::SERVICE_UNAVAILABLE &&
58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      state != GoogleServiceAuthError::REQUEST_CANCELED) {
59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Invalidate OAuth2 refresh token to force Gaia sign-in flow. This is
60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // needed because sign-out/sign-in solution is suggested to the user.
61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // TODO(nkostylev): Remove after crosbug.com/25978 is implemented.
62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    LOG(WARNING) << "Invalidate OAuth token because of a sync error: "
63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 << sync_service->GetAuthError().ToString();
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    std::string email = user->email();
654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    DCHECK(!email.empty());
66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // TODO(nkostyelv): Change observer after active user has changed.
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    user_manager::User::OAuthTokenStatus old_status =
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        user->oauth_token_status();
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    user_manager::UserManager::Get()->SaveUserOAuthStatus(
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        email, user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (user->GetType() == user_manager::USER_TYPE_SUPERVISED &&
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        old_status != user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) {
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       // Attempt to restore token from file.
746e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      ChromeUserManager::Get()
756e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          ->GetSupervisedUserManager()
766e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)          ->LoadSupervisedUserToken(
776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              profile_,
786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)              base::Bind(&AuthSyncObserver::OnSupervisedTokenLoaded,
796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                         base::Unretained(this)));
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       content::RecordAction(
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           base::UserMetricsAction("ManagedUsers_Chromeos_Sync_Invalidated"));
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  } else if (state == GoogleServiceAuthError::NONE) {
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if (user->GetType() == user_manager::USER_TYPE_SUPERVISED &&
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        user->oauth_token_status() ==
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) {
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) <<
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "Got an incorrectly invalidated token case, restoring token status.";
896e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      user_manager::UserManager::Get()->SaveUserOAuthStatus(
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          user->email(), user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       content::RecordAction(
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           base::UserMetricsAction("ManagedUsers_Chromeos_Sync_Recovered"));
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
94d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
96d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void AuthSyncObserver::OnSupervisedTokenLoaded(const std::string& token) {
986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  ChromeUserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken(
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      profile_, token);
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
102d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}  // namespace chromeos
103