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

Commit 533759ec authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Enforce profile password quality policy on unified device lock" into sc-dev am: b8a73935

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/15123981

Change-Id: Ie48d4af31eab2ef702aba693cf0797c5fdcc3813
parents 1e970869 b8a73935
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -104,8 +104,6 @@ class ActiveAdmin {
    private static final String TAG_PASSWORD_HISTORY_LENGTH = "password-history-length";
    private static final String TAG_MIN_PASSWORD_LENGTH = "min-password-length";
    private static final String TAG_PASSWORD_QUALITY = "password-quality";
    private static final String TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT =
            "password-quality-applies-parent";
    private static final String TAG_POLICIES = "policies";
    private static final String TAG_CROSS_PROFILE_WIDGET_PROVIDERS =
            "cross-profile-widget-providers";
@@ -158,7 +156,6 @@ class ActiveAdmin {

    @NonNull
    PasswordPolicy mPasswordPolicy = new PasswordPolicy();
    boolean mPasswordPolicyAppliesToParent = true;

    @DevicePolicyManager.PasswordComplexity
    int mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
@@ -363,9 +360,6 @@ class ActiveAdmin {
                writeAttributeValueToXml(
                        out, TAG_MIN_PASSWORD_NONLETTER, mPasswordPolicy.nonLetter);
            }

            writeAttributeValueToXml(out, TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT,
                    mPasswordPolicyAppliesToParent);
        }
        if (passwordHistoryLength != DEF_PASSWORD_HISTORY_LENGTH) {
            writeAttributeValueToXml(
@@ -669,8 +663,6 @@ class ActiveAdmin {
                mPasswordPolicy.symbols = parser.getAttributeInt(null, ATTR_VALUE);
            } else if (TAG_MIN_PASSWORD_NONLETTER.equals(tag)) {
                mPasswordPolicy.nonLetter = parser.getAttributeInt(null, ATTR_VALUE);
            } else if (TAG_PASSWORD_QUALITY_APPLIES_TO_PARENT.equals(tag)) {
                mPasswordPolicyAppliesToParent = parser.getAttributeBoolean(null, ATTR_VALUE);
            } else if (TAG_MAX_TIME_TO_UNLOCK.equals(tag)) {
                maximumTimeToUnlock = parser.getAttributeLong(null, ATTR_VALUE);
            } else if (TAG_STRONG_AUTH_UNLOCK_TIMEOUT.equals(tag)) {
@@ -1036,9 +1028,6 @@ class ActiveAdmin {
        pw.print("minimumPasswordNonLetter=");
        pw.println(mPasswordPolicy.nonLetter);

        pw.print("passwordPolicyAppliesToParent=");
        pw.println(mPasswordPolicyAppliesToParent);

        pw.print("maximumTimeToUnlock=");
        pw.println(maximumTimeToUnlock);

+5 −17
Original line number Diff line number Diff line
@@ -3827,10 +3827,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                isProfileOwner(caller) || isDeviceOwner(caller) || isSystemUid(caller)
                || isPasswordLimitingAdminTargetingP(caller));
        final boolean qualityMayApplyToParent =
                canSetPasswordQualityOnParent(who.getPackageName(), caller);
        if (!qualityMayApplyToParent) {
            Preconditions.checkCallAuthorization(!parent,
        if (parent) {
            Preconditions.checkCallAuthorization(
                    canSetPasswordQualityOnParent(who.getPackageName(), caller),
                    "Profile Owner may not apply password quality requirements device-wide");
        }
@@ -3856,7 +3855,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                if (passwordPolicy.quality != quality) {
                    passwordPolicy.quality = quality;
                    ap.mPasswordComplexity = PASSWORD_COMPLEXITY_NONE;
                    ap.mPasswordPolicyAppliesToParent = qualityMayApplyToParent;
                    resetInactivePasswordRequirementsIfRPlus(userId, ap);
                    updatePasswordValidityCheckpointLocked(userId, parent);
                    updatePasswordQualityCacheForUserGroup(userId);
@@ -4588,8 +4586,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
        }
        ArrayList<PasswordMetrics> adminMetrics = new ArrayList<>();
        synchronized (getLockObject()) {
        final List<ActiveAdmin> admins;
        synchronized (getLockObject()) {
            if (deviceWideOnly) {
                admins = getActiveAdminsForUserAndItsManagedProfilesLocked(userId,
                        /* shouldIncludeProfileAdmins */ (user) -> false);
@@ -4597,18 +4595,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                admins = getActiveAdminsForLockscreenPoliciesLocked(userId);
            }
            for (ActiveAdmin admin : admins) {
                final boolean isAdminOfUser = userId == admin.getUserHandle().getIdentifier();
                // Use the password metrics from the admin in one of three cases:
                // (1) The admin is of the user we're getting the minimum metrics for. The admin
                //     always affects the user it's managing. This applies also to the parent
                //     ActiveAdmin instance: It'd have the same user handle.
                // (2) The mPasswordPolicyAppliesToParent field is true: That indicates the
                //     call to setPasswordQuality was made by an admin that may affect the parent.
                if (isAdminOfUser || admin.mPasswordPolicyAppliesToParent) {
                adminMetrics.add(admin.mPasswordPolicy.getMinMetrics());
            }
        }
        }
        return PasswordMetrics.merge(adminMetrics);
    }
@@ -4821,7 +4810,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
                    admin.mPasswordComplexity = passwordComplexity;
                    // Reset the password policy.
                    admin.mPasswordPolicy = new PasswordPolicy();
                    admin.mPasswordPolicyAppliesToParent = true;
                    updatePasswordValidityCheckpointLocked(caller.getUserId(), calledOnParent);
                    updatePasswordQualityCacheForUserGroup(caller.getUserId());
                    saveSettingsLocked(caller.getUserId());
+199 −0
Original line number Diff line number Diff line
@@ -5427,6 +5427,205 @@ public class DevicePolicyManagerTest extends DpmTestBase {
        }
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileQualityRequirementMet()
            throws Exception {
        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set profile password quality requirement. No password added yet so
        // profile.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();

        // Set a work challenge and verify profile.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
                .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ProfileComplexityRequirementMet()
            throws Exception {
        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set profile password complexity requirement. No password added yet so
        // profile.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();

        // Set a work challenge and verify profile.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(managedProfileUserId))
                .thenReturn(computeForPasswordOrPin("5156".getBytes(), /* isPin */ true));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ParentQualityRequirementMet()
            throws Exception {
        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set parent password quality requirement. No password added yet so
        // parent.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(computeForPasswordOrPin("acbdXYZ5".getBytes(), /* isPin */ false));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_SeparateWorkChallenge_ParentComplexityRequirementMet()
            throws Exception {
        // Create work profile with empty separate challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ true);

        // Set parent password complexity requirement. No password added yet so
        // parent.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify parent.isActivePasswordSufficient is now true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(computeForPasswordOrPin("1234".getBytes(), /* isPin */ true));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ProfileQualityRequirementMet()
            throws Exception {
        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set profile password quality requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ProfileComplexityRequirementMet()
            throws Exception {
        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set profile password complexity requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(computeForPasswordOrPin("51567548".getBytes(), /* isPin */ true));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ParentQualityRequirementMet()
            throws Exception {
        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set parent password quality requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(computeForPasswordOrPin("abcdXYZ5".getBytes(), /* isPin */ false));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    @Test
    public void isActivePasswordSufficient_UnifiedWorkChallenge_ParentComplexityRequirementMet()
            throws Exception {
        // Create work profile with unified challenge
        final int managedProfileUserId = 15;
        final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, 19436);
        addManagedProfileForPasswordTests(managedProfileUserId, managedProfileAdminUid,
                /* separateChallenge */ false);

        // Set parent password complexity requirement. No password added yet so
        // {profile, parent}.isActivePasswordSufficient should return false
        mContext.binder.callingUid = managedProfileAdminUid;
        parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM);
        assertThat(dpm.isActivePasswordSufficient()).isFalse();
        assertThat(parentDpm.isActivePasswordSufficient()).isFalse();

        // Set a device lockscreen and verify {profile, parent}.isActivePasswordSufficient is true
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(computeForPasswordOrPin("5156".getBytes(), /* isPin */ true));
        assertThat(dpm.isActivePasswordSufficient()).isTrue();
        assertThat(parentDpm.isActivePasswordSufficient()).isTrue();
    }

    private void addManagedProfileForPasswordTests(int userId, int adminUid,
            boolean separateChallenge) throws Exception {
        addManagedProfile(admin1, adminUid, admin1);
        when(getServices().userManager.getProfileParent(userId))
                .thenReturn(new UserInfo(UserHandle.USER_SYSTEM, "user system", 0));
        doReturn(separateChallenge).when(getServices().lockPatternUtils)
                .isSeparateProfileChallengeEnabled(userId);
        when(getServices().userManager.getCredentialOwnerProfile(userId))
                .thenReturn(separateChallenge ? userId : UserHandle.USER_SYSTEM);
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(userId))
                .thenReturn(new PasswordMetrics(CREDENTIAL_TYPE_NONE));
        when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM))
                .thenReturn(new PasswordMetrics(CREDENTIAL_TYPE_NONE));
    }

    @Test
    public void testPasswordQualityAppliesToParentPreS() throws Exception {
        final int managedProfileUserId = CALLER_USER_HANDLE;