authentication_dialog_unittest.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // Copyright 2021 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ash/in_session_auth/authentication_dialog.h"
  5. #include <cctype>
  6. #include "ash/components/login/auth/auth_performer.h"
  7. #include "ash/components/login/auth/mock_auth_performer.h"
  8. #include "ash/components/login/auth/public/auth_factors_data.h"
  9. #include "ash/components/login/auth/public/cryptohome_key_constants.h"
  10. #include "ash/public/cpp/in_session_auth_token_provider.h"
  11. #include "ash/public/cpp/test/mock_in_session_auth_token_provider.h"
  12. #include "ash/test/ash_test_base.h"
  13. #include "base/logging.h"
  14. #include "base/test/bind.h"
  15. #include "base/unguessable_token.h"
  16. #include "chromeos/ash/components/cryptohome/common_types.h"
  17. #include "chromeos/ash/components/cryptohome/cryptohome_parameters.h"
  18. #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h"
  19. #include "testing/gmock/include/gmock/gmock.h"
  20. #include "testing/gtest/include/gtest/gtest.h"
  21. #include "ui/events/keycodes/keyboard_codes_posix.h"
  22. #include "ui/views/controls/button/label_button.h"
  23. #include "ui/views/controls/textfield/textfield.h"
  24. namespace ash {
  25. namespace {
  26. using ::cryptohome::KeyLabel;
  27. using ::testing::_;
  28. const char kTestAccount[] = "user@test.com";
  29. const char kExpectedPassword[] = "qwerty";
  30. base::UnguessableToken kToken = base::UnguessableToken::Create();
  31. } // namespace
  32. class AuthenticationDialogTest : public AshTestBase {
  33. public:
  34. void SetUp() override {
  35. AshTestBase::SetUp();
  36. UserDataAuthClient::InitializeFake();
  37. auth_token_provider_ = std::make_unique<MockInSessionAuthTokenProvider>();
  38. }
  39. void StartAuthSession(std::unique_ptr<UserContext> user_context,
  40. bool ephemeral,
  41. AuthPerformer::StartSessionCallback callback) {
  42. user_context->SetAuthFactorsData(
  43. AuthFactorsData{{cryptohome::KeyDefinition::CreateForPassword(
  44. "secret", KeyLabel(kCryptohomeGaiaKeyLabel), 0)}});
  45. std::move(callback).Run(true, std::move(user_context), absl::nullopt);
  46. }
  47. void GetAuthToken(std::unique_ptr<UserContext> user_context,
  48. InSessionAuthTokenProvider::OnAuthTokenGenerated callback) {
  49. std::move(callback).Run(kToken, base::Minutes(5));
  50. }
  51. protected:
  52. void CreateAndShowDialog() {
  53. auto auth_performer =
  54. std::make_unique<MockAuthPerformer>(UserDataAuthClient::Get());
  55. auth_performer_ = auth_performer.get();
  56. EXPECT_CALL(*auth_performer_, StartAuthSession)
  57. .WillRepeatedly(
  58. testing::Invoke(this, &AuthenticationDialogTest::StartAuthSession));
  59. // `dialog_` is a `DialogDelegateView` and will be owned by the
  60. // underlying widget.
  61. dialog_ = new AuthenticationDialog(
  62. base::BindLambdaForTesting([&](bool success,
  63. const base::UnguessableToken& token,
  64. base::TimeDelta timeout) {
  65. success_ = success;
  66. token_ = token;
  67. }),
  68. auth_token_provider_.get(), std::move(auth_performer),
  69. AccountId::FromUserEmail(kTestAccount));
  70. test_api_ = std::make_unique<AuthenticationDialog::TestApi>(dialog_);
  71. dialog_->Show();
  72. }
  73. void TypePassword(const std::string& password) {
  74. auto* generator = GetEventGenerator();
  75. generator->MoveMouseTo(
  76. test_api_->GetPasswordTextfield()->GetBoundsInScreen().CenterPoint());
  77. generator->ClickLeftButton();
  78. for (char c : password) {
  79. EXPECT_TRUE(std::isalpha(c));
  80. generator->PressAndReleaseKey(
  81. static_cast<ui::KeyboardCode>(ui::KeyboardCode::VKEY_A + (c - 'a')),
  82. ui::EF_NONE);
  83. }
  84. }
  85. void PressOkButton() {
  86. auto* generator = GetEventGenerator();
  87. generator->MoveMouseTo(
  88. dialog_->GetOkButton()->GetBoundsInScreen().CenterPoint());
  89. generator->ClickLeftButton();
  90. }
  91. absl::optional<bool> success_;
  92. base::UnguessableToken token_;
  93. base::raw_ptr<AuthenticationDialog> dialog_;
  94. std::unique_ptr<MockInSessionAuthTokenProvider> auth_token_provider_;
  95. base::raw_ptr<MockAuthPerformer> auth_performer_;
  96. std::unique_ptr<AuthenticationDialog::TestApi> test_api_;
  97. };
  98. TEST_F(AuthenticationDialogTest, CallbackCalledOnCancel) {
  99. CreateAndShowDialog();
  100. dialog_->Cancel();
  101. EXPECT_TRUE(success_.has_value());
  102. EXPECT_EQ(success_.value(), false);
  103. }
  104. TEST_F(AuthenticationDialogTest, CallbackCalledOnClose) {
  105. CreateAndShowDialog();
  106. dialog_->Close();
  107. EXPECT_TRUE(success_.has_value());
  108. EXPECT_EQ(success_.value(), false);
  109. }
  110. TEST_F(AuthenticationDialogTest, CorrectPasswordProvided) {
  111. CreateAndShowDialog();
  112. TypePassword(kExpectedPassword);
  113. EXPECT_CALL(*auth_performer_,
  114. AuthenticateWithPassword(kCryptohomeGaiaKeyLabel,
  115. kExpectedPassword, _, _))
  116. .WillOnce([](const std::string& key_label, const std::string& password,
  117. std::unique_ptr<UserContext> user_context,
  118. AuthOperationCallback callback) {
  119. std::move(callback).Run(std::move(user_context), absl::nullopt);
  120. });
  121. EXPECT_CALL(*auth_token_provider_, ExchangeForToken)
  122. .WillOnce(testing::Invoke(this, &AuthenticationDialogTest::GetAuthToken));
  123. PressOkButton();
  124. EXPECT_TRUE(success_.has_value());
  125. EXPECT_TRUE(success_.value());
  126. EXPECT_EQ(token_, kToken);
  127. }
  128. TEST_F(AuthenticationDialogTest, IncorrectPasswordProvidedThenCorrect) {
  129. CreateAndShowDialog();
  130. TypePassword("ytrewq");
  131. EXPECT_CALL(*auth_performer_,
  132. AuthenticateWithPassword(kCryptohomeGaiaKeyLabel, _, _, _))
  133. .WillRepeatedly([](const std::string& key_label,
  134. const std::string& password,
  135. std::unique_ptr<UserContext> user_context,
  136. AuthOperationCallback callback) {
  137. std::move(callback).Run(
  138. std::move(user_context),
  139. password == kExpectedPassword
  140. ? absl::nullopt
  141. : absl::optional<CryptohomeError>{CryptohomeError{
  142. user_data_auth::
  143. CRYPTOHOME_ERROR_AUTHORIZATION_KEY_NOT_FOUND}});
  144. });
  145. PressOkButton();
  146. TypePassword(kExpectedPassword);
  147. EXPECT_CALL(*auth_token_provider_, ExchangeForToken)
  148. .WillOnce(testing::Invoke(this, &AuthenticationDialogTest::GetAuthToken));
  149. PressOkButton();
  150. EXPECT_TRUE(success_.has_value());
  151. EXPECT_TRUE(success_.value());
  152. EXPECT_EQ(token_, kToken);
  153. }
  154. TEST_F(AuthenticationDialogTest, AuthSessionRestartedWhenExpired) {
  155. CreateAndShowDialog();
  156. TypePassword(kExpectedPassword);
  157. int number_of_calls = 0;
  158. EXPECT_CALL(*auth_performer_,
  159. AuthenticateWithPassword(kCryptohomeGaiaKeyLabel,
  160. kExpectedPassword, _, _))
  161. .WillRepeatedly([&number_of_calls](
  162. const std::string& key_label,
  163. const std::string& password,
  164. std::unique_ptr<UserContext> user_context,
  165. AuthOperationCallback callback) {
  166. std::move(callback).Run(
  167. std::move(user_context),
  168. number_of_calls++
  169. ? absl::nullopt
  170. : absl::optional<CryptohomeError>{CryptohomeError{
  171. user_data_auth::CRYPTOHOME_INVALID_AUTH_SESSION_TOKEN}});
  172. });
  173. EXPECT_CALL(*auth_token_provider_, ExchangeForToken)
  174. .WillOnce(testing::Invoke(this, &AuthenticationDialogTest::GetAuthToken));
  175. PressOkButton();
  176. EXPECT_TRUE(success_.has_value());
  177. EXPECT_TRUE(success_.value());
  178. EXPECT_EQ(token_, kToken);
  179. }
  180. } // namespace ash