manager_password_service.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/chromeos/manager_password_service.h"
6
7#include "base/bind.h"
8#include "base/logging.h"
9#include "base/metrics/histogram.h"
10#include "base/values.h"
11#include "chrome/browser/chromeos/login/auth/key.h"
12#include "chrome/browser/chromeos/login/auth/user_context.h"
13#include "chrome/browser/chromeos/login/managed/locally_managed_user_constants.h"
14#include "chrome/browser/chromeos/login/managed/supervised_user_authentication.h"
15#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
16#include "chrome/browser/chromeos/login/users/user.h"
17#include "chrome/browser/chromeos/login/users/user_manager.h"
18#include "chrome/browser/supervised_user/supervised_user_constants.h"
19#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
20
21namespace chromeos {
22
23ManagerPasswordService::ManagerPasswordService() : weak_ptr_factory_(this) {}
24
25ManagerPasswordService::~ManagerPasswordService() {}
26
27void ManagerPasswordService::Init(
28    const std::string& user_id,
29    SupervisedUserSyncService* user_service,
30    SupervisedUserSharedSettingsService* shared_settings_service) {
31  user_id_ = user_id;
32  user_service_ = user_service;
33  settings_service_ = shared_settings_service;
34  settings_service_subscription_ = settings_service_->Subscribe(
35      base::Bind(&ManagerPasswordService::OnSharedSettingsChange,
36                 weak_ptr_factory_.GetWeakPtr()));
37
38  authenticator_ = new ExtendedAuthenticator(this);
39
40  UserManager* user_manager = UserManager::Get();
41
42  SupervisedUserManager* supervised_user_manager =
43      user_manager->GetSupervisedUserManager();
44
45  const UserList& users = user_manager->GetUsers();
46
47  for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
48    if ((*it)->GetType() != User::USER_TYPE_LOCALLY_MANAGED)
49      continue;
50    if (user_id != supervised_user_manager->GetManagerUserId((*it)->email()))
51      continue;
52    OnSharedSettingsChange(
53        supervised_user_manager->GetUserSyncId((*it)->email()),
54        supervised_users::kChromeOSPasswordData);
55  }
56}
57
58void ManagerPasswordService::OnSharedSettingsChange(
59    const std::string& su_id,
60    const std::string& key) {
61  if (key != supervised_users::kChromeOSPasswordData)
62    return;
63
64  SupervisedUserManager* supervised_user_manager =
65      UserManager::Get()->GetSupervisedUserManager();
66  const User* user = supervised_user_manager->FindBySyncId(su_id);
67  // No user on device.
68  if (user == NULL)
69    return;
70
71  const base::Value* value = settings_service_->GetValue(su_id, key);
72
73  if (value == NULL) {
74    LOG(WARNING) << "Got empty value from sync.";
75    return;
76  }
77  const base::DictionaryValue* dict;
78  if (!value->GetAsDictionary(&dict)) {
79    LOG(WARNING) << "Got non-dictionary value from sync.";
80    return;
81  }
82
83  SupervisedUserAuthentication* auth =
84      supervised_user_manager->GetAuthentication();
85
86  if (!auth->NeedPasswordChange(user->email(), dict) &&
87      !auth->HasIncompleteKey(user->email())) {
88    return;
89  }
90  scoped_ptr<base::DictionaryValue> wrapper(dict->DeepCopy());
91  user_service_->GetSupervisedUsersAsync(
92      base::Bind(&ManagerPasswordService::GetSupervisedUsersCallback,
93                 weak_ptr_factory_.GetWeakPtr(),
94                 su_id,
95                 user->email(),
96                 Passed(&wrapper)));
97}
98
99void ManagerPasswordService::GetSupervisedUsersCallback(
100    const std::string& sync_su_id,
101    const std::string& user_id,
102    scoped_ptr<base::DictionaryValue> password_data,
103    const base::DictionaryValue* supervised_users) {
104  const base::DictionaryValue* supervised_user = NULL;
105  if (!supervised_users->GetDictionary(sync_su_id, &supervised_user))
106    return;
107  std::string master_key;
108  std::string encryption_key;
109  std::string signature_key;
110  if (!supervised_user->GetString(SupervisedUserSyncService::kMasterKey,
111                                  &master_key)) {
112    LOG(WARNING) << "Can not apply password change to " << user_id
113                 << ": no master key found";
114    UMA_HISTOGRAM_ENUMERATION(
115        "ManagedUsers.ChromeOS.PasswordChange",
116        SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_NO_MASTER_KEY,
117        SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
118    return;
119  }
120
121  if (!supervised_user->GetString(
122          SupervisedUserSyncService::kPasswordSignatureKey, &signature_key) ||
123      !supervised_user->GetString(
124          SupervisedUserSyncService::kPasswordEncryptionKey,
125          &encryption_key)) {
126    LOG(WARNING) << "Can not apply password change to " << user_id
127                 << ": no signature / encryption keys.";
128    UMA_HISTOGRAM_ENUMERATION(
129        "ManagedUsers.ChromeOS.PasswordChange",
130        SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_NO_SIGNATURE_KEY,
131        SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
132    return;
133  }
134
135  UserContext manager_key(user_id);
136  manager_key.SetKey(Key(master_key));
137  manager_key.SetIsUsingOAuth(false);
138
139  // As master key can have old label, leave label field empty - it will work
140  // as wildcard.
141
142  std::string new_key;
143  int revision;
144
145  bool has_data = password_data->GetStringWithoutPathExpansion(
146      kEncryptedPassword, &new_key);
147  has_data &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
148                                                            &revision);
149  if (!has_data) {
150    LOG(WARNING) << "Can not apply password change to " << user_id
151                 << ": incomplete password data.";
152    UMA_HISTOGRAM_ENUMERATION(
153        "ManagedUsers.ChromeOS.PasswordChange",
154        SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_NO_PASSWORD_DATA,
155        SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
156    return;
157  }
158
159  cryptohome::KeyDefinition new_key_definition(
160      new_key,
161      kCryptohomeSupervisedUserKeyLabel,
162      cryptohome::PRIV_AUTHORIZED_UPDATE || cryptohome::PRIV_MOUNT);
163  new_key_definition.revision = revision;
164
165  new_key_definition.encryption_key = encryption_key;
166  new_key_definition.signature_key = signature_key;
167
168  authenticator_->AddKey(manager_key,
169                         new_key_definition,
170                         true /* replace existing */,
171                         base::Bind(&ManagerPasswordService::OnAddKeySuccess,
172                                    weak_ptr_factory_.GetWeakPtr(),
173                                    manager_key,
174                                    user_id,
175                                    Passed(&password_data)));
176}
177
178void ManagerPasswordService::OnAuthenticationFailure(
179    ExtendedAuthenticator::AuthState state) {
180  UMA_HISTOGRAM_ENUMERATION(
181      "ManagedUsers.ChromeOS.PasswordChange",
182      SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_MASTER_KEY_FAILURE,
183      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
184  LOG(ERROR) << "Can not apply password change, master key failure";
185}
186
187void ManagerPasswordService::OnAddKeySuccess(
188    const UserContext& master_key_context,
189    const std::string& user_id,
190    scoped_ptr<base::DictionaryValue> password_data) {
191  VLOG(0) << "Password changed for " << user_id;
192  UMA_HISTOGRAM_ENUMERATION(
193      "ManagedUsers.ChromeOS.PasswordChange",
194      SupervisedUserAuthentication::PASSWORD_CHANGED_IN_MANAGER_SESSION,
195      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
196
197  SupervisedUserAuthentication* auth =
198      UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
199  int old_schema = auth->GetPasswordSchema(user_id);
200  auth->StorePasswordData(user_id, *password_data.get());
201
202  if (auth->HasIncompleteKey(user_id))
203    auth->MarkKeyIncomplete(user_id, false /* key is complete now */);
204
205  // Check if we have legacy labels for keys.
206  // TODO(antrim): Migrate it to GetLabels call once wad@ implement it.
207  if (old_schema == SupervisedUserAuthentication::SCHEMA_PLAIN) {
208    // 1) Add new manager key (using old key).
209    // 2) Remove old supervised user key.
210    // 3) Remove old manager key.
211    authenticator_->TransformKeyIfNeeded(
212        master_key_context,
213        base::Bind(&ManagerPasswordService::OnKeyTransformedIfNeeded,
214                   weak_ptr_factory_.GetWeakPtr()));
215  }
216}
217
218void ManagerPasswordService::OnKeyTransformedIfNeeded(
219    const UserContext& master_key_context) {
220  const Key* const key = master_key_context.GetKey();
221  DCHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN, key->GetKeyType());
222  cryptohome::KeyDefinition new_master_key(key->GetSecret(),
223                                           kCryptohomeMasterKeyLabel,
224                                           cryptohome::PRIV_DEFAULT);
225  // Use new master key for further actions.
226  UserContext new_master_key_context = master_key_context;
227  new_master_key_context.GetKey()->SetLabel(kCryptohomeMasterKeyLabel);
228  authenticator_->AddKey(
229      master_key_context,
230      new_master_key,
231      true /* replace existing */,
232      base::Bind(&ManagerPasswordService::OnNewManagerKeySuccess,
233                 weak_ptr_factory_.GetWeakPtr(),
234                 new_master_key_context));
235}
236
237void ManagerPasswordService::OnNewManagerKeySuccess(
238    const UserContext& master_key_context) {
239  VLOG(1) << "Added new master key for " << master_key_context.GetUserID();
240  authenticator_->RemoveKey(
241      master_key_context,
242      kLegacyCryptohomeSupervisedUserKeyLabel,
243      base::Bind(&ManagerPasswordService::OnOldSupervisedUserKeyDeleted,
244                 weak_ptr_factory_.GetWeakPtr(),
245                 master_key_context));
246}
247
248void ManagerPasswordService::OnOldSupervisedUserKeyDeleted(
249    const UserContext& master_key_context) {
250  VLOG(1) << "Removed old supervised user key for "
251          << master_key_context.GetUserID();
252  authenticator_->RemoveKey(
253      master_key_context,
254      kLegacyCryptohomeMasterKeyLabel,
255      base::Bind(&ManagerPasswordService::OnOldManagerKeyDeleted,
256                 weak_ptr_factory_.GetWeakPtr(),
257                 master_key_context));
258}
259
260void ManagerPasswordService::OnOldManagerKeyDeleted(
261    const UserContext& master_key_context) {
262  VLOG(1) << "Removed old master key for " << master_key_context.GetUserID();
263}
264
265void ManagerPasswordService::Shutdown() {
266  settings_service_subscription_.reset();
267}
268
269}  // namespace chromeos
270