Add CTS test for password reset token when device lock is cleared

This is to prevent regression when password reset token on work profile
with unified work challenge gets invalidated if the device lock is cleared
and re-added.

Bug: 65579699
Test: cts-tradefed run commandAndExit cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.ManagedProfileTest#testResetPasswordTokenUsableAfterClearingLock
Change-Id: Ia6ec0d7f09cf1e61c6fc2cac154c09e3e734ce3c
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ResetPasswordWithTokenTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ResetPasswordWithTokenTest.java
index 26c200d..6487b50 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ResetPasswordWithTokenTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ResetPasswordWithTokenTest.java
@@ -24,6 +24,7 @@
 public class ResetPasswordWithTokenTest extends BaseManagedProfileTest {
 
     private static final String PASSWORD0 = "1234";
+    // This needs to be in sync with ManagedProfileTest.RESET_PASSWORD_TEST_DEFAULT_PASSWORD
     private static final String PASSWORD1 = "123456";
 
     private static final byte[] token = "abcdefghijklmnopqrstuvwxyz0123456789".getBytes();
@@ -44,9 +45,8 @@
      * to put the profile in RUNNING_LOCKED state, and will be called by the hostside logic before
      * {@link #testResetPasswordBeforeUnlock} is exercised.
      */
-    public void setupWorkProfileAndLock() {
-        assertTrue(mDevicePolicyManager.setResetPasswordToken(ADMIN_RECEIVER_COMPONENT, token));
-        assertTrue(mDevicePolicyManager.isResetPasswordTokenActive(ADMIN_RECEIVER_COMPONENT));
+    public void testSetupWorkProfileAndLock() {
+        testSetResetPasswordToken();
         // Reset password on the work profile will enable separate work challenge for it.
         assertTrue(mDevicePolicyManager.resetPasswordWithToken(ADMIN_RECEIVER_COMPONENT, PASSWORD0,
                 token, 0));
@@ -55,7 +55,7 @@
                 DevicePolicyManager.PASSWORD_QUALITY_NUMERIC);
         mDevicePolicyManager.setPasswordMinimumLength(ADMIN_RECEIVER_COMPONENT, 6);
 
-        mDevicePolicyManager.lockNow(DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY);
+        testLockWorkProfile();
     }
 
     public void testResetPasswordBeforeUnlock() {
@@ -69,4 +69,13 @@
             fail("Did not throw expected exception.");
         } catch (IllegalStateException expected) {}
     }
+
+    public void testSetResetPasswordToken() {
+        assertTrue(mDevicePolicyManager.setResetPasswordToken(ADMIN_RECEIVER_COMPONENT, token));
+        assertTrue(mDevicePolicyManager.isResetPasswordTokenActive(ADMIN_RECEIVER_COMPONENT));
+    }
+
+    public void testLockWorkProfile() {
+        mDevicePolicyManager.lockNow(DevicePolicyManager.FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY);
+    }
 }
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 27f479f..157c59c 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -84,6 +84,9 @@
 
     private static final String PARAM_PROFILE_ID = "profile-id";
 
+    // Password needs to be in sync with ResetPasswordWithTokenTest.PASSWORD1
+    private static final String RESET_PASSWORD_TEST_DEFAULT_PASSWORD = "123456";
+
     private int mParentUserId;
 
     // ID of the profile we'll create. This will always be a profile of the parent.
@@ -982,12 +985,47 @@
         }
 
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ResetPasswordWithTokenTest",
-                "setupWorkProfileAndLock", mProfileUserId);
+                "testSetupWorkProfileAndLock", mProfileUserId);
         waitUntilProfileLocked();
         runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ResetPasswordWithTokenTest",
                 "testResetPasswordBeforeUnlock", mProfileUserId);
         // Password needs to be in sync with ResetPasswordWithTokenTest.PASSWORD1
-        verifyUserCredential("123456", mProfileUserId);
+        verifyUserCredential(RESET_PASSWORD_TEST_DEFAULT_PASSWORD, mProfileUserId);
+    }
+
+    /**
+     * Test password reset token is still functional after the primary user clears and
+     * re-adds back its device lock. This is to detect a regression where the work profile
+     * undergoes an untrusted credential reset (causing synthetic password to change, invalidating
+     * existing password reset token) if it has unified work challenge and the primary user clears
+     * the device lock.
+     */
+    public void testResetPasswordTokenUsableAfterClearingLock() throws Exception {
+        if (!mHasFeature || !mSupportsFbe) {
+            return;
+        }
+        final String devicePassword = "1234";
+
+        runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ResetPasswordWithTokenTest",
+                "testSetResetPasswordToken", mProfileUserId);
+        try {
+            changeUserCredential(devicePassword, null, mParentUserId);
+            changeUserCredential(null, devicePassword, mParentUserId);
+            changeUserCredential(devicePassword, null, mParentUserId);
+
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ResetPasswordWithTokenTest",
+                    "testLockWorkProfile", mProfileUserId);
+            waitUntilProfileLocked();
+            runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".ResetPasswordWithTokenTest",
+                    "testResetPasswordBeforeUnlock", mProfileUserId);
+            verifyUserCredential(RESET_PASSWORD_TEST_DEFAULT_PASSWORD, mProfileUserId);
+        } finally {
+            changeUserCredential(null, devicePassword, mParentUserId);
+            // Cycle the device screen to flush stale password information from keyguard,
+            // otherwise it will still ask for the non-existent password.
+            executeShellCommand("input keyevent KEYCODE_WAKEUP");
+            executeShellCommand("input keyevent KEYCODE_SLEEP");
+        }
     }
 
     private void disableActivityForUser(String activityName, int userId)