Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / managed / supervised_user_authentication.cc
index a45b929..db514a9 100644 (file)
@@ -5,11 +5,20 @@
 #include "chrome/browser/chromeos/login/managed/supervised_user_authentication.h"
 
 #include "base/base64.h"
-#include "base/command_line.h"
+#include "base/json/json_file_value_serializer.h"
+#include "base/macros.h"
+#include "base/metrics/histogram.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/chromeos/login/managed/locally_managed_user_constants.h"
 #include "chrome/browser/chromeos/login/supervised_user_manager.h"
-#include "chromeos/chromeos_switches.h"
+#include "chrome/browser/chromeos/login/user.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/profiles/profile_helper.h"
+#include "chromeos/cryptohome/signed_secret.pb.h"
+#include "content/public/browser/browser_thread.h"
+#include "crypto/hmac.h"
 #include "crypto/random.h"
 #include "crypto/symmetric_key.h"
 
@@ -20,10 +29,17 @@ namespace {
 // Byte size of hash salt.
 const unsigned kSaltSize = 32;
 
-// Parameters of cryptographic hashing.
+// Parameters of cryptographic hashing for new user schema.
 const unsigned kNumIterations = 1234;
 const unsigned kKeySizeInBits = 256;
 
+// Size of key signature.
+const unsigned kHMACKeySizeInBits = 256;
+const int kSignatureLength = 32;
+
+// Size of master key (in bytes).
+const int kMasterKeySize = 32;
+
 std::string CreateSalt() {
     char result[kSaltSize];
     crypto::RandBytes(&result, sizeof(result));
@@ -32,36 +48,62 @@ std::string CreateSalt() {
         sizeof(result)));
 }
 
-std::string BuildPasswordForHashWithSaltSchema(
-  const std::string& salt,
-  const std::string& plain_password) {
-  scoped_ptr<crypto::SymmetricKey> key(
-      crypto::SymmetricKey::DeriveKeyFromPassword(
-          crypto::SymmetricKey::AES,
-          plain_password, salt,
-          kNumIterations, kKeySizeInBits));
+std::string BuildRawHMACKey() {
+  scoped_ptr<crypto::SymmetricKey> key(crypto::SymmetricKey::GenerateRandomKey(
+      crypto::SymmetricKey::AES, kHMACKeySizeInBits));
   std::string raw_result, result;
   key->GetRawKey(&raw_result);
   base::Base64Encode(raw_result, &result);
   return result;
 }
 
+base::DictionaryValue* LoadPasswordData(base::FilePath profile_dir) {
+  JSONFileValueSerializer serializer(profile_dir.Append(kPasswordUpdateFile));
+  std::string error_message;
+  int error_code = JSONFileValueSerializer::JSON_NO_ERROR;
+  scoped_ptr<base::Value> value(
+      serializer.Deserialize(&error_code, &error_message));
+  if (JSONFileValueSerializer::JSON_NO_ERROR != error_code) {
+    LOG(ERROR) << "Could not deserialize password data, error = " << error_code
+               << " / " << error_message;
+    return NULL;
+  }
+  base::DictionaryValue* result;
+  if (!value->GetAsDictionary(&result)) {
+    LOG(ERROR) << "Stored password data is not a dictionary";
+    return NULL;
+  }
+  ignore_result(value.release());
+  return result;
+}
+
+void OnPasswordDataLoaded(
+    const SupervisedUserAuthentication::PasswordDataCallback& success_callback,
+    const base::Closure& failure_callback,
+    base::DictionaryValue* value) {
+  if (!value) {
+    failure_callback.Run();
+    return;
+  }
+  success_callback.Run(value);
+  delete value;
+}
+
 }  // namespace
 
 SupervisedUserAuthentication::SupervisedUserAuthentication(
     SupervisedUserManager* owner)
       : owner_(owner),
