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

Commit 7f88b683 authored by Pavel Grafov's avatar Pavel Grafov Committed by Android (Google) Code Review
Browse files

Merge "Respect admin requirements when changing password via adb command"

parents 767a899a a182b9cb
Loading
Loading
Loading
Loading
+64 −23
Original line number Diff line number Diff line
@@ -16,14 +16,22 @@

package com.android.server.locksettings;

import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;

import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE;
import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;

import android.app.ActivityManager;
import android.app.admin.PasswordMetrics;
import android.os.ShellCommand;

import com.android.internal.widget.LockPatternUtils;
import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
import com.android.internal.widget.LockscreenCredential;
import com.android.internal.widget.PasswordValidationError;

import java.io.PrintWriter;
import java.util.List;

class LockSettingsShellCommand extends ShellCommand {

@@ -70,18 +78,19 @@ class LockSettingsShellCommand extends ShellCommand {
            if (!checkCredential()) {
                return -1;
            }
            boolean success = true;
            switch (cmd) {
                case COMMAND_SET_PATTERN:
                    runSetPattern();
                    success = runSetPattern();
                    break;
                case COMMAND_SET_PASSWORD:
                    runSetPassword();
                    success = runSetPassword();
                    break;
                case COMMAND_SET_PIN:
                    runSetPin();
                    success = runSetPin();
                    break;
                case COMMAND_CLEAR:
                    runClear();
                    success = runClear();
                    break;
                case COMMAND_SP:
                    runChangeSp();
@@ -102,7 +111,7 @@ class LockSettingsShellCommand extends ShellCommand {
                    getErrPrintWriter().println("Unknown command: " + cmd);
                    break;
            }
            return 0;
            return success ? 0 : -1;
        } catch (Exception e) {
            getErrPrintWriter().println("Error while executing command: " + cmd);
            e.printStackTrace(getErrPrintWriter());
@@ -201,34 +210,66 @@ class LockSettingsShellCommand extends ShellCommand {
        }
    }

    private void runSetPattern() {
        mLockPatternUtils.setLockCredential(
                LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern(
                        mNew.getBytes())),
                getOldCredential(),
                mCurrentUserId);
    private boolean runSetPattern() {
        final LockscreenCredential pattern = LockscreenCredential.createPattern(
                LockPatternUtils.byteArrayToPattern(mNew.getBytes()));
        if (!isNewCredentialSufficient(pattern)) {
            return false;
        }
        mLockPatternUtils.setLockCredential(pattern, getOldCredential(), mCurrentUserId);
        getOutPrintWriter().println("Pattern set to '" + mNew + "'");
        return true;
    }

    private void runSetPassword() {
        mLockPatternUtils.setLockCredential(LockscreenCredential.createPassword(mNew),
                getOldCredential(),
                mCurrentUserId);
    private boolean runSetPassword() {
        final LockscreenCredential password = LockscreenCredential.createPassword(mNew);
        if (!isNewCredentialSufficient(password)) {
            return false;
        }
        mLockPatternUtils.setLockCredential(password, getOldCredential(), mCurrentUserId);
        getOutPrintWriter().println("Password set to '" + mNew + "'");
        return true;
    }

    private void runSetPin() {
        mLockPatternUtils.setLockCredential(LockscreenCredential.createPin(mNew),
                getOldCredential(),
                mCurrentUserId);
    private boolean runSetPin() {
        final LockscreenCredential pin = LockscreenCredential.createPin(mNew);
        if (!isNewCredentialSufficient(pin)) {
            return false;
        }
        mLockPatternUtils.setLockCredential(pin, getOldCredential(), mCurrentUserId);
        getOutPrintWriter().println("Pin set to '" + mNew + "'");
        return true;
    }

    private void runClear() {
        mLockPatternUtils.setLockCredential(LockscreenCredential.createNone(),
                getOldCredential(),
                mCurrentUserId);
    private boolean runClear() {
        LockscreenCredential none = LockscreenCredential.createNone();
        if (!isNewCredentialSufficient(none)) {
            return false;
        }
        mLockPatternUtils.setLockCredential(none, getOldCredential(), mCurrentUserId);
        getOutPrintWriter().println("Lock credential cleared");
        return true;
    }

    private boolean isNewCredentialSufficient(LockscreenCredential credential) {
        final PasswordMetrics requiredMetrics =
                mLockPatternUtils.getRequestedPasswordMetrics(mCurrentUserId);
        final List<PasswordValidationError> errors;
        if (credential.isPassword() || credential.isPin()) {
            errors = PasswordMetrics.validatePassword(requiredMetrics, PASSWORD_COMPLEXITY_NONE,
                    credential.isPin(), credential.getCredential());
        } else {
            PasswordMetrics metrics = new PasswordMetrics(
                    credential.isPattern() ? CREDENTIAL_TYPE_PATTERN : CREDENTIAL_TYPE_NONE);
            errors = PasswordMetrics.validatePasswordMetrics(
                    requiredMetrics, PASSWORD_COMPLEXITY_NONE, false /* isPin */, metrics);
        }
        if (!errors.isEmpty()) {
            getOutPrintWriter().println(
                    "New credential doesn't satisfy admin policies: " + errors.get(0));
            return false;
        }
        return true;
    }

    private void runSetDisabled() {
+88 −5
Original line number Diff line number Diff line
@@ -17,11 +17,13 @@
package com.android.server.locksettings;

import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;

import static junit.framework.Assert.assertEquals;

import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.never;
@@ -34,6 +36,8 @@ import static java.io.FileDescriptor.in;
import static java.io.FileDescriptor.out;

import android.app.ActivityManager;
import android.app.admin.PasswordMetrics;
import android.app.admin.PasswordPolicy;
import android.content.Context;
import android.os.Binder;
import android.os.Handler;
@@ -96,8 +100,7 @@ public class LockSettingsShellCommandTest {
        assertEquals(-1, mCommand.exec(mBinder, in, out, err,
                new String[] { "set-pin", "--old", "1234" },
                mShellCallback, mResultReceiver));
        verify(mLockPatternUtils, never()).setLockCredential(any(), any(),
                anyInt(), anyBoolean());
        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
    }

    @Test
@@ -109,6 +112,8 @@ public class LockSettingsShellCommandTest {
                PASSWORD_QUALITY_NUMERIC);
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_NUMERIC));
        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
                new String[] { "set-pin", "--old", "1234", "4321" },
                mShellCallback, mResultReceiver));
@@ -118,6 +123,23 @@ public class LockSettingsShellCommandTest {
                mUserId);
    }

