| // 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 <memory> |
| #include <string> |
| #include <string_view> |
| |
| #include "ash/auth/views/active_session_auth_view.h" |
| #include "ash/auth/views/auth_common.h" |
| #include "ash/auth/views/auth_view_utils.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/public/cpp/auth/active_session_auth_controller.h" |
| #include "ash/public/cpp/login_types.h" |
| #include "ash/public/cpp/shell_window_ids.h" |
| #include "ash/session/session_controller_impl.h" |
| #include "ash/shell.h" |
| #include "ash/strings/grit/ash_strings.h" |
| #include "base/check.h" |
| #include "base/check_op.h" |
| #include "base/functional/bind.h" |
| #include "base/i18n/time_formatting.h" |
| #include "base/logging.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/notreached.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/time/time.h" |
| #include "chromeos/ash/components/cryptohome/auth_factor_conversions.h" |
| #include "chromeos/ash/components/cryptohome/constants.h" |
| #include "chromeos/ash/components/dbus/userdataauth/userdataauth_client.h" |
| #include "chromeos/ash/components/login/auth/auth_performer.h" |
| #include "chromeos/ash/components/login/auth/public/auth_callbacks.h" |
| #include "chromeos/ash/components/login/auth/public/auth_session_intent.h" |
| #include "chromeos/ash/components/login/auth/public/session_auth_factors.h" |
| #include "chromeos/ash/components/login/auth/public/user_context.h" |
| #include "chromeos/ash/components/osauth/impl/auth_surface_registry.h" |
| #include "chromeos/ash/components/osauth/public/auth_session_storage.h" |
| #include "components/account_id/account_id.h" |
| #include "components/user_manager/known_user.h" |
| #include "components/user_manager/user.h" |
| #include "components/user_manager/user_manager.h" |
| #include "ui/aura/window.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/mojom/ui_base_types.mojom-shared.h" |
| #include "ui/base/mojom/window_show_state.mojom.h" |
| #include "ui/base/ui_base_types.h" |
| #include "ui/display/screen.h" |
| #include "ui/gfx/geometry/size.h" |
| #include "ui/views/widget/widget.h" |
| #include "ui/views/widget/widget_delegate.h" |
| |
| // Enable VLOG level 1. |
| #undef ENABLED_VLOG_LEVEL |
| #define ENABLED_VLOG_LEVEL 1 |
| |
| namespace ash { |
| |
| namespace { |
| |
| // Read the salt from local state. |
| std::string GetUserSalt(const AccountId& account_id) { |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| if (const std::string* salt = |
| known_user.FindStringPath(account_id, prefs::kQuickUnlockPinSalt)) { |
| return *salt; |
| } |
| return {}; |
| } |
| |
| const char* ReasonToString(AuthRequest::Reason reason) { |
| switch (reason) { |
| case AuthRequest::Reason::kPasswordManager: |
| return "PasswordManager"; |
| case AuthRequest::Reason::kSettings: |
| return "Settings"; |
| case AuthRequest::Reason::kWebAuthN: |
| return "WebAuthN"; |
| } |
| NOTREACHED(); |
| } |
| |
| const char* ActiveSessionAuthStateToString( |
| ActiveSessionAuthControllerImpl::ActiveSessionAuthState state) { |
| switch (state) { |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState::kOnIdle: |
| return "OnIdle"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState::kWaitForInit: |
| return "WaitForInit"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState::kInitialized: |
| return "Initialized"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState:: |
| kPasswordAuthStarted: |
| return "PasswordAuthStarted"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState:: |
| kPasswordAuthSucceeded: |
| return "PasswordAuthSucceeded"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState:: |
| kPinAuthStarted: |
| return "PinAuthStarted"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState:: |
| kPinAuthSucceeded: |
| return "PinAuthSucceeded"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState:: |
| kFingerprintAuthSucceeded: |
| return "FingerprintAuthSucceeded"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState:: |
| kFingerprintAuthSucceededWaiting: |
| return "FingerprintAuthSucceededWaiting"; |
| case ActiveSessionAuthControllerImpl::ActiveSessionAuthState:: |
| kCloseRequested: |
| return "CloseRequested"; |
| } |
| NOTREACHED(); |
| } |
| |
| } // namespace |
| |
| // This class manages the closing process after successful fingerprint |
| // authentication. It listens for two signals: |
| // 1. The completion of the successful authentication animation. |
| // 2. The authentication callback from cryptohome. |
| // Once both signals are received, the class triggers the closing process. |
| class ActiveSessionAuthControllerImpl::FingerprintAuthTracker { |
| public: |
| explicit FingerprintAuthTracker(ActiveSessionAuthControllerImpl* owner) |
| : owner_(owner) { |
| CHECK(owner_); |
| } |
| |
| void OnAuthenticationFinished( |
| std::unique_ptr<UserContext> user_context, |
| std::optional<AuthenticationError> authentication_error) { |
| CHECK_EQ(authentication_finished_, false); |
| authentication_finished_ = true; |
| if (authentication_error.has_value()) { |
| LOG(ERROR) << "Authentication error during OnFingerprintSuccess code: " |
| << authentication_error->get_cryptohome_code(); |
| } |
| owner_->user_context_ = std::move(user_context); |
| MaybeNotifyOwner(); |
| } |
| |
| void OnAnimationFinished() { |
| VLOG(1) << "OnAnimationFinished"; |
| CHECK_EQ(animation_finished_, false); |
| animation_finished_ = true; |
| MaybeNotifyOwner(); |
| } |
| |
| void MaybeNotifyOwner() { |
| if (authentication_finished_ && animation_finished_) { |
| owner_->StartClose(); |
| } |
| CHECK(owner_); |
| CHECK(owner_->fp_auth_tracker_); |
| } |
| |
| private: |
| const raw_ptr<ActiveSessionAuthControllerImpl> owner_; |
| bool animation_finished_ = false; |
| bool authentication_finished_ = false; |
| }; |
| |
| ActiveSessionAuthControllerImpl::TestApi::TestApi( |
| ActiveSessionAuthControllerImpl* controller) |
| : controller_(controller) {} |
| |
| ActiveSessionAuthControllerImpl::TestApi::~TestApi() = default; |
| |
| AuthFactorSet ActiveSessionAuthControllerImpl::TestApi::GetAvailableFactors() |
| const { |
| return controller_->available_factors_; |
| } |
| |
| void ActiveSessionAuthControllerImpl::TestApi::SubmitPassword( |
| const std::string& password) { |
| controller_->OnPasswordSubmit(base::UTF8ToUTF16(password)); |
| } |
| |
| void ActiveSessionAuthControllerImpl::TestApi::SubmitPin( |
| const std::string& pin) { |
| controller_->OnPinSubmit(base::UTF8ToUTF16(pin)); |
| } |
| |
| void ActiveSessionAuthControllerImpl::TestApi::Close() { |
| controller_->StartClose(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::TestApi::SetPinStatus( |
| std::unique_ptr<cryptohome::PinStatus> pin_status) { |
| controller_->contents_view_->SetPinStatus(std::move(pin_status)); |
| } |
| |
| std::u16string_view |
| ActiveSessionAuthControllerImpl::TestApi::GetPinStatusMessage() const { |
| return controller_->contents_view_->GetPinStatusMessage(); |
| } |
| |
| ActiveSessionAuthControllerImpl::ActiveSessionAuthControllerImpl() = default; |
| ActiveSessionAuthControllerImpl::~ActiveSessionAuthControllerImpl() = default; |
| |
| bool ActiveSessionAuthControllerImpl::IsPreInitializedState() const { |
| return state_ == ActiveSessionAuthState::kOnIdle || |
| state_ == ActiveSessionAuthState::kWaitForInit; |
| } |
| |
| bool ActiveSessionAuthControllerImpl::IsSucceedState() const { |
| return state_ == ActiveSessionAuthState::kPasswordAuthSucceeded || |
| state_ == ActiveSessionAuthState::kPinAuthSucceeded || |
| state_ == ActiveSessionAuthState::kFingerprintAuthSucceeded || |
| state_ == ActiveSessionAuthState::kFingerprintAuthSucceededWaiting; |
| } |
| |
| bool ActiveSessionAuthControllerImpl::ShowAuthDialog( |
| std::unique_ptr<AuthRequest> auth_request) { |
| CHECK(auth_request); |
| VLOG(1) << "Show is requested with reason: " |
| << ReasonToString(auth_request->GetAuthReason()); |
| if (IsShown()) { |
| LOG(ERROR) << "ActiveSessionAuthController widget is already exists."; |
| auth_request->NotifyAuthFailure(); |
| return false; |
| } |
| |
| if (state_ == ActiveSessionAuthState::kWaitForInit) { |
| VLOG(1) << "A show request is already pending; waiting for initialization."; |
| return false; |
| } |
| |
| // This state transition checking the current state is kOnIdle. |
| SetState(ActiveSessionAuthState::kWaitForInit); |
| |
| CHECK(Shell::Get()); |
| CHECK(Shell::Get()->session_controller()); |
| |
| if (Shell::Get()->session_controller()->GetSessionState() != |
| session_manager::SessionState::ACTIVE) { |
| LOG(ERROR) << "SessionState is not active."; |
| return false; |
| } |
| |
| Shell::Get()->session_controller()->AddObserver(this); |
| |
| CHECK(!auth_request_); |
| auth_request_ = std::move(auth_request); |
| |
| title_ = l10n_util::GetStringUTF16(IDS_ASH_IN_SESSION_AUTH_TITLE); |
| description_ = auth_request_->GetDescription(); |
| auth_factor_editor_ = |
| std::make_unique<AuthFactorEditor>(UserDataAuthClient::Get()); |
| auth_performer_ = std::make_unique<AuthPerformer>(UserDataAuthClient::Get()); |
| account_id_ = Shell::Get()->session_controller()->GetActiveAccountId(); |
| |
| fingerprint_animation_finished_ = false; |
| fingerprint_authentication_finished_ = false; |
| |
| user_manager::User* active_user = |
| user_manager::UserManager::Get()->GetActiveUser(); |
| auto user_context = std::make_unique<UserContext>(*active_user); |
| |
| const bool ephemeral = |
| user_manager::UserManager::Get()->IsUserCryptohomeDataEphemeral( |
| account_id_); |
| |
| auth_performer_->StartAuthSession( |
| std::move(user_context), ephemeral, auth_request_->GetAuthSessionIntent(), |
| base::BindOnce(&ActiveSessionAuthControllerImpl::OnAuthSessionStarted, |
| weak_ptr_factory_.GetWeakPtr())); |
| |
| return true; |
| } |
| |
| bool ActiveSessionAuthControllerImpl::IsShown() const { |
| return widget_ != nullptr; |
| } |
| |
| void ActiveSessionAuthControllerImpl::SetFingerprintClient( |
| ActiveSessionFingerprintClient* fp_client) { |
| CHECK_NE(fp_client_ == nullptr, fp_client == nullptr); |
| fp_client_ = fp_client; |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnAuthSessionStarted( |
| bool user_exists, |
| std::unique_ptr<UserContext> user_context, |
| std::optional<AuthenticationError> authentication_error) { |
| user_context_ = std::move(user_context); |
| |
| if (!user_exists || authentication_error.has_value()) { |
| LOG(ERROR) << "Failed to start auth session, code " |
| << authentication_error->get_cryptohome_code(); |
| StartClose(); |
| return; |
| } |
| |
| auth_session_broadcast_id_ = user_context_->GetBroadcastId(); |
| |
| UserDataAuthClient::Get()->AddAuthFactorStatusUpdateObserver(this); |
| |
| available_factors_.Clear(); |
| const auto& auth_factors = user_context_->GetAuthFactorsData(); |
| |
| if (auth_factors.FindAnyPasswordFactor()) { |
| available_factors_.Put(AuthInputType::kPassword); |
| } |
| |
| auto* pin_factor = auth_factors.FindPinFactor(); |
| if (pin_factor) { |
| if (!pin_factor->GetPinStatus().IsLockedFactor()) { |
| available_factors_.Put(AuthInputType::kPin); |
| } |
| } |
| |
| if (available_factors_.empty() && pin_factor == nullptr) { |
| LOG(ERROR) << "No password/PIN found for user."; |
| StartClose(); |
| return; |
| } |
| |
| uma_recorder_.RecordShow(auth_request_->GetAuthReason(), available_factors_); |
| |
| MaybePrepareFingerprint( |
| BindOnce(&ActiveSessionAuthControllerImpl::AuthFactorsAreReady, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| |
| void ActiveSessionAuthControllerImpl::MaybePrepareFingerprint( |
| AuthFactorsReadyCallback on_auth_factors_ready) { |
| // If the fingerprint factor is allowed to use by the user for the current |
| // reason then start it before initialize the UI. |
| if (fp_client_ && fp_client_->IsFingerprintAvailable( |
| auth_request_->GetAuthReason(), account_id_)) { |
| VLOG(1) << "PrepareFingerprintAuth started."; |
| fp_client_->PrepareFingerprintAuth( |
| std::move(user_context_), |
| /* auth_ready_callback = */ |
| base::BindOnce(&ActiveSessionAuthControllerImpl::OnFingerprintReady, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_auth_factors_ready)), |
| /* on_scan_callback = */ |
| base::BindRepeating(&ActiveSessionAuthControllerImpl::OnFingerprintScan, |
| weak_ptr_factory_.GetWeakPtr())); |
| return; |
| } |
| std::move(on_auth_factors_ready).Run(std::move(user_context_)); |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnFingerprintReady( |
| AuthFactorsReadyCallback on_auth_factors_ready, |
| std::unique_ptr<UserContext> user_context, |
| std::optional<AuthenticationError> authentication_error) { |
| if (authentication_error.has_value()) { |
| LOG(ERROR) << "Failed to start fingerprint auth session - only " |
| "non-fingerprint factors will be available."; |
| } else { |
| fp_auth_tracker_ = std::make_unique<FingerprintAuthTracker>(this); |
| available_factors_.Put(AuthInputType::kFingerprint); |
| } |
| std::move(on_auth_factors_ready).Run(std::move(user_context)); |
| } |
| |
| void ActiveSessionAuthControllerImpl::AuthFactorsAreReady( |
| std::unique_ptr<UserContext> user_context) { |
| user_context_ = std::move(user_context); |
| InitUi(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnFingerprintScan( |
| const FingerprintAuthScanResult scan_result) { |
| CHECK(!ActiveSessionAuthControllerImpl::IsPreInitializedState()); |
| // Avoid unnecessary processing if we've already initiated close. |
| if (IsSucceedState() || state_ == ActiveSessionAuthState::kCloseRequested) { |
| return; |
| } |
| switch (scan_result) { |
| case FingerprintAuthScanResult::kSuccess: |
| contents_view_->NotifyFingerprintAuthSuccess( |
| base::BindOnce(&FingerprintAuthTracker::OnAnimationFinished, |
| base::Unretained(fp_auth_tracker_.get()))); |
| if (state_ == ActiveSessionAuthState::kPasswordAuthStarted || |
| state_ == ActiveSessionAuthState::kPinAuthStarted) { |
| SetState(ActiveSessionAuthState::kFingerprintAuthSucceededWaiting); |
| // The user_context_ is not available, we have to wait for the |
| // OnAuthComplete callback to have UserContext. |
| return; |
| } |
| HandleFingerprintAuthSuccess(); |
| return; |
| case FingerprintAuthScanResult::kTooManyAttempts: |
| uma_recorder_.RecordAuthFailed(AuthInputType::kFingerprint); |
| |
| contents_view_->SetFingerprintState( |
| FingerprintState::DISABLED_FROM_ATTEMPTS); |
| return; |
| case FingerprintAuthScanResult::kFailed: |
| uma_recorder_.RecordAuthFailed(AuthInputType::kFingerprint); |
| |
| contents_view_->NotifyFingerprintAuthFailure(); |
| return; |
| case FingerprintAuthScanResult::kFatalError: |
| contents_view_->SetFingerprintState(FingerprintState::UNAVAILABLE); |
| return; |
| } |
| NOTREACHED(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::HandleFingerprintAuthSuccess() { |
| CHECK(user_context_); |
| uma_recorder_.RecordAuthSucceeded(AuthInputType::kFingerprint); |
| SetState(ActiveSessionAuthState::kFingerprintAuthSucceeded); |
| auth_performer_->AuthenticateWithLegacyFingerprint( |
| std::move(user_context_), |
| base::BindOnce(&FingerprintAuthTracker::OnAuthenticationFinished, |
| base::Unretained(fp_auth_tracker_.get()))); |
| } |
| |
| void ActiveSessionAuthControllerImpl::InitUi() { |
| auto contents_view = std::make_unique<ActiveSessionAuthView>( |
| account_id_, title_, description_, available_factors_); |
| contents_view_ = contents_view.get(); |
| |
| views::Widget::InitParams params( |
| views::Widget::InitParams::CLIENT_OWNS_WIDGET, |
| views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); |
| params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent; |
| params.delegate = new views::WidgetDelegate(); |
| params.show_state = ui::mojom::WindowShowState::kNormal; |
| CHECK_EQ(Shell::Get()->session_controller()->GetSessionState(), |
| session_manager::SessionState::ACTIVE); |
| params.parent = Shell::GetPrimaryRootWindow()->GetChildById( |
| kShellWindowId_SystemModalContainer); |
| params.autosize = true; |
| params.name = "AuthDialogWidget"; |
| |
| params.delegate->SetInitiallyFocusedView(contents_view.get()); |
| params.delegate->SetModalType(ui::mojom::ModalType::kSystem); |
| params.delegate->SetOwnedByWidget( |
| views::WidgetDelegate::OwnedByWidgetPassKey()); |
| |
| widget_ = std::make_unique<views::Widget>(); |
| widget_->Init(std::move(params)); |
| widget_->SetVisibilityAnimationTransition(views::Widget::ANIMATE_NONE); |
| widget_->SetContentsView(std::move(contents_view)); |
| |
| contents_view_observer_.Observe(contents_view_); |
| contents_view_->AddObserver(this); |
| SetState(ActiveSessionAuthState::kInitialized); |
| |
| const auto& auth_factors = user_context_->GetAuthFactorsData(); |
| |
| auto* pin_factor = auth_factors.FindPinFactor(); |
| if (pin_factor) { |
| contents_view_->SetPinStatus( |
| std::make_unique<cryptohome::PinStatus>(pin_factor->GetPinStatus())); |
| } |
| |
| MoveToTheCenter(); |
| widget_->Show(); |
| ash::AuthParts::Get() |
| ->GetAuthSurfaceRegistry() |
| ->NotifyInSessionAuthDialogShown(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::StartClose() { |
| VLOG(1) << "Close with : " << ActiveSessionAuthStateToString(state_) |
| << " state."; |
| CHECK(user_context_); |
| CHECK(auth_request_); |
| CHECK(auth_performer_); |
| if (!IsPreInitializedState()) { |
| uma_recorder_.RecordClose(); |
| } |
| |
| if (Shell::Get() && Shell::Get()->session_controller()) { |
| Shell::Get()->session_controller()->RemoveObserver(this); |
| } |
| |
| contents_view_observer_.Reset(); |
| if (contents_view_) { |
| contents_view_->RemoveObserver(this); |
| contents_view_ = nullptr; |
| } else { |
| CHECK(IsPreInitializedState()); |
| } |
| auth_session_broadcast_id_.clear(); |
| |
| UserDataAuthClient::Get()->RemoveAuthFactorStatusUpdateObserver(this); |
| |
| auth_performer_->InvalidateCurrentAttempts(); |
| if (fp_client_ && available_factors_.Has(AuthInputType::kFingerprint)) { |
| CHECK(fp_auth_tracker_); |
| fp_client_->TerminateFingerprintAuth( |
| std::move(user_context_), |
| base::BindOnce(&ActiveSessionAuthControllerImpl::CompleteClose, |
| weak_ptr_factory_.GetWeakPtr())); |
| return; |
| } |
| CHECK(!fp_auth_tracker_); |
| CompleteClose(std::move(user_context_), std::nullopt); |
| } |
| |
| void ActiveSessionAuthControllerImpl::CompleteClose( |
| std::unique_ptr<UserContext> user_context, |
| std::optional<AuthenticationError> authentication_error) { |
| user_context_ = std::move(user_context); |
| CHECK(user_context_); |
| CHECK(auth_request_); |
| auth_performer_.reset(); |
| auth_factor_editor_.reset(); |
| |
| if (IsSucceedState()) { |
| auth_request_->NotifyAuthSuccess(std::move(user_context_)); |
| } else { |
| auth_request_->NotifyAuthFailure(); |
| user_context_.reset(); |
| } |
| auth_request_.reset(); |
| available_factors_.Clear(); |
| |
| SetState(ActiveSessionAuthState::kOnIdle); |
| |
| title_.clear(); |
| description_.clear(); |
| fp_auth_tracker_.reset(); |
| widget_.reset(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnSessionStateChanged( |
| session_manager::SessionState session_state) { |
| if (session_state == session_manager::SessionState::ACTIVE) { |
| return; |
| } |
| VLOG(1) << "SessionState changed, closing process started"; |
| switch (state_) { |
| case ActiveSessionAuthState::kOnIdle: |
| case ActiveSessionAuthState::kWaitForInit: |
| case ActiveSessionAuthState::kInitialized: |
| StartClose(); |
| return; |
| case ActiveSessionAuthState::kPasswordAuthStarted: |
| case ActiveSessionAuthState::kPinAuthStarted: |
| SetState(ActiveSessionAuthState::kCloseRequested); |
| return; |
| case ActiveSessionAuthState::kPasswordAuthSucceeded: |
| case ActiveSessionAuthState::kPinAuthSucceeded: |
| case ActiveSessionAuthState::kFingerprintAuthSucceeded: |
| case ActiveSessionAuthState::kFingerprintAuthSucceededWaiting: |
| case ActiveSessionAuthState::kCloseRequested: |
| return; |
| } |
| NOTREACHED(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnViewPreferredSizeChanged( |
| views::View* observed_view) { |
| MoveToTheCenter(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::MoveToTheCenter() { |
| widget_->CenterWindow(widget_->GetContentsView()->GetPreferredSize()); |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnPasswordSubmit( |
| std::u16string_view password) { |
| if (IsSucceedState()) { |
| return; |
| } |
| SetState(ActiveSessionAuthState::kPasswordAuthStarted); |
| uma_recorder_.RecordAuthStarted(AuthInputType::kPassword); |
| CHECK(user_context_); |
| const auto* password_factor = |
| user_context_->GetAuthFactorsData().FindAnyPasswordFactor(); |
| CHECK(password_factor); |
| |
| const cryptohome::KeyLabel key_label = password_factor->ref().label(); |
| |
| auth_performer_->AuthenticateWithPassword( |
| key_label.value(), base::UTF16ToUTF8(password), std::move(user_context_), |
| base::BindOnce(&ActiveSessionAuthControllerImpl::OnAuthComplete, |
| weak_ptr_factory_.GetWeakPtr(), AuthInputType::kPassword)); |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnPinSubmit(std::u16string_view pin) { |
| if (IsSucceedState()) { |
| return; |
| } |
| SetState(ActiveSessionAuthState::kPinAuthStarted); |
| uma_recorder_.RecordAuthStarted(AuthInputType::kPin); |
| CHECK(user_context_); |
| user_manager::KnownUser known_user(Shell::Get()->local_state()); |
| const std::string salt = GetUserSalt(account_id_); |
| |
| auth_performer_->AuthenticateWithPin( |
| base::UTF16ToUTF8(pin), salt, std::move(user_context_), |
| base::BindOnce(&ActiveSessionAuthControllerImpl::OnAuthComplete, |
| weak_ptr_factory_.GetWeakPtr(), AuthInputType::kPin)); |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnAuthComplete( |
| AuthInputType input_type, |
| std::unique_ptr<UserContext> user_context, |
| std::optional<AuthenticationError> authentication_error) { |
| user_context_ = std::move(user_context); |
| // If fingerprint auth succeeded during wait for PIN/password authentication, |
| // handle success directly. |
| if (state_ == ActiveSessionAuthState::kFingerprintAuthSucceededWaiting) { |
| HandleFingerprintAuthSuccess(); |
| return; |
| } |
| CHECK(!IsSucceedState()); |
| if (state_ == ActiveSessionAuthState::kCloseRequested) { |
| StartClose(); |
| return; |
| } |
| if (authentication_error.has_value()) { |
| uma_recorder_.RecordAuthFailed(input_type); |
| contents_view_->SetErrorTitle(l10n_util::GetStringUTF16( |
| input_type == AuthInputType::kPassword |
| ? IDS_ASH_IN_SESSION_AUTH_PASSWORD_INCORRECT |
| : IDS_ASH_IN_SESSION_AUTH_PIN_INCORRECT)); |
| SetState(ActiveSessionAuthState::kInitialized); |
| } else { |
| uma_recorder_.RecordAuthSucceeded(input_type); |
| SetState(input_type == AuthInputType::kPassword |
| ? ActiveSessionAuthState::kPasswordAuthSucceeded |
| : ActiveSessionAuthState::kPinAuthSucceeded); |
| StartClose(); |
| } |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnClose() { |
| switch (state_) { |
| case ActiveSessionAuthState::kOnIdle: |
| case ActiveSessionAuthState::kWaitForInit: |
| NOTREACHED(); |
| case ActiveSessionAuthState::kInitialized: |
| StartClose(); |
| return; |
| case ActiveSessionAuthState::kPasswordAuthStarted: |
| case ActiveSessionAuthState::kPinAuthStarted: |
| SetState(ActiveSessionAuthState::kCloseRequested); |
| return; |
| case ActiveSessionAuthState::kPasswordAuthSucceeded: |
| case ActiveSessionAuthState::kPinAuthSucceeded: |
| case ActiveSessionAuthState::kFingerprintAuthSucceeded: |
| case ActiveSessionAuthState::kFingerprintAuthSucceededWaiting: |
| case ActiveSessionAuthState::kCloseRequested: |
| return; |
| } |
| NOTREACHED(); |
| } |
| |
| void ActiveSessionAuthControllerImpl::SetState(ActiveSessionAuthState state) { |
| VLOG(1) << "SetState is requested from: " |
| << ActiveSessionAuthStateToString(state_) |
| << " state to : " << ActiveSessionAuthStateToString(state) |
| << " state."; |
| switch (state) { |
| case ActiveSessionAuthState::kOnIdle: |
| break; |
| case ActiveSessionAuthState::kWaitForInit: |
| CHECK(state_ == ActiveSessionAuthState::kOnIdle); |
| break; |
| case ActiveSessionAuthState::kInitialized: |
| CHECK(state_ == ActiveSessionAuthState::kWaitForInit || |
| state_ == ActiveSessionAuthState::kPasswordAuthStarted || |
| state_ == ActiveSessionAuthState::kPinAuthStarted); |
| contents_view_->SetInputEnabled(true); |
| break; |
| case ActiveSessionAuthState::kPasswordAuthStarted: |
| // Disable the UI while we are waiting for the response, except the close |
| // button. |
| CHECK_EQ(state_, ActiveSessionAuthState::kInitialized); |
| contents_view_->SetInputEnabled(false); |
| break; |
| case ActiveSessionAuthState::kPasswordAuthSucceeded: |
| CHECK_EQ(state_, ActiveSessionAuthState::kPasswordAuthStarted); |
| break; |
| case ActiveSessionAuthState::kPinAuthStarted: |
| CHECK_EQ(state_, ActiveSessionAuthState::kInitialized); |
| contents_view_->SetInputEnabled(false); |
| break; |
| case ActiveSessionAuthState::kPinAuthSucceeded: |
| CHECK_EQ(state_, ActiveSessionAuthState::kPinAuthStarted); |
| break; |
| case ActiveSessionAuthState::kFingerprintAuthSucceeded: |
| CHECK(state_ == ActiveSessionAuthState::kInitialized || |
| state_ == ActiveSessionAuthState::kFingerprintAuthSucceededWaiting); |
| contents_view_->SetInputEnabled(false); |
| break; |
| case ActiveSessionAuthState::kFingerprintAuthSucceededWaiting: |
| CHECK(state_ == ActiveSessionAuthState::kPasswordAuthStarted || |
| state_ == ActiveSessionAuthState::kPinAuthStarted); |
| contents_view_->SetInputEnabled(false); |
| break; |
| case ActiveSessionAuthState::kCloseRequested: |
| CHECK(state_ == ActiveSessionAuthState::kPasswordAuthStarted || |
| state_ == ActiveSessionAuthState::kPinAuthStarted); |
| contents_view_->SetInputEnabled(false); |
| break; |
| } |
| state_ = state; |
| } |
| |
| void ActiveSessionAuthControllerImpl::OnAuthFactorStatusUpdate( |
| const user_data_auth::AuthFactorStatusUpdate& update) { |
| switch (state_) { |
| case ActiveSessionAuthState::kInitialized: |
| case ActiveSessionAuthState::kPinAuthStarted: |
| case ActiveSessionAuthState::kPasswordAuthStarted: |
| CHECK_NE(auth_session_broadcast_id_, ""); |
| if (auth_session_broadcast_id_ == update.broadcast_id()) { |
| auto auth_factor = cryptohome::DeserializeAuthFactor( |
| update.auth_factor_with_status(), |
| /*fallback_type=*/cryptohome::AuthFactorType::kPassword); |
| if (auth_factor.ref().type() == cryptohome::AuthFactorType::kPin) { |
| auto pin_status = auth_factor.GetPinStatus(); |
| contents_view_->SetPinStatus( |
| std::make_unique<cryptohome::PinStatus>(pin_status)); |
| } |
| } |
| return; |
| |
| case ActiveSessionAuthState::kOnIdle: |
| case ActiveSessionAuthState::kWaitForInit: |
| return; |
| |
| case ActiveSessionAuthState::kPasswordAuthSucceeded: |
| case ActiveSessionAuthState::kPinAuthSucceeded: |
| case ActiveSessionAuthState::kFingerprintAuthSucceeded: |
| case ActiveSessionAuthState::kFingerprintAuthSucceededWaiting: |
| case ActiveSessionAuthState::kCloseRequested: |
| // No need to handle PIN updates as dialog closing is in progress. |
| return; |
| } |
| NOTREACHED(); |
| } |
| |
| } // namespace ash |