Merge "Enforce profile password quality policy on unified device lock" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
b8a739355f
@@ -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);
|
||||
|
||||
|
||||
@@ -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<>();
|
||||
final List<ActiveAdmin> admins;
|
||||
synchronized (getLockObject()) {
|
||||
final List<ActiveAdmin> admins;
|
||||
if (deviceWideOnly) {
|
||||
admins = getActiveAdminsForUserAndItsManagedProfilesLocked(userId,
|
||||
/* shouldIncludeProfileAdmins */ (user) -> false);
|
||||
@@ -4597,16 +4595,7 @@ 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());
|
||||
}
|
||||
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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user