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)