[go: nahoru, domu]

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);