diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java index bcee2c1bd9eaf..34c73d2e2e4e7 100644 --- a/services/core/java/com/android/server/LockSettingsService.java +++ b/services/core/java/com/android/server/LockSettingsService.java @@ -146,6 +146,7 @@ public class LockSettingsService extends ILockSettings.Stub { private final LockPatternUtils mLockPatternUtils; private final NotificationManager mNotificationManager; private final UserManager mUserManager; + private final DevicePolicyManager mDevicePolicyManager; private final IActivityManager mActivityManager; private final KeyStore mKeyStore; @@ -333,6 +334,10 @@ public class LockSettingsService extends ILockSettings.Stub { return (UserManager) mContext.getSystemService(Context.USER_SERVICE); } + public DevicePolicyManager getDevicePolicyManager() { + return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + } + public KeyStore getKeyStore() { return KeyStore.getInstance(); } @@ -380,6 +385,7 @@ public class LockSettingsService extends ILockSettings.Stub { mStorage = injector.getStorage(); mNotificationManager = injector.getNotificationManager(); mUserManager = injector.getUserManager(); + mDevicePolicyManager = injector.getDevicePolicyManager(); mStrongAuthTracker = injector.getStrongAuthTracker(); mStrongAuthTracker.register(mStrongAuth); @@ -2015,14 +2021,17 @@ public class LockSettingsService extends ILockSettings.Stub { } } long handle = getSyntheticPasswordHandleLocked(userId); - AuthenticationToken auth = mSpManager.unwrapPasswordBasedSyntheticPassword( - getGateKeeperService(), handle, savedCredential, userId).authToken; + AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword( + getGateKeeperService(), handle, savedCredential, userId); + VerifyCredentialResponse response = authResult.gkResponse; + AuthenticationToken auth = authResult.authToken; if (auth != null) { // We are performing a trusted credential change i.e. a correct existing credential // is provided setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, userId); mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); - } else { + } else if (response != null + && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){ // We are performing an untrusted credential change i.e. by DevicePolicyManager. // So provision a new SP and SID. This would invalidate existing escrow tokens. // Still support this for now but this flow will be removed in the next release. @@ -2031,6 +2040,10 @@ public class LockSettingsService extends ILockSettings.Stub { initializeSyntheticPasswordLocked(null, credential, credentialType, userId); synchronizeUnifiedWorkChallengeForProfiles(userId, null); mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId); + } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ { + Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " + + (response != null ? "rate limit exceeded" : "failed")); + return; } notifyActivePasswordMetricsAvailable(credential, userId); @@ -2042,7 +2055,7 @@ public class LockSettingsService extends ILockSettings.Stub { if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId); synchronized (mSpManager) { enableSyntheticPasswordLocked(); - // Migrate to synthetic password based credentials if ther user has no password, + // Migrate to synthetic password based credentials if the user has no password, // the token can then be activated immediately. AuthenticationToken auth = null; if (!isUserSecure(userId)) { @@ -2201,22 +2214,20 @@ public class LockSettingsService extends ILockSettings.Stub { Slog.i(TAG, "Managed profile can have escrow token"); return; } - DevicePolicyManager dpm = (DevicePolicyManager) - mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); // Devices with Device Owner should have escrow enabled on all users. - if (dpm.getDeviceOwnerComponentOnAnyUser() != null) { + if (mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser() != null) { Slog.i(TAG, "Corp-owned device can have escrow token"); return; } // We could also have a profile owner on the given (non-managed) user for unicorn cases - if (dpm.getProfileOwnerAsUser(userId) != null) { + if (mDevicePolicyManager.getProfileOwnerAsUser(userId) != null) { Slog.i(TAG, "User with profile owner can have escrow token"); return; } // If the device is yet to be provisioned (still in SUW), there is still // a chance that Device Owner will be set on the device later, so postpone // disabling escrow token for now. - if (!dpm.isDeviceProvisioned()) { + if (!mDevicePolicyManager.isDeviceProvisioned()) { Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned"); return; } diff --git a/services/core/java/com/android/server/SyntheticPasswordManager.java b/services/core/java/com/android/server/SyntheticPasswordManager.java index 62678801a9a2b..2517613c03e03 100644 --- a/services/core/java/com/android/server/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/SyntheticPasswordManager.java @@ -526,7 +526,7 @@ public class SyntheticPasswordManager { * RESPONSE_OK, since user authentication failures are detected earlier when trying to * decrypt SP. */ - public VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper, + public @Nullable VerifyCredentialResponse verifyChallenge(IGateKeeperService gatekeeper, @NonNull AuthenticationToken auth, long challenge, int userId) throws RemoteException { byte[] spHandle = loadSyntheticPasswordHandle(userId); if (spHandle == null) { diff --git a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java index c6265bc768f3b..a2a4019c93ade 100644 --- a/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/BaseLockSettingsServiceTests.java @@ -25,6 +25,8 @@ import static org.mockito.Mockito.when; import android.app.IActivityManager; import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; import android.content.pm.UserInfo; import android.database.sqlite.SQLiteDatabase; @@ -76,7 +78,7 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { UserManager mUserManager; MockStorageManager mStorageManager; IActivityManager mActivityManager; - + DevicePolicyManager mDevicePolicyManager; KeyStore mKeyStore; @Override @@ -89,7 +91,9 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { mUserManager = mock(UserManager.class); mStorageManager = new MockStorageManager(); mActivityManager = mock(IActivityManager.class); - mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager); + mDevicePolicyManager = mock(DevicePolicyManager.class); + mContext = new MockLockSettingsContext(getContext(), mUserManager, mNotificationManager, + mDevicePolicyManager); mStorage = new LockSettingsStorageTestable(mContext, new File(getContext().getFilesDir(), "locksettings")); File storageDir = mStorage.mStorageDir; @@ -122,6 +126,10 @@ public class BaseLockSettingsServiceTests extends AndroidTestCase { }); when(mLockPatternUtils.getLockSettings()).thenReturn(mService); + + // Adding a fake Device Owner app which will enable escrow token support in LSS. + when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn( + new ComponentName("com.dummy.package", ".FakeDeviceOwner")); } @Override diff --git a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java index c68fbdc0a2ac8..46779048e9dbb 100644 --- a/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java +++ b/services/tests/servicestests/src/com/android/server/LockSettingsStorageTests.java @@ -21,6 +21,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.ContextWrapper; import android.content.pm.UserInfo; @@ -68,7 +69,7 @@ public class LockSettingsStorageTests extends AndroidTestCase { when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0)); MockLockSettingsContext context = new MockLockSettingsContext(getContext(), mockUserManager, - mock(NotificationManager.class)); + mock(NotificationManager.class), mock(DevicePolicyManager.class)); mStorage = new LockSettingsStorageTestable(context, new File(getContext().getFilesDir(), "locksettings")); mStorage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() { diff --git a/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java index b63936fdffdff..8bceed45ab5f4 100644 --- a/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java +++ b/services/tests/servicestests/src/com/android/server/MockLockSettingsContext.java @@ -17,6 +17,7 @@ package com.android.server; import android.app.NotificationManager; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.ContextWrapper; import android.os.UserManager; @@ -25,12 +26,14 @@ public class MockLockSettingsContext extends ContextWrapper { private UserManager mUserManager; private NotificationManager mNotificationManager; + private DevicePolicyManager mDevicePolicyManager; public MockLockSettingsContext(Context base, UserManager userManager, - NotificationManager notificationManager) { + NotificationManager notificationManager, DevicePolicyManager devicePolicyManager) { super(base); mUserManager = userManager; mNotificationManager = notificationManager; + mDevicePolicyManager = devicePolicyManager; } @Override @@ -39,6 +42,8 @@ public class MockLockSettingsContext extends ContextWrapper { return mUserManager; } else if (NOTIFICATION_SERVICE.equals(name)) { return mNotificationManager; + } else if (DEVICE_POLICY_SERVICE.equals(name)) { + return mDevicePolicyManager; } else { throw new RuntimeException("System service not mocked: " + name); }