Login screen: do not show Gaia screen after failed pin login attempts
Bug: 1378915
Change-Id: I271a92fe61c6ba13e9905a5ed2813b70d272a62c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3985014
Commit-Queue: Yunke Zhou <yunkez@google.com>
Reviewed-by: Denis Kuznetsov <antrim@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1064444}
diff --git a/ash/login/login_screen_controller.cc b/ash/login/login_screen_controller.cc
index f316595..8fcf015 100644
--- a/ash/login/login_screen_controller.cc
+++ b/ash/login/login_screen_controller.cc
@@ -131,12 +131,11 @@
LOG(WARNING) << "crbug.com/1339004 : started authentication";
authentication_stage_ = AuthenticationStage::kDoAuthenticate;
- // Checking if the password is only formed of numbers with base::StringToInt
- // will easily fail due to numeric limits. ContainsOnlyChars is used instead.
- const bool is_pin =
- authenticated_by_pin && base::ContainsOnlyChars(password, "0123456789");
+ if (authenticated_by_pin)
+ DCHECK(base::ContainsOnlyChars(password, "0123456789"));
+
client_->AuthenticateUserWithPasswordOrPin(
- account_id, password, is_pin,
+ account_id, password, authenticated_by_pin,
base::BindOnce(&LoginScreenController::OnAuthenticateComplete,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
diff --git a/ash/login/ui/lock_contents_view.cc b/ash/login/ui/lock_contents_view.cc
index e632c19a..bcd7c9e 100644
--- a/ash/login/ui/lock_contents_view.cc
+++ b/ash/login/ui/lock_contents_view.cc
@@ -2038,7 +2038,8 @@
}
void LockContentsView::OnAuthenticate(bool auth_success,
- bool display_error_messages) {
+ bool display_error_messages,
+ bool authenticated_by_pin) {
AccountId account_id =
CurrentBigUserView()->GetCurrentUser().basic_user_info.account_id;
if (auth_success) {
@@ -2063,6 +2064,8 @@
true /*success*/, &unlock_attempt_by_user_[account_id]);
} else {
++unlock_attempt_by_user_[account_id];
+ if (authenticated_by_pin)
+ ++pin_unlock_attempt_by_user_[account_id];
if (display_error_messages)
ShowAuthErrorMessage();
}
@@ -2136,6 +2139,11 @@
}
}
view->auth_user()->SetAuthMethods(to_update_auth, auth_metadata);
+ if (auth_error_bubble_->GetVisible()) {
+ // Update the anchor position in case the active input view changed.
+ auth_error_bubble_->SetAnchorView(
+ view->auth_user()->GetActiveInputView());
+ }
} else if (view->public_account()) {
view->public_account()->SetAuthEnabled(true /*enabled*/, animate);
}
@@ -2269,14 +2277,20 @@
if (!big_view->auth_user())
return;
- int unlock_attempt = unlock_attempt_by_user_[big_view->GetCurrentUser()
- .basic_user_info.account_id];
+ const AccountId account_id =
+ big_view->GetCurrentUser().basic_user_info.account_id;
+ int unlock_attempt = unlock_attempt_by_user_[account_id];
+
// Show gaia signin if this is login and the user has failed too many times.
// Do not show on secondary login screen – even though it has type kLogin – as
// there is no OOBE there.
if (!ash::features::IsCryptohomeRecoveryFlowUIEnabled()) {
+ // Pin login attempt does not trigger Gaia dialog. Pin auth method will be
+ // disabled after 5 failed attempts.
+ int pin_unlock_attempt = pin_unlock_attempt_by_user_[account_id];
if (screen_type_ == LockScreen::ScreenType::kLogin &&
- unlock_attempt >= kLoginAttemptsBeforeGaiaDialog &&
+ (unlock_attempt - pin_unlock_attempt) >=
+ kLoginAttemptsBeforeGaiaDialog &&
Shell::Get()->session_controller()->GetSessionState() !=
session_manager::SessionState::LOGIN_SECONDARY) {
Shell::Get()->login_screen_controller()->ShowGaiaSignin(
diff --git a/ash/login/ui/lock_contents_view.h b/ash/login/ui/lock_contents_view.h
index 12686af..4497918 100644
--- a/ash/login/ui/lock_contents_view.h
+++ b/ash/login/ui/lock_contents_view.h
@@ -363,7 +363,9 @@
void SwapActiveAuthBetweenPrimaryAndSecondary(bool is_primary);
// Called when an authentication check is complete.
- void OnAuthenticate(bool auth_success, bool display_error_messages);
+ void OnAuthenticate(bool auth_success,
+ bool display_error_messages,
+ bool authenticated_by_pin);
// Tries to lookup the stored state for |user|. Returns an unowned pointer
// that is invalidated whenver |users_| changes.
@@ -550,6 +552,7 @@
// Tracks the unlock attempt of each user before a successful sign-in.
base::flat_map<AccountId, int> unlock_attempt_by_user_;
+ base::flat_map<AccountId, int> pin_unlock_attempt_by_user_;
// Whether a lock screen app is currently active (i.e. lock screen note action
// state is reported as kActive by the data dispatcher).
diff --git a/ash/login/ui/lock_contents_view_unittest.cc b/ash/login/ui/lock_contents_view_unittest.cc
index 5fe15acb..75d13f1 100644
--- a/ash/login/ui/lock_contents_view_unittest.cc
+++ b/ash/login/ui/lock_contents_view_unittest.cc
@@ -1229,6 +1229,42 @@
Mock::VerifyAndClearExpectations(client.get());
}
+// Gaia screen is not shown for failed login attempt using pin.
+TEST_F(LockContentsViewUnitTest, GaiaNeverShownAfterFailedPinAuth) {
+ ASSERT_NO_FATAL_FAILURE(ShowLoginScreen());
+ LockContentsView* contents =
+ LockScreen::TestApi(LockScreen::Get()).contents_view();
+
+ // Add user who can use pin authentication.
+ const std::string email = "user@domain.com";
+ AddUserByEmail(email);
+ contents->OnPinEnabledForUserChanged(AccountId::FromUserEmail(email), true);
+
+ auto client = std::make_unique<MockLoginScreenClient>();
+ client->set_authenticate_user_callback_result(false);
+
+ LoginBigUserView* big_view =
+ LockContentsView::TestApi(contents).primary_big_view();
+ LoginPinView* pin_view =
+ LoginAuthUserView::TestApi(big_view->auth_user()).pin_view();
+ LoginPinView::TestApi pin_pad_api{pin_view};
+ ui::test::EventGenerator* generator = GetEventGenerator();
+
+ auto submit_pin = [&]() {
+ pin_pad_api.ClickOnDigit(1);
+ generator->PressKey(ui::KeyboardCode::VKEY_RETURN, 0);
+ };
+
+ EXPECT_TRUE(pin_view->GetVisible());
+
+ // ShowGaiaSignin is never triggered.
+ EXPECT_CALL(*client, ShowGaiaSignin(_)).Times(0);
+ for (int i = 0; i < LockContentsView::kLoginAttemptsBeforeGaiaDialog + 1; ++i)
+ submit_pin();
+
+ Mock::VerifyAndClearExpectations(client.get());
+}
+
TEST_F(LockContentsViewUnitTest, ErrorBubbleOnUntrustedDetachableBase) {
auto fake_detachable_base_model =
std::make_unique<FakeLoginDetachableBaseModel>(DataDispatcher());
diff --git a/ash/login/ui/login_auth_user_view.cc b/ash/login/ui/login_auth_user_view.cc
index 280b111..08f3c09 100644
--- a/ash/login/ui/login_auth_user_view.cc
+++ b/ash/login/ui/login_auth_user_view.cc
@@ -42,6 +42,7 @@
#include "base/feature_list.h"
#include "base/i18n/time_formatting.h"
#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
@@ -1722,14 +1723,21 @@
password_view_->SetReadOnly(true);
pin_input_view_->SetReadOnly(true);
+ // Checking if the password is only formed of numbers with base::StringToInt
+ // will easily fail due to numeric limits. ContainsOnlyChars is used instead.
+ const bool authenticated_by_pin =
+ ShouldAuthenticateWithPin() &&
+ base::ContainsOnlyChars(base::UTF16ToUTF8(password), "0123456789");
+
Shell::Get()->login_screen_controller()->AuthenticateUserWithPasswordOrPin(
current_user().basic_user_info.account_id, base::UTF16ToUTF8(password),
- ShouldAuthenticateWithPin(),
+ authenticated_by_pin,
base::BindOnce(&LoginAuthUserView::OnAuthComplete,
- weak_factory_.GetWeakPtr()));
+ weak_factory_.GetWeakPtr(), authenticated_by_pin));
}
-void LoginAuthUserView::OnAuthComplete(absl::optional<bool> auth_success) {
+void LoginAuthUserView::OnAuthComplete(bool authenticated_by_pin,
+ absl::optional<bool> auth_success) {
bool failed = !auth_success.value_or(false);
LOG(WARNING) << "crbug.com/1339004 : OnAuthComplete " << failed;
@@ -1744,7 +1752,8 @@
pin_input_view_->SetReadOnly(false);
}
- on_auth_.Run(auth_success.value(), /*display_error_messages=*/true);
+ on_auth_.Run(auth_success.value(), /*display_error_messages=*/true,
+ authenticated_by_pin);
}
void LoginAuthUserView::OnChallengeResponseAuthComplete(
@@ -1767,7 +1776,8 @@
}
on_auth_.Run(auth_success.value_or(false),
- /*display_error_messages=*/false);
+ /*display_error_messages=*/false,
+ /*authenticated_by_pin*/ false);
}
void LoginAuthUserView::OnSmartLockArrowButtonTapped() {
diff --git a/ash/login/ui/login_auth_user_view.h b/ash/login/ui/login_auth_user_view.h
index 392a2f2..ef8adce 100644
--- a/ash/login/ui/login_auth_user_view.h
+++ b/ash/login/ui/login_auth_user_view.h
@@ -125,7 +125,8 @@
using >
base::RepeatingCallback<void(bool auth_success,
- bool display_error_messages)>;
+ bool display_error_messages,
+ bool authenticated_by_pin)>;
using >
struct Callbacks {
@@ -231,7 +232,8 @@
void OnAuthSubmit(const std::u16string& password);
// Called with the result of the request started in |OnAuthSubmit| or
// |AttemptAuthenticateWithExternalBinary|.
- void OnAuthComplete(absl::optional<bool> auth_success);
+ void OnAuthComplete(bool authenticated_by_pin,
+ absl::optional<bool> auth_success);
// Called with the result of the request started in
// |AttemptAuthenticateWithChallengeResponse|.
void OnChallengeResponseAuthComplete(absl::optional<bool> auth_success);