supervised_user_registration_utility.cc revision 1320f92c476a1ad9d19dba2a48c72b75566198e9
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/supervised_user/supervised_user_registration_utility.h"
6
7#include "base/base64.h"
8#include "base/bind.h"
9#include "base/command_line.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/prefs/pref_service.h"
12#include "base/rand_util.h"
13#include "base/strings/utf_string_conversions.h"
14#include "chrome/browser/profiles/profile.h"
15#include "chrome/browser/signin/chrome_signin_client_factory.h"
16#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
17#include "chrome/browser/signin/signin_manager_factory.h"
18#include "chrome/browser/supervised_user/supervised_user_constants.h"
19#include "chrome/browser/supervised_user/supervised_user_refresh_token_fetcher.h"
20#include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
21#include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h"
22#include "chrome/browser/supervised_user/supervised_user_shared_settings_update.h"
23#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
24#include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
25#include "chrome/common/chrome_switches.h"
26#include "chrome/common/pref_names.h"
27#include "components/signin/core/browser/profile_oauth2_token_service.h"
28#include "components/signin/core/browser/signin_client.h"
29#include "components/signin/core/browser/signin_manager.h"
30#include "content/public/browser/browser_thread.h"
31#include "google_apis/gaia/gaia_urls.h"
32#include "google_apis/gaia/google_service_auth_error.h"
33#include "sync/util/get_session_name.h"
34
35using base::DictionaryValue;
36
37namespace {
38
39SupervisedUserRegistrationUtility* g_instance_for_tests = NULL;
40
41// Actual implementation of SupervisedUserRegistrationUtility.
42class SupervisedUserRegistrationUtilityImpl
43    : public SupervisedUserRegistrationUtility,
44      public SupervisedUserSyncServiceObserver {
45 public:
46  SupervisedUserRegistrationUtilityImpl(
47      PrefService* prefs,
48      scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher,
49      SupervisedUserSyncService* service,
50      SupervisedUserSharedSettingsService* shared_settings_service);
51
52  virtual ~SupervisedUserRegistrationUtilityImpl();
53
54  // Registers a new supervised user with the server. |supervised_user_id| is a
55  // new unique ID for the new supervised user. If its value is the same as that
56  // of one of the existing supervised users, then the same user will be created
57  // on this machine (and if he has no avatar in sync, his avatar will be
58  // updated). |info| contains necessary information like the display name of
59  // the user and his avatar. |callback| is called with the result of the
60  // registration. We use the info here and not the profile, because on Chrome
61  // OS the profile of the supervised user does not yet exist.
62  virtual void Register(const std::string& supervised_user_id,
63                        const SupervisedUserRegistrationInfo& info,
64                        const RegistrationCallback& callback) OVERRIDE;
65
66  // SupervisedUserSyncServiceObserver:
67  virtual void OnSupervisedUserAcknowledged(
68      const std::string& supervised_user_id) OVERRIDE;
69  virtual void OnSupervisedUsersSyncingStopped() OVERRIDE;
70  virtual void OnSupervisedUsersChanged() OVERRIDE;
71
72 private:
73  // Fetches the supervised user token when we have the device name.
74  void FetchToken(const std::string& client_name);
75
76  // Called when we have received a token for the supervised user.
77  void OnReceivedToken(const GoogleServiceAuthError& error,
78                       const std::string& token);
79
80  // Dispatches the callback and cleans up if all the conditions have been met.
81  void CompleteRegistrationIfReady();
82
83  // Aborts any registration currently in progress. If |run_callback| is true,
84  // calls the callback specified in Register() with the given |error|.
85  void AbortPendingRegistration(bool run_callback,
86                                const GoogleServiceAuthError& error);
87
88  // If |run_callback| is true, dispatches the callback with the saved token
89  // (which may be empty) and the given |error|. In any case, resets internal
90  // variables to be ready for the next registration.
91  void CompleteRegistration(bool run_callback,
92                            const GoogleServiceAuthError& error);
93
94  // Cancels any registration currently in progress, without calling the
95  // callback or reporting an error.
96  void CancelPendingRegistration();
97
98  // SupervisedUserSharedSettingsUpdate acknowledgment callback for password
99  // data in shared settings.
100  void OnPasswordChangeAcknowledged(bool success);
101
102  PrefService* prefs_;
103  scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher_;
104
105  // A |KeyedService| owned by the custodian profile.
106  SupervisedUserSyncService* supervised_user_sync_service_;
107
108  // A |KeyedService| owned by the custodian profile.
109  SupervisedUserSharedSettingsService* supervised_user_shared_settings_service_;
110
111  std::string pending_supervised_user_id_;
112  std::string pending_supervised_user_token_;
113  bool pending_supervised_user_acknowledged_;
114  bool is_existing_supervised_user_;
115  bool avatar_updated_;
116  RegistrationCallback callback_;
117  scoped_ptr<SupervisedUserSharedSettingsUpdate> password_update_;
118
119  base::WeakPtrFactory<SupervisedUserRegistrationUtilityImpl> weak_ptr_factory_;
120
121  DISALLOW_COPY_AND_ASSIGN(SupervisedUserRegistrationUtilityImpl);
122};
123
124} // namespace
125
126SupervisedUserRegistrationInfo::SupervisedUserRegistrationInfo(
127    const base::string16& name,
128    int avatar_index)
129    : avatar_index(avatar_index),
130      name(name) {
131}
132
133SupervisedUserRegistrationInfo::~SupervisedUserRegistrationInfo() {}
134
135ScopedTestingSupervisedUserRegistrationUtility::
136    ScopedTestingSupervisedUserRegistrationUtility(
137        SupervisedUserRegistrationUtility* instance) {
138  SupervisedUserRegistrationUtility::SetUtilityForTests(instance);
139}
140
141ScopedTestingSupervisedUserRegistrationUtility::
142    ~ScopedTestingSupervisedUserRegistrationUtility() {
143  SupervisedUserRegistrationUtility::SetUtilityForTests(NULL);
144}
145
146// static
147scoped_ptr<SupervisedUserRegistrationUtility>
148SupervisedUserRegistrationUtility::Create(Profile* profile) {
149  if (g_instance_for_tests) {
150    SupervisedUserRegistrationUtility* result = g_instance_for_tests;
151    g_instance_for_tests = NULL;
152    return make_scoped_ptr(result);
153  }
154
155  ProfileOAuth2TokenService* token_service =
156      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
157  SigninManagerBase* signin_manager =
158      SigninManagerFactory::GetForProfile(profile);
159  SigninClient* signin_client =
160      ChromeSigninClientFactory::GetForProfile(profile);
161  std::string signin_scoped_device_id =
162      signin_client->GetSigninScopedDeviceId();
163  scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher =
164      SupervisedUserRefreshTokenFetcher::Create(
165          token_service,
166          signin_manager->GetAuthenticatedAccountId(),
167          signin_scoped_device_id,
168          profile->GetRequestContext());
169  SupervisedUserSyncService* supervised_user_sync_service =
170      SupervisedUserSyncServiceFactory::GetForProfile(profile);
171  SupervisedUserSharedSettingsService* supervised_user_shared_settings_service =
172      SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(profile);
173  return make_scoped_ptr(SupervisedUserRegistrationUtility::CreateImpl(
174      profile->GetPrefs(),
175      token_fetcher.Pass(),
176      supervised_user_sync_service,
177      supervised_user_shared_settings_service));
178}
179
180// static
181std::string SupervisedUserRegistrationUtility::GenerateNewSupervisedUserId() {
182  std::string new_supervised_user_id;
183  base::Base64Encode(base::RandBytesAsString(8), &new_supervised_user_id);
184  return new_supervised_user_id;
185}
186
187// static
188void SupervisedUserRegistrationUtility::SetUtilityForTests(
189    SupervisedUserRegistrationUtility* utility) {
190  if (g_instance_for_tests)
191    delete g_instance_for_tests;
192  g_instance_for_tests = utility;
193}
194
195// static
196SupervisedUserRegistrationUtility*
197SupervisedUserRegistrationUtility::CreateImpl(
198      PrefService* prefs,
199      scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher,
200      SupervisedUserSyncService* service,
201      SupervisedUserSharedSettingsService* shared_settings_service) {
202  return new SupervisedUserRegistrationUtilityImpl(prefs,
203                                                   token_fetcher.Pass(),
204                                                   service,
205                                                   shared_settings_service);
206}
207
208namespace {
209
210SupervisedUserRegistrationUtilityImpl::SupervisedUserRegistrationUtilityImpl(
211    PrefService* prefs,
212    scoped_ptr<SupervisedUserRefreshTokenFetcher> token_fetcher,
213    SupervisedUserSyncService* service,
214    SupervisedUserSharedSettingsService* shared_settings_service)
215    : prefs_(prefs),
216      token_fetcher_(token_fetcher.Pass()),
217      supervised_user_sync_service_(service),
218      supervised_user_shared_settings_service_(shared_settings_service),
219      pending_supervised_user_acknowledged_(false),
220      is_existing_supervised_user_(false),
221      avatar_updated_(false),
222      weak_ptr_factory_(this) {
223  supervised_user_sync_service_->AddObserver(this);
224}
225
226SupervisedUserRegistrationUtilityImpl::
227~SupervisedUserRegistrationUtilityImpl() {
228  supervised_user_sync_service_->RemoveObserver(this);
229  CancelPendingRegistration();
230}
231
232void SupervisedUserRegistrationUtilityImpl::Register(
233    const std::string& supervised_user_id,
234    const SupervisedUserRegistrationInfo& info,
235    const RegistrationCallback& callback) {
236  DCHECK(pending_supervised_user_id_.empty());
237  callback_ = callback;
238  pending_supervised_user_id_ = supervised_user_id;
239
240  bool need_password_update = !info.password_data.empty();
241  const base::DictionaryValue* dict =
242      prefs_->GetDictionary(prefs::kSupervisedUsers);
243  is_existing_supervised_user_ = dict->HasKey(supervised_user_id);
244  if (!is_existing_supervised_user_) {
245    supervised_user_sync_service_->AddSupervisedUser(
246        pending_supervised_user_id_,
247        base::UTF16ToUTF8(info.name),
248        info.master_key,
249        info.password_signature_key,
250        info.password_encryption_key,
251        info.avatar_index);
252  } else {
253    const base::DictionaryValue* value = NULL;
254    bool success =
255        dict->GetDictionaryWithoutPathExpansion(supervised_user_id, &value);
256    DCHECK(success);
257    std::string key;
258    bool need_keys = !info.password_signature_key.empty() ||
259                     !info.password_encryption_key.empty();
260    bool have_keys =
261        value->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
262                         &key) &&
263        !key.empty() &&
264        value->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
265                         &key) &&
266        !key.empty();
267
268    bool keys_need_update = need_keys && !have_keys;
269
270    if (keys_need_update) {
271      supervised_user_sync_service_->UpdateSupervisedUser(
272          pending_supervised_user_id_,
273          base::UTF16ToUTF8(info.name),
274          info.master_key,
275          info.password_signature_key,
276          info.password_encryption_key,
277          info.avatar_index);
278    } else {
279      // The user already exists and does not need to be updated.
280      need_password_update = false;
281      OnSupervisedUserAcknowledged(supervised_user_id);
282    }
283    avatar_updated_ =
284        supervised_user_sync_service_->UpdateSupervisedUserAvatarIfNeeded(
285            supervised_user_id,
286            info.avatar_index);
287  }
288#if defined(OS_CHROMEOS)
289  const char* kAvatarKey = supervised_users::kChromeOSAvatarIndex;
290#else
291  const char* kAvatarKey = supervised_users::kChromeAvatarIndex;
292#endif
293  supervised_user_shared_settings_service_->SetValue(
294      pending_supervised_user_id_, kAvatarKey,
295      base::FundamentalValue(info.avatar_index));
296  if (need_password_update) {
297    password_update_.reset(new SupervisedUserSharedSettingsUpdate(
298        supervised_user_shared_settings_service_,
299        pending_supervised_user_id_,
300        supervised_users::kChromeOSPasswordData,
301        scoped_ptr<base::Value>(info.password_data.DeepCopy()),
302        base::Bind(
303            &SupervisedUserRegistrationUtilityImpl::
304                OnPasswordChangeAcknowledged,
305            weak_ptr_factory_.GetWeakPtr())));
306  }
307
308  syncer::GetSessionName(
309      content::BrowserThread::GetBlockingPool(),
310      base::Bind(&SupervisedUserRegistrationUtilityImpl::FetchToken,
311                 weak_ptr_factory_.GetWeakPtr()));
312}
313
314void SupervisedUserRegistrationUtilityImpl::CancelPendingRegistration() {
315  AbortPendingRegistration(
316      false,  // Don't run the callback. The error will be ignored.
317      GoogleServiceAuthError(GoogleServiceAuthError::NONE));
318}
319
320void SupervisedUserRegistrationUtilityImpl::OnSupervisedUserAcknowledged(
321    const std::string& supervised_user_id) {
322  DCHECK_EQ(pending_supervised_user_id_, supervised_user_id);
323  DCHECK(!pending_supervised_user_acknowledged_);
324  pending_supervised_user_acknowledged_ = true;
325  CompleteRegistrationIfReady();
326}
327
328void SupervisedUserRegistrationUtilityImpl::OnPasswordChangeAcknowledged(
329    bool success) {
330  DCHECK(password_update_);
331  DCHECK(success);
332  password_update_.reset();
333  CompleteRegistrationIfReady();
334}
335
336void SupervisedUserRegistrationUtilityImpl::OnSupervisedUsersSyncingStopped() {
337  AbortPendingRegistration(
338      true,  // Run the callback.
339      GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
340}
341
342void SupervisedUserRegistrationUtilityImpl::OnSupervisedUsersChanged() {}
343
344void SupervisedUserRegistrationUtilityImpl::FetchToken(
345    const std::string& client_name) {
346  token_fetcher_->Start(
347      pending_supervised_user_id_, client_name,
348      base::Bind(&SupervisedUserRegistrationUtilityImpl::OnReceivedToken,
349                 weak_ptr_factory_.GetWeakPtr()));
350}
351
352void SupervisedUserRegistrationUtilityImpl::OnReceivedToken(
353    const GoogleServiceAuthError& error,
354    const std::string& token) {
355  if (error.state() != GoogleServiceAuthError::NONE) {
356    CompleteRegistration(true, error);
357    return;
358  }
359
360  DCHECK(!token.empty());
361  pending_supervised_user_token_ = token;
362  CompleteRegistrationIfReady();
363}
364
365void SupervisedUserRegistrationUtilityImpl::CompleteRegistrationIfReady() {
366  bool skip_check = CommandLine::ForCurrentProcess()->HasSwitch(
367      switches::kNoSupervisedUserAcknowledgmentCheck);
368
369  if (!pending_supervised_user_acknowledged_ && !skip_check)
370    return;
371  if (password_update_ && !skip_check)
372    return;
373  if (pending_supervised_user_token_.empty())
374    return;
375
376  GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
377  CompleteRegistration(true, error);
378}
379
380void SupervisedUserRegistrationUtilityImpl::AbortPendingRegistration(
381    bool run_callback,
382    const GoogleServiceAuthError& error) {
383  pending_supervised_user_token_.clear();
384  CompleteRegistration(run_callback, error);
385}
386
387void SupervisedUserRegistrationUtilityImpl::CompleteRegistration(
388    bool run_callback,
389    const GoogleServiceAuthError& error) {
390  if (callback_.is_null())
391    return;
392
393  if (pending_supervised_user_token_.empty()) {
394    DCHECK(!pending_supervised_user_id_.empty());
395
396    if (!is_existing_supervised_user_) {
397      // Remove the pending supervised user if we weren't successful.
398      // However, check that we are not importing a supervised user
399      // before deleting it from sync to avoid accidental deletion of
400      // existing supervised users by just canceling the registration for
401      // example.
402      supervised_user_sync_service_->DeleteSupervisedUser(
403          pending_supervised_user_id_);
404    } else if (avatar_updated_) {
405      // Canceling (or failing) a supervised user import that did set the avatar
406      // should undo this change.
407      supervised_user_sync_service_->ClearSupervisedUserAvatar(
408          pending_supervised_user_id_);
409    }
410  }
411
412  if (run_callback)
413    callback_.Run(error, pending_supervised_user_token_);
414  callback_.Reset();
415}
416
417} // namespace
418