1// Copyright 2013 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/managed_mode/managed_user_registration_utility.h"
6
7#include "base/base64.h"
8#include "base/bind.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/prefs/pref_service.h"
11#include "base/rand_util.h"
12#include "base/strings/utf_string_conversions.h"
13#include "chrome/browser/managed_mode/managed_user_refresh_token_fetcher.h"
14#include "chrome/browser/managed_mode/managed_user_service.h"
15#include "chrome/browser/managed_mode/managed_user_service_factory.h"
16#include "chrome/browser/managed_mode/managed_user_sync_service.h"
17#include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
18#include "chrome/browser/prefs/scoped_user_pref_update.h"
19#include "chrome/browser/signin/profile_oauth2_token_service.h"
20#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
21#include "chrome/browser/sync/glue/device_info.h"
22#include "chrome/common/pref_names.h"
23#include "google_apis/gaia/gaia_urls.h"
24#include "google_apis/gaia/google_service_auth_error.h"
25
26using base::DictionaryValue;
27
28const char kAcknowledged[] = "acknowledged";
29const char kName[] = "name";
30const char kMasterKey[] = "masterKey";
31
32ManagedUserRegistrationInfo::ManagedUserRegistrationInfo(const string16& name)
33    : name(name) {
34}
35
36ManagedUserRegistrationUtility::ManagedUserRegistrationUtility(
37    PrefService* prefs,
38    scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher,
39    ManagedUserSyncService* service)
40    : weak_ptr_factory_(this),
41      prefs_(prefs),
42      token_fetcher_(token_fetcher.Pass()),
43      managed_user_sync_service_(service),
44      pending_managed_user_acknowledged_(false),
45      is_existing_managed_user_(false) {
46  managed_user_sync_service_->AddObserver(this);
47}
48
49ManagedUserRegistrationUtility::~ManagedUserRegistrationUtility() {
50  managed_user_sync_service_->RemoveObserver(this);
51  CancelPendingRegistration();
52}
53
54// static
55scoped_ptr<ManagedUserRegistrationUtility>
56ManagedUserRegistrationUtility::Create(Profile* profile) {
57  scoped_ptr<ManagedUserRefreshTokenFetcher> token_fetcher =
58      ManagedUserRefreshTokenFetcher::Create(
59          ProfileOAuth2TokenServiceFactory::GetForProfile(profile),
60          profile->GetRequestContext());
61  ManagedUserSyncService* managed_user_sync_service =
62      ManagedUserSyncServiceFactory::GetForProfile(profile);
63  return make_scoped_ptr(new ManagedUserRegistrationUtility(
64      profile->GetPrefs(), token_fetcher.Pass(), managed_user_sync_service));
65}
66
67// static
68std::string ManagedUserRegistrationUtility::GenerateNewManagedUserId() {
69  std::string new_managed_user_id;
70  bool success = base::Base64Encode(base::RandBytesAsString(8),
71                                    &new_managed_user_id);
72  DCHECK(success);
73  return new_managed_user_id;
74}
75
76void ManagedUserRegistrationUtility::Register(
77    const std::string& managed_user_id,
78    const ManagedUserRegistrationInfo& info,
79    const RegistrationCallback& callback) {
80  DCHECK(pending_managed_user_id_.empty());
81  callback_ = callback;
82  pending_managed_user_id_ = managed_user_id;
83
84  const DictionaryValue* dict = prefs_->GetDictionary(prefs::kManagedUsers);
85  is_existing_managed_user_ = dict->HasKey(managed_user_id);
86  if (!is_existing_managed_user_) {
87    managed_user_sync_service_->AddManagedUser(pending_managed_user_id_,
88                                               base::UTF16ToUTF8(info.name),
89                                               info.master_key);
90  } else {
91    // User already exists, don't wait for acknowledgment.
92    OnManagedUserAcknowledged(managed_user_id);
93  }
94
95  browser_sync::DeviceInfo::GetClientName(
96      base::Bind(&ManagedUserRegistrationUtility::FetchToken,
97                 weak_ptr_factory_.GetWeakPtr()));
98}
99
100void ManagedUserRegistrationUtility::CancelPendingRegistration() {
101  AbortPendingRegistration(
102      false,  // Don't run the callback. The error will be ignored.
103      GoogleServiceAuthError(GoogleServiceAuthError::NONE));
104}
105
106void ManagedUserRegistrationUtility::OnManagedUserAcknowledged(
107    const std::string& managed_user_id) {
108  DCHECK_EQ(pending_managed_user_id_, managed_user_id);
109  DCHECK(!pending_managed_user_acknowledged_);
110  pending_managed_user_acknowledged_ = true;
111  CompleteRegistrationIfReady();
112}
113
114void ManagedUserRegistrationUtility::OnManagedUsersSyncingStopped() {
115  AbortPendingRegistration(
116      true,   // Run the callback.
117      GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED));
118}
119
120void ManagedUserRegistrationUtility::FetchToken(
121    const std::string& client_name) {
122  token_fetcher_->Start(
123      pending_managed_user_id_, client_name,
124      base::Bind(&ManagedUserRegistrationUtility::OnReceivedToken,
125                 weak_ptr_factory_.GetWeakPtr()));
126}
127
128void ManagedUserRegistrationUtility::OnReceivedToken(
129    const GoogleServiceAuthError& error,
130    const std::string& token) {
131  if (error.state() != GoogleServiceAuthError::NONE) {
132    CompleteRegistration(true, error);
133    return;
134  }
135
136  DCHECK(!token.empty());
137  pending_managed_user_token_ = token;
138  CompleteRegistrationIfReady();
139}
140
141void ManagedUserRegistrationUtility::CompleteRegistrationIfReady() {
142  if (!pending_managed_user_acknowledged_ ||
143      pending_managed_user_token_.empty()) {
144    return;
145  }
146
147  GoogleServiceAuthError error(GoogleServiceAuthError::NONE);
148  CompleteRegistration(true, error);
149}
150
151void ManagedUserRegistrationUtility::AbortPendingRegistration(
152    bool run_callback,
153    const GoogleServiceAuthError& error) {
154  pending_managed_user_token_.clear();
155  CompleteRegistration(run_callback, error);
156}
157
158void ManagedUserRegistrationUtility::CompleteRegistration(
159    bool run_callback,
160    const GoogleServiceAuthError& error) {
161  if (callback_.is_null())
162    return;
163
164  // We check that the user being registered is not an existing managed
165  // user before deleting it from sync to avoid accidental deletion of
166  // existing managed users by just canceling the registration for example.
167  if (pending_managed_user_token_.empty() && !is_existing_managed_user_) {
168    DCHECK(!pending_managed_user_id_.empty());
169    // Remove the pending managed user if we weren't successful.
170    DictionaryPrefUpdate update(prefs_, prefs::kManagedUsers);
171    bool success =
172        update->RemoveWithoutPathExpansion(pending_managed_user_id_, NULL);
173    DCHECK(success);
174    managed_user_sync_service_->DeleteManagedUser(pending_managed_user_id_);
175  }
176
177  if (run_callback)
178    callback_.Run(error, pending_managed_user_token_);
179  callback_.Reset();
180}
181