cros: Dedup concurrent auth attempts on views-based lock screen.
If there are concurrent attempts (ie, spamming spacebar and enter) lock
would get into a bad state. Prevent concurrent attempts.
Bug: 719015
Change-Id: I4e40368fc8daa1d6ba3c47d4d181a0331b29d2a2
Reviewed-on: https://chromium-review.googlesource.com/688734
Commit-Queue: Jacob Dufault <jdufault@chromium.org>
Reviewed-by: Xiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521111}
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index f9f1334..0640092 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -31,7 +31,8 @@
} // namespace
-LoginScreenController::LoginScreenController() : binding_(this) {}
+LoginScreenController::LoginScreenController()
+ : binding_(this), weak_factory_(this) {}
LoginScreenController::~LoginScreenController() = default;
@@ -122,13 +123,18 @@
}
}
-void LoginScreenController::AuthenticateUser(
- const AccountId& account_id,
- const std::string& password,
- bool authenticated_by_pin,
- mojom::LoginScreenClient::AuthenticateUserCallback callback) {
- if (!login_screen_client_)
+void LoginScreenController::AuthenticateUser(const AccountId& account_id,
+ const std::string& password,
+ bool authenticated_by_pin,
+ OnAuthenticateCallback callback) {
+ // Ignore concurrent auth attempts. This can happen if the user quickly enters
+ // two separate passwords and hits enter.
+ if (!login_screen_client_ || is_authenticating_) {
+ LOG_IF(ERROR, is_authenticating_) << "Ignoring concurrent auth attempt";
+ std::move(callback).Run(base::nullopt);
return;
+ }
+ is_authenticating_ = true;
// If auth is disabled by the debug overlay bypass the mojo call entirely, as
// it will dismiss the lock screen if the password is correct.
@@ -136,25 +142,26 @@
case ForceFailAuth::kOff:
break;
case ForceFailAuth::kImmediate:
- std::move(callback).Run(false);
+ OnAuthenticateComplete(std::move(callback), false /*success*/);
return;
case ForceFailAuth::kDelayed:
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE, base::BindOnce(std::move(callback), false),
+ FROM_HERE,
+ base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
+ weak_factory_.GetWeakPtr(), base::Passed(&callback),
+ false),
base::TimeDelta::FromSeconds(1));
return;
}
- // We cannot execute auth requests directly via GetSystemSalt because it
- // expects a base::Callback instance, but |callback| is a base::OnceCallback.
- // Instead, we store |callback| on this object and invoke it locally once we
- // have the system salt.
- DCHECK(!pending_user_auth_) << "More than one concurrent auth attempt";
- pending_user_auth_ = base::BindOnce(
- &LoginScreenController::DoAuthenticateUser, base::Unretained(this),
+ // |DoAuthenticateUser| requires the system salt, so we fetch it first, and
+ // then run |DoAuthenticateUser| as a continuation.
+ auto do_authenticate = base::BindOnce(
+ &LoginScreenController::DoAuthenticateUser, weak_factory_.GetWeakPtr(),
account_id, password, authenticated_by_pin, std::move(callback));
- chromeos::SystemSaltGetter::Get()->GetSystemSalt(base::Bind(
- &LoginScreenController::OnGetSystemSalt, base::Unretained(this)));
+ chromeos::SystemSaltGetter::Get()->GetSystemSalt(base::BindRepeating(
+ &LoginScreenController::OnGetSystemSalt, weak_factory_.GetWeakPtr(),
+ base::Passed(&do_authenticate)));
}
void LoginScreenController::HandleFocusLeavingLockScreenApps(bool reverse) {
@@ -240,12 +247,11 @@
login_screen_client_.FlushForTesting();
}
-void LoginScreenController::DoAuthenticateUser(
- const AccountId& account_id,
- const std::string& password,
- bool authenticated_by_pin,
- mojom::LoginScreenClient::AuthenticateUserCallback callback,
- const std::string& system_salt) {
+void LoginScreenController::DoAuthenticateUser(const AccountId& account_id,
+ const std::string& password,
+ bool authenticated_by_pin,
+ OnAuthenticateCallback callback,
+ const std::string& system_salt) {
int dummy_value;
bool is_pin =
authenticated_by_pin && base::StringToInt(password, &dummy_value);
@@ -273,12 +279,22 @@
Shell::Get()->metrics()->login_metrics_recorder()->SetAuthMethod(
is_pin ? LoginMetricsRecorder::AuthMethod::kPin
: LoginMetricsRecorder::AuthMethod::kPassword);
- login_screen_client_->AuthenticateUser(account_id, hashed_password, is_pin,
- std::move(callback));
+ login_screen_client_->AuthenticateUser(
+ account_id, hashed_password, is_pin,
+ base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
+ weak_factory_.GetWeakPtr(), base::Passed(&callback)));
}
-void LoginScreenController::OnGetSystemSalt(const std::string& system_salt) {
- std::move(pending_user_auth_).Run(system_salt);
+void LoginScreenController::OnAuthenticateComplete(
+ OnAuthenticateCallback callback,
+ bool success) {
+ is_authenticating_ = false;
+ std::move(callback).Run(success);
+}
+
+void LoginScreenController::OnGetSystemSalt(PendingDoAuthenticateUser then,
+ const std::string& system_salt) {
+ std::move(then).Run(system_salt);
}
LoginDataDispatcher* LoginScreenController::DataDispatcher() const {