Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f5d0b425 authored by Rubin Xu's avatar Rubin Xu
Browse files

Recognize numeric PIN in resetPasswordWithToken()

If the new password is numeric only, treat it as numeric
PIN when setting it as new lockscreen password.

Bug: 172054475
Bug: 181489206
Test: atest FrameworksServicesTests:DevicePolicyManagerTest
Change-Id: Ie15f1966a76344d3bb8e8778599fbd604bfa8c69
parent 397cb14b
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -691,6 +691,19 @@ public final class PasswordMetrics implements Parcelable {
        return minMetrics;
    }

    /**
     * Returns true if password is non-empty and contains digits only.
     * @param password
     * @return
     */
    public static boolean isNumericOnly(@NonNull String password) {
        if (password.length() == 0) return false;
        for (int i = 0; i < password.length(); i++) {
            if (categoryChar(password.charAt(i)) != CHAR_DIGIT) return false;
        }
        return true;
    }

    @Override
    public boolean equals(@Nullable Object o) {
        if (this == o) return true;
+9 −4
Original line number Diff line number Diff line
@@ -4954,6 +4954,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            int flags, CallerIdentity caller) {
        final int callingUid = caller.getUid();
        final int userHandle = UserHandle.getUserId(callingUid);
        final boolean isPin = PasswordMetrics.isNumericOnly(password);
        synchronized (getLockObject()) {
            final PasswordMetrics minMetrics = getPasswordMinimumMetricsUnchecked(userHandle);
            final List<PasswordValidationError> validationErrors;
@@ -4961,12 +4962,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
            // TODO: Consider changing validation API to take LockscreenCredential.
            if (password.isEmpty()) {
                validationErrors = PasswordMetrics.validatePasswordMetrics(
                        minMetrics, complexity, false /* isPin */,
                        minMetrics, complexity, isPin,
                        new PasswordMetrics(CREDENTIAL_TYPE_NONE));
            } else {
                // TODO(b/120484642): remove getBytes() below
                validationErrors = PasswordMetrics.validatePassword(
                        minMetrics, complexity, false, password.getBytes());
                        minMetrics, complexity, isPin, password.getBytes());
            }
            if (!validationErrors.isEmpty()) {
@@ -4992,8 +4993,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        // Don't do this with the lock held, because it is going to call
        // back in to the service.
        final long ident = mInjector.binderClearCallingIdentity();
        final LockscreenCredential newCredential =
                LockscreenCredential.createPasswordOrNone(password);
        final LockscreenCredential newCredential;
        if (isPin) {
            newCredential = LockscreenCredential.createPin(password);
        } else {
            newCredential = LockscreenCredential.createPasswordOrNone(password);
        }
        try {
            if (tokenHandle == 0 || token == null) {
                if (!mLockPatternUtils.setLockCredential(newCredential,
+40 −0
Original line number Diff line number Diff line
@@ -5089,6 +5089,46 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        assertThat(dpm.clearResetPasswordToken(admin1)).isTrue();
    }

    @Test
    public void resetPasswordWithToken_NumericPin() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // adding a token
        final byte[] token = new byte[32];
        final long handle = 123456;
        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
                nullable(EscrowTokenStateChangeCallback.class)))
                .thenReturn(handle);
        assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue();

        // Test resetting with a numeric pin
        final String pin = "123456";
        when(getServices().lockPatternUtils.setLockCredentialWithToken(
                LockscreenCredential.createPin(pin), handle, token,
                UserHandle.USER_SYSTEM)).thenReturn(true);
        assertThat(dpm.resetPasswordWithToken(admin1, pin, token, 0)).isTrue();
    }

    @Test
    public void resetPasswordWithToken_EmptyPassword() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
        setupDeviceOwner();
        // adding a token
        final byte[] token = new byte[32];
        final long handle = 123456;
        when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
                nullable(EscrowTokenStateChangeCallback.class)))
                .thenReturn(handle);
        assertThat(dpm.setResetPasswordToken(admin1, token)).isTrue();

        // Test resetting with an empty password
        final String password = "";
        when(getServices().lockPatternUtils.setLockCredentialWithToken(
                LockscreenCredential.createNone(), handle, token,
                UserHandle.USER_SYSTEM)).thenReturn(true);
        assertThat(dpm.resetPasswordWithToken(admin1, password, token, 0)).isTrue();
    }

    @Test
    public void testIsActivePasswordSufficient() throws Exception {
        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;