Add a method which allows storing PIN length on disk from cache
This CL aims at adding a method that would allow storing length of PIN on disk from cache, i.e. PasswordMetrics object containing the pin length. Bug: b/267222046 Test: Tested by building and flashing on local Change-Id: I846377c4fc06a230ae5a078c98949a2134df2722
This commit is contained in:
@@ -57,6 +57,7 @@ interface ILockSettings {
|
||||
void removeGatekeeperPasswordHandle(long gatekeeperPasswordHandle);
|
||||
int getCredentialType(int userId);
|
||||
int getPinLength(int userId);
|
||||
boolean refreshStoredPinLength(int userId);
|
||||
byte[] getHashFactor(in LockscreenCredential currentCredential, int userId);
|
||||
void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in LockscreenCredential managedUserPassword);
|
||||
boolean getSeparateProfileChallengeEnabled(int userId);
|
||||
|
||||
@@ -622,6 +622,24 @@ public class LockPatternUtils {
|
||||
return PIN_LENGTH_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method saves the pin length value to disk based on the user's auto pin
|
||||
* confirmation flag setting. If the auto pin confirmation flag is disabled, or if the
|
||||
* user does not have a PIN setup, or if length of PIN is less than minimum storable PIN length
|
||||
* value, the pin length value is set to PIN_LENGTH_UNAVAILABLE. Otherwise, if the
|
||||
* flag is enabled, the pin length value is set to the actual length of the user's PIN.
|
||||
* @param userId user id of the user whose pin length we want to save
|
||||
* @return true/false depending on whether PIN length has been saved or not
|
||||
*/
|
||||
public boolean refreshStoredPinLength(int userId) {
|
||||
try {
|
||||
return getLockSettings().refreshStoredPinLength(userId);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Could not store PIN length on disk " + e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Records that the user has chosen a pattern at some time, even if the pattern is
|
||||
* currently cleared.
|
||||
|
||||
@@ -116,6 +116,7 @@ import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.EventLog;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
@@ -1228,6 +1229,26 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link LockPatternUtils#refreshStoredPinLength(int)}
|
||||
* @param userId user id of the user whose pin length we want to save
|
||||
* @return true/false depending on whether PIN length has been saved or not
|
||||
*/
|
||||
@Override
|
||||
public boolean refreshStoredPinLength(int userId) {
|
||||
checkPasswordHavePermission();
|
||||
synchronized (mSpManager) {
|
||||
PasswordMetrics passwordMetrics = getUserPasswordMetrics(userId);
|
||||
if (passwordMetrics != null) {
|
||||
final long protectorId = getCurrentLskfBasedProtectorId(userId);
|
||||
return mSpManager.refreshPinLengthOnDisk(passwordMetrics, protectorId, userId);
|
||||
} else {
|
||||
Log.w(TAG, "PasswordMetrics is not available");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This API is cached; whenever the result would change,
|
||||
* {@link com.android.internal.widget.LockPatternUtils#invalidateCredentialTypeCache}
|
||||
|
||||
@@ -120,6 +120,11 @@ class LockSettingsStorage {
|
||||
writeKeyValue(mOpenHelper.getWritableDatabase(), key, value, userId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean isAutoPinConfirmSettingEnabled(int userId) {
|
||||
return getBoolean(LockPatternUtils.AUTO_PIN_CONFIRM, false, userId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void writeKeyValue(SQLiteDatabase db, String key, String value, int userId) {
|
||||
ContentValues cv = new ContentValues();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.server.locksettings;
|
||||
|
||||
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
|
||||
import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
|
||||
import static com.android.internal.widget.LockPatternUtils.PIN_LENGTH_UNAVAILABLE;
|
||||
|
||||
@@ -545,6 +546,11 @@ class SyntheticPasswordManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public boolean isAutoPinConfirmationFeatureAvailable() {
|
||||
return LockPatternUtils.isAutoPinConfirmFeatureAvailable();
|
||||
}
|
||||
|
||||
private synchronized boolean isWeaverAvailable() {
|
||||
if (mWeaver != null) {
|
||||
return true;
|
||||
@@ -901,8 +907,8 @@ class SyntheticPasswordManager {
|
||||
LockscreenCredential credential, SyntheticPassword sp, int userId) {
|
||||
long protectorId = generateProtectorId();
|
||||
int pinLength = PIN_LENGTH_UNAVAILABLE;
|
||||
if (LockPatternUtils.isAutoPinConfirmFeatureAvailable()) {
|
||||
pinLength = derivePinLength(credential, userId);
|
||||
if (isAutoPinConfirmationFeatureAvailable()) {
|
||||
pinLength = derivePinLength(credential.size(), credential.isPin(), userId);
|
||||
}
|
||||
// There's no need to store password data about an empty LSKF.
|
||||
PasswordData pwd = credential.isNone() ? null :
|
||||
@@ -978,13 +984,13 @@ class SyntheticPasswordManager {
|
||||
return protectorId;
|
||||
}
|
||||
|
||||
private int derivePinLength(LockscreenCredential credential, int userId) {
|
||||
if (!credential.isPin()
|
||||
|| !mStorage.getBoolean(LockPatternUtils.AUTO_PIN_CONFIRM, false, userId)
|
||||
|| credential.size() < LockPatternUtils.MIN_AUTO_PIN_REQUIREMENT_LENGTH) {
|
||||
private int derivePinLength(int sizeOfCredential, boolean isPinCredential, int userId) {
|
||||
if (!isPinCredential
|
||||
|| !mStorage.isAutoPinConfirmSettingEnabled(userId)
|
||||
|| sizeOfCredential < LockPatternUtils.MIN_AUTO_PIN_REQUIREMENT_LENGTH) {
|
||||
return PIN_LENGTH_UNAVAILABLE;
|
||||
}
|
||||
return credential.size();
|
||||
return sizeOfCredential;
|
||||
}
|
||||
|
||||
public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
|
||||
@@ -1347,18 +1353,38 @@ class SyntheticPasswordManager {
|
||||
savePasswordMetrics(credential, result.syntheticPassword, protectorId, userId);
|
||||
syncState(userId); // Not strictly needed as the upgrade can be re-done, but be safe.
|
||||
}
|
||||
if (LockPatternUtils.isAutoPinConfirmFeatureAvailable()
|
||||
&& result.syntheticPassword != null && pwd != null) {
|
||||
int expectedPinLength = derivePinLength(credential, userId);
|
||||
if (pwd.pinLength != expectedPinLength) {
|
||||
pwd.pinLength = expectedPinLength;
|
||||
saveState(PASSWORD_DATA_NAME, pwd.toBytes(), protectorId, userId);
|
||||
syncState(userId);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link LockPatternUtils#refreshStoredPinLength(int)}
|
||||
* @param passwordMetrics passwordMetrics object containing the cached pin length
|
||||
* @param userId userId of the user whose pin length we want to store on disk
|
||||
* @param protectorId current LSKF based protectorId
|
||||
* @return true/false depending on whether PIN length has been saved on disk
|
||||
*/
|
||||
public boolean refreshPinLengthOnDisk(PasswordMetrics passwordMetrics,
|
||||
long protectorId, int userId) {
|
||||
if (!isAutoPinConfirmationFeatureAvailable()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
byte[] pwdDataBytes = loadState(PASSWORD_DATA_NAME, protectorId, userId);
|
||||
if (pwdDataBytes == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PasswordData pwd = PasswordData.fromBytes(pwdDataBytes);
|
||||
int pinLength = derivePinLength(passwordMetrics.length,
|
||||
passwordMetrics.credType == CREDENTIAL_TYPE_PIN, userId);
|
||||
if (pwd.pinLength != pinLength) {
|
||||
pwd.pinLength = pinLength;
|
||||
saveState(PASSWORD_DATA_NAME, pwd.toBytes(), protectorId, userId);
|
||||
syncState(userId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to unlock a token-based SP protector (weak or strong), given its ID and the claimed
|
||||
* token. On success, returns the user's synthetic password, and also does a Gatekeeper
|
||||
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package com.android.server.locksettings;
|
||||
|
||||
import static android.app.admin.DevicePolicyManager.DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_FLAG;
|
||||
import static android.provider.DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -50,7 +47,6 @@ import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.storage.IStorageManager;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings;
|
||||
import android.security.KeyStore;
|
||||
|
||||
@@ -235,9 +231,6 @@ public abstract class BaseLockSettingsServiceTests {
|
||||
// Adding a fake Device Owner app which will enable escrow token support in LSS.
|
||||
when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()).thenReturn(
|
||||
new ComponentName("com.dummy.package", ".FakeDeviceOwner"));
|
||||
// TODO(b/258213147): Remove
|
||||
DeviceConfig.setProperty(NAMESPACE_DEVICE_POLICY_MANAGER,
|
||||
DEPRECATE_USERMANAGERINTERNAL_DEVICEPOLICY_FLAG, "true", /* makeDefault= */ false);
|
||||
when(mUserManagerInternal.isDeviceManaged()).thenReturn(true);
|
||||
when(mDeviceStateCache.isUserOrganizationManaged(anyInt())).thenReturn(true);
|
||||
when(mDeviceStateCache.isDeviceProvisioned()).thenReturn(true);
|
||||
|
||||
@@ -87,7 +87,10 @@ public class LockSettingsStorageTestable extends LockSettingsStorage {
|
||||
PersistentDataBlockManagerInternal getPersistentDataBlockManager() {
|
||||
return mPersistentDataBlockManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoPinConfirmSettingEnabled(int userId) {
|
||||
return true;
|
||||
}
|
||||
private File remapToStorageDir(File origPath) {
|
||||
File mappedPath = new File(mStorageDir, origPath.toString());
|
||||
mappedPath.getParentFile().mkdirs();
|
||||
|
||||
@@ -112,6 +112,11 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoPinConfirmationFeatureAvailable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IWeaver getWeaverHidlService() throws RemoteException {
|
||||
return mWeaverService;
|
||||
|
||||
@@ -606,6 +606,24 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
assertArrayEquals(PAYLOAD2, deserialized.passwordHandle);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStorePinLengthOnDisk() {
|
||||
int userId = 1;
|
||||
LockscreenCredential lockscreenCredentialPin = LockscreenCredential.createPin("123456");
|
||||
MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage,
|
||||
mGateKeeperService, mUserManager, mPasswordSlotManager);
|
||||
SyntheticPassword sp = manager.newSyntheticPassword(userId);
|
||||
long protectorId = manager.createLskfBasedProtector(mGateKeeperService,
|
||||
lockscreenCredentialPin, sp,
|
||||
userId);
|
||||
PasswordMetrics passwordMetrics =
|
||||
PasswordMetrics.computeForCredential(lockscreenCredentialPin);
|
||||
boolean result = manager.refreshPinLengthOnDisk(passwordMetrics, protectorId, userId);
|
||||
|
||||
assertEquals(manager.getPinLength(protectorId, userId), lockscreenCredentialPin.size());
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPasswordDataV2VersionCredentialTypePin_deserialize() {
|
||||
// Test that we can deserialize existing PasswordData and don't inadvertently change the
|
||||
|
||||
Reference in New Issue
Block a user