webauthn_dialog_controller_impl.cc 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. // Copyright 2020 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/webauthn_dialog_controller_impl.h"
  5. #include "ash/in_session_auth/auth_dialog_contents_view.h"
  6. #include "ash/in_session_auth/webauthn_request_registrar_impl.h"
  7. #include "ash/public/cpp/in_session_auth_dialog_client.h"
  8. #include "ash/session/session_controller_impl.h"
  9. #include "ash/shell.h"
  10. #include "base/bind.h"
  11. #include "base/callback.h"
  12. #include "base/strings/string_util.h"
  13. #include "components/user_manager/known_user.h"
  14. #include "ui/aura/window.h"
  15. #include "ui/views/widget/widget.h"
  16. namespace ash {
  17. WebAuthNDialogControllerImpl::WebAuthNDialogControllerImpl()
  18. : webauthn_request_registrar_(
  19. std::make_unique<WebAuthnRequestRegistrarImpl>()) {}
  20. WebAuthNDialogControllerImpl::~WebAuthNDialogControllerImpl() = default;
  21. void WebAuthNDialogControllerImpl::SetClient(
  22. InSessionAuthDialogClient* client) {
  23. client_ = client;
  24. }
  25. void WebAuthNDialogControllerImpl::ShowAuthenticationDialog(
  26. aura::Window* source_window,
  27. const std::string& origin_name,
  28. FinishCallback finish_callback) {
  29. DCHECK(client_);
  30. // Concurrent requests are not supported.
  31. DCHECK(!dialog_);
  32. source_window_tracker_.Add(source_window);
  33. finish_callback_ = std::move(finish_callback);
  34. AccountId account_id =
  35. Shell::Get()->session_controller()->GetActiveAccountId();
  36. // GAIA password option is not offered.
  37. uint32_t auth_methods = AuthDialogContentsView::kAuthPassword;
  38. if (client_->IsFingerprintAuthAvailable(account_id)) {
  39. client_->StartFingerprintAuthSession(
  40. account_id,
  41. base::BindOnce(
  42. &WebAuthNDialogControllerImpl::OnStartFingerprintAuthSession,
  43. weak_factory_.GetWeakPtr(), account_id, auth_methods, source_window,
  44. origin_name));
  45. // OnStartFingerprintAuthSession checks PIN availability.
  46. return;
  47. }
  48. client_->CheckPinAuthAvailability(
  49. account_id,
  50. base::BindOnce(&WebAuthNDialogControllerImpl::OnPinCanAuthenticate,
  51. weak_factory_.GetWeakPtr(), auth_methods, source_window,
  52. origin_name));
  53. }
  54. void WebAuthNDialogControllerImpl::OnStartFingerprintAuthSession(
  55. AccountId account_id,
  56. uint32_t auth_methods,
  57. aura::Window* source_window,
  58. const std::string& origin_name,
  59. bool success) {
  60. if (success)
  61. auth_methods |= AuthDialogContentsView::kAuthFingerprint;
  62. client_->CheckPinAuthAvailability(
  63. account_id,
  64. base::BindOnce(&WebAuthNDialogControllerImpl::OnPinCanAuthenticate,
  65. weak_factory_.GetWeakPtr(), auth_methods, source_window,
  66. origin_name));
  67. }
  68. void WebAuthNDialogControllerImpl::OnPinCanAuthenticate(
  69. uint32_t auth_methods,
  70. aura::Window* source_window,
  71. const std::string& origin_name,
  72. bool pin_auth_available) {
  73. if (pin_auth_available)
  74. auth_methods |= AuthDialogContentsView::kAuthPin;
  75. if (auth_methods == 0) {
  76. // If neither fingerprint nor PIN is available, we shouldn't receive the
  77. // request.
  78. LOG(ERROR) << "Neither fingerprint nor PIN is available.";
  79. Cancel();
  80. return;
  81. }
  82. if (!source_window_tracker_.Contains(source_window)) {
  83. LOG(ERROR) << "Source window is no longer available.";
  84. Cancel();
  85. return;
  86. }
  87. Shell* shell = Shell::Get();
  88. AccountId account_id = shell->session_controller()->GetActiveAccountId();
  89. const UserSession* session =
  90. shell->session_controller()->GetUserSessionByAccountId(account_id);
  91. DCHECK(session);
  92. UserAvatar avatar = session->user_info.avatar;
  93. // TODO(b/156258540): move UserSelectionScreen::BuildAshUserAvatarForUser to
  94. // somewhere that UserToUserSession could call, to support animated avatars.
  95. AuthDialogContentsView::AuthMethodsMetadata auth_metadata;
  96. auth_metadata.autosubmit_pin_length =
  97. user_manager::KnownUser(shell->local_state())
  98. .GetUserPinLength(account_id);
  99. source_window_tracker_.Remove(source_window);
  100. dialog_ = std::make_unique<InSessionAuthDialog>(
  101. auth_methods, source_window, origin_name, auth_metadata, avatar);
  102. }
  103. void WebAuthNDialogControllerImpl::DestroyAuthenticationDialog() {
  104. DCHECK(client_);
  105. if (!dialog_)
  106. return;
  107. if (dialog_->GetAuthMethods() & AuthDialogContentsView::kAuthFingerprint)
  108. client_->EndFingerprintAuthSession();
  109. dialog_.reset();
  110. source_window_tracker_.RemoveAll();
  111. }
  112. void WebAuthNDialogControllerImpl::AuthenticateUserWithPasswordOrPin(
  113. const std::string& password,
  114. bool authenticated_by_pin,
  115. OnAuthenticateCallback callback) {
  116. DCHECK(client_);
  117. // TODO(b/156258540): Check that PIN is enabled / set up for this user.
  118. if (authenticated_by_pin &&
  119. !base::ContainsOnlyChars(password, "0123456789")) {
  120. OnAuthenticateComplete(std::move(callback), false);
  121. return;
  122. }
  123. client_->AuthenticateUserWithPasswordOrPin(
  124. password, authenticated_by_pin,
  125. base::BindOnce(&WebAuthNDialogControllerImpl::OnAuthenticateComplete,
  126. weak_factory_.GetWeakPtr(), std::move(callback)));
  127. }
  128. void WebAuthNDialogControllerImpl::AuthenticateUserWithFingerprint(
  129. base::OnceCallback<void(bool, FingerprintState)> views_callback) {
  130. DCHECK(client_);
  131. client_->AuthenticateUserWithFingerprint(
  132. base::BindOnce(&WebAuthNDialogControllerImpl::OnFingerprintAuthComplete,
  133. weak_factory_.GetWeakPtr(), std::move(views_callback)));
  134. }
  135. void WebAuthNDialogControllerImpl::OnAuthenticateComplete(
  136. OnAuthenticateCallback callback,
  137. bool success) {
  138. if (success) {
  139. std::move(callback).Run(/*success=*/true, /*can_use_pin=*/true);
  140. OnAuthSuccess();
  141. return;
  142. }
  143. // PIN might be locked out after an unsuccessful authentication, check if it's
  144. // still available so the UI can be updated.
  145. AccountId account_id =
  146. Shell::Get()->session_controller()->GetActiveAccountId();
  147. client_->CheckPinAuthAvailability(
  148. account_id, base::BindOnce(std::move(callback), /*success=*/false));
  149. }
  150. void WebAuthNDialogControllerImpl::OnFingerprintAuthComplete(
  151. base::OnceCallback<void(bool, FingerprintState)> views_callback,
  152. bool success,
  153. FingerprintState fingerprint_state) {
  154. // If success is false and retry is allowed, the view will start another
  155. // fingerprint check.
  156. std::move(views_callback).Run(success, fingerprint_state);
  157. if (success)
  158. OnAuthSuccess();
  159. }
  160. void WebAuthNDialogControllerImpl::OnAuthSuccess() {
  161. DestroyAuthenticationDialog();
  162. if (finish_callback_)
  163. std::move(finish_callback_).Run(true);
  164. }
  165. void WebAuthNDialogControllerImpl::Cancel() {
  166. DestroyAuthenticationDialog();
  167. if (finish_callback_)
  168. std::move(finish_callback_).Run(false);
  169. }
  170. void WebAuthNDialogControllerImpl::OpenInSessionAuthHelpPage() {
  171. DCHECK(client_);
  172. client_->OpenInSessionAuthHelpPage();
  173. }
  174. void WebAuthNDialogControllerImpl::CheckAvailability(
  175. FinishCallback on_availability_checked) const {
  176. // Assumes the requests are for the active user (no teleported window).
  177. AccountId account_id =
  178. Shell::Get()->session_controller()->GetActiveAccountId();
  179. if (client_->IsFingerprintAuthAvailable(account_id)) {
  180. std::move(on_availability_checked).Run(true);
  181. return;
  182. }
  183. client_->CheckPinAuthAvailability(account_id,
  184. std::move(on_availability_checked));
  185. }
  186. } // namespace ash