Change existing LockPatternUtil APIs to fail untrusted password updates.
Add alternative APIs to allow untrusted password changes explicitly, so the caller can choose to use them if needed. Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/locksettings/ Bug: 120039091 Change-Id: I4ca03c9185081d300d7e325965b1e20515e33d51
This commit is contained in:
@@ -1680,7 +1680,6 @@ Lcom/android/internal/widget/LockPatternUtils;->patternToHash(Ljava/util/List;)[
|
||||
Lcom/android/internal/widget/LockPatternUtils;->patternToString(Ljava/util/List;)Ljava/lang/String;
|
||||
Lcom/android/internal/widget/LockPatternUtils;->reportFailedPasswordAttempt(I)V
|
||||
Lcom/android/internal/widget/LockPatternUtils;->reportSuccessfulPasswordAttempt(I)V
|
||||
Lcom/android/internal/widget/LockPatternUtils;->saveLockPassword(Ljava/lang/String;Ljava/lang/String;II)V
|
||||
Lcom/android/internal/widget/LockPatternUtils;->setLockoutAttemptDeadline(II)J
|
||||
Lcom/android/internal/widget/LockPatternUtils;->setLong(Ljava/lang/String;JI)V
|
||||
Lcom/android/internal/widget/LockPatternUtils;->setOwnerInfo(Ljava/lang/String;I)V
|
||||
|
||||
@@ -42,7 +42,7 @@ interface ILockSettings {
|
||||
long getLong(in String key, in long defaultValue, in int userId);
|
||||
@UnsupportedAppUsage
|
||||
String getString(in String key, in String defaultValue, in int userId);
|
||||
void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId);
|
||||
void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId, boolean allowUntrustedChange);
|
||||
void resetKeyStore(int userId);
|
||||
VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId,
|
||||
in ICheckCredentialProgressCallback progressCallback);
|
||||
|
||||
@@ -669,17 +669,25 @@ public class LockPatternUtils {
|
||||
/**
|
||||
* Clear any lock pattern or password.
|
||||
*/
|
||||
public void clearLock(byte[] savedCredential, int userHandle) {
|
||||
public boolean clearLock(byte[] savedCredential, int userHandle) {
|
||||
return clearLock(savedCredential, userHandle, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear any lock pattern or password, with the option to ignore incorrect existing credential.
|
||||
*/
|
||||
public boolean clearLock(byte[] savedCredential, int userHandle, boolean allowUntrustedChange) {
|
||||
final int currentQuality = getKeyguardStoredPasswordQuality(userHandle);
|
||||
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle);
|
||||
|
||||
try{
|
||||
getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE,
|
||||
savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle);
|
||||
savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle,
|
||||
allowUntrustedChange);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to clear lock", e);
|
||||
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (userHandle == UserHandle.USER_SYSTEM) {
|
||||
@@ -689,6 +697,7 @@ public class LockPatternUtils {
|
||||
}
|
||||
|
||||
onAfterChangingPassword(userHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -726,19 +735,28 @@ public class LockPatternUtils {
|
||||
/**
|
||||
* Save a lock pattern.
|
||||
* @param pattern The new pattern to save.
|
||||
* @param savedPattern The previously saved pattern, converted to byte[] format
|
||||
* @param userId the user whose pattern is to be saved.
|
||||
*
|
||||
* @return whether this was successful or not.
|
||||
*/
|
||||
public void saveLockPattern(List<LockPatternView.Cell> pattern, int userId) {
|
||||
this.saveLockPattern(pattern, null, userId);
|
||||
public boolean saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
|
||||
int userId) {
|
||||
return saveLockPattern(pattern, savedPattern, userId, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a lock pattern.
|
||||
* @param pattern The new pattern to save.
|
||||
* @param savedPattern The previously saved pattern, converted to byte[] format
|
||||
* @param userId the user whose pattern is to be saved.
|
||||
* @param allowUntrustedChange whether we want to allow saving a new password if the existing
|
||||
* password being provided is incorrect.
|
||||
*
|
||||
* @return whether this was successful or not.
|
||||
*/
|
||||
public void saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
|
||||
int userId) {
|
||||
public boolean saveLockPattern(List<LockPatternView.Cell> pattern, byte[] savedPattern,
|
||||
int userId, boolean allowUntrustedChange) {
|
||||
if (!hasSecureLockScreen()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"This operation requires the lock screen feature.");
|
||||
@@ -753,11 +771,11 @@ public class LockPatternUtils {
|
||||
setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId);
|
||||
try {
|
||||
getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern,
|
||||
PASSWORD_QUALITY_SOMETHING, userId);
|
||||
PASSWORD_QUALITY_SOMETHING, userId, allowUntrustedChange);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Couldn't save lock pattern", e);
|
||||
setKeyguardStoredPasswordQuality(currentQuality, userId);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Update the device encryption password.
|
||||
if (userId == UserHandle.USER_SYSTEM
|
||||
@@ -771,6 +789,7 @@ public class LockPatternUtils {
|
||||
|
||||
reportPatternWasChosen(userId);
|
||||
onAfterChangingPassword(userId);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateCryptoUserInfo(int userId) {
|
||||
@@ -873,17 +892,20 @@ public class LockPatternUtils {
|
||||
* password.
|
||||
* @param password The password to save
|
||||
* @param savedPassword The previously saved lock password, or null if none
|
||||
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)}
|
||||
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
|
||||
* android.content.ComponentName)}
|
||||
* @param userHandle The userId of the user to change the password for
|
||||
*
|
||||
* @return whether this was successful or not.
|
||||
*
|
||||
* @deprecated Pass password as a byte array
|
||||
*/
|
||||
@Deprecated
|
||||
public void saveLockPassword(String password, String savedPassword, int requestedQuality,
|
||||
public boolean saveLockPassword(String password, String savedPassword, int requestedQuality,
|
||||
int userHandle) {
|
||||
byte[] passwordBytes = password != null ? password.getBytes() : null;
|
||||
byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null;
|
||||
saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
|
||||
return saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -893,11 +915,34 @@ public class LockPatternUtils {
|
||||
* @param password The password to save
|
||||
* @param savedPassword The previously saved lock password, or null if none
|
||||
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
|
||||
* android.content.ComponentName)}
|
||||
* android.content.ComponentName)}
|
||||
* @param userHandle The userId of the user to change the password for
|
||||
*
|
||||
* @return whether this was successful or not.
|
||||
*/
|
||||
public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
|
||||
public boolean saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality,
|
||||
int userHandle) {
|
||||
return saveLockPassword(password, savedPassword, requestedQuality,
|
||||
userHandle, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a lock password. Does not ensure that the password is as good
|
||||
* as the requested mode, but will adjust the mode to be as good as the
|
||||
* password.
|
||||
* @param password The password to save
|
||||
* @param savedPassword The previously saved lock password, or null if none
|
||||
* @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(
|
||||
* android.content.ComponentName)}
|
||||
* @param userHandle The userId of the user to change the password for
|
||||
* @param allowUntrustedChange whether we want to allow saving a new password if the existing
|
||||
* password being provided is incorrect.
|
||||
*
|
||||
* @return whether this method saved the new password successfully or not. This flow will fail
|
||||
* and return false if the given credential is wrong and allowUntrustedChange is false.
|
||||
*/
|
||||
public boolean saveLockPassword(byte[] password, byte[] savedPassword,
|
||||
int requestedQuality, int userHandle, boolean allowUntrustedChange) {
|
||||
if (!hasSecureLockScreen()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"This operation requires the lock screen feature.");
|
||||
@@ -919,16 +964,17 @@ public class LockPatternUtils {
|
||||
setKeyguardStoredPasswordQuality(newKeyguardQuality, userHandle);
|
||||
try {
|
||||
getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword,
|
||||
requestedQuality, userHandle);
|
||||
requestedQuality, userHandle, allowUntrustedChange);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to save lock password", e);
|
||||
setKeyguardStoredPasswordQuality(currentQuality, userHandle);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
updateEncryptionPasswordIfNeeded(password, passwordQuality, userHandle);
|
||||
updatePasswordHistory(password, userHandle);
|
||||
onAfterChangingPassword(userHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -323,8 +323,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
Arrays.fill(newPasswordChars, '\u0000');
|
||||
final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
|
||||
setLockCredentialInternal(newPassword, CREDENTIAL_TYPE_PASSWORD,
|
||||
managedUserPassword, quality, managedUserId);
|
||||
setLockCredentialInternal(newPassword, CREDENTIAL_TYPE_PASSWORD, managedUserPassword,
|
||||
quality, managedUserId, false);
|
||||
// We store a private credential for the managed user that's unlocked by the primary
|
||||
// account holder's credential. As such, the user will never be prompted to enter this
|
||||
// password directly, so we always store a password.
|
||||
@@ -1302,12 +1302,14 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
|
||||
setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE,
|
||||
profilePasswordMap.get(managedUserId),
|
||||
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
|
||||
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
|
||||
false);
|
||||
} else {
|
||||
Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
|
||||
// Supplying null here would lead to untrusted credential change
|
||||
setLockCredentialInternal(null, CREDENTIAL_TYPE_NONE, null,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId);
|
||||
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, managedUserId,
|
||||
true);
|
||||
}
|
||||
mStorage.removeChildProfileLock(managedUserId);
|
||||
removeKeystoreProfileKey(managedUserId);
|
||||
@@ -1330,8 +1332,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
// should call setLockCredentialInternal.
|
||||
@Override
|
||||
public void setLockCredential(byte[] credential, int type,
|
||||
byte[] savedCredential, int requestedQuality, int userId)
|
||||
throws RemoteException {
|
||||
byte[] savedCredential, int requestedQuality, int userId,
|
||||
boolean allowUntrustedChange) throws RemoteException {
|
||||
|
||||
if (!mLockPatternUtils.hasSecureLockScreen()) {
|
||||
throw new UnsupportedOperationException(
|
||||
@@ -1339,7 +1341,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
checkWritePermission(userId);
|
||||
synchronized (mSeparateChallengeLock) {
|
||||
setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId);
|
||||
setLockCredentialInternal(credential, type, savedCredential, requestedQuality, userId,
|
||||
allowUntrustedChange);
|
||||
setSeparateProfileChallengeEnabledLocked(userId, true, null);
|
||||
notifyPasswordChanged(userId);
|
||||
}
|
||||
@@ -1347,7 +1350,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
}
|
||||
|
||||
private void setLockCredentialInternal(byte[] credential, @CredentialType int credentialType,
|
||||
byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
|
||||
byte[] savedCredential, int requestedQuality, int userId,
|
||||
boolean allowUntrustedChange) throws RemoteException {
|
||||
// Normalize savedCredential and credential such that empty string is always represented
|
||||
// as null.
|
||||
if (savedCredential == null || savedCredential.length == 0) {
|
||||
@@ -1359,7 +1363,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
synchronized (mSpManager) {
|
||||
if (isSyntheticPasswordBasedCredentialLocked(userId)) {
|
||||
spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
|
||||
requestedQuality, userId);
|
||||
requestedQuality, userId, allowUntrustedChange);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1410,7 +1414,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
|
||||
currentHandle.type, requestedQuality, userId);
|
||||
spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
|
||||
requestedQuality, userId);
|
||||
requestedQuality, userId, allowUntrustedChange);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1705,7 +1709,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
|
||||
if (shouldReEnrollBaseZero) {
|
||||
setLockCredentialInternal(credential, storedHash.type, credentialToVerify,
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId);
|
||||
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, userId, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1796,7 +1800,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
storedHash.type == CREDENTIAL_TYPE_PATTERN
|
||||
? DevicePolicyManager.PASSWORD_QUALITY_SOMETHING
|
||||
: DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
|
||||
/* TODO(roosa): keep the same password quality */, userId);
|
||||
/* TODO(roosa): keep the same password quality */, userId, false);
|
||||
if (!hasChallenge) {
|
||||
notifyActivePasswordMetricsAvailable(storedHash.type, credential, userId);
|
||||
// Use credentials to create recoverable keystore snapshot.
|
||||
@@ -1841,7 +1845,7 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
/* TODO(roosa): keep the same password quality */;
|
||||
if (shouldReEnroll) {
|
||||
setLockCredentialInternal(credential, storedHash.type, credential,
|
||||
reEnrollQuality, userId);
|
||||
reEnrollQuality, userId, false);
|
||||
} else {
|
||||
// Now that we've cleared of all required GK migration, let's do the final
|
||||
// migration to synthetic password.
|
||||
@@ -2544,7 +2548,8 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
|
||||
@GuardedBy("mSpManager")
|
||||
private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType,
|
||||
byte[] savedCredential, int requestedQuality, int userId) throws RemoteException {
|
||||
byte[] savedCredential, int requestedQuality, int userId,
|
||||
boolean allowUntrustedChange) throws RemoteException {
|
||||
if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
|
||||
if (isManagedProfileWithUnifiedLock(userId)) {
|
||||
// get credential from keystore when managed profile has unified lock
|
||||
@@ -2565,27 +2570,31 @@ public class LockSettingsService extends ILockSettings.Stub {
|
||||
VerifyCredentialResponse response = authResult.gkResponse;
|
||||
AuthenticationToken auth = authResult.authToken;
|
||||
|
||||
// If existing credential is provided, then it must match.
|
||||
// If existing credential is provided, the existing credential must match.
|
||||
if (savedCredential != null && auth == null) {
|
||||
throw new RemoteException("Failed to enroll " +
|
||||
(credentialType == CREDENTIAL_TYPE_PASSWORD ? "password" : "pattern"));
|
||||
throw new IllegalStateException("Failed to enroll "
|
||||
+ (credentialType == CREDENTIAL_TYPE_PASSWORD
|
||||
? "password" : "pattern"));
|
||||
}
|
||||
|
||||
boolean untrustedReset = false;
|
||||
if (auth != null) {
|
||||
onAuthTokenKnownForUser(userId, auth);
|
||||
} else if (response != null
|
||||
&& response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
|
||||
} else if (response == null) {
|
||||
throw new IllegalStateException("Password change failed.");
|
||||
} else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR) {
|
||||
// We are performing an untrusted credential change, by DevicePolicyManager or other
|
||||
// internal callers that don't provide the existing credential
|
||||
Slog.w(TAG, "Untrusted credential change invoked");
|
||||
// Try to get a cached auth token, so we can keep SP unchanged.
|
||||
auth = mSpCache.get(userId);
|
||||
if (!allowUntrustedChange) {
|
||||
throw new IllegalStateException("Untrusted credential change was invoked but it was"
|
||||
+ " not allowed. This is likely a bug. Auth token is null: "
|
||||
+ Boolean.toString(auth == null));
|
||||
}
|
||||
untrustedReset = true;
|
||||
} else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
|
||||
Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
|
||||
(response != null ? "rate limit exceeded" : "failed"));
|
||||
return;
|
||||
} else /* responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
|
||||
throw new IllegalStateException("Rate limit exceeded, so password was not changed.");
|
||||
}
|
||||
|
||||
if (auth != null) {
|
||||
|
||||
@@ -5133,11 +5133,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
|
||||
final boolean result;
|
||||
try {
|
||||
if (token == null) {
|
||||
// This is the legacy reset password for DPM. Here we want to be able to override
|
||||
// the old device password without necessarily knowing it.
|
||||
if (!TextUtils.isEmpty(password)) {
|
||||
mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality,
|
||||
userHandle);
|
||||
userHandle, /*allowUntrustedChange */true);
|
||||
} else {
|
||||
mLockPatternUtils.clearLock(null, userHandle);
|
||||
mLockPatternUtils.clearLock(null, userHandle,
|
||||
/*allowUntrustedChange */ true);
|
||||
}
|
||||
result = true;
|
||||
} else {
|
||||
|
||||
@@ -61,12 +61,12 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// clear password
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, true);
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
// set a new password
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
@@ -81,7 +81,7 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// Untrusted change password
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
|
||||
assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
@@ -99,7 +99,7 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
// Untrusted change password
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true);
|
||||
|
||||
// Verify the password
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword,
|
||||
@@ -124,10 +124,12 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// Untrusted change password
|
||||
assertExpectException(IllegalStateException.class, /* messageRegex= */ null,
|
||||
assertExpectException(
|
||||
IllegalStateException.class,
|
||||
/* messageRegex= */ "Untrusted credential reset not possible without cached SP",
|
||||
() -> mService.setLockCredential(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID));
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, true));
|
||||
assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
// Verify the new password doesn't work but the old one still does
|
||||
|
||||
@@ -85,9 +85,9 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
try {
|
||||
mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD,
|
||||
"badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
"badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
fail("Did not fail when enrolling using incorrect credential");
|
||||
} catch (RemoteException expected) {
|
||||
} catch (IllegalStateException expected) {
|
||||
assertTrue(expected.getMessage().equals(FAILED_MESSAGE));
|
||||
}
|
||||
assertVerifyCredentials(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid);
|
||||
@@ -97,7 +97,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
final String PASSWORD = "password";
|
||||
initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234);
|
||||
mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(),
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
|
||||
assertFalse(mService.havePassword(PRIMARY_USER_ID));
|
||||
assertFalse(mService.havePattern(PRIMARY_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
@@ -108,7 +108,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2";
|
||||
mService.setLockCredential(firstUnifiedPassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
|
||||
null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
|
||||
@@ -143,15 +143,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
mStorageManager.setIgnoreBadUnlock(true);
|
||||
// Change primary password and verify that profile SID remains
|
||||
mService.setLockCredential(secondUnifiedPassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
firstUnifiedPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, firstUnifiedPassword.getBytes(),
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
mStorageManager.setIgnoreBadUnlock(false);
|
||||
assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID));
|
||||
|
||||
// Clear unified challenge
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID,
|
||||
false);
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID));
|
||||
assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID));
|
||||
@@ -162,7 +163,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
final String profilePassword = "testManagedProfileSeparateChallenge-profile";
|
||||
mService.setLockCredential(primaryPassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID, false);
|
||||
/* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new
|
||||
* credential as part of verifyCredential() before the new credential is committed in
|
||||
* StorageManager. So we relax the check in our mock StorageManager to allow that.
|
||||
@@ -170,7 +171,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
mStorageManager.setIgnoreBadUnlock(true);
|
||||
mService.setLockCredential(profilePassword.getBytes(),
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID);
|
||||
PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID, false);
|
||||
mStorageManager.setIgnoreBadUnlock(false);
|
||||
|
||||
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
@@ -197,7 +198,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
// Change primary credential and make sure we don't affect profile
|
||||
mStorageManager.setIgnoreBadUnlock(true);
|
||||
mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
|
||||
primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
mStorageManager.setIgnoreBadUnlock(false);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
|
||||
@@ -208,7 +209,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
private void testCreateCredential(int userId, String credential, int type, int quality)
|
||||
throws RemoteException {
|
||||
mService.setLockCredential(credential.getBytes(), type, null, quality,
|
||||
userId);
|
||||
userId, false);
|
||||
assertVerifyCredentials(userId, credential, type, -1);
|
||||
}
|
||||
|
||||
@@ -218,7 +219,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
try {
|
||||
mService.setLockCredential(credential.getBytes(), type, null, quality,
|
||||
userId);
|
||||
userId, false);
|
||||
fail("An exception should have been thrown.");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// Success - the exception was expected.
|
||||
@@ -233,7 +234,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
|
||||
final long sid = 1234;
|
||||
initializeStorageWithCredential(userId, oldCredential, oldType, sid);
|
||||
mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(),
|
||||
quality, userId);
|
||||
quality, userId, false);
|
||||
assertVerifyCredentials(userId, newCredential, newType, sid);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
enableSyntheticPassword();
|
||||
@@ -127,7 +127,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
: PASSWORD_QUALITY_UNSPECIFIED;
|
||||
int type = password != null ? LockPatternUtils.CREDENTIAL_TYPE_PASSWORD
|
||||
: LockPatternUtils.CREDENTIAL_TYPE_NONE;
|
||||
mService.setLockCredential(password, type, null, quality, userId);
|
||||
mService.setLockCredential(password, type, null, quality, userId, false);
|
||||
}
|
||||
|
||||
public void testSyntheticPasswordChangeCredential() throws RemoteException {
|
||||
@@ -137,7 +137,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
@@ -166,12 +166,12 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
// clear password
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
|
||||
assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
|
||||
|
||||
// set a new password
|
||||
mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
@@ -186,7 +186,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(
|
||||
badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID)
|
||||
.getResponseCode());
|
||||
@@ -245,7 +245,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
final byte[] password = "getASyntheticPassword".getBytes();
|
||||
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
|
||||
|
||||
reset(mAuthSecretService);
|
||||
mService.onUnlockUser(PRIMARY_USER_ID);
|
||||
@@ -257,7 +257,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes();
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
|
||||
@@ -294,9 +294,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
"testManagedProfileSeparateChallengeMigration-profile".getBytes();
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
|
||||
final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID);
|
||||
final long profileSid = mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID);
|
||||
final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
|
||||
@@ -404,7 +404,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
|
||||
|
||||
mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password,
|
||||
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
|
||||
|
||||
mLocalService.setLockCredentialWithToken(newPassword,
|
||||
LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token,
|
||||
@@ -443,7 +443,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
// Set up pre-SP user password
|
||||
disableSyntheticPassword();
|
||||
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
enableSyntheticPassword();
|
||||
|
||||
long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
|
||||
@@ -491,12 +491,12 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
public void testgetHashFactorPrimaryUser() throws RemoteException {
|
||||
final byte[] password = "password".getBytes();
|
||||
mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
|
||||
assertNotNull(hashFactor);
|
||||
|
||||
mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
|
||||
password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
|
||||
password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID, false);
|
||||
final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
|
||||
assertNotNull(newHashFactor);
|
||||
// Hash factor should never change after password change/removal
|
||||
@@ -506,7 +506,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
|
||||
final byte[] pattern = "1236".getBytes();
|
||||
mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
|
||||
null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
|
||||
null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID, false);
|
||||
mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
|
||||
assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
|
||||
}
|
||||
@@ -515,9 +515,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
|
||||
final byte[] primaryPassword = "primary".getBytes();
|
||||
final byte[] profilePassword = "profile".getBytes();
|
||||
mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID, false);
|
||||
mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
|
||||
PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
|
||||
PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID, false);
|
||||
assertNotNull(mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user