diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index 251c5d83fbb9c..9b64d8fe84b4d 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -30,6 +30,7 @@ import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSW import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PASSWORD_SIZE; +import static com.android.internal.widget.LockPatternUtils.MIN_LOCK_PATTERN_SIZE; import static com.android.internal.widget.PasswordValidationError.CONTAINS_INVALID_CHARACTERS; import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE; import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_DIGITS; @@ -201,7 +202,9 @@ public final class PasswordMetrics implements Parcelable { return PasswordMetrics.computeForPasswordOrPin(credential.getCredential(), credential.isPin()); } else if (credential.isPattern()) { - return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); + PasswordMetrics metrics = new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); + metrics.length = credential.size(); + return metrics; } else if (credential.isNone()) { return new PasswordMetrics(CREDENTIAL_TYPE_NONE); } else { @@ -529,13 +532,8 @@ public final class PasswordMetrics implements Parcelable { return Collections.singletonList( new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0)); } - if (credential.isPassword() || credential.isPin()) { - return validatePassword(adminMetrics, minComplexity, credential.isPin(), - credential.getCredential()); - } else { - return validatePasswordMetrics(adminMetrics, minComplexity, - new PasswordMetrics(credential.getType())); - } + PasswordMetrics actualMetrics = computeForCredential(credential); + return validatePasswordMetrics(adminMetrics, minComplexity, actualMetrics); } /** @@ -584,9 +582,18 @@ public final class PasswordMetrics implements Parcelable { || !bucket.allowsCredType(actualMetrics.credType)) { return Collections.singletonList(new PasswordValidationError(WEAK_CREDENTIAL_TYPE, 0)); } - if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD - && actualMetrics.credType != CREDENTIAL_TYPE_PIN) { - return Collections.emptyList(); // Nothing to check for pattern or none. + if (actualMetrics.credType == CREDENTIAL_TYPE_PATTERN) { + // For pattern, only need to check the length against the hardcoded minimum. If the + // pattern length is unavailable (e.g., PasswordMetrics that was stored on-disk before + // the pattern length started being included in it), assume it is okay. + if (actualMetrics.length != 0 && actualMetrics.length < MIN_LOCK_PATTERN_SIZE) { + return Collections.singletonList(new PasswordValidationError(TOO_SHORT, + MIN_LOCK_PATTERN_SIZE)); + } + return Collections.emptyList(); + } + if (actualMetrics.credType == CREDENTIAL_TYPE_NONE) { + return Collections.emptyList(); // Nothing to check for none. } if (actualMetrics.credType == CREDENTIAL_TYPE_PIN && actualMetrics.nonNumeric > 0) { diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java index 84c54006fc67b..3c476300cf6bd 100644 --- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java @@ -42,6 +42,7 @@ import android.platform.test.annotations.Presubmit; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockscreenCredential; import com.android.internal.widget.PasswordValidationError; @@ -419,6 +420,21 @@ public class PasswordMetricsTest { PasswordValidationError.TOO_SHORT, 6); } + private LockscreenCredential createPattern(String patternString) { + return LockscreenCredential.createPattern(LockPatternUtils.byteArrayToPattern( + patternString.getBytes())); + } + + @Test + public void testValidateCredential_pattern() { + PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_NONE); + assertValidationErrors( + validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, createPattern("123")), + PasswordValidationError.TOO_SHORT, 4); + assertValidationErrors( + validateCredential(adminMetrics, PASSWORD_COMPLEXITY_NONE, createPattern("1234"))); + } + /** * @param expected sequence of validation error codes followed by requirement values, must have * even number of elements. Empty means no errors.