Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc43d11a authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Apply Identity Check to all biometric prompt requests" into main

parents 76920fbb fb089450
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -86,3 +86,10 @@ flag {
  description: "This flag is for test API changes related to Identity Check"
  bug: "347123256"
}

flag {
  name: "identity_check_all_surfaces"
  namespace: "biometrics_framework"
  description: "This flag applies Identity Check to all biometric prompt requests"
  bug: "402534668"
}
+5 −15
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ import android.os.UserManager;
import android.util.Pair;
import android.util.Slog;

import com.android.internal.R;
import com.android.server.biometrics.sensors.LockoutTracker;

import java.lang.annotation.Retention;
@@ -128,7 +127,7 @@ class PreAuthInfo {
        promptInfo.setDeviceCredentialAllowed(Utils.isCredentialRequested(promptInfo));
        final boolean isMandatoryBiometricsAuthentication =
                updateAuthenticatorsIfIdentityCheckIsActive(promptInfo, effectiveUserId,
                        trustManager, settingObserver, context);
                        trustManager, settingObserver);

        final boolean biometricRequested = Utils.isBiometricRequested(promptInfo);
        final int requestedStrength = Utils.getPublicBiometricStrength(promptInfo);
@@ -184,24 +183,18 @@ class PreAuthInfo {

    private static boolean updateAuthenticatorsIfIdentityCheckIsActive(PromptInfo promptInfo,
            int effectiveUserId, ITrustManager trustManager,
            BiometricService.SettingObserver settingObserver, Context context) {
            BiometricService.SettingObserver settingObserver) {
        if (!Flags.identityCheckTestApi() && dropCredentialFallback(promptInfo.getAuthenticators(),
                settingObserver.getMandatoryBiometricsEnabledAndRequirementsSatisfiedForUser(
                        effectiveUserId), trustManager)) {
            promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
            promptInfo.setIdentityCheckActive(true);
            if (promptInfo.getNegativeButtonText() == null) {
                promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
            }
            return true;
        } else if (Flags.identityCheckTestApi()
                && (promptInfo.getAuthenticators() & BiometricManager.Authenticators.IDENTITY_CHECK)
                != 0 && settingObserver.isIdentityCheckActive(effectiveUserId)) {
                && Utils.shouldApplyIdentityCheck(promptInfo.getAuthenticators())
                && settingObserver.isIdentityCheckActive(effectiveUserId)) {
            promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG);
            promptInfo.setIdentityCheckActive(true);
            if (promptInfo.getNegativeButtonText() == null) {
                promptInfo.setNegativeButtonText(context.getString(R.string.cancel));
            }
            return true;
        }

@@ -210,10 +203,7 @@ class PreAuthInfo {

    private static boolean dropCredentialFallback(int authenticators,
            boolean isMandatoryBiometricsEnabled, ITrustManager trustManager) {
        final boolean isMandatoryBiometricsRequested =
                (authenticators & BiometricManager.Authenticators.IDENTITY_CHECK)
                        == BiometricManager.Authenticators.IDENTITY_CHECK;
        if (isMandatoryBiometricsEnabled && isMandatoryBiometricsRequested) {
        if (isMandatoryBiometricsEnabled && Utils.shouldApplyIdentityCheck(authenticators)) {
            try {
                final boolean isInSignificantPlace = trustManager.isInSignificantPlace();
                return !isInSignificantPlace;
+28 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricPrompt.AuthenticationResultType;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.IBiometricService;
import android.hardware.biometrics.PromptInfo;
import android.hardware.biometrics.SensorProperties;
@@ -149,6 +150,33 @@ public class Utils {
        return (authenticators & Authenticators.IDENTITY_CHECK) != 0;
    }

    /**
     *
     * @param authenticators composed of one or more values from {@link Authenticators}
     * @return true if Identity Check requirements should be applied depending on the authenticators
     */
    static boolean shouldApplyIdentityCheck(@Authenticators.Types int authenticators) {
        final boolean isIdentityCheckAllSurfacesEnabled =
                Flags.identityCheckAllSurfaces() && Flags.bpFallbackOptions();
        final boolean isMandatoryOrBiometricRequested =
                isMandatoryBiometricsRequested(authenticators)
                        || isBiometricRequested(authenticators);
        final boolean isOnlyStrongBiometricRequested =
                isOnlyStrongBiometricRequested(authenticators);

        if (isIdentityCheckAllSurfacesEnabled) {
            return isMandatoryOrBiometricRequested && !isOnlyStrongBiometricRequested;
        }

        return isMandatoryBiometricsRequested(authenticators);
    }

    private static boolean isOnlyStrongBiometricRequested(
            @Authenticators.Types int authenticators) {
        return getPublicBiometricStrength(authenticators) == Authenticators.BIOMETRIC_STRONG
                && !isCredentialRequested(authenticators);
    }

    /**
     * @param promptInfo should be first processed by
     * {@link #combineAuthenticatorBundles(PromptInfo)}
+78 −14
Original line number Diff line number Diff line
@@ -208,7 +208,7 @@ public class PreAuthInfoTest {

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IDENTITY_CHECK_TEST_API)
    public void testMandatoryBiometricsStatus_whenAllRequirementsSatisfiedAndSensorAvailable()
    public void testMandatoryBiometricsStatus_whenAllRequirementsSatisfiedAndSensorAvailable_identityCheckAuthenticator()
            throws Exception {
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(true);

@@ -225,55 +225,102 @@ public class PreAuthInfoTest {

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IDENTITY_CHECK_TEST_API)
    public void testMandatoryBiometricsStatus_whenAllRequirementsSatisfiedAndSensorUnavailable()
    public void testMandatoryBiometricsAndStrongBiometricsStatus_whenRequirementsNotSatisfied_identityCheckAuthenticator()
            throws Exception {
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(true);
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(false);

        final BiometricSensor sensor = getFaceSensor();
        final PromptInfo promptInfo = new PromptInfo();
        promptInfo.setAuthenticators(BiometricManager.Authenticators.IDENTITY_CHECK
                | BiometricManager.Authenticators.BIOMETRIC_STRONG);
        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
                mSettingObserver, List.of(sensor), USER_ID, promptInfo, TEST_PACKAGE_NAME,
                false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
                mUserManager);

        assertThat(preAuthInfo.eligibleSensors).hasSize(1);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IDENTITY_CHECK_TEST_API)
    public void testMandatoryBiometricsStatus_whenRequirementsNotSatisfiedAndSensorAvailable_identityCheckAuthenticator()
            throws Exception {
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(false);

        final BiometricSensor sensor = getFaceSensor();
        final PromptInfo promptInfo = new PromptInfo();
        promptInfo.setAuthenticators(BiometricManager.Authenticators.IDENTITY_CHECK);
        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
                mSettingObserver, List.of(), USER_ID, promptInfo, TEST_PACKAGE_NAME,
                mSettingObserver, List.of(sensor), USER_ID, promptInfo, TEST_PACKAGE_NAME,
                false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
                mUserManager);

        assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo(
                BiometricManager.BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE);
        assertThat(preAuthInfo.eligibleSensors).hasSize(0);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IDENTITY_CHECK_TEST_API)
    public void testMandatoryBiometricsAndStrongBiometricsStatus_whenRequirementsNotSatisfied()
    @RequiresFlagsEnabled({Flags.FLAG_IDENTITY_CHECK_TEST_API,
            Flags.FLAG_IDENTITY_CHECK_ALL_SURFACES, Flags.FLAG_BP_FALLBACK_OPTIONS})
    public void testIdentityCheckStatus_whenAllRequirementsSatisfiedAndSensorAvailable_biometricStrongAndDeviceCredential()
            throws Exception {
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(true);

        final BiometricSensor sensor = getFaceSensor();
        final PromptInfo promptInfo = new PromptInfo();
        promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG
                | BiometricManager.Authenticators.DEVICE_CREDENTIAL);
        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
                mSettingObserver, List.of(sensor), USER_ID, promptInfo, TEST_PACKAGE_NAME,
                false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
                mUserManager);

        assertThat(promptInfo.isDeviceCredentialAllowed()).isTrue();
        assertThat(preAuthInfo.getIsMandatoryBiometricsAuthentication()).isTrue();
        assertThat(preAuthInfo.eligibleSensors).hasSize(1);
    }

    @Test
    @RequiresFlagsEnabled({Flags.FLAG_IDENTITY_CHECK_TEST_API,
            Flags.FLAG_IDENTITY_CHECK_ALL_SURFACES, Flags.FLAG_BP_FALLBACK_OPTIONS})
    public void testIdentityCheckStatus_whenRequirementsNotSatisfied_biometricStrongAndDeviceCredential()
            throws Exception {
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(false);

        final BiometricSensor sensor = getFaceSensor();
        final PromptInfo promptInfo = new PromptInfo();
        promptInfo.setAuthenticators(BiometricManager.Authenticators.IDENTITY_CHECK
                | BiometricManager.Authenticators.BIOMETRIC_STRONG);
        promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG
                | BiometricManager.Authenticators.DEVICE_CREDENTIAL);
        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
                mSettingObserver, List.of(sensor), USER_ID, promptInfo, TEST_PACKAGE_NAME,
                false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
                mUserManager);

        assertThat(promptInfo.isDeviceCredentialAllowed()).isTrue();
        assertThat(preAuthInfo.getIsMandatoryBiometricsAuthentication()).isFalse();
        assertThat(preAuthInfo.eligibleSensors).hasSize(1);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IDENTITY_CHECK_TEST_API)
    public void testMandatoryBiometricsStatus_whenRequirementsNotSatisfiedAndSensorAvailable()
    @RequiresFlagsEnabled({Flags.FLAG_IDENTITY_CHECK_TEST_API,
            Flags.FLAG_IDENTITY_CHECK_ALL_SURFACES, Flags.FLAG_BP_FALLBACK_OPTIONS})
    public void testIdentityCheckStatus_whenRequirementsNotSatisfiedAndSensorAvailable_biometricStrongAndDeviceCredential()
            throws Exception {
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(false);

        final BiometricSensor sensor = getFaceSensor();
        final PromptInfo promptInfo = new PromptInfo();
        promptInfo.setAuthenticators(BiometricManager.Authenticators.IDENTITY_CHECK);
        promptInfo.setAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG
                | BiometricManager.Authenticators.DEVICE_CREDENTIAL);
        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
                mSettingObserver, List.of(sensor), USER_ID, promptInfo, TEST_PACKAGE_NAME,
                false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
                mUserManager);

        assertThat(preAuthInfo.getCanAuthenticateResult()).isEqualTo(
                BiometricManager.BIOMETRIC_ERROR_IDENTITY_CHECK_NOT_ACTIVE);
        assertThat(preAuthInfo.eligibleSensors).hasSize(0);
        assertThat(promptInfo.isDeviceCredentialAllowed()).isTrue();
        assertThat(preAuthInfo.getIsMandatoryBiometricsAuthentication()).isFalse();
        assertThat(preAuthInfo.eligibleSensors).hasSize(1);
    }

    @Test
@@ -315,6 +362,23 @@ public class PreAuthInfoTest {
        assertThat(promptInfo.getNegativeButtonText()).isEqualTo(TEST_PACKAGE_NAME);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_IDENTITY_CHECK_TEST_API)
    public void testMandatoryBiometricsNegativeButtonText_whenNotSet()
            throws Exception {
        when(mSettingObserver.isIdentityCheckActive(anyInt())).thenReturn(true);

        final BiometricSensor sensor = getFaceSensor();
        final PromptInfo promptInfo = new PromptInfo();
        promptInfo.setAuthenticators(BiometricManager.Authenticators.IDENTITY_CHECK);
        final PreAuthInfo preAuthInfo = PreAuthInfo.create(mTrustManager, mDevicePolicyManager,
                mSettingObserver, List.of(sensor), USER_ID, promptInfo, TEST_PACKAGE_NAME,
                false /* checkDevicePolicyManager */, mContext, mBiometricCameraManager,
                mUserManager);
        assertThat(preAuthInfo.getIsMandatoryBiometricsAuthentication()).isTrue();
        assertThat(promptInfo.getNegativeButtonText()).isEqualTo(null);
    }

    @Test
    @RequiresFlagsEnabled(Flags.FLAG_EFFECTIVE_USER_BP)
    public void testCredentialOwnerIdAsUserId() throws Exception {
+33 −0
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.server.biometrics;
import static android.Manifest.permission.SET_BIOMETRIC_DIALOG_ADVANCED;
import static android.hardware.biometrics.BiometricManager.Authenticators;

import static com.google.common.truth.Truth.assertThat;

import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
@@ -34,8 +36,10 @@ import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.Flags;
import android.hardware.biometrics.PromptInfo;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;

@@ -314,4 +318,33 @@ public class UtilsTest {
        // All biometric bits are removed
        assertEquals(0, authenticators & Authenticators.BIOMETRIC_MIN_STRENGTH);
    }

    @Test
    @RequiresFlagsEnabled({Flags.FLAG_IDENTITY_CHECK_ALL_SURFACES, Flags.FLAG_BP_FALLBACK_OPTIONS})
    public void testShouldApplyIdentityCheck_singleAuthenticator_returnsTrue() {
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.IDENTITY_CHECK)).isTrue();
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.BIOMETRIC_WEAK)).isTrue();
    }

    @Test
    @RequiresFlagsEnabled({Flags.FLAG_IDENTITY_CHECK_ALL_SURFACES, Flags.FLAG_BP_FALLBACK_OPTIONS})
    public void testShouldApplyIdentityCheck_combinationAuthenticators_returnsTrue() {
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.IDENTITY_CHECK
                | Authenticators.DEVICE_CREDENTIAL)).isTrue();
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.DEVICE_CREDENTIAL
                | Authenticators.BIOMETRIC_STRONG)).isTrue();
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.BIOMETRIC_WEAK
                | Authenticators.DEVICE_CREDENTIAL)).isTrue();
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.BIOMETRIC_WEAK
                | Authenticators.IDENTITY_CHECK)).isTrue();
    }

    @Test
    @RequiresFlagsEnabled({Flags.FLAG_IDENTITY_CHECK_ALL_SURFACES, Flags.FLAG_BP_FALLBACK_OPTIONS})
    public void testShouldApplyIdentityCheck_returnsFalse() {
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.BIOMETRIC_STRONG
                | Authenticators.IDENTITY_CHECK)).isFalse();
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.BIOMETRIC_STRONG)).isFalse();
        assertThat(Utils.shouldApplyIdentityCheck(Authenticators.DEVICE_CREDENTIAL)).isFalse();
    }
}