15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/base64.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/json/json_file_value_serializer.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/macros.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/metrics/histogram.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string_util.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/login/supervised/supervised_user_constants.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/chromeos/profiles/profile_helper.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/cryptohome/signed_secret.pb.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/login/auth/key.h"
199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "components/user_manager/user.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "components/user_manager/user_manager.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "crypto/hmac.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/random.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/symmetric_key.h"
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Byte size of hash salt.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const unsigned kSaltSize = 32;
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Size of key signature.
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const unsigned kHMACKeySizeInBits = 256;
354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)const int kSignatureLength = 32;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Size of master key (in bytes).
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const int kMasterKeySize = 32;
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)std::string CreateSalt() {
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    char result[kSaltSize];
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    crypto::RandBytes(&result, sizeof(result));
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return base::StringToLowerASCII(base::HexEncode(
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        reinterpret_cast<const void*>(result),
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        sizeof(result)));
46effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch}
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochstd::string BuildRawHMACKey() {
490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  scoped_ptr<crypto::SymmetricKey> key(crypto::SymmetricKey::GenerateRandomKey(
50effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      crypto::SymmetricKey::AES, kHMACKeySizeInBits));
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string raw_result, result;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  key->GetRawKey(&raw_result);
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Base64Encode(raw_result, &result);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::DictionaryValue* LoadPasswordData(base::FilePath profile_dir) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONFileValueSerializer serializer(profile_dir.Append(kPasswordUpdateFile));
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string error_message;
60e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch  int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
61effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  scoped_ptr<base::Value> value(
62e5d81f57cb97b3b6b7fccc9c5610d21eb81db09dBen Murdoch      serializer.Deserialize(&error_code, &error_message));
630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (JSONFileValueSerializer::JSON_NO_ERROR != error_code) {
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Could not deserialize password data, error = " << error_code
6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)               << " / " << error_message;
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue* result;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value->GetAsDictionary(&result)) {
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Stored password data is not a dictionary";
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ignore_result(value.release());
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void OnPasswordDataLoaded(
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const SupervisedUserAuthentication::PasswordDataCallback& success_callback,
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    const base::Closure& failure_callback,
80c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    base::DictionaryValue* value) {
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    failure_callback.Run();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  success_callback.Run(value);
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete value;
87bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)SupervisedUserAuthentication::SupervisedUserAuthentication(
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    SupervisedUserManager* owner)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : owner_(owner),
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        stable_schema_(SCHEMA_SALT_HASHED) {
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SupervisedUserAuthentication::~SupervisedUserAuthentication() {}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SupervisedUserAuthentication::Schema
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)SupervisedUserAuthentication::GetStableSchema() {
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  return stable_schema_;
102a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UserContext SupervisedUserAuthentication::TransformKey(
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const UserContext& context) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UserContext result = context;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int user_schema = GetPasswordSchema(context.GetUserID());
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (user_schema == SCHEMA_PLAIN)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (user_schema == SCHEMA_SALT_HASHED) {
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::DictionaryValue holder;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::string salt;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    owner_->GetPasswordInformation(context.GetUserID(), &holder);
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    holder.GetStringWithoutPathExpansion(kSalt, &salt);
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!salt.empty());
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Key* const key = result.GetKey();
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key->Transform(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234, salt);
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    key->SetLabel(kCryptohomeSupervisedUserKeyLabel);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    result.SetIsUsingOAuth(false);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  NOTREACHED() << "Unknown password schema for " << context.GetUserID();
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return context;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1267d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1277d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)bool SupervisedUserAuthentication::FillDataForNewUser(
1287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& user_id,
1297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string& password,
1307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue* password_data,
1317d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    base::DictionaryValue* extra_data) {
1327d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  Schema schema = stable_schema_;
1337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (schema == SCHEMA_PLAIN)
1347d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return false;
1357d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  if (schema == SCHEMA_SALT_HASHED) {
1377d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    password_data->SetIntegerWithoutPathExpansion(kSchemaVersion, schema);
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    std::string salt = CreateSalt();
1397d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    password_data->SetStringWithoutPathExpansion(kSalt, salt);
1407d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    int revision = kMinPasswordRevision;
1417d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    password_data->SetIntegerWithoutPathExpansion(kPasswordRevision, revision);
1427d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    Key key(password);
1437d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    key.Transform(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234, salt);
1447d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string salted_password = key.GetSecret();
1457d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string base64_signature_key = BuildRawHMACKey();
1467d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    const std::string base64_signature =
1477d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        BuildPasswordSignature(salted_password, revision, base64_signature_key);
1487d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    password_data->SetStringWithoutPathExpansion(kEncryptedPassword,
1497d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                 salted_password);
1507d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    password_data->SetStringWithoutPathExpansion(kPasswordSignature,
1517d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)                                                 base64_signature);
1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra_data->SetStringWithoutPathExpansion(kPasswordEncryptionKey,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              BuildRawHMACKey());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extra_data->SetStringWithoutPathExpansion(kPasswordSignatureKey,
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                              base64_signature_key);
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return true;
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
16168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
16268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
16368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)std::string SupervisedUserAuthentication::GenerateMasterKey() {
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  char master_key_bytes[kMasterKeySize];
16568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  crypto::RandBytes(&master_key_bytes, sizeof(master_key_bytes));
166a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  return base::StringToLowerASCII(
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      base::HexEncode(reinterpret_cast<const void*>(master_key_bytes),
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                      sizeof(master_key_bytes)));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SupervisedUserAuthentication::StorePasswordData(
172f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const std::string& user_id,
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue& password_data) {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue holder;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->GetPasswordInformation(user_id, &holder);
176868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::Value* value;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (password_data.GetWithoutPathExpansion(kSchemaVersion, &value))
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      holder.SetWithoutPathExpansion(kSchemaVersion, value->DeepCopy());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (password_data.GetWithoutPathExpansion(kSalt, &value))
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      holder.SetWithoutPathExpansion(kSalt, value->DeepCopy());
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (password_data.GetWithoutPathExpansion(kPasswordRevision, &value))
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      holder.SetWithoutPathExpansion(kPasswordRevision, value->DeepCopy());
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->SetPasswordInformation(user_id, &holder);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
18568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)SupervisedUserAuthentication::Schema
187f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SupervisedUserAuthentication::GetPasswordSchema(
188a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  const std::string& user_id) {
189f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  base::DictionaryValue holder;
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
191a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  owner_->GetPasswordInformation(user_id, &holder);
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Default version.
193a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int schema_version_index;
194a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  Schema schema_version = SCHEMA_PLAIN;
195a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  if (holder.GetIntegerWithoutPathExpansion(kSchemaVersion,
196a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                            &schema_version_index)) {
197a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    schema_version = static_cast<Schema>(schema_version_index);
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  }
199f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return schema_version;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SupervisedUserAuthentication::NeedPasswordChange(
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_id,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue* password_data) {
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue local;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->GetPasswordInformation(user_id, &local);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int local_schema = SCHEMA_PLAIN;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int local_revision = kMinPasswordRevision;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int updated_schema = SCHEMA_PLAIN;
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int updated_revision = kMinPasswordRevision;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  local.GetIntegerWithoutPathExpansion(kSchemaVersion, &local_schema);
212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  local.GetIntegerWithoutPathExpansion(kPasswordRevision, &local_revision);
2130529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  password_data->GetIntegerWithoutPathExpansion(kSchemaVersion,
2140529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                &updated_schema);
2150529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
2160529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                &updated_revision);
2170529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  if (updated_schema > local_schema)
2180529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    return true;
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(updated_schema, local_schema);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return updated_revision > local_revision;
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SupervisedUserAuthentication::ScheduleSupervisedPasswordChange(
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& supervised_user_id,
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const base::DictionaryValue* password_data) {
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const user_manager::User* user =
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user_manager::UserManager::Get()->FindUser(supervised_user_id);
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::FilePath profile_path = ProfileHelper::GetProfilePathByUserIdHash(
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      user->username_hash());
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  JSONFileValueSerializer serializer(profile_path.Append(kPasswordUpdateFile));
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!serializer.Serialize(*password_data)) {
23290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    LOG(ERROR) << "Failed to schedule password update for supervised user "
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << supervised_user_id;
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UMA_HISTOGRAM_ENUMERATION(
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "ManagedUsers.ChromeOS.PasswordChange",
2367d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_STORE_DATA,
2371e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
2381e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return;
239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue holder;
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  owner_->GetPasswordInformation(supervised_user_id, &holder);
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  holder.SetBoolean(kRequirePasswordUpdate, true);
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->SetPasswordInformation(supervised_user_id, &holder);
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SupervisedUserAuthentication::HasScheduledPasswordUpdate(
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_id) {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue holder;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->GetPasswordInformation(user_id, &holder);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool require_update = false;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  holder.GetBoolean(kRequirePasswordUpdate, &require_update);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return require_update;
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void SupervisedUserAuthentication::ClearScheduledPasswordUpdate(
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_id) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue holder;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->GetPasswordInformation(user_id, &holder);
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  holder.SetBoolean(kRequirePasswordUpdate, false);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->SetPasswordInformation(user_id, &holder);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SupervisedUserAuthentication::HasIncompleteKey(
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& user_id) {
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::DictionaryValue holder;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  owner_->GetPasswordInformation(user_id, &holder);
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool incomplete_key = false;
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  holder.GetBoolean(kHasIncompleteKey, &incomplete_key);
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return incomplete_key;
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
272effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid SupervisedUserAuthentication::MarkKeyIncomplete(const std::string& user_id,
273effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch                                                     bool incomplete) {
274effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  base::DictionaryValue holder;
275effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  owner_->GetPasswordInformation(user_id, &holder);
276effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  holder.SetBoolean(kHasIncompleteKey, incomplete);
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  owner_->SetPasswordInformation(user_id, &holder);
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
280effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochvoid SupervisedUserAuthentication::LoadPasswordUpdateData(
281effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const std::string& user_id,
282effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const PasswordDataCallback& success_callback,
283effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    const base::Closure& failure_callback) {
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const user_manager::User* user =
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      user_manager::UserManager::Get()->FindUser(user_id);
286a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  base::FilePath profile_path =
287a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      ProfileHelper::GetProfilePathByUserIdHash(user->username_hash());
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  PostTaskAndReplyWithResult(
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::BrowserThread::GetBlockingPool(),
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FROM_HERE,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&LoadPasswordData, profile_path),
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&OnPasswordDataLoaded, success_callback, failure_callback));
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)std::string SupervisedUserAuthentication::BuildPasswordSignature(
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int revision,
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& base64_signature_key) {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ac::chrome::managedaccounts::account::Secret secret;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  secret.set_revision(revision);
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  secret.set_secret(password);
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string buffer;
303868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!secret.SerializeToString(&buffer))
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << "Protobuf::SerializeToString failed";
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string signature_key;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Base64Decode(base64_signature_key, &signature_key);
30723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
30823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  crypto::HMAC hmac(crypto::HMAC::SHA256);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!hmac.Init(signature_key))
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << "HMAC::Init failed";
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unsigned char out_bytes[kSignatureLength];
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!hmac.Sign(buffer, out_bytes, sizeof(out_bytes)))
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(FATAL) << "HMAC::Sign failed";
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string raw_result(out_bytes, out_bytes + sizeof(out_bytes));
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
318868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string result;
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Base64Encode(raw_result, &result);
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace chromeos
324c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)