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