Enforce password complexity in lockscreen setting
Enforce a lock screen that adheres with the required complexity set by the admin. This is done by querying the DevicePolicyManager for the complexity set for the given user, and merging it with the complexity from the "change lock screen" intent (if any). If the admin sets a higher complexity requirement than the app triggering the lock screen change request, then the admin-set complexity is enforced and the user is not shown information about the requesting app. Bug: 165573442 Test: Manually, set complexity using TestDPC and see it applies. Test: m RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.password.ChooseLockGenericTest Test: m RunSettingsRoboTests ROBOTEST_FILTER=com.android.settings.password.ChooseLockPasswordTest Change-Id: If3f24f7430bdcbcd34265339f7d2a1ff82a44fc1
This commit is contained in:
@@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_HIGH;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_LOW;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_MEDIUM;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_COMPLEXITY_NONE;
|
||||
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
|
||||
|
||||
import static com.android.settings.password.ChooseLockGeneric.ChooseLockGenericFragment.KEY_LOCK_SETTINGS_FOOTER;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_CALLER_APP_NAME;
|
||||
@@ -90,6 +91,7 @@ public class ChooseLockGenericTest {
|
||||
Global.putInt(application.getContentResolver(), Global.DEVICE_PROVISIONED, 1);
|
||||
ShadowStorageManager.reset();
|
||||
ShadowPersistentDataBlockManager.reset();
|
||||
ShadowLockPatternUtils.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -377,6 +379,64 @@ public class ChooseLockGenericTest {
|
||||
ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_CREDENTIAL)).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreferencesOrFinish_ComplexityIsReadFromDPM() {
|
||||
ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
|
||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
|
||||
|
||||
initActivity(null);
|
||||
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||
|
||||
FooterPreference footer = mFragment.findPreference(KEY_LOCK_SETTINGS_FOOTER);
|
||||
assertThat(footer.getTitle()).isEqualTo(null);
|
||||
|
||||
Intent intent = mFragment.getLockPasswordIntent(PASSWORD_QUALITY_COMPLEX);
|
||||
assertThat(intent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
|
||||
PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreferencesOrFinish_ComplexityIsMergedWithDPM() {
|
||||
ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
|
||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_HIGH);
|
||||
Intent intent = new Intent()
|
||||
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
|
||||
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_LOW);
|
||||
initActivity(intent);
|
||||
|
||||
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||
|
||||
// Footer should be null because admin complexity wins.
|
||||
FooterPreference footer = mFragment.findPreference(KEY_LOCK_SETTINGS_FOOTER);
|
||||
assertThat(footer.getTitle()).isEqualTo(null);
|
||||
|
||||
Intent passwordIntent = mFragment.getLockPasswordIntent(PASSWORD_QUALITY_COMPLEX);
|
||||
assertThat(passwordIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
|
||||
PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updatePreferencesOrFinish_ComplexityIsMergedWithDPM_AppIsHigher() {
|
||||
ShadowStorageManager.setIsFileEncryptedNativeOrEmulated(false);
|
||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
|
||||
Intent intent = new Intent()
|
||||
.putExtra(EXTRA_KEY_CALLER_APP_NAME, "app name")
|
||||
.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, PASSWORD_COMPLEXITY_HIGH);
|
||||
initActivity(intent);
|
||||
|
||||
mFragment.updatePreferencesOrFinish(false /* isRecreatingActivity */);
|
||||
|
||||
// Footer should include app name because app requirement is higher.
|
||||
CharSequence expectedTitle =
|
||||
mActivity.getString(R.string.unlock_footer_high_complexity_requested, "app name");
|
||||
FooterPreference footer = mFragment.findPreference(KEY_LOCK_SETTINGS_FOOTER);
|
||||
assertThat(footer.getTitle()).isEqualTo(expectedTitle);
|
||||
|
||||
Intent passwordIntent = mFragment.getLockPasswordIntent(PASSWORD_QUALITY_COMPLEX);
|
||||
assertThat(passwordIntent.getIntExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
|
||||
PASSWORD_COMPLEXITY_NONE)).isEqualTo(PASSWORD_COMPLEXITY_HIGH);
|
||||
}
|
||||
|
||||
private void initActivity(@Nullable Intent intent) {
|
||||
if (intent == null) {
|
||||
intent = new Intent();
|
||||
|
@@ -31,6 +31,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED
|
||||
import static com.android.internal.widget.LockPatternUtils.PASSWORD_TYPE_KEY;
|
||||
import static com.android.settings.password.ChooseLockGeneric.CONFIRM_CREDENTIALS;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_REQUESTED_MIN_COMPLEXITY;
|
||||
import static com.android.settings.password.ChooseLockSettingsHelper.EXTRA_KEY_UNIFICATION_PROFILE_ID;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static com.google.common.truth.Truth.assertWithMessage;
|
||||
@@ -67,6 +68,7 @@ import org.robolectric.shadows.ShadowDrawable;
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(shadows = {
|
||||
SettingsShadowResources.class,
|
||||
ShadowLockPatternUtils.class,
|
||||
ShadowUtils.class,
|
||||
ShadowDevicePolicyManager.class,
|
||||
})
|
||||
@@ -84,6 +86,7 @@ public class ChooseLockPasswordTest {
|
||||
@After
|
||||
public void tearDown() {
|
||||
SettingsShadowResources.reset();
|
||||
ShadowLockPatternUtils.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -378,6 +381,29 @@ public class ChooseLockPasswordTest {
|
||||
assertThat(drawable.getCreatedFromResId()).isNotEqualTo(R.drawable.ic_fingerprint_header);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateComplexityMergedFromDpmOnCreate() {
|
||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
|
||||
|
||||
assertPasswordValidationResult(
|
||||
/* minComplexity= */ PASSWORD_COMPLEXITY_HIGH,
|
||||
/* passwordType= */ PASSWORD_QUALITY_NUMERIC,
|
||||
/* userEnteredPassword= */ LockscreenCredential.createNone(),
|
||||
"PIN must be at least 8 digits");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validateComplexityMergedFromUnificationUserOnCreate() {
|
||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_LOW);
|
||||
ShadowLockPatternUtils.setRequiredPasswordComplexity(123, PASSWORD_COMPLEXITY_HIGH);
|
||||
|
||||
Intent intent = createIntentForPasswordValidation(PASSWORD_COMPLEXITY_NONE,
|
||||
PASSWORD_QUALITY_NUMERIC);
|
||||
intent.putExtra(EXTRA_KEY_UNIFICATION_PROFILE_ID, 123);
|
||||
assertPasswordValidationResultForIntent(LockscreenCredential.createNone(), intent,
|
||||
"PIN must be at least 8 digits");
|
||||
}
|
||||
|
||||
private ChooseLockPassword buildChooseLockPasswordActivity(Intent intent) {
|
||||
return Robolectric.buildActivity(ChooseLockPassword.class, intent).setup().get();
|
||||
}
|
||||
@@ -400,14 +426,27 @@ public class ChooseLockPasswordTest {
|
||||
private void assertPasswordValidationResult(@PasswordComplexity int minComplexity,
|
||||
int passwordType, LockscreenCredential userEnteredPassword,
|
||||
String... expectedValidationResult) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(CONFIRM_CREDENTIALS, false);
|
||||
intent.putExtra(PASSWORD_TYPE_KEY, passwordType);
|
||||
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
|
||||
Intent intent = createIntentForPasswordValidation(minComplexity, passwordType);
|
||||
assertPasswordValidationResultForIntent(userEnteredPassword, intent,
|
||||
expectedValidationResult);
|
||||
}
|
||||
|
||||
private void assertPasswordValidationResultForIntent(LockscreenCredential userEnteredPassword,
|
||||
Intent intent, String... expectedValidationResult) {
|
||||
ChooseLockPassword activity = buildChooseLockPasswordActivity(intent);
|
||||
ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
|
||||
fragment.validatePassword(userEnteredPassword);
|
||||
String[] messages = fragment.convertErrorCodeToMessages();
|
||||
assertThat(messages).asList().containsExactly((Object[]) expectedValidationResult);
|
||||
assertThat(messages).asList().containsExactly(expectedValidationResult);
|
||||
}
|
||||
|
||||
private Intent createIntentForPasswordValidation(
|
||||
@PasswordComplexity int minComplexity,
|
||||
int passwordType) {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra(CONFIRM_CREDENTIALS, false);
|
||||
intent.putExtra(PASSWORD_TYPE_KEY, passwordType);
|
||||
intent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY, minComplexity);
|
||||
return intent;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user