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