| // 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 "chrome/browser/ash/auth/legacy_fingerprint_engine.h" |
| |
| #include "ash/constants/ash_features.h" |
| #include "ash/constants/ash_pref_names.h" |
| #include "ash/constants/ash_switches.h" |
| #include "base/command_line.h" |
| #include "base/containers/contains.h" |
| #include "base/feature_list.h" |
| #include "base/notreached.h" |
| #include "chrome/browser/ash/login/quick_unlock/quick_unlock_utils.h" |
| #include "chrome/browser/ash/profiles/profile_helper.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chromeos/ash/components/cryptohome/auth_factor.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/authentication_error.h" |
| #include "chromeos/ash/components/login/auth/public/user_context.h" |
| #include "components/prefs/pref_service.h" |
| |
| namespace ash { |
| namespace { |
| |
| const char kFactorsOptionAll[] = "all"; |
| const char kFactorsOptionFingerprint[] = "FINGERPRINT"; |
| |
| bool HasPolicyValue(const PrefService& pref_service, |
| LegacyFingerprintEngine::Purpose purpose, |
| const char* value) { |
| const base::Value::List* factors = nullptr; |
| switch (purpose) { |
| case LegacyFingerprintEngine::Purpose::kUnlock: |
| factors = &pref_service.GetList(prefs::kQuickUnlockModeAllowlist); |
| break; |
| case LegacyFingerprintEngine::Purpose::kWebAuthn: |
| factors = &pref_service.GetList(prefs::kWebAuthnFactors); |
| break; |
| default: |
| return false; |
| } |
| return base::Contains(*factors, base::Value(value)); |
| } |
| |
| // Check if fingerprint is disabled for a specific purpose (so not including |
| // kAny) by reading the policy value. |
| bool IsFingerprintDisabledByPolicySinglePurpose( |
| const PrefService& pref_service, |
| LegacyFingerprintEngine::Purpose purpose) { |
| DCHECK(purpose != LegacyFingerprintEngine::Purpose::kAny); |
| const bool enabled = |
| HasPolicyValue(pref_service, purpose, kFactorsOptionAll) || |
| HasPolicyValue(pref_service, purpose, kFactorsOptionFingerprint); |
| return !enabled; |
| } |
| |
| bool HasRecord(const PrefService& pref_service) { |
| return pref_service.GetInteger(prefs::kQuickUnlockFingerprintRecord) != 0; |
| } |
| |
| } // namespace |
| |
| LegacyFingerprintEngine::LegacyFingerprintEngine(AuthPerformer* auth_performer) |
| : auth_performer_(auth_performer) {} |
| |
| LegacyFingerprintEngine::~LegacyFingerprintEngine() = default; |
| |
| LegacyFingerprintEngine::Purpose |
| LegacyFingerprintEngine::FromQuickUnlockPurpose( |
| quick_unlock::Purpose purpose) const { |
| switch (purpose) { |
| case quick_unlock::Purpose::kAny: |
| return LegacyFingerprintEngine::Purpose::kAny; |
| case quick_unlock::Purpose::kUnlock: |
| return LegacyFingerprintEngine::Purpose::kUnlock; |
| case quick_unlock::Purpose::kWebAuthn: |
| return LegacyFingerprintEngine::Purpose::kWebAuthn; |
| case quick_unlock::Purpose::kNumOfPurposes: |
| NOTREACHED(); |
| } |
| NOTREACHED(); |
| } |
| |
| quick_unlock::Purpose LegacyFingerprintEngine::ToQuickUnlockPurpose( |
| LegacyFingerprintEngine::Purpose purpose) const { |
| switch (purpose) { |
| case LegacyFingerprintEngine::Purpose::kAny: |
| return quick_unlock::Purpose::kAny; |
| case LegacyFingerprintEngine::Purpose::kUnlock: |
| return quick_unlock::Purpose::kUnlock; |
| case LegacyFingerprintEngine::Purpose::kWebAuthn: |
| return quick_unlock::Purpose::kWebAuthn; |
| } |
| NOTREACHED(); |
| } |
| |
| bool LegacyFingerprintEngine::IsFingerprintDisabledByPolicy( |
| const PrefService& pref_service, |
| LegacyFingerprintEngine::Purpose purpose) const { |
| // TODO(b/274087315): Create a TestApi for this class. |
| if (auto* test_api = quick_unlock::TestApi::Get(); |
| test_api && test_api->IsQuickUnlockOverridden()) { |
| return !test_api->IsFingerprintEnabledByPolicy( |
| ToQuickUnlockPurpose(purpose)); |
| } |
| |
| if (purpose == LegacyFingerprintEngine::Purpose::kAny) { |
| return IsFingerprintDisabledByPolicySinglePurpose( |
| pref_service, LegacyFingerprintEngine::Purpose::kUnlock) && |
| IsFingerprintDisabledByPolicySinglePurpose( |
| pref_service, LegacyFingerprintEngine::Purpose::kWebAuthn); |
| } |
| return IsFingerprintDisabledByPolicySinglePurpose(pref_service, purpose); |
| } |
| |
| bool IsFingerprintSupported() { |
| const base::CommandLine* command_line = |
| base::CommandLine::ForCurrentProcess(); |
| return base::FeatureList::IsEnabled(features::kQuickUnlockFingerprint) && |
| command_line->HasSwitch(switches::kFingerprintSensorLocation); |
| } |
| |
| bool LegacyFingerprintEngine::IsFingerprintEnabled( |
| const PrefService& pref_service, |
| LegacyFingerprintEngine::Purpose purpose) const { |
| // TODO(b/274087315): Create a TestApi for this class. |
| if (auto* test_api = quick_unlock::TestApi::Get(); |
| test_api && test_api->IsQuickUnlockOverridden()) { |
| // When we override behavior for test we don't need to check |
| // `IsFingerprintSupported` |
| return !IsFingerprintDisabledByPolicy(pref_service, purpose); |
| } |
| |
| return !IsFingerprintDisabledByPolicy(pref_service, purpose) && |
| IsFingerprintSupported(); |
| } |
| |
| bool LegacyFingerprintEngine::IsFingerprintAvailable( |
| Purpose purpose, |
| const AccountId& account_id) { |
| auto* profile = ProfileHelper::Get()->GetProfileByAccountId(account_id); |
| |
| auto* pref_service = profile->GetPrefs(); |
| |
| if (!pref_service) { |
| return false; |
| } |
| |
| if (profile != ProfileManager::GetPrimaryUserProfile() || |
| IsFingerprintDisabledByPolicy(*pref_service, purpose)) { |
| return false; |
| } |
| |
| return HasRecord(*pref_service); |
| } |
| |
| void LegacyFingerprintEngine::PrepareLegacyFingerprintFactor( |
| std::unique_ptr<UserContext> user_context, |
| AuthOperationCallback callback) { |
| auth_performer_->PrepareAuthFactor( |
| std::move(user_context), cryptohome::AuthFactorType::kLegacyFingerprint, |
| std::move(callback)); |
| } |
| |
| void LegacyFingerprintEngine::TerminateLegacyFingerprintFactor( |
| std::unique_ptr<UserContext> user_context, |
| AuthOperationCallback callback) { |
| auth_performer_->TerminateAuthFactor( |
| std::move(user_context), cryptohome::AuthFactorType::kLegacyFingerprint, |
| std::move(callback)); |
| } |
| |
| } // namespace ash |