1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.biometrics; 18 19 import static android.Manifest.permission.MANAGE_BIOMETRIC; 20 import static android.Manifest.permission.TEST_BIOMETRIC; 21 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL; 22 import static android.adaptiveauth.Flags.FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS; 23 import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE; 24 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_CANCELED; 25 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_SUCCESS; 26 27 import static junit.framework.Assert.assertEquals; 28 29 import static org.junit.Assert.assertThrows; 30 import static org.mockito.ArgumentMatchers.any; 31 import static org.mockito.ArgumentMatchers.anyInt; 32 import static org.mockito.ArgumentMatchers.anyString; 33 import static org.mockito.ArgumentMatchers.eq; 34 import static org.mockito.Mockito.doNothing; 35 import static org.mockito.Mockito.doThrow; 36 import static org.mockito.Mockito.mock; 37 import static org.mockito.Mockito.never; 38 import static org.mockito.Mockito.verify; 39 import static org.mockito.Mockito.when; 40 41 import android.app.AppOpsManager; 42 import android.content.Context; 43 import android.content.pm.PackageManager; 44 import android.content.res.Resources; 45 import android.hardware.biometrics.AuthenticationStateListener; 46 import android.hardware.biometrics.BiometricManager; 47 import android.hardware.biometrics.Flags; 48 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback; 49 import android.hardware.biometrics.IBiometricService; 50 import android.hardware.biometrics.IBiometricServiceReceiver; 51 import android.hardware.biometrics.PromptInfo; 52 import android.hardware.biometrics.fingerprint.SensorProps; 53 import android.hardware.face.FaceSensorConfigurations; 54 import android.hardware.face.FaceSensorPropertiesInternal; 55 import android.hardware.face.IFaceService; 56 import android.hardware.fingerprint.FingerprintSensorConfigurations; 57 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 58 import android.hardware.fingerprint.IFingerprintService; 59 import android.hardware.iris.IIrisService; 60 import android.os.Binder; 61 import android.os.Handler; 62 import android.os.RemoteException; 63 import android.os.UserHandle; 64 import android.os.test.TestLooper; 65 import android.platform.test.annotations.Presubmit; 66 import android.platform.test.flag.junit.CheckFlagsRule; 67 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 68 import android.platform.test.flag.junit.SetFlagsRule; 69 70 import androidx.test.InstrumentationRegistry; 71 import androidx.test.filters.SmallTest; 72 73 import com.android.internal.R; 74 import com.android.server.LocalServices; 75 import com.android.server.companion.virtual.VirtualDeviceManagerInternal; 76 77 import org.junit.Before; 78 import org.junit.Rule; 79 import org.junit.Test; 80 import org.mockito.ArgumentCaptor; 81 import org.mockito.Captor; 82 import org.mockito.Mock; 83 import org.mockito.junit.MockitoJUnit; 84 import org.mockito.junit.MockitoRule; 85 import org.mockito.stubbing.Stubber; 86 87 import java.util.List; 88 89 @Presubmit 90 @SmallTest 91 public class AuthServiceTest { 92 93 private static final String TEST_OP_PACKAGE_NAME = "test_package"; 94 95 private AuthService mAuthService; 96 97 @Rule 98 public MockitoRule mockitorule = MockitoJUnit.rule(); 99 @Rule 100 public final CheckFlagsRule mCheckFlagsRule = 101 DeviceFlagsValueProvider.createCheckFlagsRule(); 102 103 @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 104 105 @Mock 106 private Context mContext; 107 @Mock 108 private Resources mResources; 109 @Mock 110 private PackageManager mPackageManager; 111 @Mock 112 IBiometricServiceReceiver mReceiver; 113 @Mock 114 AuthService.Injector mInjector; 115 @Mock 116 IBiometricService mBiometricService; 117 @Mock 118 IFingerprintService mFingerprintService; 119 @Mock 120 IIrisService mIrisService; 121 @Mock 122 IFaceService mFaceService; 123 @Mock 124 125 AppOpsManager mAppOpsManager; 126 @Mock 127 private VirtualDeviceManagerInternal mVdmInternal; 128 @Mock 129 private BiometricHandlerProvider mBiometricHandlerProvider; 130 @Captor 131 private ArgumentCaptor<List<FingerprintSensorPropertiesInternal>> mFingerprintPropsCaptor; 132 @Captor 133 private ArgumentCaptor<FingerprintSensorConfigurations> mFingerprintSensorConfigurationsCaptor; 134 @Captor 135 private ArgumentCaptor<FaceSensorConfigurations> mFaceSensorConfigurationsCaptor; 136 @Captor 137 private ArgumentCaptor<List<FaceSensorPropertiesInternal>> mFacePropsCaptor; 138 139 private final TestLooper mFingerprintLooper = new TestLooper(); 140 private final TestLooper mFaceLooper = new TestLooper(); 141 142 @Before setUp()143 public void setUp() { 144 // Placeholder test config 145 final String[] config = { 146 "0:2:15", // ID0:Fingerprint:Strong 147 "1:4:15", // ID1:Iris:Strong 148 "2:8:15", // ID2:Face:Strong 149 }; 150 LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class); 151 LocalServices.addService(VirtualDeviceManagerInternal.class, mVdmInternal); 152 153 when(mResources.getIntArray(eq(R.array.config_udfps_sensor_props))).thenReturn(new int[0]); 154 when(mResources.getBoolean(eq(R.bool.config_is_powerbutton_fps))).thenReturn(false); 155 when(mResources.getInteger(eq(R.integer.config_fingerprintMaxTemplatesPerUser))).thenReturn( 156 1); 157 when(mResources.getBoolean(eq(R.bool.config_faceAuthSupportsSelfIllumination))).thenReturn( 158 false); 159 when(mResources.getInteger(eq(R.integer.config_faceMaxTemplatesPerUser))).thenReturn(1); 160 161 when(mContext.getPackageManager()).thenReturn(mPackageManager); 162 when(mContext.getResources()).thenReturn(mResources); 163 when(mInjector.getBiometricService()).thenReturn(mBiometricService); 164 when(mInjector.getConfiguration(any())).thenReturn(config); 165 when(mInjector.getFaceConfiguration(any())).thenReturn(config); 166 when(mInjector.getFingerprintConfiguration(any())).thenReturn(config); 167 when(mInjector.getIrisConfiguration(any())).thenReturn(config); 168 when(mInjector.getFingerprintService()).thenReturn(mFingerprintService); 169 when(mInjector.getFaceService()).thenReturn(mFaceService); 170 when(mInjector.getIrisService()).thenReturn(mIrisService); 171 when(mInjector.getAppOps(any())).thenReturn(mAppOpsManager); 172 when(mInjector.isHidlDisabled(any())).thenReturn(false); 173 when(mInjector.getBiometricHandlerProvider()).thenReturn(mBiometricHandlerProvider); 174 when(mBiometricHandlerProvider.getFingerprintHandler()).thenReturn( 175 new Handler(mFingerprintLooper.getLooper())); 176 when(mBiometricHandlerProvider.getFaceHandler()).thenReturn( 177 new Handler(mFaceLooper.getLooper())); 178 179 setInternalAndTestBiometricPermissions(mContext, false /* hasPermission */); 180 } 181 182 @Test testRegisterNullService_doesNotRegister()183 public void testRegisterNullService_doesNotRegister() throws Exception { 184 setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); 185 186 // Config contains Fingerprint, Iris, Face, but services are all null 187 188 when(mInjector.getFingerprintService()).thenReturn(null); 189 when(mInjector.getFaceService()).thenReturn(null); 190 when(mInjector.getIrisService()).thenReturn(null); 191 192 mAuthService = new AuthService(mContext, mInjector); 193 mAuthService.onStart(); 194 195 verify(mBiometricService, never()).registerAuthenticator( 196 anyInt(), 197 anyInt(), 198 anyInt(), 199 any()); 200 } 201 202 @Test testRegisterAuthenticator_registerAuthenticators()203 public void testRegisterAuthenticator_registerAuthenticators() throws RemoteException { 204 final int fingerprintId = 0; 205 final int fingerprintStrength = 15; 206 207 final int faceId = 1; 208 final int faceStrength = 4095; 209 210 final String[] config = { 211 // ID0:Fingerprint:Strong 212 String.format("%d:2:%d", fingerprintId, fingerprintStrength), 213 // ID2:Face:Convenience 214 String.format("%d:8:%d", faceId, faceStrength) 215 }; 216 217 when(mInjector.getFingerprintConfiguration(any())).thenReturn(config); 218 when(mInjector.getFaceConfiguration(any())).thenReturn(config); 219 when(mInjector.getFingerprintAidlInstances()).thenReturn(new String[]{}); 220 when(mInjector.getFaceAidlInstances()).thenReturn(new String[]{}); 221 222 mAuthService = new AuthService(mContext, mInjector); 223 mAuthService.onStart(); 224 225 mFingerprintLooper.dispatchAll(); 226 mFaceLooper.dispatchAll(); 227 228 verify(mFingerprintService).registerAuthenticators( 229 mFingerprintSensorConfigurationsCaptor.capture()); 230 231 final SensorProps[] fingerprintProp = mFingerprintSensorConfigurationsCaptor.getValue() 232 .getSensorPropForInstance("defaultHIDL"); 233 234 assertEquals(fingerprintProp[0].commonProps.sensorId, fingerprintId); 235 assertEquals(fingerprintProp[0].commonProps.sensorStrength, 236 Utils.authenticatorStrengthToPropertyStrength(fingerprintStrength)); 237 238 verify(mFaceService).registerAuthenticators(mFaceSensorConfigurationsCaptor.capture()); 239 240 final android.hardware.biometrics.face.SensorProps[] faceProp = 241 mFaceSensorConfigurationsCaptor.getValue() 242 .getSensorPropForInstance("defaultHIDL"); 243 244 assertEquals(faceProp[0].commonProps.sensorId, faceId); 245 assertEquals(faceProp[0].commonProps.sensorStrength, 246 Utils.authenticatorStrengthToPropertyStrength(faceStrength)); 247 } 248 249 // TODO(b/141025588): Check that an exception is thrown when the userId != callingUserId 250 @Test testAuthenticate_appOpsOk_callsBiometricServiceAuthenticate()251 public void testAuthenticate_appOpsOk_callsBiometricServiceAuthenticate() throws Exception { 252 when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_USE_BIOMETRIC), anyInt(), any(), any(), 253 any())).thenReturn(AppOpsManager.MODE_ALLOWED); 254 mAuthService = new AuthService(mContext, mInjector); 255 mAuthService.onStart(); 256 257 final Binder token = new Binder(); 258 final PromptInfo promptInfo = new PromptInfo(); 259 final long sessionId = 0; 260 final int userId = 0; 261 262 mAuthService.mImpl.authenticate( 263 token, 264 sessionId, 265 userId, 266 mReceiver, 267 TEST_OP_PACKAGE_NAME, 268 promptInfo); 269 waitForIdle(); 270 verify(mBiometricService).authenticate( 271 eq(token), 272 eq(sessionId), 273 eq(userId), 274 eq(mReceiver), 275 eq(TEST_OP_PACKAGE_NAME), 276 eq(promptInfo)); 277 } 278 279 @Test testAuthenticate_appOpsDenied_doesNotCallBiometricService()280 public void testAuthenticate_appOpsDenied_doesNotCallBiometricService() throws Exception { 281 when(mAppOpsManager.noteOp(eq(AppOpsManager.OP_USE_BIOMETRIC), anyInt(), any(), any(), 282 any())).thenReturn(AppOpsManager.MODE_ERRORED); 283 mAuthService = new AuthService(mContext, mInjector); 284 mAuthService.onStart(); 285 286 final Binder token = new Binder(); 287 final PromptInfo promptInfo = new PromptInfo(); 288 final long sessionId = 0; 289 final int userId = 0; 290 291 mAuthService.mImpl.authenticate( 292 token, 293 sessionId, 294 userId, 295 mReceiver, 296 TEST_OP_PACKAGE_NAME, 297 promptInfo); 298 waitForIdle(); 299 verify(mBiometricService, never()).authenticate( 300 eq(token), 301 eq(sessionId), 302 eq(userId), 303 eq(mReceiver), 304 eq(TEST_OP_PACKAGE_NAME), 305 eq(promptInfo)); 306 verify(mReceiver).onError(eq(TYPE_NONE), eq(BIOMETRIC_ERROR_CANCELED), anyInt()); 307 } 308 309 @Test testAuthenticate_missingRequiredParam()310 public void testAuthenticate_missingRequiredParam() throws Exception { 311 mAuthService = new AuthService(mContext, mInjector); 312 mAuthService.onStart(); 313 314 final PromptInfo promptInfo = new PromptInfo(); 315 final long sessionId = 0; 316 final int userId = 0; 317 318 mAuthService.mImpl.authenticate( 319 null /* token */, 320 sessionId, 321 userId, 322 mReceiver, 323 TEST_OP_PACKAGE_NAME, 324 promptInfo); 325 waitForIdle(); 326 verify(mReceiver).onError(eq(TYPE_NONE), eq(BIOMETRIC_ERROR_CANCELED), anyInt()); 327 } 328 329 @Test testAuthenticate_noVdmInternalService_noCrash()330 public void testAuthenticate_noVdmInternalService_noCrash() throws Exception { 331 LocalServices.removeServiceForTest(VirtualDeviceManagerInternal.class); 332 mAuthService = new AuthService(mContext, mInjector); 333 mAuthService.onStart(); 334 335 final Binder token = new Binder(); 336 337 // This should not crash 338 mAuthService.mImpl.authenticate( 339 token, 340 0, /* sessionId */ 341 0, /* userId */ 342 mReceiver, 343 TEST_OP_PACKAGE_NAME, 344 new PromptInfo()); 345 waitForIdle(); 346 } 347 348 @Test testAuthenticate_callsVirtualDeviceManagerOnAuthenticationPrompt()349 public void testAuthenticate_callsVirtualDeviceManagerOnAuthenticationPrompt() 350 throws Exception { 351 mAuthService = new AuthService(mContext, mInjector); 352 mAuthService.onStart(); 353 354 final Binder token = new Binder(); 355 356 mAuthService.mImpl.authenticate( 357 token, 358 0, /* sessionId */ 359 0, /* userId */ 360 mReceiver, 361 TEST_OP_PACKAGE_NAME, 362 new PromptInfo()); 363 waitForIdle(); 364 365 ArgumentCaptor<Integer> uidCaptor = ArgumentCaptor.forClass(Integer.class); 366 verify(mVdmInternal).onAuthenticationPrompt(uidCaptor.capture()); 367 assertEquals((int) (uidCaptor.getValue()), Binder.getCallingUid()); 368 } 369 370 @Test testAuthenticate_throwsWhenUsingTestApis()371 public void testAuthenticate_throwsWhenUsingTestApis() { 372 final PromptInfo promptInfo = mock(PromptInfo.class); 373 when(promptInfo.requiresInternalPermission()).thenReturn(false); 374 when(promptInfo.requiresTestOrInternalPermission()).thenReturn(true); 375 376 testAuthenticate_throwsSecurityException(promptInfo); 377 } 378 379 @Test testAuthenticate_throwsWhenUsingPrivateApis()380 public void testAuthenticate_throwsWhenUsingPrivateApis() { 381 final PromptInfo promptInfo = mock(PromptInfo.class); 382 when(promptInfo.requiresInternalPermission()).thenReturn(true); 383 when(promptInfo.requiresTestOrInternalPermission()).thenReturn(false); 384 385 testAuthenticate_throwsSecurityException(promptInfo); 386 } 387 388 @Test testAuthenticate_throwsWhenUsingAdvancedApis()389 public void testAuthenticate_throwsWhenUsingAdvancedApis() { 390 final PromptInfo promptInfo = mock(PromptInfo.class); 391 when(promptInfo.requiresAdvancedPermission()).thenReturn(true); 392 393 testAuthenticate_throwsSecurityException(promptInfo); 394 } 395 testAuthenticate_throwsSecurityException(PromptInfo promptInfo)396 private void testAuthenticate_throwsSecurityException(PromptInfo promptInfo) { 397 mAuthService = new AuthService(mContext, mInjector); 398 mAuthService.onStart(); 399 400 assertThrows(SecurityException.class, () -> { 401 mAuthService.mImpl.authenticate( 402 null /* token */, 403 10 /* sessionId */, 404 2 /* userId */, 405 mReceiver, 406 TEST_OP_PACKAGE_NAME, 407 promptInfo); 408 waitForIdle(); 409 }); 410 } 411 412 @Test testCanAuthenticate_callsBiometricServiceCanAuthenticate()413 public void testCanAuthenticate_callsBiometricServiceCanAuthenticate() throws Exception { 414 mAuthService = new AuthService(mContext, mInjector); 415 mAuthService.onStart(); 416 417 final int userId = 0; 418 final int expectedResult = BIOMETRIC_SUCCESS; 419 final int authenticators = 0; 420 when(mBiometricService.canAuthenticate(anyString(), anyInt(), anyInt(), anyInt())) 421 .thenReturn(expectedResult); 422 423 final int result = mAuthService.mImpl 424 .canAuthenticate(TEST_OP_PACKAGE_NAME, userId, authenticators); 425 426 assertEquals(expectedResult, result); 427 waitForIdle(); 428 verify(mBiometricService).canAuthenticate( 429 eq(TEST_OP_PACKAGE_NAME), 430 eq(userId), 431 eq(UserHandle.getCallingUserId()), 432 eq(authenticators)); 433 } 434 435 @Test testHasEnrolledBiometrics_callsBiometricServiceHasEnrolledBiometrics()436 public void testHasEnrolledBiometrics_callsBiometricServiceHasEnrolledBiometrics() 437 throws Exception { 438 setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); 439 440 mAuthService = new AuthService(mContext, mInjector); 441 mAuthService.onStart(); 442 443 final int userId = 0; 444 final boolean expectedResult = true; 445 when(mBiometricService.hasEnrolledBiometrics(anyInt(), anyString())).thenReturn( 446 expectedResult); 447 448 final boolean result = mAuthService.mImpl.hasEnrolledBiometrics(userId, 449 TEST_OP_PACKAGE_NAME); 450 451 assertEquals(expectedResult, result); 452 waitForIdle(); 453 verify(mBiometricService).hasEnrolledBiometrics( 454 eq(userId), 455 eq(TEST_OP_PACKAGE_NAME)); 456 } 457 458 @Test testRegisterAuthenticationStateListener_callsFingerprintService()459 public void testRegisterAuthenticationStateListener_callsFingerprintService() 460 throws Exception { 461 setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); 462 463 mAuthService = new AuthService(mContext, mInjector); 464 mAuthService.onStart(); 465 466 final AuthenticationStateListener listener = mock(AuthenticationStateListener.class); 467 468 mAuthService.mImpl.registerAuthenticationStateListener(listener); 469 470 waitForIdle(); 471 verify(mFingerprintService).registerAuthenticationStateListener( 472 eq(listener)); 473 } 474 475 @Test testRegisterAuthenticationStateListener_callsFaceService()476 public void testRegisterAuthenticationStateListener_callsFaceService() throws Exception { 477 mSetFlagsRule.enableFlags(FLAG_REPORT_BIOMETRIC_AUTH_ATTEMPTS); 478 setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); 479 480 mAuthService = new AuthService(mContext, mInjector); 481 mAuthService.onStart(); 482 483 final AuthenticationStateListener listener = mock(AuthenticationStateListener.class); 484 485 mAuthService.mImpl.registerAuthenticationStateListener(listener); 486 487 waitForIdle(); 488 verify(mFaceService).registerAuthenticationStateListener(eq(listener)); 489 } 490 491 @Test testRegisterKeyguardCallback_callsBiometricServiceRegisterKeyguardCallback()492 public void testRegisterKeyguardCallback_callsBiometricServiceRegisterKeyguardCallback() 493 throws Exception { 494 setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); 495 496 mAuthService = new AuthService(mContext, mInjector); 497 mAuthService.onStart(); 498 499 final IBiometricEnabledOnKeyguardCallback callback = 500 new IBiometricEnabledOnKeyguardCallback.Default(); 501 502 mAuthService.mImpl.registerEnabledOnKeyguardCallback(callback); 503 504 waitForIdle(); 505 verify(mBiometricService).registerEnabledOnKeyguardCallback( 506 eq(callback)); 507 } 508 509 @Test(expected = UnsupportedOperationException.class) testGetLastAuthenticationTime_flaggedOff_throwsUnsupportedOperationException()510 public void testGetLastAuthenticationTime_flaggedOff_throwsUnsupportedOperationException() 511 throws Exception { 512 mSetFlagsRule.disableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME); 513 setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); 514 515 mAuthService = new AuthService(mContext, mInjector); 516 mAuthService.onStart(); 517 518 mAuthService.mImpl.getLastAuthenticationTime(0, 519 BiometricManager.Authenticators.BIOMETRIC_STRONG); 520 } 521 522 @Test testGetLastAuthenticationTime_flaggedOn_callsBiometricService()523 public void testGetLastAuthenticationTime_flaggedOn_callsBiometricService() 524 throws Exception { 525 mSetFlagsRule.enableFlags(Flags.FLAG_LAST_AUTHENTICATION_TIME); 526 setInternalAndTestBiometricPermissions(mContext, true /* hasPermission */); 527 528 mAuthService = new AuthService(mContext, mInjector); 529 mAuthService.onStart(); 530 531 final int userId = 0; 532 final int authenticators = BiometricManager.Authenticators.BIOMETRIC_STRONG; 533 534 mAuthService.mImpl.getLastAuthenticationTime(userId, authenticators); 535 536 waitForIdle(); 537 verify(mBiometricService).getLastAuthenticationTime(eq(userId), eq(authenticators)); 538 } 539 setInternalAndTestBiometricPermissions( Context context, boolean hasPermission)540 private static void setInternalAndTestBiometricPermissions( 541 Context context, boolean hasPermission) { 542 for (String p : List.of(TEST_BIOMETRIC, MANAGE_BIOMETRIC, USE_BIOMETRIC_INTERNAL)) { 543 when(context.checkCallingPermission(eq(p))).thenReturn(hasPermission 544 ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED); 545 when(context.checkCallingOrSelfPermission(eq(p))).thenReturn(hasPermission 546 ? PackageManager.PERMISSION_GRANTED : PackageManager.PERMISSION_DENIED); 547 final Stubber doPermCheck = 548 hasPermission ? doNothing() : doThrow(SecurityException.class); 549 doPermCheck.when(context).enforceCallingPermission(eq(p), any()); 550 doPermCheck.when(context).enforceCallingOrSelfPermission(eq(p), any()); 551 } 552 } 553 waitForIdle()554 private static void waitForIdle() { 555 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 556 } 557 } 558