    @Test
    public void testChangePin_nonCompliant() throws Exception {
        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
        when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
                PASSWORD_QUALITY_NUMERIC);
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPin("1234"), mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_ALPHABETIC));
        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
                new String[] { "set-pin", "--old", "1234", "4321" },
                mShellCallback, mResultReceiver));
        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
    }

    @Test
    public void testChangePin_noLockScreen() throws Exception {
        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
@@ -137,15 +159,34 @@ public class LockSettingsShellCommandTest {
                PASSWORD_QUALITY_ALPHABETIC);
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPassword("1234"), mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_ALPHABETIC));
        assertEquals(0,  mCommand.exec(new Binder(), in, out, err,
                new String[] { "set-password", "--old", "1234", "4321" },
                new String[] { "set-password", "--old", "1234", "abcd" },
                mShellCallback, mResultReceiver));
        verify(mLockPatternUtils).setLockCredential(
                LockscreenCredential.createPassword("4321"),
                LockscreenCredential.createPassword("abcd"),
                LockscreenCredential.createPassword("1234"),
                mUserId);
    }

    @Test
    public void testChangePassword_nonCompliant() throws Exception {
        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false);
        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true);
        when(mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId)).thenReturn(
                PASSWORD_QUALITY_ALPHABETIC);
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPassword("1234"), mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_COMPLEX));
        assertEquals(-1,  mCommand.exec(new Binder(), in, out, err,
                new String[] { "set-password", "--old", "1234", "weakpassword" },
                mShellCallback, mResultReceiver));
        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
    }

    @Test
    public void testChangePassword_noLockScreen() throws Exception {
        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
@@ -164,6 +205,8 @@ public class LockSettingsShellCommandTest {
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPattern(stringToPattern("1234")),
                mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_SOMETHING));
        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
                new String[] { "set-pattern", "--old", "1234", "4321" },
                mShellCallback, mResultReceiver));
@@ -173,6 +216,22 @@ public class LockSettingsShellCommandTest {
                mUserId);
    }

    @Test
    public void testChangePattern_nonCompliant() throws Exception {
        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPattern(stringToPattern("1234")),
                mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_NUMERIC));
        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
                new String[] { "set-pattern", "--old", "1234", "4321" },
                mShellCallback, mResultReceiver));
        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
    }

    @Test
    public void testChangePattern_noLockScreen() throws Exception {
        when(mLockPatternUtils.hasSecureLockScreen()).thenReturn(false);
@@ -191,6 +250,8 @@ public class LockSettingsShellCommandTest {
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPattern(stringToPattern("1234")),
                mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_UNSPECIFIED));
        assertEquals(0, mCommand.exec(new Binder(), in, out, err,
                new String[] { "clear", "--old", "1234" },
                mShellCallback, mResultReceiver));
@@ -200,7 +261,29 @@ public class LockSettingsShellCommandTest {
                mUserId);
    }

    @Test
    public void testClear_nonCompliant() throws Exception {
        when(mLockPatternUtils.isSecure(mUserId)).thenReturn(true);
        when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(true);
        when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(false);
        when(mLockPatternUtils.checkCredential(
                LockscreenCredential.createPattern(stringToPattern("1234")),
                mUserId, null)).thenReturn(true);
        when(mLockPatternUtils.getRequestedPasswordMetrics(mUserId))
                .thenReturn(metricsForAdminQuality(PASSWORD_QUALITY_SOMETHING));
        assertEquals(-1, mCommand.exec(new Binder(), in, out, err,
                new String[] { "clear", "--old", "1234" },
                mShellCallback, mResultReceiver));
        verify(mLockPatternUtils, never()).setLockCredential(any(), any(), anyInt());
    }

    private List<LockPatternView.Cell> stringToPattern(String str) {
        return LockPatternUtils.byteArrayToPattern(str.getBytes());
    }

    private PasswordMetrics metricsForAdminQuality(int quality) {
        PasswordPolicy policy = new PasswordPolicy();
        policy.quality = quality;
        return policy.getMinMetrics();
    }
}