diff --git a/chrome/browser/ash/login/quick_unlock/pin_backend.h b/chrome/browser/ash/login/quick_unlock/pin_backend.h index d37ac662b3cbd..684265ea1eade 100644 --- a/chrome/browser/ash/login/quick_unlock/pin_backend.h +++ b/chrome/browser/ash/login/quick_unlock/pin_backend.h @@ -10,6 +10,7 @@ #include "base/functional/callback.h" #include "chromeos/ash/components/login/auth/public/auth_callbacks.h" #include "chromeos/ash/components/login/auth/public/key.h" +#include "chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h" #include "components/prefs/pref_service.h" class AccountId; @@ -24,7 +25,7 @@ enum class Purpose; // Provides high-level access to the user's PIN. The underlying storage can be // either cryptohome or prefs. -class PinBackend { +class PinBackend : public ash::auth::PinBackendDelegate { public: using BoolCallback = base::OnceCallback; @@ -45,7 +46,7 @@ class PinBackend { PinBackend(const PinBackend&) = delete; PinBackend& operator=(const PinBackend&) = delete; - ~PinBackend(); + ~PinBackend() override; // Check to see if the PinBackend supports login. This is true when the // cryptohome backend is available. @@ -61,7 +62,7 @@ class PinBackend { void Set(const AccountId& account_id, const std::string& auth_token, const std::string& pin, - BoolCallback did_set); + BoolCallback did_set) override; // Set the state of PIN auto submit for the given user. Called when enabling // auto submit through the confirmation dialog in Settings. @@ -73,7 +74,7 @@ class PinBackend { // Remove the given user's PIN. void Remove(const AccountId& account_id, const std::string& auth_token, - BoolCallback did_remove); + BoolCallback did_remove) override; // Is PIN authentication available for the given account? Even if PIN is set, // it may not be available for authentication due to some additional diff --git a/chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h b/chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h index 4aedbc989ca5a..02e4dcbacd99a 100644 --- a/chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h +++ b/chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h @@ -7,7 +7,7 @@ #include "base/memory/singleton.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h" -#include "chromeos/ash/services/auth_factor_config/quick_unlock_storage_delegate.h" +#include "chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h" #include "components/account_id/account_id.h" class Profile; diff --git a/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.cc b/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.cc index 53facc245e706..fd72894250e33 100644 --- a/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.cc +++ b/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.cc @@ -88,13 +88,13 @@ void CryptohomeRecoverySetupScreen::ExitScreen( } void CryptohomeRecoverySetupScreen::OnRecoveryConfigured( - auth::RecoveryFactorEditor::ConfigureResult result) { + auth::mojom::ConfigureResult result) { switch (result) { - case auth::RecoveryFactorEditor::ConfigureResult::kSuccess: + case auth::mojom::ConfigureResult::kSuccess: ExitScreen(*context(), Result::DONE); break; - case auth::RecoveryFactorEditor::ConfigureResult::kInvalidTokenError: - case auth::RecoveryFactorEditor::ConfigureResult::kClientError: + case auth::mojom::ConfigureResult::kInvalidTokenError: + case auth::mojom::ConfigureResult::kFatalError: LOG(ERROR) << "Failed to setup recovery factor, result " << static_cast(result); ExitScreen(*context(), Result::SKIPPED); diff --git a/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.h b/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.h index 8e37d5d25ffba..da135885b1c37 100644 --- a/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.h +++ b/chrome/browser/ash/login/screens/cryptohome_recovery_setup_screen.h @@ -47,7 +47,7 @@ class CryptohomeRecoverySetupScreen : public BaseScreen { private: void ExitScreen(WizardContext& wizard_context, Result result); - void OnRecoveryConfigured(auth::RecoveryFactorEditor::ConfigureResult result); + void OnRecoveryConfigured(auth::mojom::ConfigureResult result); base::WeakPtr view_ = nullptr; ScreenExitCallback exit_callback_; base::WeakPtrFactory weak_ptr_factory_{this}; diff --git a/chrome/browser/chrome_browser_interface_binders.cc b/chrome/browser/chrome_browser_interface_binders.cc index 4ebc6bbf0d5f6..246931c75a3fe 100644 --- a/chrome/browser/chrome_browser_interface_binders.cc +++ b/chrome/browser/chrome_browser_interface_binders.cc @@ -1122,6 +1122,9 @@ void PopulateChromeWebUIFrameBinders( RegisterWebUIControllerInterfaceBinder(map); + RegisterWebUIControllerInterfaceBinder(map); + RegisterWebUIControllerInterfaceBinder< ash::cellular_setup::mojom::ESimManager, ash::settings::OSSettingsUI, ash::NetworkUI, ash::OobeUI>(map); diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/local_data_recovery_dialog.js b/chrome/browser/resources/settings/chromeos/os_people_page/local_data_recovery_dialog.js index 74170d34db575..0e0b62781e534 100644 --- a/chrome/browser/resources/settings/chromeos/os_people_page/local_data_recovery_dialog.js +++ b/chrome/browser/resources/settings/chromeos/os_people_page/local_data_recovery_dialog.js @@ -16,7 +16,7 @@ import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js'; import '../../settings_shared.css.js'; import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; -import {AuthFactor, FactorObserverInterface, FactorObserverReceiver, ManagementType, RecoveryFactorEditor_ConfigureResult} from 'chrome://resources/mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js'; +import {AuthFactor, ConfigureResult, FactorObserverInterface, FactorObserverReceiver, ManagementType} from 'chrome://resources/mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js'; import {mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {getTemplate} from './local_data_recovery_dialog.html.js'; @@ -94,7 +94,7 @@ class LocalDataRecoveryDialogElement extends const {result} = await this.recoveryFactorEditor.configure( this.authToken.token, false); - if (result !== RecoveryFactorEditor_ConfigureResult.kSuccess) { + if (result !== ConfigureResult.kSuccess) { console.error('RecoveryFactorEditor::Configure failed:', result); } } finally { diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen.js b/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen.js index bc5f82548e767..55b8321049c6e 100644 --- a/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen.js +++ b/chrome/browser/resources/settings/chromeos/os_people_page/lock_screen.js @@ -34,7 +34,7 @@ import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common import {LockScreenProgress, recordLockScreenProgress} from 'chrome://resources/ash/common/quick_unlock/lock_screen_constants.js'; import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/ash/common/web_ui_listener_behavior.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; -import {AuthFactor, FactorObserverInterface, FactorObserverReceiver, ManagementType, RecoveryFactorEditor_ConfigureResult} from 'chrome://resources/mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js'; +import {AuthFactor, ConfigureResult, FactorObserverInterface, FactorObserverReceiver, ManagementType} from 'chrome://resources/mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js'; import {afterNextRender, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {Setting} from '../../mojom-webui/setting.mojom-webui.js'; @@ -642,13 +642,13 @@ class SettingsLockScreenElement extends SettingsLockScreenElementBase { const {result} = await this.recoveryFactorEditor.configure( this.authToken.token, shouldEnable); switch (result) { - case RecoveryFactorEditor_ConfigureResult.kSuccess: + case ConfigureResult.kSuccess: break; - case RecoveryFactorEditor_ConfigureResult.kInvalidTokenError: + case ConfigureResult.kInvalidTokenError: // This will open the password prompt. this.dispatchAuthTokenInvalidEvent_(); return; - case RecoveryFactorEditor_ConfigureResult.kClientError: + case ConfigureResult.kFatalError: console.error('Error configuring recovery'); return; } diff --git a/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js b/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js index 0b89cfb3c74d4..18be3d458df08 100644 --- a/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js +++ b/chrome/browser/resources/settings/chromeos/os_people_page/lock_state_behavior.js @@ -4,7 +4,7 @@ import {I18nBehavior, I18nBehaviorInterface} from 'chrome://resources/ash/common/i18n_behavior.js'; import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/ash/common/web_ui_listener_behavior.js'; -import {AuthFactorConfig, AuthFactorConfigInterface, RecoveryFactorEditor, RecoveryFactorEditorInterface} from 'chrome://resources/mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js'; +import {AuthFactorConfig, AuthFactorConfigInterface, PinFactorEditor, PinFactorEditorInterface, RecoveryFactorEditor, RecoveryFactorEditorInterface} from 'chrome://resources/mojo/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-webui.js'; /** * @fileoverview @@ -78,6 +78,13 @@ export const LockStateBehaviorImpl = { */ recoveryFactorEditor: {type: Object, value: RecoveryFactorEditor.getRemote()}, + + /** + * Interface for calls to the ash PinFactorEditor service. May be + * overridden by tests. + * @type {PinFactorEditorInterface} + */ + pinFactorEditor: {type: Object, value: PinFactorEditor.getRemote()}, }, /** @override */ @@ -222,6 +229,13 @@ export class LockStateBehaviorInterface { * @type {RecoveryFactorEditorInterface} */ this.recoveryFactorEditor; + + /** + * Interface for calls to the ash PinFactorEditor service. May be + * overridden by tests. + * @type {PinFactorEditorInterface} + */ + this.pinFactorEditor; } /** diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc b/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc index bb2a44ca6780e..0e2dd83f08d04 100644 --- a/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc +++ b/chrome/browser/ui/webui/settings/ash/os_settings_ui.cc @@ -15,6 +15,7 @@ #include "ash/webui/personalization_app/search/search.mojom.h" #include "ash/webui/personalization_app/search/search_handler.h" #include "base/metrics/histogram_functions.h" +#include "chrome/browser/ash/login/quick_unlock/pin_backend.h" #include "chrome/browser/ash/login/quick_unlock/quick_unlock_factory.h" #include "chrome/browser/ash/web_applications/personalization_app/personalization_app_manager.h" #include "chrome/browser/ash/web_applications/personalization_app/personalization_app_manager_factory.h" @@ -250,6 +251,15 @@ void OSSettingsUI::BindInterface( web_ui()->GetWebContents(), std::move(receiver)); } +void OSSettingsUI::BindInterface( + mojo::PendingReceiver receiver) { + auto* pin_backend = quick_unlock::PinBackend::GetInstance(); + CHECK(pin_backend); + auth::BindToPinFactorEditor(std::move(receiver), + quick_unlock::QuickUnlockFactory::GetDelegate(), + *pin_backend); +} + WEB_UI_CONTROLLER_TYPE_IMPL(OSSettingsUI) } // namespace ash::settings diff --git a/chrome/browser/ui/webui/settings/ash/os_settings_ui.h b/chrome/browser/ui/webui/settings/ash/os_settings_ui.h index 408e646d41521..75a485f5a8037 100644 --- a/chrome/browser/ui/webui/settings/ash/os_settings_ui.h +++ b/chrome/browser/ui/webui/settings/ash/os_settings_ui.h @@ -149,6 +149,8 @@ class OSSettingsUI : public ui::MojoWebUIController { mojo::PendingReceiver receiver); void BindInterface( mojo::PendingReceiver receiver); + void BindInterface( + mojo::PendingReceiver receiver); // Binds to the Jelly dynamic color Mojo void BindInterface( diff --git a/chromeos/ash/services/auth_factor_config/BUILD.gn b/chromeos/ash/services/auth_factor_config/BUILD.gn index 1fc52c5902035..4a51951b265ee 100644 --- a/chromeos/ash/services/auth_factor_config/BUILD.gn +++ b/chromeos/ash/services/auth_factor_config/BUILD.gn @@ -10,9 +10,11 @@ static_library("auth_factor_config") { sources = [ "auth_factor_config.cc", "auth_factor_config.h", + "chrome_browser_delegates.h", "in_process_instances.cc", "in_process_instances.h", - "quick_unlock_storage_delegate.h", + "pin_factor_editor.cc", + "pin_factor_editor.h", "recovery_factor_editor.cc", "recovery_factor_editor.h", ] diff --git a/chromeos/ash/services/auth_factor_config/auth_factor_config.cc b/chromeos/ash/services/auth_factor_config/auth_factor_config.cc index 7fd2876417492..83e82554984e2 100644 --- a/chromeos/ash/services/auth_factor_config/auth_factor_config.cc +++ b/chromeos/ash/services/auth_factor_config/auth_factor_config.cc @@ -88,7 +88,21 @@ void AuthFactorConfig::GetManagementType( : mojom::ManagementType::kNone; std::move(callback).Run(result); - break; + return; + } + case mojom::AuthFactor::kPin: { + const auto* user = ::user_manager::UserManager::Get()->GetPrimaryUser(); + CHECK(user); + const PrefService* prefs = quick_unlock_storage_->GetPrefService(*user); + CHECK(prefs); + + if (prefs->IsManagedPreference(prefs::kQuickUnlockModeAllowlist) || + prefs->IsManagedPreference(prefs::kWebAuthnFactors)) { + std::move(callback).Run(mojom::ManagementType::kUser); + } else { + std::move(callback).Run(mojom::ManagementType::kNone); + } + return; } } } @@ -106,7 +120,37 @@ void AuthFactorConfig::IsEditable(const std::string& auth_token, std::move(callback).Run( prefs->IsUserModifiablePreference(prefs::kRecoveryFactorBehavior)); - break; + return; + } + case mojom::AuthFactor::kPin: { + const auto* user = ::user_manager::UserManager::Get()->GetPrimaryUser(); + CHECK(user); + const PrefService* prefs = quick_unlock_storage_->GetPrefService(*user); + CHECK(prefs); + + // Lists of factors that are allowed for some purpose. + const base::Value::List* pref_lists[] = { + &prefs->GetList(prefs::kQuickUnlockModeAllowlist), + &prefs->GetList(prefs::kWebAuthnFactors), + }; + + // Values in factor lists that match PINs. + const base::Value pref_list_values[] = { + base::Value("all"), + base::Value("PIN"), + }; + + for (const auto* pref_list : pref_lists) { + for (const auto& pref_list_value : pref_list_values) { + if (base::Contains(*pref_list, pref_list_value)) { + std::move(callback).Run(true); + return; + } + } + } + + std::move(callback).Run(false); + return; } } } diff --git a/chromeos/ash/services/auth_factor_config/auth_factor_config.h b/chromeos/ash/services/auth_factor_config/auth_factor_config.h index 5ffb625b0a79c..725357a56c50b 100644 --- a/chromeos/ash/services/auth_factor_config/auth_factor_config.h +++ b/chromeos/ash/services/auth_factor_config/auth_factor_config.h @@ -5,8 +5,8 @@ #ifndef CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_AUTH_FACTOR_CONFIG_H_ #define CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_AUTH_FACTOR_CONFIG_H_ +#include "chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h" #include "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom.h" -#include "chromeos/ash/services/auth_factor_config/quick_unlock_storage_delegate.h" #include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/remote_set.h" diff --git a/chromeos/ash/services/auth_factor_config/quick_unlock_storage_delegate.h b/chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h similarity index 51% rename from chromeos/ash/services/auth_factor_config/quick_unlock_storage_delegate.h rename to chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h index a61546b5d138d..bd65f25e654ef 100644 --- a/chromeos/ash/services/auth_factor_config/quick_unlock_storage_delegate.h +++ b/chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h @@ -1,12 +1,13 @@ -// Copyright 2022 The Chromium Authors +// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_QUICK_UNLOCK_STORAGE_DELEGATE_H_ -#define CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_QUICK_UNLOCK_STORAGE_DELEGATE_H_ +#ifndef CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_CHROME_BROWSER_DELEGATES_H_ +#define CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_CHROME_BROWSER_DELEGATES_H_ #include #include +#include "base/functional/callback.h" #include "chromeos/ash/components/login/auth/public/user_context.h" #include "components/prefs/pref_service.h" #include "components/user_manager/user.h" @@ -29,6 +30,25 @@ class QuickUnlockStorageDelegate { virtual PrefService* GetPrefService(const ::user_manager::User& user) = 0; }; +class PinBackendDelegate { + public: + using BoolCallback = base::OnceCallback; + + PinBackendDelegate() = default; + PinBackendDelegate(const PinBackendDelegate&) = delete; + PinBackendDelegate& operator=(const PinBackendDelegate&) = delete; + virtual ~PinBackendDelegate() = default; + + virtual void Set(const AccountId& account_id, + const std::string& auth_token, + const std::string& pin, + BoolCallback did_set) = 0; + + virtual void Remove(const AccountId& account_id, + const std::string& auth_token, + BoolCallback did_remove) = 0; +}; + } // namespace ash::auth -#endif // CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_QUICK_UNLOCK_STORAGE_DELEGATE_H_ +#endif // CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_CHROME_BROWSER_DELEGATES_H_ diff --git a/chromeos/ash/services/auth_factor_config/in_process_instances.cc b/chromeos/ash/services/auth_factor_config/in_process_instances.cc index 686bdaa7d57e0..6420a3cfbaa4d 100644 --- a/chromeos/ash/services/auth_factor_config/in_process_instances.cc +++ b/chromeos/ash/services/auth_factor_config/in_process_instances.cc @@ -8,6 +8,7 @@ #include "base/no_destructor.h" #include "chromeos/ash/services/auth_factor_config/auth_factor_config.h" +#include "chromeos/ash/services/auth_factor_config/pin_factor_editor.h" #include "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-test-utils.h" #include "chromeos/ash/services/auth_factor_config/recovery_factor_editor.h" @@ -28,6 +29,13 @@ RecoveryFactorEditor& GetRecoveryFactorEditorImpl( return *recovery_factor_editor; } +PinFactorEditor& GetPinFactorEditorImpl(QuickUnlockStorageDelegate& storage, + PinBackendDelegate& pin_backend) { + static base::NoDestructor pin_factor_editor( + &GetAuthFactorConfigImpl(storage), &pin_backend, &storage); + return *pin_factor_editor; +} + } // namespace void BindToAuthFactorConfig( @@ -52,4 +60,12 @@ mojom::RecoveryFactorEditor& GetRecoveryFactorEditor( return GetRecoveryFactorEditorImpl(delegate); } +void BindToPinFactorEditor( + mojo::PendingReceiver receiver, + QuickUnlockStorageDelegate& storage, + PinBackendDelegate& pin_backend) { + GetPinFactorEditorImpl(storage, pin_backend) + .BindReceiver(std::move(receiver)); +} + } // namespace ash::auth diff --git a/chromeos/ash/services/auth_factor_config/in_process_instances.h b/chromeos/ash/services/auth_factor_config/in_process_instances.h index d90fe868d44ba..91ff755d09352 100644 --- a/chromeos/ash/services/auth_factor_config/in_process_instances.h +++ b/chromeos/ash/services/auth_factor_config/in_process_instances.h @@ -5,8 +5,8 @@ #ifndef CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_IN_PROCESS_INSTANCES_H_ #define CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_IN_PROCESS_INSTANCES_H_ +#include "chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h" #include "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom-forward.h" -#include "chromeos/ash/services/auth_factor_config/quick_unlock_storage_delegate.h" #include "chromeos/ash/services/auth_factor_config/recovery_factor_editor.h" #include "mojo/public/cpp/bindings/pending_receiver.h" @@ -32,6 +32,11 @@ void BindToRecoveryFactorEditor( mojom::RecoveryFactorEditor& GetRecoveryFactorEditor( QuickUnlockStorageDelegate&); +void BindToPinFactorEditor( + mojo::PendingReceiver receiver, + QuickUnlockStorageDelegate&, + PinBackendDelegate&); + } // namespace ash::auth #endif // CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_IN_PROCESS_INSTANCES_H_ diff --git a/chromeos/ash/services/auth_factor_config/pin_factor_editor.cc b/chromeos/ash/services/auth_factor_config/pin_factor_editor.cc new file mode 100644 index 0000000000000..373e4b36b483b --- /dev/null +++ b/chromeos/ash/services/auth_factor_config/pin_factor_editor.cc @@ -0,0 +1,81 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromeos/ash/services/auth_factor_config/pin_factor_editor.h" +#include "ash/constants/ash_features.h" +#include "ash/constants/ash_pref_names.h" +#include "chromeos/ash/services/auth_factor_config/auth_factor_config.h" +#include "components/user_manager/known_user.h" +#include "components/user_manager/user_manager.h" + +namespace ash::auth { + +PinFactorEditor::PinFactorEditor(AuthFactorConfig* auth_factor_config, + PinBackendDelegate* pin_backend, + QuickUnlockStorageDelegate* storage) + : auth_factor_config_(auth_factor_config), + pin_backend_(pin_backend), + quick_unlock_storage_(storage) { + CHECK(auth_factor_config_); + CHECK(pin_backend_); + CHECK(quick_unlock_storage_); +} + +PinFactorEditor::~PinFactorEditor() = default; + +void PinFactorEditor::SetPin( + const std::string& auth_token, + const std::string& pin, + base::OnceCallback callback) { + const auto* user = user_manager::UserManager::Get()->GetPrimaryUser(); + CHECK(user); + auto* user_context_ptr = + quick_unlock_storage_->GetUserContext(user, auth_token); + if (user_context_ptr == nullptr) { + LOG(ERROR) << "Invalid auth token"; + std::move(callback).Run(mojom::ConfigureResult::kInvalidTokenError); + return; + } + + pin_backend_->Set( + user->GetAccountId(), auth_token, pin, + base::BindOnce(&PinFactorEditor::OnPinConfigured, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void PinFactorEditor::RemovePin( + const std::string& auth_token, + base::OnceCallback callback) { + const auto* user = user_manager::UserManager::Get()->GetPrimaryUser(); + CHECK(user); + auto* user_context_ptr = + quick_unlock_storage_->GetUserContext(user, auth_token); + if (user_context_ptr == nullptr) { + LOG(ERROR) << "Invalid auth token"; + std::move(callback).Run(mojom::ConfigureResult::kInvalidTokenError); + return; + } + + pin_backend_->Remove( + user->GetAccountId(), auth_token, + base::BindOnce(&PinFactorEditor::OnPinConfigured, + weak_factory_.GetWeakPtr(), std::move(callback))); +} + +void PinFactorEditor::OnPinConfigured( + base::OnceCallback callback, + bool success) { + const mojom::ConfigureResult result = + success ? mojom::ConfigureResult::kSuccess + : mojom::ConfigureResult::kFatalError; + std::move(callback).Run(result); + auth_factor_config_->NotifyFactorObservers(mojom::AuthFactor::kPin); +} + +void PinFactorEditor::BindReceiver( + mojo::PendingReceiver receiver) { + receivers_.Add(this, std::move(receiver)); +} + +} // namespace ash::auth diff --git a/chromeos/ash/services/auth_factor_config/pin_factor_editor.h b/chromeos/ash/services/auth_factor_config/pin_factor_editor.h new file mode 100644 index 0000000000000..733767d6af094 --- /dev/null +++ b/chromeos/ash/services/auth_factor_config/pin_factor_editor.h @@ -0,0 +1,57 @@ +// Copyright 2023 The Chromium Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_PIN_FACTOR_EDITOR_H_ +#define CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_PIN_FACTOR_EDITOR_H_ + +#include "chromeos/ash/components/login/auth/auth_factor_editor.h" +#include "chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h" +#include "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom.h" +#include "mojo/public/cpp/bindings/receiver_set.h" + +namespace ash::auth { + +class AuthFactorConfig; + +// The implementation of the PinFactorEditor service. +// TODO(crbug.com/1327627): This is currently a fake and only flips a boolean +// corresponding to the current state. No changes are sent to cryptohome. +// Clients may use this API only if the CryptohomeRecoverySetup feature flag is +// enabled. +class PinFactorEditor : public mojom::PinFactorEditor { + public: + PinFactorEditor(AuthFactorConfig*, + PinBackendDelegate* pin_backend, + QuickUnlockStorageDelegate* storage); + ~PinFactorEditor() override; + + PinFactorEditor(const PinFactorEditor&) = delete; + PinFactorEditor& operator=(const PinFactorEditor&) = delete; + + void SetPin( + const std::string& auth_token, + const std::string& pin, + base::OnceCallback callback) override; + void RemovePin( + const std::string& auth_token, + base::OnceCallback callback) override; + + void BindReceiver(mojo::PendingReceiver receiver); + + private: + void OnPinConfigured( + base::OnceCallback callback, + bool success); + + raw_ptr auth_factor_config_; + raw_ptr pin_backend_; + raw_ptr quick_unlock_storage_; + mojo::ReceiverSet receivers_; + AuthFactorEditor auth_factor_editor_; + base::WeakPtrFactory weak_factory_{this}; +}; + +} // namespace ash::auth + +#endif // CHROMEOS_ASH_SERVICES_AUTH_FACTOR_CONFIG_PIN_FACTOR_EDITOR_H_ diff --git a/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom b/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom index b3d816916b033..d29d6a719b0e8 100644 --- a/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom +++ b/chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom @@ -21,9 +21,9 @@ module ash.auth.mojom; // An enumeration of all authentication factors. enum AuthFactor { kRecovery, + kPin, // TODO(crbug.com/1327627): Add support for other authentication factors: // kPassword, - // kPin, // kFingerprint, }; @@ -69,21 +69,37 @@ interface AuthFactorConfig { IsEditable(string auth_token, AuthFactor factor) => (bool editable); }; +// Returned from various operations that change ("configure") something about +// an auth factor. +enum ConfigureResult { + // The configuration operation was successful. + kSuccess, + // Returned if the token used to access configuration was invalid. Clients + // should obtain a new token before trying again. + kInvalidTokenError, + // Returned if the client uses the API incorrectly or the backend could not + // process the request. + kFatalError, +}; + // Interface for methods specific to recovery authentication. Served from chrome // ash, intended to be consumed by the following webuis: // * chrome://os-settings // * chrome://oobe interface RecoveryFactorEditor { - // Return code of |Configure|. - enum ConfigureResult { - kSuccess, - kInvalidTokenError, - // Returned if the client uses the API incorrectly, e.g. if the client - // enables recovery even though it is not supported. - kClientError, - }; // Enables or disables recovery authentication. Clients must not attempt to // enable recovery if recovery is not editable. Enabling recovery when it is // already enabled is a no-op and succeeds; similarly for disabling. Configure(string auth_token, bool enabled) => (ConfigureResult result); }; + +// Interface for methods specific to pin authentication. Served from chrome +// ash, intended to be consumed by the following webuis: +// * chrome://os-settings +// * chrome://oobe +interface PinFactorEditor { + // Set the user pin to the desired value. + SetPin(string auth_token, string pin) => (ConfigureResult result); + // Remove the pin factor for the user. + RemovePin(string auth_token) => (ConfigureResult result); +}; diff --git a/chromeos/ash/services/auth_factor_config/recovery_factor_editor.cc b/chromeos/ash/services/auth_factor_config/recovery_factor_editor.cc index dc8a25a32fa63..0e536ec7b346a 100644 --- a/chromeos/ash/services/auth_factor_config/recovery_factor_editor.cc +++ b/chromeos/ash/services/auth_factor_config/recovery_factor_editor.cc @@ -30,7 +30,7 @@ void RecoveryFactorEditor::BindReceiver( void RecoveryFactorEditor::Configure( const std::string& auth_token, bool enabled, - base::OnceCallback callback) { + base::OnceCallback callback) { DCHECK(features::IsCryptohomeRecoverySetupEnabled()); const auto* user = ::user_manager::UserManager::Get()->GetPrimaryUser(); @@ -38,7 +38,7 @@ void RecoveryFactorEditor::Configure( quick_unlock_storage_->GetUserContext(user, auth_token); if (user_context_ptr == nullptr) { LOG(ERROR) << "Invalid auth token"; - std::move(callback).Run(ConfigureResult::kInvalidTokenError); + std::move(callback).Run(mojom::ConfigureResult::kInvalidTokenError); return; } @@ -47,7 +47,7 @@ void RecoveryFactorEditor::Configure( cryptohome::AuthFactorType::kRecovery); if (enabled == currently_enabled) { - std::move(callback).Run(ConfigureResult::kSuccess); + std::move(callback).Run(mojom::ConfigureResult::kSuccess); return; } @@ -67,20 +67,20 @@ void RecoveryFactorEditor::Configure( } void RecoveryFactorEditor::OnRecoveryFactorConfigured( - base::OnceCallback callback, + base::OnceCallback callback, std::unique_ptr context, absl::optional error) { if (error.has_value()) { // Handle expired auth session gracefully. if (error->get_cryptohome_code() == user_data_auth::CRYPTOHOME_INVALID_AUTH_SESSION_TOKEN) { - std::move(callback).Run(ConfigureResult::kInvalidTokenError); + std::move(callback).Run(mojom::ConfigureResult::kInvalidTokenError); return; } LOG(ERROR) << "Configuring recovery factor failed, code " << error->get_cryptohome_code(); - std::move(callback).Run(ConfigureResult::kClientError); + std::move(callback).Run(mojom::ConfigureResult::kFatalError); return; } @@ -91,13 +91,13 @@ void RecoveryFactorEditor::OnRecoveryFactorConfigured( } void RecoveryFactorEditor::OnGetAuthFactorsConfiguration( - base::OnceCallback callback, + base::OnceCallback callback, std::unique_ptr context, absl::optional error) { if (error.has_value()) { LOG(ERROR) << "Refreshing list of configured auth factors failed, code " << error->get_cryptohome_code(); - std::move(callback).Run(ConfigureResult::kClientError); + std::move(callback).Run(mojom::ConfigureResult::kFatalError); return; } @@ -125,7 +125,7 @@ void RecoveryFactorEditor::OnGetAuthFactorsConfiguration( quick_unlock_storage_->SetUserContext(user, std::move(context)); - std::move(callback).Run(ConfigureResult::kSuccess); + std::move(callback).Run(mojom::ConfigureResult::kSuccess); auth_factor_config_->NotifyFactorObservers(mojom::AuthFactor::kRecovery); } diff --git a/chromeos/ash/services/auth_factor_config/recovery_factor_editor.h b/chromeos/ash/services/auth_factor_config/recovery_factor_editor.h index 6576129e464c7..5e6450bf7f5ee 100644 --- a/chromeos/ash/services/auth_factor_config/recovery_factor_editor.h +++ b/chromeos/ash/services/auth_factor_config/recovery_factor_editor.h @@ -7,8 +7,8 @@ #include "chromeos/ash/components/login/auth/auth_factor_editor.h" #include "chromeos/ash/components/login/auth/public/authentication_error.h" +#include "chromeos/ash/services/auth_factor_config/chrome_browser_delegates.h" #include "chromeos/ash/services/auth_factor_config/public/mojom/auth_factor_config.mojom.h" -#include "chromeos/ash/services/auth_factor_config/quick_unlock_storage_delegate.h" #include "mojo/public/cpp/bindings/receiver_set.h" namespace ash::auth { @@ -28,16 +28,16 @@ class RecoveryFactorEditor : public mojom::RecoveryFactorEditor { void Configure(const std::string& auth_token, bool enabled, - base::OnceCallback) override; + base::OnceCallback) override; private: void OnRecoveryFactorConfigured( - base::OnceCallback callback, + base::OnceCallback callback, std::unique_ptr context, absl::optional error); void OnGetAuthFactorsConfiguration( - base::OnceCallback callback, + base::OnceCallback callback, std::unique_ptr context, absl::optional error);