summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Biggers <ebiggers@google.com> 2023-10-10 22:50:51 +0000
committer Eric Biggers <ebiggers@google.com> 2023-10-10 23:01:45 +0000
commit1c95758cf9d6a72a493ec410ff585028adc2f4fb (patch)
tree58cbd88afa82fd1137375235f05f580d4386c1c3
parent008cc90195926f9aa2b7223721e6ccb714bd85bf (diff)
Add a verification flow for the user to exit repair mode
Create a special user id USER_REPAIR_MODE and an intent ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL for the repair mode client triggering a exiting repair mode verification flow that verifies credentials the user enrolled in normal mode. Functions in LockSettings are updated to handle the new user id. Information needed to verify the repair mode user is retrieved from the repair mode file when the verifyCredential api is called. Bug: 277561275 Test: atest com.android.server.locksettings Test: am start -a android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL settings put global repair_mode_active 1 am start -a android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL The credential is verified successfully. Change-Id: I51699d157e9de1a57bc36797ea005bcdd51aadb3 Merged-In: I51699d157e9de1a57bc36797ea005bcdd51aadb3 (cherry picked from commit 5ebbd7d30dca21980550780beb7135526f78db86)
-rw-r--r--core/java/android/app/KeyguardManager.java9
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java62
-rw-r--r--core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java13
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java45
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsStorage.java7
-rw-r--r--services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java40
-rw-r--r--services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java101
7 files changed, 214 insertions, 63 deletions
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 6d2feb8f0ee3..2d554031ab48 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -126,6 +126,15 @@ public class KeyguardManager {
"android.app.action.PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL";
/**
+ * Intent used to prompt user for device credential that is written by
+ * {@link #ACTION_PREPARE_REPAIR_MODE_DEVICE_CREDENTIAL} for exiting
+ * repair mode.
+ * @hide
+ */
+ public static final String ACTION_CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL =
+ "android.app.action.CONFIRM_REPAIR_MODE_DEVICE_CREDENTIAL";
+
+ /**
* A CharSequence dialog title to show to the user when used with a
* {@link #ACTION_CONFIRM_DEVICE_CREDENTIAL}.
* @hide
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index aaa3a773ab01..d5b8f62aaf2b 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -180,6 +180,11 @@ public class LockPatternUtils {
*/
public static final int USER_FRP = UserHandle.USER_NULL + 1;
+ /**
+ * Special user id for triggering the exiting repair mode verification flow.
+ */
+ public static final int USER_REPAIR_MODE = UserHandle.USER_NULL + 2;
+
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
@Deprecated
public final static String PASSWORD_TYPE_ALTERNATE_KEY = "lockscreen.password_type_alternate";
@@ -399,7 +404,7 @@ public class LockPatternUtils {
@UnsupportedAppUsage
public void reportFailedPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return;
}
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
@@ -408,7 +413,7 @@ public class LockPatternUtils {
@UnsupportedAppUsage
public void reportSuccessfulPasswordAttempt(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return;
}
getDevicePolicyManager().reportSuccessfulPasswordAttempt(userId);
@@ -416,21 +421,21 @@ public class LockPatternUtils {
}
public void reportPasswordLockout(int timeoutMs, int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return;
}
getTrustManager().reportUnlockLockout(timeoutMs, userId);
}
public int getCurrentFailedPasswordAttempts(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return 0;
}
return getDevicePolicyManager().getCurrentFailedPasswordAttempts(userId);
}
public int getMaximumFailedPasswordsForWipe(int userId) {
- if (userId == USER_FRP && frpCredentialEnabled(mContext)) {
+ if (isSpecialUserId(mContext, userId, /* checkDeviceSupported= */ true)) {
return 0;
}
return getDevicePolicyManager().getMaximumFailedPasswordsForWipe(
@@ -750,6 +755,17 @@ public class LockPatternUtils {
}
}
+ /** Returns the credential type corresponding to the given PIN or password quality. */
+ public static int pinOrPasswordQualityToCredentialType(int quality) {
+ if (isQualityAlphabeticPassword(quality)) {
+ return CREDENTIAL_TYPE_PASSWORD;
+ }
+ if (isQualityNumericPin(quality)) {
+ return CREDENTIAL_TYPE_PIN;
+ }
+ throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
+ }
+
/**
* Save a new lockscreen credential.
*
@@ -982,7 +998,7 @@ public class LockPatternUtils {
}
@Override
public boolean shouldBypassCache(Integer userHandle) {
- return userHandle == USER_FRP;
+ return isSpecialUserId(userHandle);
}
};
@@ -1089,9 +1105,10 @@ public class LockPatternUtils {
@UnsupportedAppUsage
public long setLockoutAttemptDeadline(int userId, int timeoutMs) {
final long deadline = SystemClock.elapsedRealtime() + timeoutMs;
- if (userId == USER_FRP) {
- // For secure password storage (that is required for FRP), the underlying storage also
- // enforces the deadline. Since we cannot store settings for the FRP user, don't.
+ if (isSpecialUserId(userId)) {
+ // For secure password storage (that is required for special users such as FRP), the
+ // underlying storage also enforces the deadline. Since we cannot store settings
+ // for special users, don't.
return deadline;
}
mLockoutDeadlines.put(userId, deadline);
@@ -1861,6 +1878,33 @@ public class LockPatternUtils {
}
/**
+ * Return {@code true} if the given user id is a special user such as {@link #USER_FRP}.
+ */
+ public static boolean isSpecialUserId(int userId) {
+ return isSpecialUserId(/* context= */ null, userId, /* checkDeviceSupported= */ false);
+ }
+
+ /**
+ * Return {@code true} if the given user id is a special user for the verification flow.
+ *
+ * @param checkDeviceSupported {@code true} to check the specified user is supported
+ * by the device.
+ */
+ private static boolean isSpecialUserId(@Nullable Context context, int userId,
+ boolean checkDeviceSupported) {
+ switch (userId) {
+ case USER_FRP:
+ if (checkDeviceSupported) return frpCredentialEnabled(context);
+ return true;
+
+ case USER_REPAIR_MODE:
+ if (checkDeviceSupported) return isRepairModeSupported(context);
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Attempt to rederive the unified work challenge for the specified profile user and unlock the
* user. If successful, this would allow the user to leave quiet mode automatically without
* additional user authentication.
diff --git a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
index 6167c4b80cee..1a668f7bdc8f 100644
--- a/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/LockPatternUtilsTest.java
@@ -37,10 +37,23 @@ public class LockPatternUtilsTest {
}
@Test
+ public void testUserRepairMode_isNotRegularUser() {
+ assertTrue(LockPatternUtils.USER_REPAIR_MODE < 0);
+ }
+
+ @Test
public void testUserFrp_isNotAReservedSpecialUser() throws Exception {
assertNotEquals(UserHandle.USER_NULL, LockPatternUtils.USER_FRP);
assertNotEquals(UserHandle.USER_ALL, LockPatternUtils.USER_FRP);
assertNotEquals(UserHandle.USER_CURRENT, LockPatternUtils.USER_FRP);
assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_FRP);
}
+
+ @Test
+ public void testUserRepairMode_isNotAReservedSpecialUser() throws Exception {
+ assertNotEquals(UserHandle.USER_NULL, LockPatternUtils.USER_REPAIR_MODE);
+ assertNotEquals(UserHandle.USER_ALL, LockPatternUtils.USER_REPAIR_MODE);
+ assertNotEquals(UserHandle.USER_CURRENT, LockPatternUtils.USER_REPAIR_MODE);
+ assertNotEquals(UserHandle.USER_CURRENT_OR_SELF, LockPatternUtils.USER_REPAIR_MODE);
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index f7a3b7ca9b63..f0988f148592 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -31,7 +31,6 @@ import static android.os.UserHandle.USER_ALL;
import static android.os.UserHandle.USER_SYSTEM;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
-import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN;
import static com.android.internal.widget.LockPatternUtils.CURRENT_LSKF_BASED_PROTECTOR_ID_KEY;
@@ -40,9 +39,12 @@ import static com.android.internal.widget.LockPatternUtils.PIN_LENGTH_UNAVAILABL
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_FOR_UNATTENDED_UPDATE;
import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_REQUEST_GK_PW_HANDLE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
import static com.android.internal.widget.LockPatternUtils.frpCredentialEnabled;
+import static com.android.internal.widget.LockPatternUtils.isSpecialUserId;
+import static com.android.internal.widget.LockPatternUtils.pinOrPasswordQualityToCredentialType;
import static com.android.internal.widget.LockPatternUtils.userOwnsFrpCredential;
import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYPE_STRONG;
import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYPE_WEAK;
@@ -1315,8 +1317,8 @@ public class LockSettingsService extends ILockSettings.Stub {
* {@link #CREDENTIAL_TYPE_PASSWORD}
*/
private int getCredentialTypeInternal(int userId) {
- if (userId == USER_FRP) {
- return getFrpCredentialType();
+ if (isSpecialUserId(userId)) {
+ return mSpManager.getSpecialUserCredentialType(userId);
}
synchronized (mSpManager) {
final long protectorId = getCurrentLskfBasedProtectorId(userId);
@@ -1332,29 +1334,6 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
- private int getFrpCredentialType() {
- PersistentData data = mStorage.readPersistentDataBlock();
- if (data.type != PersistentData.TYPE_SP_GATEKEEPER &&
- data.type != PersistentData.TYPE_SP_WEAVER) {
- return CREDENTIAL_TYPE_NONE;
- }
- int credentialType = SyntheticPasswordManager.getFrpCredentialType(data.payload);
- if (credentialType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
- return credentialType;
- }
- return pinOrPasswordQualityToCredentialType(data.qualityForUi);
- }
-
- private static int pinOrPasswordQualityToCredentialType(int quality) {
- if (LockPatternUtils.isQualityAlphabeticPassword(quality)) {
- return CREDENTIAL_TYPE_PASSWORD;
- }
- if (LockPatternUtils.isQualityNumericPin(quality)) {
- return CREDENTIAL_TYPE_PIN;
- }
- throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
- }
-
private boolean isUserSecure(int userId) {
return getCredentialTypeInternal(userId) != CREDENTIAL_TYPE_NONE;
}
@@ -1596,8 +1575,8 @@ public class LockSettingsService extends ILockSettings.Stub {
* unlock operation.
*/
private void sendCredentialsOnUnlockIfRequired(LockscreenCredential credential, int userId) {
- // Don't send credentials during the factory reset protection flow.
- if (userId == USER_FRP) {
+ // Don't send credentials during the special user flow.
+ if (isSpecialUserId(userId)) {
return;
}
@@ -2218,15 +2197,19 @@ public class LockSettingsService extends ILockSettings.Stub {
Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
return VerifyCredentialResponse.ERROR;
}
+ if (userId == USER_REPAIR_MODE && !LockPatternUtils.isRepairModeActive(mContext)) {
+ Slog.e(TAG, "Repair mode is not active on the device.");
+ return VerifyCredentialResponse.ERROR;
+ }
Slogf.i(TAG, "Verifying lockscreen credential for user %d", userId);
final AuthenticationResult authResult;
VerifyCredentialResponse response;
synchronized (mSpManager) {
- if (userId == USER_FRP) {
- return mSpManager.verifyFrpCredential(getGateKeeperService(), credential,
- progressCallback);
+ if (isSpecialUserId(userId)) {
+ return mSpManager.verifySpecialUserCredential(userId, getGateKeeperService(),
+ credential, progressCallback);
}
long protectorId = getCurrentLskfBasedProtectorId(userId);
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 1ace6e5452ad..1c5ecb70a3ae 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -19,7 +19,7 @@ package com.android.server.locksettings;
import static android.content.Context.USER_SERVICE;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
-import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+import static com.android.internal.widget.LockPatternUtils.isSpecialUserId;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
@@ -536,7 +536,8 @@ class LockSettingsStorage {
}
public void setString(String key, String value, int userId) {
- Preconditions.checkArgument(userId != USER_FRP, "cannot store lock settings for FRP user");
+ Preconditions.checkArgument(!isSpecialUserId(userId),
+ "cannot store lock settings for special user: %d", userId);
writeKeyValue(key, value, userId);
if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
@@ -561,7 +562,7 @@ class LockSettingsStorage {
}
public String getString(String key, String defaultValue, int userId) {
- if (userId == USER_FRP) {
+ if (isSpecialUserId(userId)) {
return null;
}
return readKeyValue(key, defaultValue, userId);
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 3df05c5a9e5f..8e9c21f5f35f 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -16,9 +16,14 @@
package com.android.server.locksettings;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
+import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD_OR_PIN;
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;
+import static com.android.internal.widget.LockPatternUtils.USER_FRP;
+import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
+import static com.android.internal.widget.LockPatternUtils.pinOrPasswordQualityToCredentialType;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -768,11 +773,30 @@ class SyntheticPasswordManager {
return PasswordData.fromBytes(passwordData).credentialType;
}
- static int getFrpCredentialType(byte[] payload) {
- if (payload == null) {
+ int getSpecialUserCredentialType(int userId) {
+ final PersistentData data = getSpecialUserPersistentData(userId);
+ if (data.type != PersistentData.TYPE_SP_GATEKEEPER
+ && data.type != PersistentData.TYPE_SP_WEAVER) {
+ return CREDENTIAL_TYPE_NONE;
+ }
+ if (data.payload == null) {
return LockPatternUtils.CREDENTIAL_TYPE_NONE;
}
- return PasswordData.fromBytes(payload).credentialType;
+ final int credentialType = PasswordData.fromBytes(data.payload).credentialType;
+ if (credentialType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
+ return credentialType;
+ }
+ return pinOrPasswordQualityToCredentialType(data.qualityForUi);
+ }
+
+ private PersistentData getSpecialUserPersistentData(int userId) {
+ if (userId == USER_FRP) {
+ return mStorage.readPersistentDataBlock();
+ }
+ if (userId == USER_REPAIR_MODE) {
+ return mStorage.readRepairModePersistentData();
+ }
+ throw new IllegalArgumentException("Unknown special user id " + userId);
}
/**
@@ -1057,10 +1081,10 @@ class SyntheticPasswordManager {
return sizeOfCredential;
}
- public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper,
- LockscreenCredential userCredential,
+ public VerifyCredentialResponse verifySpecialUserCredential(int sourceUserId,
+ IGateKeeperService gatekeeper, LockscreenCredential userCredential,
ICheckCredentialProgressCallback progressCallback) {
- PersistentData persistentData = mStorage.readPersistentDataBlock();
+ final PersistentData persistentData = getSpecialUserPersistentData(sourceUserId);
if (persistentData.type == PersistentData.TYPE_SP_GATEKEEPER) {
PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
byte[] stretchedLskf = stretchLskf(userCredential, pwd);
@@ -1071,14 +1095,14 @@ class SyntheticPasswordManager {
0 /* challenge */, pwd.passwordHandle,
stretchedLskfToGkPassword(stretchedLskf));
} catch (RemoteException e) {
- Slog.e(TAG, "FRP verifyChallenge failed", e);
+ Slog.e(TAG, "Persistent data credential verifyChallenge failed", e);
return VerifyCredentialResponse.ERROR;
}
return VerifyCredentialResponse.fromGateKeeperResponse(response);
} else if (persistentData.type == PersistentData.TYPE_SP_WEAVER) {
final IWeaver weaver = getWeaverService();
if (weaver == null) {
- Slog.e(TAG, "No weaver service to verify SP-based FRP credential");
+ Slog.e(TAG, "No weaver service to verify SP-based persistent data credential");
return VerifyCredentialResponse.ERROR;
}
PasswordData pwd = PasswordData.fromBytes(persistentData.payload);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
index dc47b87cad2d..70150c507460 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenRepairModeTest.java
@@ -16,6 +16,7 @@
package com.android.server.locksettings;
+import static com.android.internal.widget.LockPatternUtils.USER_REPAIR_MODE;
import static com.android.internal.widget.LockPatternUtils.VERIFY_FLAG_WRITE_REPAIR_MODE_PW;
import static org.junit.Assert.assertEquals;
@@ -31,7 +32,6 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.VerifyCredentialResponse;
import com.android.server.locksettings.LockSettingsStorage.PersistentData;
-import com.android.server.locksettings.SyntheticPasswordManager.PasswordData;
import org.junit.Before;
import org.junit.Test;
@@ -58,7 +58,7 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests {
newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
.getResponseCode());
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
- getCredentialType(mStorage.readRepairModePersistentData()));
+ mService.getCredentialType(USER_REPAIR_MODE));
}
@Test
@@ -71,7 +71,7 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests {
newPattern("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
.getResponseCode());
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
- getCredentialType(mStorage.readRepairModePersistentData()));
+ mService.getCredentialType(USER_REPAIR_MODE));
}
@Test
@@ -84,7 +84,7 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests {
newPassword("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
.getResponseCode());
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
- getCredentialType(mStorage.readRepairModePersistentData()));
+ mService.getCredentialType(USER_REPAIR_MODE));
}
@Test
@@ -109,21 +109,98 @@ public class LockscreenRepairModeTest extends BaseLockSettingsServiceTests {
newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
.getResponseCode());
assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
- getCredentialType(mStorage.readRepairModePersistentData()));
+ mService.getCredentialType(USER_REPAIR_MODE));
mService.deleteRepairModePersistentDataIfNeeded();
assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
}
+ @Test
+ public void verifyPin_userRepairMode() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyPattern_userRepairMode() {
+ mService.setLockCredential(newPattern("4321"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPattern("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PATTERN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPattern("4321"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyPassword_userRepairMode() {
+ mService.setLockCredential(newPassword("4321"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPassword("4321"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(newPassword("4321"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyCredential_userRepairMode_repairModeIsNotActive() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
+ mService.verifyCredential(newPin("1234"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
+ @Test
+ public void verifyCredential_userRepairMode_wrongPin() {
+ mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
+ assertSame(PersistentData.NONE, mStorage.readRepairModePersistentData());
+ assertEquals(VerifyCredentialResponse.RESPONSE_OK,
+ mService.verifyCredential(
+ newPin("1234"), PRIMARY_USER_ID, VERIFY_FLAG_WRITE_REPAIR_MODE_PW)
+ .getResponseCode());
+ setRepairModeActive(true);
+
+ assertEquals(LockPatternUtils.CREDENTIAL_TYPE_PIN,
+ mService.getCredentialType(USER_REPAIR_MODE));
+ assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
+ mService.verifyCredential(newPin("5678"), USER_REPAIR_MODE, 0 /* flags */)
+ .getResponseCode());
+ }
+
private void setRepairModeActive(boolean active) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.REPAIR_MODE_ACTIVE, active ? 1 : 0);
}
-
- private static int getCredentialType(PersistentData persistentData) {
- if (persistentData == null || persistentData.payload == null) {
- return LockPatternUtils.CREDENTIAL_TYPE_NONE;
- }
- return PasswordData.fromBytes(persistentData.payload).credentialType;
- }
}