manager_password_service.cc revision 29b820f8d84e3bc97d62552e54923c42407f2f29
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_ = ExtendedAuthenticator::Create(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  new_key_definition.authorization_data.push_back(
168      cryptohome::KeyDefinition::AuthorizationData(true /* encrypt */,
169                                                   false /* sign */,
170                                                   encryption_key));
171  new_key_definition.authorization_data.push_back(
172      cryptohome::KeyDefinition::AuthorizationData(false /* encrypt */,
173                                                   true /* sign */,
174                                                   signature_key));
175
176  authenticator_->AddKey(manager_key,
177                         new_key_definition,
178                         true /* replace existing */,
179                         base::Bind(&ManagerPasswordService::OnAddKeySuccess,
180                                    weak_ptr_factory_.GetWeakPtr(),
181                                    manager_key,
182                                    user_id,
183                                    Passed(&password_data)));
184}
185
186void ManagerPasswordService::OnAuthenticationFailure(
187    ExtendedAuthenticator::AuthState state) {
188  UMA_HISTOGRAM_ENUMERATION(
189      "ManagedUsers.ChromeOS.PasswordChange",
190      SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_MASTER_KEY_FAILURE,
191      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
192  LOG(ERROR) << "Can not apply password change, master key failure";
193}
194
195void ManagerPasswordService::OnAddKeySuccess(
196    const UserContext& master_key_context,
197    const std::string& user_id,
198    scoped_ptr<base::DictionaryValue> password_data) {
199  VLOG(0) << "Password changed for " << user_id;
200  UMA_HISTOGRAM_ENUMERATION(
201      "ManagedUsers.ChromeOS.PasswordChange",
202      SupervisedUserAuthentication::PASSWORD_CHANGED_IN_MANAGER_SESSION,
203      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
204
205  SupervisedUserAuthentication* auth =
206      ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
207  int old_schema = auth->GetPasswordSchema(user_id);
208  auth->StorePasswordData(user_id, *password_data.get());
209
210  if (auth->HasIncompleteKey(user_id))
211    auth->MarkKeyIncomplete(user_id, false /* key is complete now */);
212
213  // Check if we have legacy labels for keys.
214  // TODO(antrim): Migrate it to GetLabels call once wad@ implement it.
215  if (old_schema == SupervisedUserAuthentication::SCHEMA_PLAIN) {
216    // 1) Add new manager key (using old key).
217    // 2) Remove old supervised user key.
218    // 3) Remove old manager key.
219    authenticator_->TransformKeyIfNeeded(
220        master_key_context,
221        base::Bind(&ManagerPasswordService::OnKeyTransformedIfNeeded,
222                   weak_ptr_factory_.GetWeakPtr()));
223  }
224}
225
226void ManagerPasswordService::OnKeyTransformedIfNeeded(
227    const UserContext& master_key_context) {
228  const Key* const key = master_key_context.GetKey();
229  DCHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN, key->GetKeyType());
230  cryptohome::KeyDefinition new_master_key(key->GetSecret(),
231                                           kCryptohomeMasterKeyLabel,
232                                           cryptohome::PRIV_DEFAULT);
233  // Use new master key for further actions.
234  UserContext new_master_key_context = master_key_context;
235  new_master_key_context.GetKey()->SetLabel(kCryptohomeMasterKeyLabel);
236  authenticator_->AddKey(
237      master_key_context,
238      new_master_key,
239      true /* replace existing */,
240      base::Bind(&ManagerPasswordService::OnNewManagerKeySuccess,
241                 weak_ptr_factory_.GetWeakPtr(),
242                 new_master_key_context));
243}
244
245void ManagerPasswordService::OnNewManagerKeySuccess(
246    const UserContext& master_key_context) {
247  VLOG(1) << "Added new master key for " << master_key_context.GetUserID();
248  authenticator_->RemoveKey(
249      master_key_context,
250      kLegacyCryptohomeSupervisedUserKeyLabel,
251      base::Bind(&ManagerPasswordService::OnOldSupervisedUserKeyDeleted,
252                 weak_ptr_factory_.GetWeakPtr(),
253                 master_key_context));
254}
255
256void ManagerPasswordService::OnOldSupervisedUserKeyDeleted(
257    const UserContext& master_key_context) {
258  VLOG(1) << "Removed old supervised user key for "
259          << master_key_context.GetUserID();
260  authenticator_->RemoveKey(
261      master_key_context,
262      kLegacyCryptohomeMasterKeyLabel,
263      base::Bind(&ManagerPasswordService::OnOldManagerKeyDeleted,
264                 weak_ptr_factory_.GetWeakPtr(),
265                 master_key_context));
266}
267
268void ManagerPasswordService::OnOldManagerKeyDeleted(
269    const UserContext& master_key_context) {
270  VLOG(1) << "Removed old master key for " << master_key_context.GetUserID();
271}
272
273void ManagerPasswordService::Shutdown() {
274  settings_service_subscription_.reset();
275}
276
277}  // namespace chromeos
278