-        migration_enabled_(false),
-        stable_schema_(SCHEMA_PLAIN) {
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
-  if (command_line->HasSwitch(switches::kEnableSupervisedPasswordSync)) {
-    migration_enabled_ = true;
-    stable_schema_ = SCHEMA_SALT_HASHED;
-  }
+        stable_schema_(SCHEMA_SALT_HASHED) {
 }
 
 SupervisedUserAuthentication::~SupervisedUserAuthentication() {}
 
+SupervisedUserAuthentication::Schema
+SupervisedUserAuthentication::GetStableSchema() {
+  return stable_schema_;
+}
+
 std::string SupervisedUserAuthentication::TransformPassword(
     const std::string& user_id,
     const std::string& password) {
@@ -81,27 +123,74 @@ std::string SupervisedUserAuthentication::TransformPassword(
   return password;
 }
 
+UserContext SupervisedUserAuthentication::TransformPasswordInContext(
+    const UserContext& context) {
+  UserContext result;
+  result.CopyFrom(context);
+  int user_schema = GetPasswordSchema(context.username);
+  if (user_schema == SCHEMA_PLAIN)
+    return result;
+
+  if (user_schema == SCHEMA_SALT_HASHED) {
+    base::DictionaryValue holder;
+    std::string salt;
+    owner_->GetPasswordInformation(context.username, &holder);
+    holder.GetStringWithoutPathExpansion(kSalt, &salt);
+    DCHECK(!salt.empty());
+    result.password =
+        BuildPasswordForHashWithSaltSchema(salt, context.password);
+    result.need_password_hashing = false;
+    result.using_oauth = false;
+    result.key_label = kCryptohomeManagedUserKeyLabel;
+    return result;
+  }
+  NOTREACHED() << "Unknown password schema for " << context.username;
+  return context;
+}
+
 bool SupervisedUserAuthentication::FillDataForNewUser(
     const std::string& user_id,
     const std::string& password,
-    base::DictionaryValue* password_data) {
+    base::DictionaryValue* password_data,
+    base::DictionaryValue* extra_data) {
   Schema schema = stable_schema_;
   if (schema == SCHEMA_PLAIN)
     return false;
+
   if (schema == SCHEMA_SALT_HASHED) {
     password_data->SetIntegerWithoutPathExpansion(kSchemaVersion, schema);
     std::string salt = CreateSalt();
     password_data->SetStringWithoutPathExpansion(kSalt, salt);
-    password_data->SetIntegerWithoutPathExpansion(kPasswordRevision,
-        kMinPasswordRevision);
+    int revision = kMinPasswordRevision;
+    password_data->SetIntegerWithoutPathExpansion(kPasswordRevision, revision);
+    std::string salted_password =
+        BuildPasswordForHashWithSaltSchema(salt, password);
+    std::string base64_signature_key = BuildRawHMACKey();
+    std::string base64_signature =
+        BuildPasswordSignature(salted_password, revision, base64_signature_key);
     password_data->SetStringWithoutPathExpansion(kEncryptedPassword,
-        BuildPasswordForHashWithSaltSchema(salt, password));
+                                                 salted_password);
+    password_data->SetStringWithoutPathExpansion(kPasswordSignature,
+                                                 base64_signature);
+
+    extra_data->SetStringWithoutPathExpansion(kPasswordEncryptionKey,
+                                              BuildRawHMACKey());
+    extra_data->SetStringWithoutPathExpansion(kPasswordSignatureKey,
+                                              base64_signature_key);
     return true;
   }
   NOTREACHED();
   return false;
 }
 
+std::string SupervisedUserAuthentication::GenerateMasterKey() {
+  char master_key_bytes[kMasterKeySize];
+  crypto::RandBytes(&master_key_bytes, sizeof(master_key_bytes));
+  return StringToLowerASCII(
+      base::HexEncode(reinterpret_cast<const void*>(master_key_bytes),
+                      sizeof(master_key_bytes)));
+}
+
 void SupervisedUserAuthentication::StorePasswordData(
     const std::string& user_id,
     const base::DictionaryValue& password_data) {
@@ -117,11 +206,6 @@ void SupervisedUserAuthentication::StorePasswordData(
   owner_->SetPasswordInformation(user_id, &holder);
 }
 
-bool SupervisedUserAuthentication::PasswordNeedsMigration(
-    const std::string& user_id) {
-  return GetPasswordSchema(user_id) < stable_schema_;
-}
-
 SupervisedUserAuthentication::Schema
 SupervisedUserAuthentication::GetPasswordSchema(
   const std::string& user_id) {
@@ -138,11 +222,139 @@ SupervisedUserAuthentication::GetPasswordSchema(
   return schema_version;
 }
 
-void SupervisedUserAuthentication::SchedulePasswordMigration(
+bool SupervisedUserAuthentication::NeedPasswordChange(
+    const std::string& user_id,
+    const base::DictionaryValue* password_data) {
+  base::DictionaryValue local;
+  owner_->GetPasswordInformation(user_id, &local);
+  int local_schema = SCHEMA_PLAIN;
+  int local_revision = kMinPasswordRevision;
+  int updated_schema = SCHEMA_PLAIN;
+  int updated_revision = kMinPasswordRevision;
+  local.GetIntegerWithoutPathExpansion(kSchemaVersion, &local_schema);
+  local.GetIntegerWithoutPathExpansion(kPasswordRevision, &local_revision);
+  password_data->GetIntegerWithoutPathExpansion(kSchemaVersion,
+                                                &updated_schema);
+  password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
+                                                &updated_revision);
+  if (updated_schema > local_schema)
+    return true;
+  DCHECK_EQ(updated_schema, local_schema);
+  return updated_revision > local_revision;
+}
+
+void SupervisedUserAuthentication::ScheduleSupervisedPasswordChange(
     const std::string& supervised_user_id,
-    const std::string& user_password,
-    SupervisedUserLoginFlow* user_flow) {
-  // TODO(antrim): Add actual migration code once cryptohome has required API.
+    const base::DictionaryValue* password_data) {
+  const User* user = UserManager::Get()->FindUser(supervised_user_id);
+  base::FilePath profile_path = ProfileHelper::GetProfilePathByUserIdHash(
+      user->username_hash());
+  JSONFileValueSerializer serializer(profile_path.Append(kPasswordUpdateFile));
+  if (!serializer.Serialize(*password_data)) {
+    LOG(ERROR) << "Failed to schedule password update for supervised user "
+               << supervised_user_id;
+    UMA_HISTOGRAM_ENUMERATION(
+        "ManagedUsers.ChromeOS.PasswordChange",
+        SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_STORE_DATA,
+        SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
+    return;
+  }
+  base::DictionaryValue holder;
+  owner_->GetPasswordInformation(supervised_user_id, &holder);
+  holder.SetBoolean(kRequirePasswordUpdate, true);
+  owner_->SetPasswordInformation(supervised_user_id, &holder);
+}
+
+bool SupervisedUserAuthentication::HasScheduledPasswordUpdate(
+    const std::string& user_id) {
+  base::DictionaryValue holder;
+  owner_->GetPasswordInformation(user_id, &holder);
+  bool require_update = false;
+  holder.GetBoolean(kRequirePasswordUpdate, &require_update);
+  return require_update;
+}
+
+void SupervisedUserAuthentication::ClearScheduledPasswordUpdate(
+    const std::string& user_id) {
+  base::DictionaryValue holder;
+  owner_->GetPasswordInformation(user_id, &holder);
+  holder.SetBoolean(kRequirePasswordUpdate, false);
+  owner_->SetPasswordInformation(user_id, &holder);
+}
+
+bool SupervisedUserAuthentication::HasIncompleteKey(
+    const std::string& user_id) {
+  base::DictionaryValue holder;
+  owner_->GetPasswordInformation(user_id, &holder);
+  bool incomplete_key = false;
+  holder.GetBoolean(kHasIncompleteKey, &incomplete_key);
+  return incomplete_key;
+}
+
+void SupervisedUserAuthentication::MarkKeyIncomplete(const std::string& user_id,
+                                                     bool incomplete) {
+  base::DictionaryValue holder;
+  owner_->GetPasswordInformation(user_id, &holder);
+  holder.SetBoolean(kHasIncompleteKey, incomplete);
+  owner_->SetPasswordInformation(user_id, &holder);
+}
+
+void SupervisedUserAuthentication::LoadPasswordUpdateData(
+    const std::string& user_id,
+    const PasswordDataCallback& success_callback,
+    const base::Closure& failure_callback) {
+  const User* user = UserManager::Get()->FindUser(user_id);
+  base::FilePath profile_path =
+      ProfileHelper::GetProfilePathByUserIdHash(user->username_hash());
+  PostTaskAndReplyWithResult(
+      content::BrowserThread::GetBlockingPool(),
+      FROM_HERE,
+      base::Bind(&LoadPasswordData, profile_path),
+      base::Bind(&OnPasswordDataLoaded, success_callback, failure_callback));
+}
+
+// static
+std::string SupervisedUserAuthentication::BuildPasswordForHashWithSaltSchema(
+    const std::string& salt,
+    const std::string& plain_password) {
+  scoped_ptr<crypto::SymmetricKey> key(
+      crypto::SymmetricKey::DeriveKeyFromPassword(crypto::SymmetricKey::AES,
+                                                  plain_password,
+                                                  salt,
+                                                  kNumIterations,
+                                                  kKeySizeInBits));
+  std::string raw_result, result;
+  key->GetRawKey(&raw_result);
+  base::Base64Encode(raw_result, &result);
+  return result;
+}
+
+std::string SupervisedUserAuthentication::BuildPasswordSignature(
+    const std::string& password,
+    int revision,
+    const std::string& base64_signature_key) {
+  ac::chrome::managedaccounts::account::Secret secret;
+  secret.set_revision(revision);
+  secret.set_secret(password);
+  std::string buffer;
+  if (!secret.SerializeToString(&buffer))
+    LOG(FATAL) << "Protobuf::SerializeToString failed";
+  std::string signature_key;
+  base::Base64Decode(base64_signature_key, &signature_key);
+
+  crypto::HMAC hmac(crypto::HMAC::SHA256);
+  if (!hmac.Init(signature_key))
+    LOG(FATAL) << "HMAC::Init failed";
+
+  unsigned char out_bytes[kSignatureLength];
+  if (!hmac.Sign(buffer, out_bytes, sizeof(out_bytes)))
+    LOG(FATAL) << "HMAC::Sign failed";
+
+  std::string raw_result(out_bytes, out_bytes + sizeof(out_bytes));
+
+  std::string result;
+  base::Base64Encode(raw_result, &result);
+  return result;
 }
 
 }  // namespace chromeos