Merge "Add validation TOO_SHORT_WHEN_ALL_NUMERIC" into tm-dev am: 4f4e8dd340
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17799990 Change-Id: If491185fc92a96dd2895eb57cf80b3c22842fdf4 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -41,6 +41,7 @@ import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_SYM
|
|||||||
import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE;
|
import static com.android.internal.widget.PasswordValidationError.NOT_ENOUGH_UPPER_CASE;
|
||||||
import static com.android.internal.widget.PasswordValidationError.TOO_LONG;
|
import static com.android.internal.widget.PasswordValidationError.TOO_LONG;
|
||||||
import static com.android.internal.widget.PasswordValidationError.TOO_SHORT;
|
import static com.android.internal.widget.PasswordValidationError.TOO_SHORT;
|
||||||
|
import static com.android.internal.widget.PasswordValidationError.TOO_SHORT_WHEN_ALL_NUMERIC;
|
||||||
import static com.android.internal.widget.PasswordValidationError.WEAK_CREDENTIAL_TYPE;
|
import static com.android.internal.widget.PasswordValidationError.WEAK_CREDENTIAL_TYPE;
|
||||||
|
|
||||||
import android.annotation.IntDef;
|
import android.annotation.IntDef;
|
||||||
@@ -569,21 +570,15 @@ public final class PasswordMetrics implements Parcelable {
|
|||||||
result.add(new PasswordValidationError(TOO_LONG, MAX_PASSWORD_LENGTH));
|
result.add(new PasswordValidationError(TOO_LONG, MAX_PASSWORD_LENGTH));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A flag indicating whether the provided password already has non-numeric characters in
|
final PasswordMetrics minMetrics = applyComplexity(adminMetrics,
|
||||||
// it or if the admin imposes the requirement of any non-numeric characters.
|
actualMetrics.credType == CREDENTIAL_TYPE_PIN, bucket);
|
||||||
final boolean hasOrWouldNeedNonNumeric =
|
|
||||||
actualMetrics.nonNumeric > 0 || adminMetrics.nonNumeric > 0
|
|
||||||
|| adminMetrics.letters > 0 || adminMetrics.lowerCase > 0
|
|
||||||
|| adminMetrics.upperCase > 0 || adminMetrics.symbols > 0;
|
|
||||||
final PasswordMetrics minMetrics =
|
|
||||||
applyComplexity(adminMetrics, hasOrWouldNeedNonNumeric, bucket);
|
|
||||||
|
|
||||||
// Clamp required length between maximum and minimum valid values.
|
// Clamp required length between maximum and minimum valid values.
|
||||||
minMetrics.length = Math.min(MAX_PASSWORD_LENGTH,
|
minMetrics.length = Math.min(MAX_PASSWORD_LENGTH,
|
||||||
Math.max(minMetrics.length, MIN_LOCK_PASSWORD_SIZE));
|
Math.max(minMetrics.length, MIN_LOCK_PASSWORD_SIZE));
|
||||||
minMetrics.removeOverlapping();
|
minMetrics.removeOverlapping();
|
||||||
|
|
||||||
comparePasswordMetrics(minMetrics, actualMetrics, result);
|
comparePasswordMetrics(minMetrics, bucket, actualMetrics, result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -591,11 +586,23 @@ public final class PasswordMetrics implements Parcelable {
|
|||||||
/**
|
/**
|
||||||
* TODO: move to PasswordPolicy
|
* TODO: move to PasswordPolicy
|
||||||
*/
|
*/
|
||||||
private static void comparePasswordMetrics(PasswordMetrics minMetrics,
|
private static void comparePasswordMetrics(PasswordMetrics minMetrics, ComplexityBucket bucket,
|
||||||
PasswordMetrics actualMetrics, ArrayList<PasswordValidationError> result) {
|
PasswordMetrics actualMetrics, ArrayList<PasswordValidationError> result) {
|
||||||
if (actualMetrics.length < minMetrics.length) {
|
if (actualMetrics.length < minMetrics.length) {
|
||||||
result.add(new PasswordValidationError(TOO_SHORT, minMetrics.length));
|
result.add(new PasswordValidationError(TOO_SHORT, minMetrics.length));
|
||||||
}
|
}
|
||||||
|
if (actualMetrics.nonNumeric == 0 && minMetrics.nonNumeric == 0 && minMetrics.letters == 0
|
||||||
|
&& minMetrics.lowerCase == 0 && minMetrics.upperCase == 0
|
||||||
|
&& minMetrics.symbols == 0) {
|
||||||
|
// When provided password is all numeric and all numeric password is allowed.
|
||||||
|
int allNumericMinimumLength = bucket.getMinimumLength(false);
|
||||||
|
if (allNumericMinimumLength > minMetrics.length
|
||||||
|
&& allNumericMinimumLength > minMetrics.numeric
|
||||||
|
&& actualMetrics.length < allNumericMinimumLength) {
|
||||||
|
result.add(new PasswordValidationError(
|
||||||
|
TOO_SHORT_WHEN_ALL_NUMERIC, allNumericMinimumLength));
|
||||||
|
}
|
||||||
|
}
|
||||||
if (actualMetrics.letters < minMetrics.letters) {
|
if (actualMetrics.letters < minMetrics.letters) {
|
||||||
result.add(new PasswordValidationError(NOT_ENOUGH_LETTERS, minMetrics.letters));
|
result.add(new PasswordValidationError(NOT_ENOUGH_LETTERS, minMetrics.letters));
|
||||||
}
|
}
|
||||||
@@ -668,15 +675,12 @@ public final class PasswordMetrics implements Parcelable {
|
|||||||
*
|
*
|
||||||
* TODO: move to PasswordPolicy
|
* TODO: move to PasswordPolicy
|
||||||
*/
|
*/
|
||||||
public static PasswordMetrics applyComplexity(
|
public static PasswordMetrics applyComplexity(PasswordMetrics adminMetrics, boolean isPin,
|
||||||
PasswordMetrics adminMetrics, boolean withNonNumericCharacters,
|
|
||||||
int complexity) {
|
int complexity) {
|
||||||
return applyComplexity(adminMetrics, withNonNumericCharacters,
|
return applyComplexity(adminMetrics, isPin, ComplexityBucket.forComplexity(complexity));
|
||||||
ComplexityBucket.forComplexity(complexity));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static PasswordMetrics applyComplexity(
|
private static PasswordMetrics applyComplexity(PasswordMetrics adminMetrics, boolean isPin,
|
||||||
PasswordMetrics adminMetrics, boolean withNonNumericCharacters,
|
|
||||||
ComplexityBucket bucket) {
|
ComplexityBucket bucket) {
|
||||||
final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics);
|
final PasswordMetrics minMetrics = new PasswordMetrics(adminMetrics);
|
||||||
|
|
||||||
@@ -684,8 +688,7 @@ public final class PasswordMetrics implements Parcelable {
|
|||||||
minMetrics.seqLength = Math.min(minMetrics.seqLength, MAX_ALLOWED_SEQUENCE);
|
minMetrics.seqLength = Math.min(minMetrics.seqLength, MAX_ALLOWED_SEQUENCE);
|
||||||
}
|
}
|
||||||
|
|
||||||
minMetrics.length = Math.max(minMetrics.length,
|
minMetrics.length = Math.max(minMetrics.length, bucket.getMinimumLength(!isPin));
|
||||||
bucket.getMinimumLength(withNonNumericCharacters));
|
|
||||||
|
|
||||||
return minMetrics;
|
return minMetrics;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,16 +24,17 @@ public class PasswordValidationError {
|
|||||||
public static final int WEAK_CREDENTIAL_TYPE = 1;
|
public static final int WEAK_CREDENTIAL_TYPE = 1;
|
||||||
public static final int CONTAINS_INVALID_CHARACTERS = 2;
|
public static final int CONTAINS_INVALID_CHARACTERS = 2;
|
||||||
public static final int TOO_SHORT = 3;
|
public static final int TOO_SHORT = 3;
|
||||||
public static final int TOO_LONG = 4;
|
public static final int TOO_SHORT_WHEN_ALL_NUMERIC = 4;
|
||||||
public static final int CONTAINS_SEQUENCE = 5;
|
public static final int TOO_LONG = 5;
|
||||||
public static final int NOT_ENOUGH_LETTERS = 6;
|
public static final int CONTAINS_SEQUENCE = 6;
|
||||||
public static final int NOT_ENOUGH_UPPER_CASE = 7;
|
public static final int NOT_ENOUGH_LETTERS = 7;
|
||||||
public static final int NOT_ENOUGH_LOWER_CASE = 8;
|
public static final int NOT_ENOUGH_UPPER_CASE = 8;
|
||||||
public static final int NOT_ENOUGH_DIGITS = 9;
|
public static final int NOT_ENOUGH_LOWER_CASE = 9;
|
||||||
public static final int NOT_ENOUGH_SYMBOLS = 10;
|
public static final int NOT_ENOUGH_DIGITS = 10;
|
||||||
public static final int NOT_ENOUGH_NON_LETTER = 11;
|
public static final int NOT_ENOUGH_SYMBOLS = 11;
|
||||||
public static final int NOT_ENOUGH_NON_DIGITS = 12;
|
public static final int NOT_ENOUGH_NON_LETTER = 12;
|
||||||
public static final int RECENTLY_USED = 13;
|
public static final int NOT_ENOUGH_NON_DIGITS = 13;
|
||||||
|
public static final int RECENTLY_USED = 14;
|
||||||
// WARNING: if you add a new error, make sure it is presented to the user correctly in Settings.
|
// WARNING: if you add a new error, make sure it is presented to the user correctly in Settings.
|
||||||
|
|
||||||
public final int errorCode;
|
public final int errorCode;
|
||||||
@@ -61,6 +62,7 @@ public class PasswordValidationError {
|
|||||||
case WEAK_CREDENTIAL_TYPE: return "Weak credential type";
|
case WEAK_CREDENTIAL_TYPE: return "Weak credential type";
|
||||||
case CONTAINS_INVALID_CHARACTERS: return "Contains an invalid character";
|
case CONTAINS_INVALID_CHARACTERS: return "Contains an invalid character";
|
||||||
case TOO_SHORT: return "Password too short";
|
case TOO_SHORT: return "Password too short";
|
||||||
|
case TOO_SHORT_WHEN_ALL_NUMERIC: return "Password too short";
|
||||||
case TOO_LONG: return "Password too long";
|
case TOO_LONG: return "Password too long";
|
||||||
case CONTAINS_SEQUENCE: return "Sequence too long";
|
case CONTAINS_SEQUENCE: return "Sequence too long";
|
||||||
case NOT_ENOUGH_LETTERS: return "Too few letters";
|
case NOT_ENOUGH_LETTERS: return "Too few letters";
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.platform.test.annotations.Presubmit;
|
import android.platform.test.annotations.Presubmit;
|
||||||
|
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import androidx.test.filters.SmallTest;
|
import androidx.test.filters.SmallTest;
|
||||||
import androidx.test.runner.AndroidJUnit4;
|
|
||||||
|
|
||||||
import com.android.internal.widget.PasswordValidationError;
|
import com.android.internal.widget.PasswordValidationError;
|
||||||
|
|
||||||
@@ -324,6 +324,56 @@ public class PasswordMetricsTest {
|
|||||||
PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
|
PasswordValidationError.WEAK_CREDENTIAL_TYPE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidatePasswordMetrics_pinAndComplexityHigh() {
|
||||||
|
PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
|
||||||
|
PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PIN);
|
||||||
|
actualMetrics.length = 6;
|
||||||
|
actualMetrics.seqLength = 1;
|
||||||
|
|
||||||
|
assertValidationErrors(
|
||||||
|
validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
|
||||||
|
PasswordValidationError.TOO_SHORT, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidatePasswordMetrics_nonAllNumberPasswordAndComplexityHigh() {
|
||||||
|
PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
|
||||||
|
PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
|
||||||
|
actualMetrics.length = 5;
|
||||||
|
actualMetrics.nonNumeric = 1;
|
||||||
|
actualMetrics.seqLength = 1;
|
||||||
|
|
||||||
|
assertValidationErrors(
|
||||||
|
validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
|
||||||
|
PasswordValidationError.TOO_SHORT, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidatePasswordMetrics_allNumberPasswordAndComplexityHigh() {
|
||||||
|
PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
|
||||||
|
PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
|
||||||
|
actualMetrics.length = 6;
|
||||||
|
actualMetrics.seqLength = 1;
|
||||||
|
|
||||||
|
assertValidationErrors(
|
||||||
|
validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
|
||||||
|
PasswordValidationError.TOO_SHORT_WHEN_ALL_NUMERIC, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidatePasswordMetrics_allNumberPasswordAndRequireNonNumeric() {
|
||||||
|
PasswordMetrics adminMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
|
||||||
|
adminMetrics.nonNumeric = 1;
|
||||||
|
PasswordMetrics actualMetrics = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD);
|
||||||
|
actualMetrics.length = 6;
|
||||||
|
actualMetrics.seqLength = 1;
|
||||||
|
|
||||||
|
assertValidationErrors(
|
||||||
|
validatePasswordMetrics(adminMetrics, PASSWORD_COMPLEXITY_HIGH, actualMetrics),
|
||||||
|
PasswordValidationError.NOT_ENOUGH_NON_DIGITS, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param expected sequense of validation error codes followed by requirement values, must have
|
* @param expected sequense of validation error codes followed by requirement values, must have
|
||||||
* even number of elements. Empty means no errors.
|
* even number of elements. Empty means no errors.
|
||||||
|
|||||||
Reference in New Issue
Block a user