Loading core/java/android/app/admin/DevicePolicyManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -3020,6 +3020,10 @@ public class DevicePolicyManager { * * <p><strong>Note:</strong> Specifying password requirements using this method clears the * password complexity requirements set using {@link #setRequiredPasswordComplexity(int)}. * If this method is called on the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)}, then password complexity requirements * set on the primary {@link DevicePolicyManager} must be cleared first by calling * {@link #setRequiredPasswordComplexity} with {@link #PASSWORD_COMPLEXITY_NONE) first. * * @deprecated Prefer using {@link #setRequiredPasswordComplexity(int)}, to require a password * that satisfies a complexity level defined by the platform, rather than specifying custom Loading @@ -3039,6 +3043,9 @@ public class DevicePolicyManager { * calling app is targeting {@link android.os.Build.VERSION_CODES#S} and above, * and is calling the method the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)}. * @throws IllegalStateException if the caller is trying to set password quality on the parent * {@link DevicePolicyManager} instance while password complexity was set on the * primary {@link DevicePolicyManager} instance. */ @Deprecated public void setPasswordQuality(@NonNull ComponentName admin, int quality) { Loading Loading @@ -4055,10 +4062,18 @@ public class DevicePolicyManager { * <p><strong>Note:</strong> Specifying password requirements using this method clears any * password requirements set using the obsolete {@link #setPasswordQuality(ComponentName, int)} * and any of its associated methods. * Additionally, if there are password requirements set using the obsolete * {@link #setPasswordQuality(ComponentName, int)} on the parent {@code DevicePolicyManager} * instance, they must be cleared by calling {@link #setPasswordQuality(ComponentName, int)} * with {@link #PASSWORD_QUALITY_UNSPECIFIED} on that instance prior to setting complexity * requirement for the managed profile. * * @throws SecurityException if the calling application is not a device owner or a profile * owner. * @throws IllegalArgumentException if the complexity level is not one of the four above. * @throws IllegalStateException if the caller is trying to set password complexity while there * are password requirements specified using {@link #setPasswordQuality(ComponentName, int)} * on the parent {@code DevicePolicyManager} instance. */ public void setRequiredPasswordComplexity(@PasswordComplexity int passwordComplexity) { if (mService == null) { Loading services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +27 −0 Original line number Diff line number Diff line Loading @@ -3432,6 +3432,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { ActiveAdmin ap = getActiveAdminForCallerLocked( who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); // If setPasswordQuality is called on the parent, ensure that // the primary admin does not have password complexity state (this is an // unsupported state). if (parent) { final ActiveAdmin primaryAdmin = getActiveAdminForCallerLocked( who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, false); final boolean hasComplexitySet = primaryAdmin.mPasswordComplexity != PASSWORD_COMPLEXITY_NONE; Preconditions.checkState(!hasComplexitySet, "Cannot set password quality when complexity is set on the primary admin." + " Set the primary admin's complexity to NONE first."); } mInjector.binderWithCleanCallingIdentity(() -> { final PasswordPolicy passwordPolicy = ap.mPasswordPolicy; if (passwordPolicy.quality != quality) { Loading Loading @@ -4397,6 +4410,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final ActiveAdmin admin = getParentOfAdminIfRequired( getProfileOwnerOrDeviceOwnerLocked(caller), calledOnParent); if (admin.mPasswordComplexity != passwordComplexity) { // We require the caller to explicitly clear any password quality requirements set // on the parent DPM instance, to avoid the case where password requirements are // specified in the form of quality on the parent but complexity on the profile // itself. if (!calledOnParent) { final boolean hasQualityRequirementsOnParent = admin.hasParentActiveAdmin() && admin.getParentActiveAdmin().mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED; Preconditions.checkState(!hasQualityRequirementsOnParent, "Password quality is set on the parent when attempting to set password" + "complexity. Clear the quality by setting the password quality " + "on the parent to PASSWORD_QUALITY_UNSPECIFIED first"); } mInjector.binderWithCleanCallingIdentity(() -> { admin.mPasswordComplexity = passwordComplexity; // Reset the password policy. Loading services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +29 −0 Original line number Diff line number Diff line Loading @@ -6918,6 +6918,35 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); } @Test public void testSetRequiredPasswordComplexityFailsWithQualityOnParent() throws Exception { final int managedProfileUserId = CALLER_USER_HANDLE; final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = managedProfileAdminUid; addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R); parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX); assertThrows(IllegalStateException.class, () -> dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH)); } @Test public void testSetQualityOnParentFailsWithComplexityOnProfile() throws Exception { final int managedProfileUserId = CALLER_USER_HANDLE; final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = managedProfileAdminUid; addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R); dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH); assertThrows(IllegalStateException.class, () -> parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX)); } private void setUserUnlocked(int userHandle, boolean unlocked) { when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked); } Loading Loading
core/java/android/app/admin/DevicePolicyManager.java +15 −0 Original line number Diff line number Diff line Loading @@ -3020,6 +3020,10 @@ public class DevicePolicyManager { * * <p><strong>Note:</strong> Specifying password requirements using this method clears the * password complexity requirements set using {@link #setRequiredPasswordComplexity(int)}. * If this method is called on the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)}, then password complexity requirements * set on the primary {@link DevicePolicyManager} must be cleared first by calling * {@link #setRequiredPasswordComplexity} with {@link #PASSWORD_COMPLEXITY_NONE) first. * * @deprecated Prefer using {@link #setRequiredPasswordComplexity(int)}, to require a password * that satisfies a complexity level defined by the platform, rather than specifying custom Loading @@ -3039,6 +3043,9 @@ public class DevicePolicyManager { * calling app is targeting {@link android.os.Build.VERSION_CODES#S} and above, * and is calling the method the {@link DevicePolicyManager} instance returned by * {@link #getParentProfileInstance(ComponentName)}. * @throws IllegalStateException if the caller is trying to set password quality on the parent * {@link DevicePolicyManager} instance while password complexity was set on the * primary {@link DevicePolicyManager} instance. */ @Deprecated public void setPasswordQuality(@NonNull ComponentName admin, int quality) { Loading Loading @@ -4055,10 +4062,18 @@ public class DevicePolicyManager { * <p><strong>Note:</strong> Specifying password requirements using this method clears any * password requirements set using the obsolete {@link #setPasswordQuality(ComponentName, int)} * and any of its associated methods. * Additionally, if there are password requirements set using the obsolete * {@link #setPasswordQuality(ComponentName, int)} on the parent {@code DevicePolicyManager} * instance, they must be cleared by calling {@link #setPasswordQuality(ComponentName, int)} * with {@link #PASSWORD_QUALITY_UNSPECIFIED} on that instance prior to setting complexity * requirement for the managed profile. * * @throws SecurityException if the calling application is not a device owner or a profile * owner. * @throws IllegalArgumentException if the complexity level is not one of the four above. * @throws IllegalStateException if the caller is trying to set password complexity while there * are password requirements specified using {@link #setPasswordQuality(ComponentName, int)} * on the parent {@code DevicePolicyManager} instance. */ public void setRequiredPasswordComplexity(@PasswordComplexity int passwordComplexity) { if (mService == null) { Loading
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +27 −0 Original line number Diff line number Diff line Loading @@ -3432,6 +3432,19 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { synchronized (getLockObject()) { ActiveAdmin ap = getActiveAdminForCallerLocked( who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, parent); // If setPasswordQuality is called on the parent, ensure that // the primary admin does not have password complexity state (this is an // unsupported state). if (parent) { final ActiveAdmin primaryAdmin = getActiveAdminForCallerLocked( who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, false); final boolean hasComplexitySet = primaryAdmin.mPasswordComplexity != PASSWORD_COMPLEXITY_NONE; Preconditions.checkState(!hasComplexitySet, "Cannot set password quality when complexity is set on the primary admin." + " Set the primary admin's complexity to NONE first."); } mInjector.binderWithCleanCallingIdentity(() -> { final PasswordPolicy passwordPolicy = ap.mPasswordPolicy; if (passwordPolicy.quality != quality) { Loading Loading @@ -4397,6 +4410,20 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final ActiveAdmin admin = getParentOfAdminIfRequired( getProfileOwnerOrDeviceOwnerLocked(caller), calledOnParent); if (admin.mPasswordComplexity != passwordComplexity) { // We require the caller to explicitly clear any password quality requirements set // on the parent DPM instance, to avoid the case where password requirements are // specified in the form of quality on the parent but complexity on the profile // itself. if (!calledOnParent) { final boolean hasQualityRequirementsOnParent = admin.hasParentActiveAdmin() && admin.getParentActiveAdmin().mPasswordPolicy.quality != PASSWORD_QUALITY_UNSPECIFIED; Preconditions.checkState(!hasQualityRequirementsOnParent, "Password quality is set on the parent when attempting to set password" + "complexity. Clear the quality by setting the password quality " + "on the parent to PASSWORD_QUALITY_UNSPECIFIED first"); } mInjector.binderWithCleanCallingIdentity(() -> { admin.mPasswordComplexity = passwordComplexity; // Reset the password policy. Loading
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +29 −0 Original line number Diff line number Diff line Loading @@ -6918,6 +6918,35 @@ public class DevicePolicyManagerTest extends DpmTestBase { DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED); } @Test public void testSetRequiredPasswordComplexityFailsWithQualityOnParent() throws Exception { final int managedProfileUserId = CALLER_USER_HANDLE; final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = managedProfileAdminUid; addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R); parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX); assertThrows(IllegalStateException.class, () -> dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH)); } @Test public void testSetQualityOnParentFailsWithComplexityOnProfile() throws Exception { final int managedProfileUserId = CALLER_USER_HANDLE; final int managedProfileAdminUid = UserHandle.getUid(managedProfileUserId, DpmMockContext.SYSTEM_UID); mContext.binder.callingUid = managedProfileAdminUid; addManagedProfile(admin1, managedProfileAdminUid, admin1, VERSION_CODES.R); dpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH); assertThrows(IllegalStateException.class, () -> parentDpm.setPasswordQuality(admin1, DevicePolicyManager.PASSWORD_QUALITY_COMPLEX)); } private void setUserUnlocked(int userHandle, boolean unlocked) { when(getServices().userManager.isUserUnlocked(eq(userHandle))).thenReturn(unlocked); } Loading