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