#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"
#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"
// 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();