| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/auth/active_session_auth_controller_impl.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "ash/test/ash_test_base.h" |
| #include "base/test/run_until.h" |
| #include "base/test/test_future.h" |
| #include "chromeos/ash/components/cryptohome/system_salt_getter.h" |
| #include "chromeos/ash/components/dbus/userdataauth/fake_cryptohome_misc_client.h" |
| #include "chromeos/ash/components/dbus/userdataauth/fake_userdataauth_client.h" |
| #include "chromeos/ash/components/login/auth/public/cryptohome_key_constants.h" |
| #include "chromeos/ash/components/osauth/impl/request/password_manager_auth_request.h" |
| #include "chromeos/ash/components/osauth/impl/request/payments_autofill_auth_request.h" |
| #include "chromeos/ash/components/osauth/impl/request/settings_auth_request.h" |
| #include "chromeos/ash/components/osauth/impl/request/webauthn_auth_request.h" |
| #include "chromeos/ash/components/osauth/public/auth_parts.h" |
| #include "chromeos/ash/components/osauth/public/request/auth_request.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "components/user_manager/fake_user_manager.h" |
| #include "components/user_manager/known_user.h" |
| #include "components/user_manager/user_manager.h" |
| #include "google_apis/gaia/gaia_id.h" |
| #include "third_party/abseil-cpp/absl/functional/overload.h" |
| #include "third_party/cros_system_api/dbus/cryptohome/dbus-constants.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace ash { |
| |
| namespace { |
| |
| constexpr char kUserEmail[] = "[email protected]"; |
| constexpr GaiaId::Literal kFakeGaia("fake_gaia"); |
| constexpr char kExpectedPassword[] = "expected_password"; |
| constexpr char kExpectedPin[] = "123456"; |
| constexpr char kExpectedSalt[] = "test salt"; |
| constexpr char kRpId[] = "example.com"; |
| |
| } // namespace |
| |
| enum class TestVariant { |
| kWebAuthN, |
| kPasswordManager, |
| kSettings, |
| kPaymentsAutofill, |
| }; |
| |
| // The first element of the pair is the variant of the auth dialog to be |
| // shown, the second element is the expected result if the user has no |
| // authentication factors. |
| class ActiveSessionAuthControllerTest |
| : public NoSessionAshTestBase, |
| public testing::WithParamInterface<std::pair<TestVariant, bool>> { |
| public: |
| using TokenBasedCallback = |
| base::test::TestFuture<bool, const ash::AuthProofToken&, base::TimeDelta>; |
| using WebAuthNCallback = base::test::TestFuture<bool>; |
| using OnAuthComplete = std::variant<std::unique_ptr<TokenBasedCallback>, |
| std::unique_ptr<WebAuthNCallback>>; |
| |
| void SetUp() override { |
| InitializeUserManager(); |
| AddUserToUserManager(); |
| SystemSaltGetter::Initialize(); |
| CryptohomeMiscClient::InitializeFake(); |
| UserDataAuthClient::InitializeFake(); |
| auth_parts_ = AuthParts::Create(local_state()); |
| |
| NoSessionAshTestBase::SetUp(); |
| |
| ClearLogin(); |
| SimulateUserLogin({kUserEmail, user_manager::UserType::kRegular}); |
| } |
| |
| void TearDown() override { |
| Shell::Get()->session_controller()->ClearUserSessionsForTest(); |
| |
| auth_parts_.reset(); |
| user_manager_->Destroy(); |
| user_manager_.reset(); |
| SystemSaltGetter::Shutdown(); |
| CryptohomeMiscClient::Shutdown(); |
| UserDataAuthClient::Shutdown(); |
| |
| NoSessionAshTestBase::TearDown(); |
| } |
| |
| void InitializeUserManager() { |
| user_manager_ = |
| std::make_unique<user_manager::FakeUserManager>(local_state()); |
| user_manager_->Initialize(); |
| } |
| |
| void AddUserToUserManager() { |
| account_id_ = AccountId::FromUserEmailGaiaId(kUserEmail, kFakeGaia); |
| user_manager_->AddGaiaUser(account_id_, user_manager::UserType::kRegular); |
| user_manager_->UserLoggedIn( |
| account_id_, |
| user_manager::FakeUserManager::GetFakeUsernameHash(account_id_)); |
| ASSERT_FALSE(user_manager_->IsUserCryptohomeDataEphemeral(account_id_)); |
| } |
| |
| std::string HashPassword(const std::string& unhashed_password) { |
| Key key(std::move(unhashed_password)); |
| key.Transform(Key::KEY_TYPE_SALTED_SHA256_TOP_HALF, |
| SystemSaltGetter::ConvertRawSaltToHexString( |
| FakeCryptohomeMiscClient::GetStubSystemSalt())); |
| return key.GetSecret(); |
| } |
| |
| std::string HashPin(const std::string& unhashed_pin) { |
| Key key(std::move(unhashed_pin)); |
| key.Transform(Key::KEY_TYPE_SALTED_PBKDF2_AES256_1234, kExpectedSalt); |
| return key.GetSecret(); |
| } |
| |
| void AddGaiaPassword(const AccountId& user, const std::string& password) { |
| auto account_identifier = |
| cryptohome::CreateAccountIdentifierFromAccountId(user); |
| |
| FakeUserDataAuthClient::TestApi::Get()->AddExistingUser(account_identifier); |
| |
| // Hash the password, as only hashed passwords appear at the userdataauth |
| // level. |
| Key key(HashPassword(password)); |
| |
| user_data_auth::AuthFactor auth_factor; |
| user_data_auth::AuthInput auth_input; |
| |
| auth_factor.set_label(ash::kCryptohomeGaiaKeyLabel); |
| auth_factor.set_type(user_data_auth::AUTH_FACTOR_TYPE_PASSWORD); |
| |
| auth_input.mutable_password_input()->set_secret(key.GetSecret()); |
| |
| // Add the password key to the user. |
| FakeUserDataAuthClient::TestApi::Get()->AddAuthFactor( |
| account_identifier, auth_factor, auth_input); |
| } |
| |
| void AddCryptohomePin(const AccountId& user, const std::string& pin) { |
| auto account_identifier = |
| cryptohome::CreateAccountIdentifierFromAccountId(user); |
| |
| // Hash the pin, as only hashed secrets appear at the userdataauth |
| // level. |
| Key key(HashPin(pin)); |
| |
| // Add the pin key to the user. |
| user_data_auth::AuthFactor auth_factor; |
| user_data_auth::AuthInput auth_input; |
| |
| auth_factor.set_label(ash::kCryptohomePinLabel); |
| auth_factor.set_type(user_data_auth::AUTH_FACTOR_TYPE_PIN); |
| |
| auth_input.mutable_password_input()->set_secret(key.GetSecret()); |
| |
| FakeUserDataAuthClient::TestApi::Get()->AddAuthFactor( |
| account_identifier, auth_factor, auth_input); |
| } |
| |
| OnAuthComplete ShowAuthDialogForVariant(TestVariant variant) { |
| auto make_password_manager_request = []() { |
| auto future = std::make_unique<TokenBasedCallback>(); |
| |
| Shell::Get()->active_session_auth_controller()->ShowAuthDialog( |
| std::make_unique<PasswordManagerAuthRequest>(u"", |
| future->GetCallback())); |
| |
| return OnAuthComplete{std::move(future)}; |
| }; |
| |
| auto make_settings_request = []() { |
| auto future = std::make_unique<TokenBasedCallback>(); |
| |
| Shell::Get()->active_session_auth_controller()->ShowAuthDialog( |
| std::make_unique<SettingsAuthRequest>(future->GetCallback())); |
| |
| return OnAuthComplete{std::move(future)}; |
| }; |
| |
| auto make_webauthn_request = []() { |
| auto future = std::make_unique<WebAuthNCallback>(); |
| |
| Shell::Get()->active_session_auth_controller()->ShowAuthDialog( |
| std::make_unique<WebAuthNAuthRequest>(kRpId, future->GetCallback())); |
| |
| return OnAuthComplete{std::move(future)}; |
| }; |
| |
| auto make_payments_autofill_request = []() { |
| auto future = std::make_unique<TokenBasedCallback>(); |
| |
| Shell::Get()->active_session_auth_controller()->ShowAuthDialog( |
| std::make_unique<PaymentsAutofillAuthRequest>(u"", |
| future->GetCallback())); |
| |
| return OnAuthComplete{std::move(future)}; |
| }; |
| |
| switch (variant) { |
| case TestVariant::kWebAuthN: |
| return make_webauthn_request(); |
| case TestVariant::kPasswordManager: |
| return make_password_manager_request(); |
| case TestVariant::kSettings: |
| return make_settings_request(); |
| case TestVariant::kPaymentsAutofill: |
| return make_payments_autofill_request(); |
| } |
| } |
| |
| protected: |
| AccountId account_id_; |
| std::unique_ptr<user_manager::FakeUserManager> user_manager_; |
| std::unique_ptr<AuthParts> auth_parts_; |
| }; |
| |
| // Tests that the StartAuthSession call to cryptohome includes the correct |
| // account id. |
| TEST_P(ActiveSessionAuthControllerTest, |
| StartAuthSessionCalledWithCorrectAccountIdAndReturnsPasswordFactor) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| ShowAuthDialogForVariant(GetParam().first); |
| |
| base::RunLoop().RunUntilIdle(); |
| |
| EXPECT_TRUE( |
| FakeUserDataAuthClient::Get() |
| ->WasCalled<FakeUserDataAuthClient::Operation::kStartAuthSession>()); |
| auto start_auth_session_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kStartAuthSession>(); |
| EXPECT_EQ(start_auth_session_request.account_id().account_id(), kUserEmail); |
| AuthFactorSet available_factors = |
| ActiveSessionAuthControllerImpl::TestApi(controller) |
| .GetAvailableFactors(); |
| EXPECT_EQ(1u, available_factors.size()); |
| EXPECT_TRUE(available_factors.Has(AuthInputType::kPassword)); |
| } |
| |
| // Tests that the ListAuthFactors call to cryptohome includes the correct |
| // account id and returns the password and pin factors. |
| TEST_P(ActiveSessionAuthControllerTest, StartAuthSessionReturnsPasswordAndPin) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| AddCryptohomePin(account_id_, kExpectedPin); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| AuthFactorSet available_factors = |
| ActiveSessionAuthControllerImpl::TestApi(controller) |
| .GetAvailableFactors(); |
| |
| EXPECT_EQ(2u, available_factors.size()); |
| EXPECT_TRUE(available_factors.Has(AuthInputType::kPassword)); |
| EXPECT_TRUE(available_factors.Has(AuthInputType::kPin)); |
| } |
| |
| // Tests that the AuthenticateAuthFactor call to cryptohome includes the |
| // correct account id and password, and that the `OnAuthComplete` callback |
| // is called with correct parameters. |
| TEST_P(ActiveSessionAuthControllerTest, SubmitPassword) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| ActiveSessionAuthControllerImpl::TestApi(controller) |
| .SubmitPassword(kExpectedPassword); |
| |
| // Await authentication. |
| base::RunLoop().RunUntilIdle(); |
| |
| auto authenticate_auth_factor_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor>(); |
| |
| EXPECT_EQ( |
| authenticate_auth_factor_request.auth_input().password_input().secret(), |
| HashPassword(kExpectedPassword)); |
| |
| std::visit( |
| [](auto&& arg) { |
| EXPECT_TRUE(arg->IsReady()); |
| EXPECT_EQ(arg->template Get<bool>(), true); |
| }, |
| future); |
| } |
| |
| // Tests that the AuthenticateAuthFactor call to cryptohome includes the |
| // correct account id and password, and that the `OnAuthComplete` callback |
| // is not called with wrong credentials. |
| TEST_P(ActiveSessionAuthControllerTest, WrongPassword) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| FakeUserDataAuthClient::Get()->SetNextOperationError( |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor, |
| cryptohome::ErrorWrapper::CreateFromErrorCodeOnly( |
| user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED)); |
| |
| ActiveSessionAuthControllerImpl::TestApi(controller) |
| .SubmitPassword(kExpectedPassword); |
| |
| // Await authentication. |
| base::RunLoop().RunUntilIdle(); |
| |
| auto authenticate_auth_factor_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor>(); |
| |
| EXPECT_EQ( |
| authenticate_auth_factor_request.auth_input().password_input().secret(), |
| HashPassword(kExpectedPassword)); |
| |
| std::visit([](auto&& arg) { EXPECT_FALSE(arg->IsReady()); }, future); |
| } |
| |
| // Tests that the AuthenticateAuthFactor call to cryptohome includes the |
| // correct account id and pin, and that the `OnAuthComplete` callback |
| // is called with the correct credentials. |
| TEST_P(ActiveSessionAuthControllerTest, SubmitPin) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| AddCryptohomePin(account_id_, kExpectedPin); |
| |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| known_user.SetStringPref(account_id_, prefs::kQuickUnlockPinSalt, |
| kExpectedSalt); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| ActiveSessionAuthControllerImpl::TestApi(controller).SubmitPin(kExpectedPin); |
| |
| // Await authentication. |
| base::RunLoop().RunUntilIdle(); |
| |
| auto authenticate_auth_factor_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor>(); |
| |
| EXPECT_EQ(authenticate_auth_factor_request.auth_input().pin_input().secret(), |
| HashPin(kExpectedPin)); |
| |
| std::visit( |
| [](auto&& arg) { |
| EXPECT_TRUE(arg->IsReady()); |
| EXPECT_EQ(arg->template Get<bool>(), true); |
| }, |
| future); |
| } |
| |
| // Tests that the AuthenticateAuthFactor call to cryptohome includes the |
| // account id and pin, and that the `OnAuthComplete` callback |
| // is not called with a wrong credentials error reply. |
| TEST_P(ActiveSessionAuthControllerTest, WrongPin) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| AddCryptohomePin(account_id_, kExpectedPin); |
| |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| known_user.SetStringPref(account_id_, prefs::kQuickUnlockPinSalt, |
| kExpectedSalt); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| FakeUserDataAuthClient::Get()->SetNextOperationError( |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor, |
| cryptohome::ErrorWrapper::CreateFromErrorCodeOnly( |
| user_data_auth::CRYPTOHOME_ERROR_AUTHORIZATION_KEY_FAILED)); |
| |
| ActiveSessionAuthControllerImpl::TestApi(controller).SubmitPin(kExpectedPin); |
| |
| // Await authentication. |
| base::RunLoop().RunUntilIdle(); |
| |
| auto authenticate_auth_factor_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor>(); |
| |
| EXPECT_EQ(authenticate_auth_factor_request.auth_input().pin_input().secret(), |
| HashPin(kExpectedPin)); |
| |
| std::visit([](auto&& arg) { EXPECT_FALSE(arg->IsReady()); }, future); |
| } |
| |
| // Tests that the AuthenticateAuthFactor calls to cryptohome are |
| // correctly formed when pin and password authentication are both |
| // tried. |
| TEST_P(ActiveSessionAuthControllerTest, BadPinThenGoodPassword) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| AddCryptohomePin(account_id_, kExpectedPin); |
| const std::string bad_pin = "bad_pin"; |
| |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| known_user.SetStringPref(account_id_, prefs::kQuickUnlockPinSalt, |
| kExpectedSalt); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| // Await authentication with pin. |
| FakeUserDataAuthClient::TestApi::Get()->set_enable_auth_check(true); |
| ActiveSessionAuthControllerImpl::TestApi(controller).SubmitPin(bad_pin); |
| base::RunLoop().RunUntilIdle(); |
| |
| auto authenticate_auth_factor_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor>(); |
| |
| EXPECT_EQ(authenticate_auth_factor_request.auth_input().pin_input().secret(), |
| HashPin(bad_pin)); |
| |
| std::visit([](auto&& arg) { EXPECT_FALSE(arg->IsReady()); }, future); |
| |
| // Await authentication with password. |
| ActiveSessionAuthControllerImpl::TestApi(controller) |
| .SubmitPassword(kExpectedPassword); |
| base::RunLoop().RunUntilIdle(); |
| |
| authenticate_auth_factor_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor>(); |
| |
| EXPECT_EQ( |
| authenticate_auth_factor_request.auth_input().password_input().secret(), |
| HashPassword(kExpectedPassword)); |
| |
| std::visit( |
| [](auto&& arg) { |
| EXPECT_TRUE(arg->IsReady()); |
| EXPECT_EQ(arg->template Get<bool>(), true); |
| }, |
| future); |
| } |
| |
| // Check the format and content of pin lockout status message. |
| TEST_P(ActiveSessionAuthControllerTest, PinLockoutMessage) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| AddCryptohomePin(account_id_, kExpectedPin); |
| const std::string bad_pin = "bad_pin"; |
| |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| known_user.SetStringPref(account_id_, prefs::kQuickUnlockPinSalt, |
| kExpectedSalt); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| auto test_api = ActiveSessionAuthControllerImpl::TestApi(controller); |
| |
| ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| ASSERT_TRUE(base::test::RunUntil([&]() { return controller->IsShown(); })); |
| |
| const base::TimeDelta in_a_while = base::Seconds(60); |
| test_api.SetPinStatus(std::make_unique<cryptohome::PinStatus>(in_a_while)); |
| |
| EXPECT_EQ( |
| test_api.GetPinStatusMessage(), |
| l10n_util::GetStringFUTF16(IDS_ASH_IN_SESSION_AUTH_PIN_DELAY_REQUIRED, |
| u"1 minute, 0 seconds")); |
| |
| test_api.SetPinStatus( |
| std::make_unique<cryptohome::PinStatus>(base::TimeDelta::Max())); |
| EXPECT_EQ( |
| test_api.GetPinStatusMessage(), |
| l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_PIN_TOO_MANY_ATTEMPTS)); |
| } |
| |
| // Tests that the OnAuthCancel callback is called with the correct |
| // parameters. |
| TEST_P(ActiveSessionAuthControllerTest, OnAuthCancel) { |
| AddGaiaPassword(account_id_, kExpectedPassword); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| ActiveSessionAuthControllerImpl::TestApi(controller).Close(); |
| |
| // Await close. |
| base::RunLoop().RunUntilIdle(); |
| |
| std::visit(absl::Overload( |
| [](std::unique_ptr<WebAuthNCallback>& callback) { |
| EXPECT_TRUE(callback->IsReady()); |
| EXPECT_FALSE(callback->Get<bool>()); |
| }, |
| [](std::unique_ptr<TokenBasedCallback>& callback) { |
| EXPECT_TRUE(callback->IsReady()); |
| EXPECT_FALSE(callback->Get<bool>()); |
| EXPECT_EQ(callback->Get<1>(), std::string{}); |
| }), |
| future); |
| } |
| |
| // Tests that the dialog is not shown if the user has no authentication factors. |
| TEST_P(ActiveSessionAuthControllerTest, WithoutAnyFactor) { |
| auto account_identifier = |
| cryptohome::CreateAccountIdentifierFromAccountId(account_id_); |
| |
| FakeUserDataAuthClient::TestApi::Get()->AddExistingUser(account_identifier); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| base::RunLoop().RunUntilIdle(); |
| std::visit( |
| [expected = GetParam().second](auto&& arg) { |
| EXPECT_TRUE(arg->IsReady()); |
| EXPECT_EQ(arg->template Get<bool>(), expected); |
| }, |
| future); |
| } |
| |
| // Validate PIN status with PIN only. |
| TEST_P(ActiveSessionAuthControllerTest, PinOnlyLockoutMessage) { |
| auto account_identifier = |
| cryptohome::CreateAccountIdentifierFromAccountId(account_id_); |
| |
| FakeUserDataAuthClient::TestApi::Get()->AddExistingUser(account_identifier); |
| |
| AddCryptohomePin(account_id_, kExpectedPin); |
| const std::string bad_pin = "bad_pin"; |
| |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| known_user.SetStringPref(account_id_, prefs::kQuickUnlockPinSalt, |
| kExpectedSalt); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| auto test_api = ActiveSessionAuthControllerImpl::TestApi(controller); |
| |
| ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| ASSERT_TRUE(base::test::RunUntil([&]() { return controller->IsShown(); })); |
| |
| const base::TimeDelta in_a_while = base::Seconds(60); |
| test_api.SetPinStatus(std::make_unique<cryptohome::PinStatus>(in_a_while)); |
| |
| EXPECT_EQ( |
| test_api.GetPinStatusMessage(), |
| l10n_util::GetStringFUTF16(IDS_ASH_IN_SESSION_AUTH_PIN_DELAY_REQUIRED, |
| u"1 minute, 0 seconds")); |
| |
| test_api.SetPinStatus( |
| std::make_unique<cryptohome::PinStatus>(base::TimeDelta::Max())); |
| EXPECT_EQ( |
| test_api.GetPinStatusMessage(), |
| l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_PIN_TOO_MANY_ATTEMPTS)); |
| } |
| |
| // Tests that the AuthenticateAuthFactor call to cryptohome includes the |
| // correct account id and pin, and that the `OnAuthComplete` callback |
| // is called with the correct credentials. |
| TEST_P(ActiveSessionAuthControllerTest, PinOnlySubmit) { |
| auto account_identifier = |
| cryptohome::CreateAccountIdentifierFromAccountId(account_id_); |
| |
| FakeUserDataAuthClient::TestApi::Get()->AddExistingUser(account_identifier); |
| |
| AddCryptohomePin(account_id_, kExpectedPin); |
| |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| known_user.SetStringPref(account_id_, prefs::kQuickUnlockPinSalt, |
| kExpectedSalt); |
| |
| auto* controller = static_cast<ActiveSessionAuthControllerImpl*>( |
| Shell::Get()->active_session_auth_controller()); |
| |
| auto future = ShowAuthDialogForVariant(GetParam().first); |
| |
| // Await show. |
| base::RunLoop().RunUntilIdle(); |
| |
| ActiveSessionAuthControllerImpl::TestApi(controller).SubmitPin(kExpectedPin); |
| |
| // Await authentication. |
| base::RunLoop().RunUntilIdle(); |
| |
| auto authenticate_auth_factor_request = |
| FakeUserDataAuthClient::Get() |
| ->GetLastRequest< |
| FakeUserDataAuthClient::Operation::kAuthenticateAuthFactor>(); |
| |
| EXPECT_EQ(authenticate_auth_factor_request.auth_input().pin_input().secret(), |
| HashPin(kExpectedPin)); |
| |
| std::visit( |
| [](auto&& arg) { |
| EXPECT_TRUE(arg->IsReady()); |
| EXPECT_EQ(arg->template Get<bool>(), true); |
| }, |
| future); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| ActiveSessionAuthControllerTest, |
| testing::Values(std::make_pair(TestVariant::kWebAuthN, false), |
| std::make_pair(TestVariant::kSettings, false), |
| std::make_pair(TestVariant::kPasswordManager, false), |
| std::make_pair(TestVariant::kPaymentsAutofill, true))); |
| |
| } // namespace ash |