Check password blacklist when setting credential
If the password is valid by all other checks, see if it is present on
the blacklist and disallow it if it is.
Test: set a password blacklist, try and set a blacklisted password and
see an explanation, set a non-blacklisted password successfully.
Test: make ROBOTEST_FILTER=ChooseLockPasswordTest RunSettingsRoboTests
Bug: 63578054
Fix: 65659151
Change-Id: Id155b824ad4b5839c23b6f5fd3fdfdcfc78c3df1
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 4beaf8f..68cac15 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -88,6 +88,7 @@
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
<uses-permission android:name="android.permission.READ_PRINT_SERVICES" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
+ <uses-permission android:name="android.permission.TEST_BLACKLISTED_PASSWORD" />
<application android:label="@string/settings_label"
android:icon="@drawable/ic_launcher_settings"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4a8e7e3..c282566 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1336,6 +1336,9 @@
<!-- Error shown when in PIN mode and PIN has been used recently. Please keep this string short! -->
<string name="lockpassword_pin_recently_used">Device admin doesn\'t allow using a recent PIN</string>
+ <!-- Error shown when a user is choosing a PIN for their work phone, but what they suggest is blocked by their company's IT administrator. The user should try another PIN that's less common and more complicated. -->
+ <string name="lockpassword_pin_blacklisted_by_admin">Common PINs are blocked by your IT admin. Try a different PIN.</string>
+
<!-- Error shown when in PASSWORD mode and user enters an invalid character -->
<string name="lockpassword_illegal_character">This can\'t include an invalid character</string>
@@ -1388,6 +1391,9 @@
<string name="lockpassword_password_recently_used">Device admin doesn\'t allow using a recent
password</string>
+ <!-- Error shown when a user is choosing a PASSWORD for their work phone, but what they suggest is blocked by their company's IT administrator. The user should try another PASSWORD that's less common and more complicated. -->
+ <string name="lockpassword_password_blacklisted_by_admin">Common passwords are blocked by your IT admin. Try a different password.</string>
+
<!-- [CHAR_LIMIT=NONE] Error shown when the user tries to set an ascending or descending sequence of digits -->
<string name="lockpassword_pin_no_sequential_digits">Ascending, descending, or repeated sequence
of digits isn\'t allowed</string>
diff --git a/src/com/android/settings/password/ChooseLockPassword.java b/src/com/android/settings/password/ChooseLockPassword.java
index e5fbe6c..4e54f3c 100644
--- a/src/com/android/settings/password/ChooseLockPassword.java
+++ b/src/com/android/settings/password/ChooseLockPassword.java
@@ -228,19 +228,20 @@
private static final int MIN_NON_LETTER_IN_PASSWORD = 5;
// Error code returned from {@link #validatePassword(String)}.
- private static final int NO_ERROR = 0;
- private static final int CONTAIN_INVALID_CHARACTERS = 1 << 0;
- private static final int TOO_SHORT = 1 << 1;
- private static final int TOO_LONG = 1 << 2;
- private static final int CONTAIN_NON_DIGITS = 1 << 3;
- private static final int CONTAIN_SEQUENTIAL_DIGITS = 1 << 4;
- private static final int RECENTLY_USED = 1 << 5;
- private static final int NOT_ENOUGH_LETTER = 1 << 6;
- private static final int NOT_ENOUGH_UPPER_CASE = 1 << 7;
- private static final int NOT_ENOUGH_LOWER_CASE = 1 << 8;
- private static final int NOT_ENOUGH_DIGITS = 1 << 9;
- private static final int NOT_ENOUGH_SYMBOLS = 1 << 10;
- private static final int NOT_ENOUGH_NON_LETTER = 1 << 11;
+ static final int NO_ERROR = 0;
+ static final int CONTAIN_INVALID_CHARACTERS = 1 << 0;
+ static final int TOO_SHORT = 1 << 1;
+ static final int TOO_LONG = 1 << 2;
+ static final int CONTAIN_NON_DIGITS = 1 << 3;
+ static final int CONTAIN_SEQUENTIAL_DIGITS = 1 << 4;
+ static final int RECENTLY_USED = 1 << 5;
+ static final int NOT_ENOUGH_LETTER = 1 << 6;
+ static final int NOT_ENOUGH_UPPER_CASE = 1 << 7;
+ static final int NOT_ENOUGH_LOWER_CASE = 1 << 8;
+ static final int NOT_ENOUGH_DIGITS = 1 << 9;
+ static final int NOT_ENOUGH_SYMBOLS = 1 << 10;
+ static final int NOT_ENOUGH_NON_LETTER = 1 << 11;
+ static final int BLACKLISTED = 1 << 12;
/**
* Keep track internally of where the user is in choosing a pattern.
@@ -720,6 +721,17 @@
break;
}
}
+
+ // Only check the blacklist if the password is otherwise valid. Checking the blacklist
+ // can be expensive and it is not useful to report the fact it is on a blacklist if it
+ // couldn't be set anyway.
+ if (errorCode == NO_ERROR) {
+ if (mLockPatternUtils.getDevicePolicyManager()
+ .isPasswordBlacklisted(mUserId, password)) {
+ errorCode |= BLACKLISTED;
+ }
+ }
+
return errorCode;
}
@@ -787,7 +799,7 @@
* @param errorCode error code returned from {@link #validatePassword(String)}.
* @return an array of messages describing the error, important messages come first.
*/
- private String[] convertErrorCodeToMessages(int errorCode) {
+ String[] convertErrorCodeToMessages(int errorCode) {
List<String> messages = new ArrayList<>();
if ((errorCode & CONTAIN_INVALID_CHARACTERS) > 0) {
messages.add(getString(R.string.lockpassword_illegal_character));
@@ -842,6 +854,11 @@
messages.add(getString((mIsAlphaMode) ? R.string.lockpassword_password_recently_used
: R.string.lockpassword_pin_recently_used));
}
+ if ((errorCode & BLACKLISTED) > 0) {
+ messages.add(getString((mIsAlphaMode)
+ ? R.string.lockpassword_password_blacklisted_by_admin
+ : R.string.lockpassword_pin_blacklisted_by_admin));
+ }
return messages.toArray(new String[0]);
}
diff --git a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
index c003603..70e68fe 100644
--- a/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
+++ b/tests/robotests/src/com/android/settings/password/ChooseLockPasswordTest.java
@@ -128,6 +128,36 @@
}
@Test
+ public void blacklist_addsErrorMessageForPin() {
+ final ChooseLockPassword activity = buildChooseLockPasswordActivity(
+ new IntentBuilder(application)
+ .setUserId(UserHandle.myUserId())
+ // Set to numeric for a PIN
+ .setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC)
+ .build());
+ final ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
+ final int errors = ChooseLockPasswordFragment.BLACKLISTED;
+ final String[] messages = fragment.convertErrorCodeToMessages(errors);
+ assertThat(messages).isEqualTo(new String[] {
+ activity.getString(R.string.lockpassword_pin_blacklisted_by_admin) });
+ }
+
+ @Test
+ public void blacklist_addsErrorMessageForPassword() {
+ final ChooseLockPassword activity = buildChooseLockPasswordActivity(
+ new IntentBuilder(application)
+ .setUserId(UserHandle.myUserId())
+ // Set to alphabetic for a password
+ .setPasswordQuality(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC)
+ .build());
+ final ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(activity);
+ final int errors = ChooseLockPasswordFragment.BLACKLISTED;
+ final String[] messages = fragment.convertErrorCodeToMessages(errors);
+ assertThat(messages).isEqualTo(new String[] {
+ activity.getString(R.string.lockpassword_password_blacklisted_by_admin) });
+ }
+
+ @Test
public void assertThat_chooseLockIconChanged_WhenFingerprintExtraSet() {
ShadowDrawable drawable = setActivityAndGetIconDrawable(true);
assertThat(drawable.getCreatedFromResId()).isEqualTo(R.drawable.ic_fingerprint_header);
@@ -139,17 +169,22 @@
assertThat(drawable.getCreatedFromResId()).isNotEqualTo(R.drawable.ic_fingerprint_header);
}
+ private ChooseLockPassword buildChooseLockPasswordActivity(Intent intent) {
+ return Robolectric.buildActivity(ChooseLockPassword.class, intent).setup().get();
+ }
+
+ private ChooseLockPasswordFragment getChooseLockPasswordFragment(ChooseLockPassword activity) {
+ return (ChooseLockPasswordFragment)
+ activity.getFragmentManager().findFragmentById(R.id.main_content);
+ }
+
private ShadowDrawable setActivityAndGetIconDrawable(boolean addFingerprintExtra) {
- ChooseLockPassword passwordActivity =
- Robolectric.buildActivity(
- ChooseLockPassword.class,
- new IntentBuilder(application)
- .setUserId(UserHandle.myUserId())
- .setForFingerprint(addFingerprintExtra)
- .build())
- .setup().get();
- ChooseLockPasswordFragment fragment = (ChooseLockPasswordFragment)
- passwordActivity.getFragmentManager().findFragmentById(R.id.main_content);
+ ChooseLockPassword passwordActivity = buildChooseLockPasswordActivity(
+ new IntentBuilder(application)
+ .setUserId(UserHandle.myUserId())
+ .setForFingerprint(addFingerprintExtra)
+ .build());
+ ChooseLockPasswordFragment fragment = getChooseLockPasswordFragment(passwordActivity);
return Shadows.shadowOf(((GlifLayout) fragment.getView()).getIcon());
}
}