Merge changes from topic "frp-fix"
* changes: Fix FRP credential overwritten before it is verified Convert locksettings unit tests to use FakeSettingsProvider
This commit is contained in:
@@ -550,16 +550,6 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
return (BiometricManager) mContext.getSystemService(Context.BIOMETRIC_SERVICE);
|
||||
}
|
||||
|
||||
public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
|
||||
int defaultValue) {
|
||||
return Settings.Global.getInt(contentResolver, keyName, defaultValue);
|
||||
}
|
||||
|
||||
public int settingsSecureGetInt(ContentResolver contentResolver, String keyName,
|
||||
int defaultValue, int userId) {
|
||||
return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId);
|
||||
}
|
||||
|
||||
public java.security.KeyStore getJavaKeyStore() {
|
||||
try {
|
||||
java.security.KeyStore ks = java.security.KeyStore.getInstance(
|
||||
@@ -1027,9 +1017,9 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
private void enforceFrpResolved() {
|
||||
final ContentResolver cr = mContext.getContentResolver();
|
||||
final boolean inSetupWizard = mInjector.settingsSecureGetInt(cr,
|
||||
final boolean inSetupWizard = Settings.Secure.getIntForUser(cr,
|
||||
Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_SYSTEM) == 0;
|
||||
final boolean secureFrp = mInjector.settingsSecureGetInt(cr,
|
||||
final boolean secureFrp = Settings.Secure.getIntForUser(cr,
|
||||
Settings.Secure.SECURE_FRP_MODE, 0, UserHandle.USER_SYSTEM) == 1;
|
||||
if (inSetupWizard && secureFrp) {
|
||||
throw new SecurityException("Cannot change credential in SUW while factory reset"
|
||||
@@ -2155,7 +2145,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
if (credential == null || credential.isNone()) {
|
||||
throw new IllegalArgumentException("Credential can't be null or empty");
|
||||
}
|
||||
if (userId == USER_FRP && mInjector.settingsGlobalGetInt(mContext.getContentResolver(),
|
||||
if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
|
||||
Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
|
||||
return VerifyCredentialResponse.ERROR;
|
||||
@@ -3282,6 +3272,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
for (UserInfo user : users) {
|
||||
if (userOwnsFrpCredential(mContext, user)) {
|
||||
if (!isUserSecure(user.id)) {
|
||||
Slogf.d(TAG, "Clearing FRP credential tied to user %d", user.id);
|
||||
mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
|
||||
0, null);
|
||||
}
|
||||
|
||||
@@ -550,7 +550,7 @@ class LockSettingsStorage {
|
||||
mCache.clear();
|
||||
}
|
||||
|
||||
@Nullable @VisibleForTesting
|
||||
@Nullable
|
||||
PersistentDataBlockManagerInternal getPersistentDataBlockManager() {
|
||||
if (mPersistentDataBlockManagerInternal == null) {
|
||||
mPersistentDataBlockManagerInternal =
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.hardware.weaver.V1_0.WeaverStatus;
|
||||
import android.os.RemoteCallbackList;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.security.GateKeeper;
|
||||
import android.security.Scrypt;
|
||||
import android.service.gatekeeper.GateKeeperResponse;
|
||||
@@ -457,6 +458,11 @@ public class SyntheticPasswordManager {
|
||||
mPasswordSlotManager = passwordSlotManager;
|
||||
}
|
||||
|
||||
private boolean isDeviceProvisioned() {
|
||||
return Settings.Global.getInt(mContext.getContentResolver(),
|
||||
Settings.Global.DEVICE_PROVISIONED, 0) != 0;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected IWeaver getWeaverService() throws RemoteException {
|
||||
try {
|
||||
@@ -770,6 +776,17 @@ public class SyntheticPasswordManager {
|
||||
private int getNextAvailableWeaverSlot() {
|
||||
Set<Integer> usedSlots = getUsedWeaverSlots();
|
||||
usedSlots.addAll(mPasswordSlotManager.getUsedSlots());
|
||||
// If the device is not yet provisioned, then the Weaver slot used by the FRP credential may
|
||||
// be still needed and must not be reused yet. (This *should* instead check "has FRP been
|
||||
// resolved yet?", which would allow reusing the slot a bit earlier. However, the
|
||||
// SECURE_FRP_MODE setting gets set to 1 too late for it to be used here.)
|
||||
if (!isDeviceProvisioned()) {
|
||||
PersistentData persistentData = mStorage.readPersistentDataBlock();
|
||||
if (persistentData != null && persistentData.type == PersistentData.TYPE_SP_WEAVER) {
|
||||
int slot = persistentData.userId; // Note: field name is misleading
|
||||
usedSlots.add(slot);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < mWeaverConfig.slots; i++) {
|
||||
if (!usedSlots.contains(i)) {
|
||||
return i;
|
||||
@@ -814,9 +831,14 @@ public class SyntheticPasswordManager {
|
||||
|
||||
protectorSecret = transformUnderWeaverSecret(stretchedLskf, weaverSecret);
|
||||
} else {
|
||||
// Weaver is unavailable, so make the protector use Gatekeeper to verify the LSKF
|
||||
// instead. However, skip Gatekeeper when the LSKF is empty, since it wouldn't give any
|
||||
// benefit in that case as Gatekeeper isn't expected to provide secure deletion.
|
||||
// Weaver is unavailable, so make the protector use Gatekeeper (GK) to verify the LSKF.
|
||||
//
|
||||
// However, skip GK when the LSKF is empty. There are two reasons for this, one
|
||||
// performance and one correctness. The performance reason is that GK wouldn't give any
|
||||
// benefit with an empty LSKF anyway, since GK isn't expected to provide secure
|
||||
// deletion. The correctness reason is that it is unsafe to enroll a password in the
|
||||
// 'fakeUserId' GK range on an FRP-protected device that is in the setup wizard with FRP
|
||||
// not passed yet, as that may overwrite the enrollment used by the FRP credential.
|
||||
if (!credential.isNone()) {
|
||||
// In case GK enrollment leaves persistent state around (in RPMB), this will nuke
|
||||
// them to prevent them from accumulating and causing problems.
|
||||
@@ -908,12 +930,40 @@ public class SyntheticPasswordManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNoneCredential(PasswordData pwd) {
|
||||
return pwd == null || pwd.credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE;
|
||||
}
|
||||
|
||||
private boolean shouldSynchronizeFrpCredential(@Nullable PasswordData pwd, int userId) {
|
||||
if (mStorage.getPersistentDataBlockManager() == null) {
|
||||
return false;
|
||||
}
|
||||
UserInfo userInfo = mUserManager.getUserInfo(userId);
|
||||
if (!LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)) {
|
||||
return false;
|
||||
}
|
||||
// When initializing the synthetic password of the user that will own the FRP credential,
|
||||
// the FRP data block must not be cleared if the device isn't provisioned yet, since in this
|
||||
// case the old value of the block may still be needed for the FRP authentication step. The
|
||||
// FRP data block will instead be cleared later, by
|
||||
// LockSettingsService.DeviceProvisionedObserver.clearFrpCredentialIfOwnerNotSecure().
|
||||
//
|
||||
// Don't check the SECURE_FRP_MODE setting here, as it gets set to 1 too late.
|
||||
//
|
||||
// Don't delay anything for a nonempty credential. A nonempty credential can be set before
|
||||
// the device has been provisioned, but it's guaranteed to be after FRP was resolved.
|
||||
if (isNoneCredential(pwd) && !isDeviceProvisioned()) {
|
||||
Slog.d(TAG, "Not clearing FRP credential yet because device is not yet provisioned");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void synchronizeFrpPassword(@Nullable PasswordData pwd, int requestedQuality,
|
||||
int userId) {
|
||||
if (mStorage.getPersistentDataBlockManager() != null
|
||||
&& LockPatternUtils.userOwnsFrpCredential(mContext,
|
||||
mUserManager.getUserInfo(userId))) {
|
||||
if (pwd != null && pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
|
||||
if (shouldSynchronizeFrpCredential(pwd, userId)) {
|
||||
Slogf.d(TAG, "Syncing Gatekeeper-based FRP credential tied to user %d", userId);
|
||||
if (!isNoneCredential(pwd)) {
|
||||
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP, userId, requestedQuality,
|
||||
pwd.toBytes());
|
||||
} else {
|
||||
@@ -924,10 +974,9 @@ public class SyntheticPasswordManager {
|
||||
|
||||
private void synchronizeWeaverFrpPassword(@Nullable PasswordData pwd, int requestedQuality,
|
||||
int userId, int weaverSlot) {
|
||||
if (mStorage.getPersistentDataBlockManager() != null
|
||||
&& LockPatternUtils.userOwnsFrpCredential(mContext,
|
||||
mUserManager.getUserInfo(userId))) {
|
||||
if (pwd != null && pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
|
||||
if (shouldSynchronizeFrpCredential(pwd, userId)) {
|
||||
Slogf.d(TAG, "Syncing Weaver-based FRP credential tied to user %d", userId);
|
||||
if (!isNoneCredential(pwd)) {
|
||||
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, weaverSlot,
|
||||
requestedQuality, pwd.toBytes());
|
||||
} else {
|
||||
@@ -1058,7 +1107,7 @@ public class SyntheticPasswordManager {
|
||||
AuthenticationResult result = new AuthenticationResult();
|
||||
|
||||
if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) {
|
||||
// This should never happen, due to the migration done in LSS.bootCompleted().
|
||||
// This should never happen, due to the migration done in LSS.onThirdPartyAppsStarted().
|
||||
Slogf.wtf(TAG, "Synthetic password not found for user %d", userId);
|
||||
result.gkResponse = VerifyCredentialResponse.ERROR;
|
||||
return result;
|
||||
|
||||
@@ -33,6 +33,7 @@ import android.app.admin.DevicePolicyManagerInternal;
|
||||
import android.app.admin.DeviceStateCache;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.hardware.authsecret.V1_0.IAuthSecret;
|
||||
@@ -41,14 +42,18 @@ import android.hardware.fingerprint.FingerprintManager;
|
||||
import android.os.FileUtils;
|
||||
import android.os.IProgressListener;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.storage.IStorageManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.provider.Settings;
|
||||
import android.security.KeyStore;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
import com.android.internal.widget.LockPatternUtils;
|
||||
import com.android.internal.widget.LockSettingsInternal;
|
||||
import com.android.internal.widget.LockscreenCredential;
|
||||
@@ -59,6 +64,7 @@ import com.android.server.wm.WindowManagerInternal;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
@@ -106,7 +112,8 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
FingerprintManager mFingerprintManager;
|
||||
FaceManager mFaceManager;
|
||||
PackageManager mPackageManager;
|
||||
FakeSettings mSettings;
|
||||
@Rule
|
||||
public FakeSettingsProviderRule mSettingsRule = FakeSettingsProvider.rule();
|
||||
|
||||
@Before
|
||||
public void setUp_baseServices() throws Exception {
|
||||
@@ -126,7 +133,6 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
mFingerprintManager = mock(FingerprintManager.class);
|
||||
mFaceManager = mock(FaceManager.class);
|
||||
mPackageManager = mock(PackageManager.class);
|
||||
mSettings = new FakeSettings();
|
||||
|
||||
LocalServices.removeServiceForTest(LockSettingsInternal.class);
|
||||
LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
|
||||
@@ -134,12 +140,13 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);
|
||||
LocalServices.addService(WindowManagerInternal.class, mMockWindowManager);
|
||||
|
||||
mContext = new MockLockSettingsContext(InstrumentationRegistry.getContext(), mUserManager,
|
||||
mNotificationManager, mDevicePolicyManager, mock(StorageManager.class),
|
||||
mock(TrustManager.class), mock(KeyguardManager.class), mFingerprintManager,
|
||||
mFaceManager, mPackageManager);
|
||||
final Context origContext = InstrumentationRegistry.getContext();
|
||||
mContext = new MockLockSettingsContext(origContext,
|
||||
mSettingsRule.mockContentResolver(origContext), mUserManager, mNotificationManager,
|
||||
mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class),
|
||||
mock(KeyguardManager.class), mFingerprintManager, mFaceManager, mPackageManager);
|
||||
mStorage = new LockSettingsStorageTestable(mContext,
|
||||
new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings"));
|
||||
new File(origContext.getFilesDir(), "locksettings"));
|
||||
File storageDir = mStorage.mStorageDir;
|
||||
if (storageDir.exists()) {
|
||||
FileUtils.deleteContents(storageDir);
|
||||
@@ -153,7 +160,7 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
mService = new LockSettingsServiceTestable(mContext, mStorage,
|
||||
mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
|
||||
mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager,
|
||||
mUserManagerInternal, mDeviceStateCache, mSettings);
|
||||
mUserManagerInternal, mDeviceStateCache);
|
||||
mService.mHasSecureLockScreen = true;
|
||||
when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
|
||||
mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
|
||||
@@ -186,10 +193,25 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
mockBiometricsHardwareFingerprintsAndTemplates(PRIMARY_USER_ID);
|
||||
mockBiometricsHardwareFingerprintsAndTemplates(MANAGED_PROFILE_USER_ID);
|
||||
|
||||
mSettings.setDeviceProvisioned(true);
|
||||
setDeviceProvisioned(true);
|
||||
mLocalService = LocalServices.getService(LockSettingsInternal.class);
|
||||
}
|
||||
|
||||
protected void setDeviceProvisioned(boolean provisioned) {
|
||||
Settings.Global.putInt(mContext.getContentResolver(),
|
||||
Settings.Global.DEVICE_PROVISIONED, provisioned ? 1 : 0);
|
||||
}
|
||||
|
||||
protected void setUserSetupComplete(boolean complete) {
|
||||
Settings.Secure.putIntForUser(mContext.getContentResolver(),
|
||||
Settings.Secure.USER_SETUP_COMPLETE, complete ? 1 : 0, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
protected void setSecureFrpMode(boolean secure) {
|
||||
Settings.Secure.putIntForUser(mContext.getContentResolver(),
|
||||
Settings.Secure.SECURE_FRP_MODE, secure ? 1 : 0, UserHandle.USER_SYSTEM);
|
||||
}
|
||||
|
||||
private UserInfo installChildProfile(int profileId) {
|
||||
final UserInfo userInfo = new UserInfo(
|
||||
profileId, null, null, UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2019 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.server.locksettings;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
|
||||
public class FakeSettings {
|
||||
|
||||
private int mDeviceProvisioned;
|
||||
private int mSecureFrpMode;
|
||||
private int mUserSetupComplete;
|
||||
|
||||
public void setDeviceProvisioned(boolean provisioned) {
|
||||
mDeviceProvisioned = provisioned ? 1 : 0;
|
||||
}
|
||||
|
||||
public void setSecureFrpMode(boolean secure) {
|
||||
mSecureFrpMode = secure ? 1 : 0;
|
||||
}
|
||||
|
||||
public void setUserSetupComplete(boolean complete) {
|
||||
mUserSetupComplete = complete ? 1 : 0;
|
||||
}
|
||||
|
||||
public int globalGetInt(String keyName) {
|
||||
switch (keyName) {
|
||||
case Settings.Global.DEVICE_PROVISIONED:
|
||||
return mDeviceProvisioned;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unhandled global settings: " + keyName);
|
||||
}
|
||||
}
|
||||
|
||||
public int secureGetInt(ContentResolver contentResolver, String keyName, int defaultValue,
|
||||
int userId) {
|
||||
if (Settings.Secure.SECURE_FRP_MODE.equals(keyName) && userId == UserHandle.USER_SYSTEM) {
|
||||
return mSecureFrpMode;
|
||||
}
|
||||
if (Settings.Secure.USER_SETUP_COMPLETE.equals(keyName)
|
||||
&& userId == UserHandle.USER_SYSTEM) {
|
||||
return mUserSetupComplete;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.app.IActivityManager;
|
||||
import android.app.admin.DeviceStateCache;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.hardware.authsecret.V1_0.IAuthSecret;
|
||||
@@ -52,14 +51,12 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
private RecoverableKeyStoreManager mRecoverableKeyStoreManager;
|
||||
private UserManagerInternal mUserManagerInternal;
|
||||
private DeviceStateCache mDeviceStateCache;
|
||||
private FakeSettings mSettings;
|
||||
|
||||
public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
|
||||
IActivityManager activityManager,
|
||||
IStorageManager storageManager, SyntheticPasswordManager spManager,
|
||||
FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
|
||||
UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache,
|
||||
FakeSettings settings) {
|
||||
UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
|
||||
super(context);
|
||||
mLockSettingsStorage = storage;
|
||||
mKeyStore = keyStore;
|
||||
@@ -70,7 +67,6 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
mRecoverableKeyStoreManager = recoverableKeyStoreManager;
|
||||
mUserManagerInternal = userManagerInternal;
|
||||
mDeviceStateCache = deviceStateCache;
|
||||
mSettings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,18 +114,6 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
return mSpManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
|
||||
int defaultValue) {
|
||||
return mSettings.globalGetInt(keyName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int settingsSecureGetInt(ContentResolver contentResolver, String keyName,
|
||||
int defaultValue, int userId) {
|
||||
return mSettings.secureGetInt(contentResolver, keyName, defaultValue, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserManagerInternal getUserManagerInternal() {
|
||||
return mUserManagerInternal;
|
||||
@@ -165,11 +149,10 @@ public class LockSettingsServiceTestable extends LockSettingsService {
|
||||
IStorageManager storageManager, IActivityManager mActivityManager,
|
||||
SyntheticPasswordManager spManager, IAuthSecret authSecretService,
|
||||
FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
|
||||
UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache,
|
||||
FakeSettings settings) {
|
||||
UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
|
||||
super(new MockInjector(context, storage, keystore, mActivityManager,
|
||||
storageManager, spManager, gsiService,
|
||||
recoverableKeyStoreManager, userManagerInternal, deviceStateCache, settings));
|
||||
storageManager, spManager, gsiService, recoverableKeyStoreManager,
|
||||
userManagerInternal, deviceStateCache));
|
||||
mGateKeeperService = gatekeeper;
|
||||
mAuthSecretService = authSecretService;
|
||||
}
|
||||
|
||||
@@ -424,8 +424,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
@Test
|
||||
public void testCredentialChangeNotPossibleInSecureFrpModeDuringSuw() {
|
||||
mSettings.setUserSetupComplete(false);
|
||||
mSettings.setSecureFrpMode(true);
|
||||
setUserSetupComplete(false);
|
||||
setSecureFrpMode(true);
|
||||
try {
|
||||
mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
|
||||
fail("Password shouldn't be changeable before FRP unlock");
|
||||
@@ -434,8 +434,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
@Test
|
||||
public void testCredentialChangePossibleInSecureFrpModeAfterSuw() {
|
||||
mSettings.setUserSetupComplete(true);
|
||||
mSettings.setSecureFrpMode(true);
|
||||
setUserSetupComplete(true);
|
||||
setSecureFrpMode(true);
|
||||
assertTrue(mService.setLockCredential(newPassword("1234"), nonePassword(),
|
||||
PRIMARY_USER_ID));
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.app.KeyguardManager;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
@@ -49,11 +50,14 @@ import androidx.test.InstrumentationRegistry;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.internal.util.test.FakeSettingsProvider;
|
||||
import com.android.internal.util.test.FakeSettingsProviderRule;
|
||||
import com.android.server.PersistentDataBlockManagerInternal;
|
||||
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -78,14 +82,17 @@ public class LockSettingsStorageTests {
|
||||
|
||||
public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 33};
|
||||
|
||||
LockSettingsStorageTestable mStorage;
|
||||
File mStorageDir;
|
||||
|
||||
private LockSettingsStorageTestable mStorage;
|
||||
private File mStorageDir;
|
||||
private File mDb;
|
||||
@Rule
|
||||
public FakeSettingsProviderRule mSettingsRule = FakeSettingsProvider.rule();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mStorageDir = new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings");
|
||||
final Context origContext = InstrumentationRegistry.getContext();
|
||||
|
||||
mStorageDir = new File(origContext.getFilesDir(), "locksettings");
|
||||
mDb = InstrumentationRegistry.getContext().getDatabasePath("locksettings.db");
|
||||
|
||||
assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
|
||||
@@ -98,8 +105,8 @@ public class LockSettingsStorageTests {
|
||||
// User 3 is a profile of user 0.
|
||||
when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
|
||||
|
||||
MockLockSettingsContext context = new MockLockSettingsContext(
|
||||
InstrumentationRegistry.getContext(), mockUserManager,
|
||||
MockLockSettingsContext context = new MockLockSettingsContext(origContext,
|
||||
mSettingsRule.mockContentResolver(origContext), mockUserManager,
|
||||
mock(NotificationManager.class), mock(DevicePolicyManager.class),
|
||||
mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class),
|
||||
mock(FingerprintManager.class), mock(FaceManager.class),
|
||||
|
||||
@@ -44,7 +44,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests {
|
||||
@Before
|
||||
public void setDeviceNotProvisioned() throws Exception {
|
||||
// FRP credential can only be verified prior to provisioning
|
||||
mSettings.setDeviceProvisioned(false);
|
||||
setDeviceProvisioned(false);
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -98,6 +98,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests {
|
||||
mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
|
||||
assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP));
|
||||
|
||||
setDeviceProvisioned(true);
|
||||
mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID);
|
||||
assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(USER_FRP));
|
||||
}
|
||||
@@ -106,7 +107,7 @@ public class LockscreenFrpTest extends BaseLockSettingsServiceTests {
|
||||
public void testFrpCredential_cannotVerifyAfterProvsioning() {
|
||||
mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
|
||||
|
||||
mSettings.setDeviceProvisioned(true);
|
||||
setDeviceProvisioned(true);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
|
||||
mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */)
|
||||
.getResponseCode());
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.app.NotificationManager;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.app.trust.TrustManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.content.Intent;
|
||||
@@ -35,22 +36,25 @@ import android.os.storage.StorageManager;
|
||||
|
||||
public class MockLockSettingsContext extends ContextWrapper {
|
||||
|
||||
private UserManager mUserManager;
|
||||
private NotificationManager mNotificationManager;
|
||||
private DevicePolicyManager mDevicePolicyManager;
|
||||
private StorageManager mStorageManager;
|
||||
private TrustManager mTrustManager;
|
||||
private KeyguardManager mKeyguardManager;
|
||||
private FingerprintManager mFingerprintManager;
|
||||
private FaceManager mFaceManager;
|
||||
private PackageManager mPackageManager;
|
||||
private final ContentResolver mContentResolver;
|
||||
private final UserManager mUserManager;
|
||||
private final NotificationManager mNotificationManager;
|
||||
private final DevicePolicyManager mDevicePolicyManager;
|
||||
private final StorageManager mStorageManager;
|
||||
private final TrustManager mTrustManager;
|
||||
private final KeyguardManager mKeyguardManager;
|
||||
private final FingerprintManager mFingerprintManager;
|
||||
private final FaceManager mFaceManager;
|
||||
private final PackageManager mPackageManager;
|
||||
|
||||
public MockLockSettingsContext(Context base, UserManager userManager,
|
||||
NotificationManager notificationManager, DevicePolicyManager devicePolicyManager,
|
||||
StorageManager storageManager, TrustManager trustManager,
|
||||
KeyguardManager keyguardManager, FingerprintManager fingerprintManager,
|
||||
FaceManager faceManager, PackageManager packageManager) {
|
||||
public MockLockSettingsContext(Context base, ContentResolver contentResolver,
|
||||
UserManager userManager, NotificationManager notificationManager,
|
||||
DevicePolicyManager devicePolicyManager, StorageManager storageManager,
|
||||
TrustManager trustManager, KeyguardManager keyguardManager,
|
||||
FingerprintManager fingerprintManager, FaceManager faceManager,
|
||||
PackageManager packageManager) {
|
||||
super(base);
|
||||
mContentResolver = contentResolver;
|
||||
mUserManager = userManager;
|
||||
mNotificationManager = notificationManager;
|
||||
mDevicePolicyManager = devicePolicyManager;
|
||||
@@ -62,6 +66,11 @@ public class MockLockSettingsContext extends ContextWrapper {
|
||||
mPackageManager = packageManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentResolver getContentResolver() {
|
||||
return mContentResolver;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSystemService(String name) {
|
||||
if (USER_SERVICE.equals(name)) {
|
||||
|
||||
@@ -136,6 +136,43 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
assertTrue(mService.isSyntheticPasswordBasedCredential(userId));
|
||||
}
|
||||
|
||||
protected void initializeSyntheticPassword(int userId) {
|
||||
synchronized (mService.mSpManager) {
|
||||
mService.initializeSyntheticPasswordLocked(userId);
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the FRP credential is updated when an LSKF-based protector is created for the user
|
||||
// that owns the FRP credential, if the device is already provisioned.
|
||||
@Test
|
||||
public void testFrpCredentialSyncedIfDeviceProvisioned() throws RemoteException {
|
||||
setDeviceProvisioned(true);
|
||||
initializeSyntheticPassword(PRIMARY_USER_ID);
|
||||
verify(mStorage.mPersistentDataBlockManager).setFrpCredentialHandle(any());
|
||||
}
|
||||
|
||||
// Tests that the FRP credential is not updated when an LSKF-based protector is created for the
|
||||
// user that owns the FRP credential, if the new credential is empty and the device is not yet
|
||||
// provisioned.
|
||||
@Test
|
||||
public void testEmptyFrpCredentialNotSyncedIfDeviceNotProvisioned() throws RemoteException {
|
||||
setDeviceProvisioned(false);
|
||||
initializeSyntheticPassword(PRIMARY_USER_ID);
|
||||
verify(mStorage.mPersistentDataBlockManager, never()).setFrpCredentialHandle(any());
|
||||
}
|
||||
|
||||
// Tests that the FRP credential is updated when an LSKF-based protector is created for the user
|
||||
// that owns the FRP credential, if the new credential is nonempty and the device is not yet
|
||||
// provisioned.
|
||||
@Test
|
||||
public void testNonEmptyFrpCredentialSyncedIfDeviceNotProvisioned() throws RemoteException {
|
||||
setDeviceProvisioned(false);
|
||||
initializeSyntheticPassword(PRIMARY_USER_ID);
|
||||
verify(mStorage.mPersistentDataBlockManager, never()).setFrpCredentialHandle(any());
|
||||
mService.setLockCredential(newPassword("password"), nonePassword(), PRIMARY_USER_ID);
|
||||
verify(mStorage.mPersistentDataBlockManager).setFrpCredentialHandle(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChangeCredential() throws RemoteException {
|
||||
final LockscreenCredential password = newPassword("password");
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.android.server.locksettings;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
|
||||
import com.google.android.collect.Sets;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@SmallTest
|
||||
@@ -17,4 +23,36 @@ public class WeaverBasedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
public void enableWeaver() throws Exception {
|
||||
mSpManager.enableWeaver();
|
||||
}
|
||||
|
||||
// Tests that if the device is not yet provisioned and the FRP credential uses Weaver, then the
|
||||
// Weaver slot of the FRP credential is not reused. Assumes that Weaver slots are allocated
|
||||
// sequentially, starting at slot 0.
|
||||
@Test
|
||||
public void testFrpWeaverSlotNotReused() {
|
||||
final int userId = 10;
|
||||
final int frpWeaverSlot = 0;
|
||||
|
||||
setDeviceProvisioned(false);
|
||||
assertEquals(Sets.newHashSet(), mPasswordSlotManager.getUsedSlots());
|
||||
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, frpWeaverSlot, 0,
|
||||
new byte[1]);
|
||||
initializeSyntheticPassword(userId); // This should allocate a Weaver slot.
|
||||
assertEquals(Sets.newHashSet(1), mPasswordSlotManager.getUsedSlots());
|
||||
}
|
||||
|
||||
// Tests that if the device is already provisioned and the FRP credential uses Weaver, then the
|
||||
// Weaver slot of the FRP credential is reused. This is not a very interesting test by itself;
|
||||
// it's here as a control for testFrpWeaverSlotNotReused().
|
||||
@Test
|
||||
public void testFrpWeaverSlotReused() {
|
||||
final int userId = 10;
|
||||
final int frpWeaverSlot = 0;
|
||||
|
||||
setDeviceProvisioned(true);
|
||||
assertEquals(Sets.newHashSet(), mPasswordSlotManager.getUsedSlots());
|
||||
mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, frpWeaverSlot, 0,
|
||||
new byte[1]);
|
||||
initializeSyntheticPassword(userId); // This should allocate a Weaver slot.
|
||||
assertEquals(Sets.newHashSet(0), mPasswordSlotManager.getUsedSlots());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user