Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / managed / supervised_user_login_flow.cc
index 24be34e..6860f71 100644 (file)
@@ -4,7 +4,9 @@
 
 #include "chrome/browser/chromeos/login/managed/supervised_user_login_flow.h"
 
+#include "base/base64.h"
 #include "base/logging.h"
+#include "base/metrics/histogram.h"
 #include "base/prefs/pref_registry_simple.h"
 #include "base/prefs/pref_service.h"
 #include "base/values.h"
@@ -12,6 +14,7 @@
 #include "chrome/browser/chromeos/login/login_utils.h"
 #include "chrome/browser/chromeos/login/managed/locally_managed_user_constants.h"
 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h"
+#include "chrome/browser/chromeos/login/managed/supervised_user_authentication.h"
 #include "chrome/browser/chromeos/login/supervised_user_manager.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
@@ -68,7 +71,175 @@ void SupervisedUserLoginFlow::ConfigureSync(const std::string& token) {
   // See also: http://crbug.com/312751
   UserManager::Get()->GetSupervisedUserManager()->ConfigureSyncWithToken(
       profile_, token);
+  SupervisedUserAuthentication* auth =
+      UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
 
+  if (auth->HasScheduledPasswordUpdate(user_id())) {
+    auth->LoadPasswordUpdateData(
+        user_id(),
+        base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoaded,
+                   weak_factory_.GetWeakPtr()),
+        base::Bind(&SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed,
+                   weak_factory_.GetWeakPtr()));
+    return;
+  }
+  Finish();
+}
+
+void SupervisedUserLoginFlow::HandleLoginSuccess(
+    const UserContext& login_context) {
+  context_.CopyFrom(login_context);
+}
+
+void SupervisedUserLoginFlow::OnPasswordChangeDataLoaded(
+    const base::DictionaryValue* password_data) {
+  // Edge case, when manager has signed in and already updated the password.
+  SupervisedUserAuthentication* auth =
+      UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
+  if (!auth->NeedPasswordChange(user_id(), password_data)) {
+    VLOG(1) << "Password already changed for " << user_id();
+    auth->ClearScheduledPasswordUpdate(user_id());
+    Finish();
+    return;
+  }
+
+  // Two cases now - we can currently have either old-style password, or new
+  // password.
+  std::string base64_signature;
+  std::string signature;
+  std::string password;
+  int revision = 0;
+  int schema = 0;
+  bool success = password_data->GetStringWithoutPathExpansion(
+      kPasswordSignature, &base64_signature);
+  success &= password_data->GetIntegerWithoutPathExpansion(kPasswordRevision,
+                                                           &revision);
+  success &=
+      password_data->GetIntegerWithoutPathExpansion(kSchemaVersion, &schema);
+  success &= password_data->GetStringWithoutPathExpansion(kEncryptedPassword,
+                                                          &password);
+  if (!success) {
+    LOG(ERROR) << "Incomplete data for password change";
+
+    UMA_HISTOGRAM_ENUMERATION(
+        "ManagedUsers.ChromeOS.PasswordChange",
+        SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_INCOMPLETE_DATA,
+        SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
+    Finish();
+    return;
+  }
+  base::Base64Decode(base64_signature, &signature);
+  scoped_ptr<base::DictionaryValue> data_copy(password_data->DeepCopy());
+  cryptohome::KeyDefinition key(password,
+                                kCryptohomeManagedUserKeyLabel,
+                                kCryptohomeManagedUserKeyPrivileges);
+
+  authenticator_ = new ExtendedAuthenticator(this);
+  SupervisedUserAuthentication::Schema current_schema =
+      auth->GetPasswordSchema(user_id());
+
+  key.revision = revision;
+
+  if (SupervisedUserAuthentication::SCHEMA_PLAIN == current_schema) {
+    // We need to add new key, and block old one. As we don't actually have
+    // signature key, use Migrate privilege instead of AuthorizedUpdate.
+    key.privileges = kCryptohomeManagedUserIncompleteKeyPrivileges;
+
+    VLOG(1) << "Adding new schema key";
+    DCHECK_EQ(context_.key_label, std::string());
+    authenticator_->AddKey(context_,
+                           key,
+                           false /* no key exists */,
+                           base::Bind(&SupervisedUserLoginFlow::OnNewKeyAdded,
+                                      weak_factory_.GetWeakPtr(),
+                                      Passed(&data_copy)));
+  } else if (SupervisedUserAuthentication::SCHEMA_SALT_HASHED ==
+             current_schema) {
+    VLOG(1) << "Updating the key";
+
+    if (auth->HasIncompleteKey(user_id())) {
+      // We need to use Migrate instead of Authorized Update privilege.
+      key.privileges = kCryptohomeManagedUserIncompleteKeyPrivileges;
+    }
+    // Just update the key.
+    DCHECK_EQ(context_.key_label, kCryptohomeManagedUserKeyLabel);
+    authenticator_->UpdateKeyAuthorized(
+        context_,
+        key,
+        signature,
+        base::Bind(&SupervisedUserLoginFlow::OnPasswordUpdated,
+                   weak_factory_.GetWeakPtr(),
+                   Passed(&data_copy)));
+  } else {
+    NOTREACHED() << "Unsupported password schema";
+  }
+}
+
+void SupervisedUserLoginFlow::OnNewKeyAdded(
+    scoped_ptr<base::DictionaryValue> password_data) {
+  VLOG(1) << "New key added";
+  SupervisedUserAuthentication* auth =
+      UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
+  auth->StorePasswordData(user_id(), *password_data.get());
+  auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
+  authenticator_->RemoveKey(
+      context_,
+      kLegacyCryptohomeManagedUserKeyLabel,
+      base::Bind(&SupervisedUserLoginFlow::OnOldKeyRemoved,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void SupervisedUserLoginFlow::OnOldKeyRemoved() {
+  UMA_HISTOGRAM_ENUMERATION(
+      "ManagedUsers.ChromeOS.PasswordChange",
+      SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
+      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
+  Finish();
+}
+
+void SupervisedUserLoginFlow::OnPasswordChangeDataLoadFailed() {
+  LOG(ERROR) << "Could not load data for password change";
+
+  UMA_HISTOGRAM_ENUMERATION(
+      "ManagedUsers.ChromeOS.PasswordChange",
+      SupervisedUserAuthentication::PASSWORD_CHANGE_FAILED_LOADING_DATA,
+      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
+  Finish();
+}
+
+void SupervisedUserLoginFlow::OnAuthenticationFailure(
+    ExtendedAuthenticator::AuthState state) {
+  LOG(ERROR) << "Authentication error during password change";
+
+  UMA_HISTOGRAM_ENUMERATION(
+      "ManagedUsers.ChromeOS.PasswordChange",
+      SupervisedUserAuthentication::
+          PASSWORD_CHANGE_FAILED_AUTHENTICATION_FAILURE,
+      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
+  Finish();
+}
+
+void SupervisedUserLoginFlow::OnPasswordUpdated(
+    scoped_ptr<base::DictionaryValue> password_data) {
+  VLOG(1) << "Updated password for supervised user";
+
+  SupervisedUserAuthentication* auth =
+      UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
+
+  // Incomplete state is not there in password_data, carry it from old state.
+  bool was_incomplete = auth->HasIncompleteKey(user_id());
+  auth->StorePasswordData(user_id(), *password_data.get());
+  if (was_incomplete)
+    auth->MarkKeyIncomplete(user_id(), true /* incomplete */);
+
+  UMA_HISTOGRAM_ENUMERATION(
+      "ManagedUsers.ChromeOS.PasswordChange",
+      SupervisedUserAuthentication::PASSWORD_CHANGED_IN_USER_SESSION,
+      SupervisedUserAuthentication::PASSWORD_CHANGE_RESULT_MAX_VALUE);
+  Finish();
+}
+
+void SupervisedUserLoginFlow::Finish() {
   LoginUtils::Get()->DoBrowserLaunch(profile_, host());
   profile_ = NULL;
   UnregisterFlowSoon();