blob: c13cf86a6b61f8c2d2ac693b318bec6f91b84afe [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/supervised_user/chromeos/manager_password_service.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "base/values.h"
#include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
#include "chrome/browser/chromeos/login/supervised/supervised_user_constants.h"
#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
#include "chrome/browser/supervised_user/supervised_user_constants.h"
#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
#include "chromeos/login/auth/key.h"
#include "chromeos/login/auth/user_context.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "components/user_manager/user_type.h"
namespace chromeos {
ManagerPasswordService::ManagerPasswordService() : weak_ptr_factory_(this) {}
ManagerPasswordService::~ManagerPasswordService() {}
void ManagerPasswordService::Init(
const std::string& user_id,
SupervisedUserSyncService* user_service,
SupervisedUserSharedSettingsService* shared_settings_service) {
user_id_ = user_id;
user_service_ = user_service;
settings_service_ = shared_settings_service;
settings_service_subscription_ = settings_service_->Subscribe(
base::Bind(&ManagerPasswordService::OnSharedSettingsChange,
weak_ptr_factory_.GetWeakPtr()));
authenticator_ = ExtendedAuthenticator::Create(this);
SupervisedUserManager* supervised_user_manager =
ChromeUserManager::Get()->GetSupervisedUserManager();
for (const user_manager::User* user :
user_manager::UserManager::Get()->GetUsers()) {
if (user->GetType() != user_manager::USER_TYPE_SUPERVISED)
continue;
if (user_id != supervised_user_manager->GetManagerUserId(user->email()))
continue;
OnSharedSettingsChange(
supervised_user_manager->GetUserSyncId(user->email()),
supervised_users::kChromeOSPasswordData);
}
}
void ManagerPasswordService::OnSharedSettingsChange(
const std::string& su_id,
const std::string& key) {
if (key != supervised_users::kChromeOSPasswordData)
return;
SupervisedUserManager* supervised_user_manager =
ChromeUserManager::Get()->GetSupervisedUserManager();
const user_manager::User* user = supervised_user_manager->FindBySyncId(su_id);
// No user on device.
if (user == NULL)
return;
const base::Value* value = settings_service_->GetValue(su_id, key);
if (value == NULL) {
LOG(WARNING) << "Got empty value from sync.";
return;
}
const base::DictionaryValue* dict;
if (!value->GetAsDictionary(&dict)) {
LOG(WARNING) << "Got non-dictionary value from sync.";
return;
}
SupervisedUserAuthentication* auth =
supervised_user_manager->GetAuthentication();
if (!auth->NeedPasswordChange(user->email(), dict) &&
!auth->HasIncompleteKey(user->email())) {
return;
}
scoped_ptr<base::DictionaryValue> wrapper(dict->DeepCopy());
user_service_->GetSupervisedUsersAsync(
base::Bind(&ManagerPasswordService::GetSupervisedUsersCallback,
weak_ptr_factory_.GetWeakPtr(),
su_id,
user->email(),
Passed(&wrapper)));
}
void ManagerPasswordService::GetSupervisedUsersCallback(
const std::string& sync_su_id,
const std::string& user_id,
scoped_ptr<base::DictionaryValue> password_data,
const base::DictionaryValue* supervised_users) {
const base::DictionaryValue* supervised_user = NULL;
if (!supervised_users->GetDictionary(sync_su_id, &supervised_user))
return;
std::string master_key;
std::string encryption_key;
std::string signature_key;
if (!supervised_user->GetString(SupervisedUserSyncService::kMasterKey,
&master_key)) {
LOG(WARNING) << "Can not apply password change to " << user_id
<< ": no master key found";
UMA_HISTOGRAM_ENUMERATION(
"ManagedUsers.ChromeOS.PasswordChange",
SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_NO_MASTER_KEY,
SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
return;
}
if (!supervised_user->GetString(
SupervisedUserSyncService::kPasswordSignatureKey, &signature_key) ||
!supervised_user->GetString(
SupervisedUserSyncService::kPasswordEncryptionKey,
&encryption_key)) {
LOG(WARNING) << "Can not apply password change to " << user_id
<< ": no signature / encryption keys.";
UMA_HISTOGRAM_ENUMERATION(
"ManagedUsers.ChromeOS.PasswordChange",
SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_NO_SIGNATURE_KEY,
SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
return;
}
UserContext manager_key(user_id);
manager_key.SetKey(Key(master_key));
manager_key.SetIsUsingOAuth(false);
// As master key can have old label, leave label field empty - it will work
// as wildcard.
std::string new_key;
int revision;
bool has_data = password_data->GetStringWithoutPathExpansion(
kEncryptedPassword, &new_key);
has_data &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
&revision);
if (!has_data) {
LOG(WARNING) << "Can not apply password change to " << user_id
<< ": incomplete password data.";
UMA_HISTOGRAM_ENUMERATION(
"ManagedUsers.ChromeOS.PasswordChange",
SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_NO_PASSWORD_DATA,
SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
return;
}
cryptohome::KeyDefinition new_key_definition(
new_key,
kCryptohomeSupervisedUserKeyLabel,
cryptohome::PRIV_AUTHORIZED_UPDATE || cryptohome::PRIV_MOUNT);
new_key_definition.revision = revision;
new_key_definition.authorization_data.push_back(
cryptohome::KeyDefinition::AuthorizationData(true /* encrypt */,
false /* sign */,
encryption_key));
new_key_definition.authorization_data.push_back(
cryptohome::KeyDefinition::AuthorizationData(false /* encrypt */,
true /* sign */,
signature_key));
authenticator_->AddKey(manager_key,
new_key_definition,
true /* replace existing */,
base::Bind(&ManagerPasswordService::OnAddKeySuccess,
weak_ptr_factory_.GetWeakPtr(),
manager_key,
user_id,
Passed(&password_data)));
}
void ManagerPasswordService::OnAuthenticationFailure(
ExtendedAuthenticator::AuthState state) {
UMA_HISTOGRAM_ENUMERATION(
"ManagedUsers.ChromeOS.PasswordChange",
SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_MASTER_KEY_FAILURE,
SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
LOG(ERROR) << "Can not apply password change, master key failure";
}
void ManagerPasswordService::OnAddKeySuccess(
const UserContext& master_key_context,
const std::string& user_id,
scoped_ptr<base::DictionaryValue> password_data) {
VLOG(0) << "Password changed for " << user_id;
UMA_HISTOGRAM_ENUMERATION(
"ManagedUsers.ChromeOS.PasswordChange",
SupervisedUserAuthentication::PASSWORD_CHANGED_IN_MANAGER_SESSION,
SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
SupervisedUserAuthentication* auth =
ChromeUserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
int old_schema = auth->GetPasswordSchema(user_id);
auth->StorePasswordData(user_id, *password_data.get());
if (auth->HasIncompleteKey(user_id))
auth->MarkKeyIncomplete(user_id, false /* key is complete now */);
// Check if we have legacy labels for keys.
// TODO(antrim): Migrate it to GetLabels call once wad@ implement it.
if (old_schema == SupervisedUserAuthentication::SCHEMA_PLAIN) {
// 1) Add new manager key (using old key).
// 2) Remove old supervised user key.
// 3) Remove old manager key.
authenticator_->TransformKeyIfNeeded(
master_key_context,
base::Bind(&ManagerPasswordService::OnKeyTransformedIfNeeded,
weak_ptr_factory_.GetWeakPtr()));
}
}
void ManagerPasswordService::OnKeyTransformedIfNeeded(
const UserContext& master_key_context) {
const Key* const key = master_key_context.GetKey();
DCHECK_NE(Key::KEY_TYPE_PASSWORD_PLAIN, key->GetKeyType());
cryptohome::KeyDefinition new_master_key(key->GetSecret(),
kCryptohomeMasterKeyLabel,
cryptohome::PRIV_DEFAULT);
// Use new master key for further actions.
UserContext new_master_key_context = master_key_context;
new_master_key_context.GetKey()->SetLabel(kCryptohomeMasterKeyLabel);
authenticator_->AddKey(
master_key_context,
new_master_key,
true /* replace existing */,
base::Bind(&ManagerPasswordService::OnNewManagerKeySuccess,
weak_ptr_factory_.GetWeakPtr(),
new_master_key_context));
}
void ManagerPasswordService::OnNewManagerKeySuccess(
const UserContext& master_key_context) {
VLOG(1) << "Added new master key for " << master_key_context.GetUserID();
authenticator_->RemoveKey(
master_key_context,
kLegacyCryptohomeSupervisedUserKeyLabel,
base::Bind(&ManagerPasswordService::OnOldSupervisedUserKeyDeleted,
weak_ptr_factory_.GetWeakPtr(),
master_key_context));
}
void ManagerPasswordService::OnOldSupervisedUserKeyDeleted(
const UserContext& master_key_context) {
VLOG(1) << "Removed old supervised user key for "
<< master_key_context.GetUserID();
authenticator_->RemoveKey(
master_key_context,
kLegacyCryptohomeMasterKeyLabel,
base::Bind(&ManagerPasswordService::OnOldManagerKeyDeleted,
weak_ptr_factory_.GetWeakPtr(),
master_key_context));
}
void ManagerPasswordService::OnOldManagerKeyDeleted(
const UserContext& master_key_context) {
VLOG(1) << "Removed old master key for " << master_key_context.GetUserID();
}
void ManagerPasswordService::Shutdown() {
settings_service_subscription_.reset();
}
} // namespace chromeos