Loading core/java/android/app/admin/PasswordMetrics.java +19 −18 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; 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.PasswordValidationError.CONTAINS_INVALID_CHARACTERS; import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE; Loading Loading @@ -74,11 +75,8 @@ public final class PasswordMetrics implements Parcelable { // consider it a complex PIN/password. public static final int MAX_ALLOWED_SEQUENCE = 3; // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN or CREDENTIAL_TYPE_PASSWORD. // Note that this class still uses CREDENTIAL_TYPE_PASSWORD to represent both numeric PIN // and alphabetic password. This is OK as long as this definition is only used internally, // and the value never gets mixed up with credential types from other parts of the framework. // TODO: fix this (ideally after we move logic to PasswordPolicy) // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN, CREDENTIAL_TYPE_PIN or // CREDENTIAL_TYPE_PASSWORD. public @CredentialType int credType; // Fields below only make sense when credType is PASSWORD. public int length = 0; Loading Loading @@ -192,13 +190,15 @@ public final class PasswordMetrics implements Parcelable { /** * Returns the {@code PasswordMetrics} for a given credential. * * If the credential is a pin or a password, equivalent to {@link #computeForPassword(byte[])}. * {@code credential} cannot be null when {@code type} is * If the credential is a pin or a password, equivalent to * {@link #computeForPasswordOrPin(byte[], boolean)}. {@code credential} cannot be null * when {@code type} is * {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}. */ public static PasswordMetrics computeForCredential(LockscreenCredential credential) { if (credential.isPassword() || credential.isPin()) { return PasswordMetrics.computeForPassword(credential.getCredential()); return PasswordMetrics.computeForPasswordOrPin(credential.getCredential(), credential.isPin()); } else if (credential.isPattern()) { return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); } else if (credential.isNone()) { Loading @@ -209,9 +209,9 @@ public final class PasswordMetrics implements Parcelable { } /** * Returns the {@code PasswordMetrics} for a given password * Returns the {@code PasswordMetrics} for a given password or pin */ public static PasswordMetrics computeForPassword(@NonNull byte[] password) { public static PasswordMetrics computeForPasswordOrPin(byte[] password, boolean isPin) { // Analyse the characters used int letters = 0; int upperCase = 0; Loading Loading @@ -245,8 +245,9 @@ public final class PasswordMetrics implements Parcelable { } } final int credType = isPin ? CREDENTIAL_TYPE_PIN : CREDENTIAL_TYPE_PASSWORD; final int seqLength = maxLengthSequence(password); return new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD, length, letters, upperCase, lowerCase, return new PasswordMetrics(credType, length, letters, upperCase, lowerCase, numeric, symbols, nonLetter, nonNumeric, seqLength); } Loading Loading @@ -353,7 +354,7 @@ public final class PasswordMetrics implements Parcelable { */ public void maxWith(PasswordMetrics other) { credType = Math.max(credType, other.credType); if (credType != CREDENTIAL_TYPE_PASSWORD) { if (credType != CREDENTIAL_TYPE_PASSWORD && credType != CREDENTIAL_TYPE_PIN) { return; } length = Math.max(length, other.length); Loading Loading @@ -408,7 +409,7 @@ public final class PasswordMetrics implements Parcelable { @Override boolean allowsCredType(int credType) { return credType == CREDENTIAL_TYPE_PASSWORD; return credType == CREDENTIAL_TYPE_PASSWORD || credType == CREDENTIAL_TYPE_PIN; } }, BUCKET_MEDIUM(PASSWORD_COMPLEXITY_MEDIUM) { Loading @@ -424,7 +425,7 @@ public final class PasswordMetrics implements Parcelable { @Override boolean allowsCredType(int credType) { return credType == CREDENTIAL_TYPE_PASSWORD; return credType == CREDENTIAL_TYPE_PASSWORD || credType == CREDENTIAL_TYPE_PIN; } }, BUCKET_LOW(PASSWORD_COMPLEXITY_LOW) { Loading Loading @@ -489,7 +490,7 @@ public final class PasswordMetrics implements Parcelable { if (!bucket.allowsCredType(credType)) { return false; } if (credType != CREDENTIAL_TYPE_PASSWORD) { if (credType != CREDENTIAL_TYPE_PASSWORD && credType != CREDENTIAL_TYPE_PIN) { return true; } return (bucket.canHaveSequence() || seqLength <= MAX_ALLOWED_SEQUENCE) Loading Loading @@ -529,7 +530,7 @@ public final class PasswordMetrics implements Parcelable { new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0)); } final PasswordMetrics enteredMetrics = computeForPassword(password); final PasswordMetrics enteredMetrics = computeForPasswordOrPin(password, isPin); return validatePasswordMetrics(adminMetrics, minComplexity, isPin, enteredMetrics); } Loading @@ -555,8 +556,8 @@ public final class PasswordMetrics implements Parcelable { || !bucket.allowsCredType(actualMetrics.credType)) { return Collections.singletonList(new PasswordValidationError(WEAK_CREDENTIAL_TYPE, 0)); } // TODO: this needs to be modified if CREDENTIAL_TYPE_PIN is added. if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD) { if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD && actualMetrics.credType != CREDENTIAL_TYPE_PIN) { return Collections.emptyList(); // Nothing to check for pattern or none. } Loading core/java/android/app/admin/PasswordPolicy.java +12 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; Loading @@ -27,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; /** * {@hide} Loading Loading @@ -58,14 +60,20 @@ public class PasswordPolicy { } else if (quality == PASSWORD_QUALITY_BIOMETRIC_WEAK || quality == PASSWORD_QUALITY_SOMETHING) { return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); } // quality is NUMERIC or stronger. } else if (quality == PASSWORD_QUALITY_NUMERIC || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) { PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PIN); result.length = length; if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) { result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE; } return result; } // quality is ALPHABETIC or stronger. PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD); result.length = length; if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) { result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE; } else if (quality == PASSWORD_QUALITY_ALPHABETIC) { if (quality == PASSWORD_QUALITY_ALPHABETIC) { result.nonNumeric = 1; } else if (quality == PASSWORD_QUALITY_ALPHANUMERIC) { result.numeric = 1; Loading core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +23 −13 Original line number Diff line number Diff line Loading @@ -93,8 +93,8 @@ public class PasswordMetricsTest { @Test public void testComputeForPassword_metrics() { final PasswordMetrics metrics = PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes()); final PasswordMetrics metrics = PasswordMetrics.computeForPasswordOrPin( "6B~0z1Z3*8A".getBytes(), /* isPin */ false); assertEquals(11, metrics.length); assertEquals(4, metrics.letters); assertEquals(3, metrics.upperCase); Loading Loading @@ -133,61 +133,71 @@ public class PasswordMetricsTest { @Test public void testDetermineComplexity_lowNumeric() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("1234".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("1234".getBytes(), /* isPin */true).determineComplexity()); } @Test public void testDetermineComplexity_lowNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("124".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("124".getBytes(), /* isPin */ true).determineComplexity()); } @Test public void testDetermineComplexity_lowAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("a!".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("a!".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_lowAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("a!1".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("a!1".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_mediumNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, PasswordMetrics.computeForPassword("1238".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("1238".getBytes(), /* isPin */ true).determineComplexity()); } @Test public void testDetermineComplexity_mediumAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, PasswordMetrics.computeForPassword("ab!c".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("ab!c".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_mediumAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, PasswordMetrics.computeForPassword("ab!1".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("ab!1".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_highNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword("12389647!".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("12389647!".getBytes(), /* isPin */ true).determineComplexity()); } @Test public void testDetermineComplexity_highAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword("alphabetic!".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("alphabetic!".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_highAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword( "alphanumeric123!".getBytes()).determineComplexity()); assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPasswordOrPin("alphanumeric123!".getBytes(), /* isPin */ false).determineComplexity()); } @Test Loading core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static org.junit.Assert.assertEquals; Loading Loading @@ -80,7 +81,7 @@ public class PasswordPolicyTest { public void testGetMinMetrics_numeric() { PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC); PasswordMetrics minMetrics = policy.getMinMetrics(); assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType); assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType); assertEquals(TEST_VALUE, minMetrics.length); assertEquals(0, minMetrics.numeric); // numeric can doesn't really require digits. assertEquals(0, minMetrics.letters); Loading @@ -104,7 +105,7 @@ public class PasswordPolicyTest { public void testGetMinMetrics_numericComplex() { PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC_COMPLEX); PasswordMetrics minMetrics = policy.getMinMetrics(); assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType); assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType); assertEquals(TEST_VALUE, minMetrics.length); assertEquals(0, minMetrics.numeric); assertEquals(0, minMetrics.letters); Loading services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +13 −9 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ 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.WIPE_EUICC; import static android.app.admin.PasswordMetrics.computeForPassword; import static android.app.admin.PasswordMetrics.computeForPasswordOrPin; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; import static android.net.InetAddresses.parseNumericAddress; Loading Loading @@ -5156,7 +5156,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { reset(mContext.spiedContext); PasswordMetrics passwordMetricsNoSymbols = computeForPassword("abcdXYZ5".getBytes()); PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin( "abcdXYZ5".getBytes(), /* isPin */ false); setActivePasswordState(passwordMetricsNoSymbols); assertThat(dpm.isActivePasswordSufficient()).isTrue(); Loading @@ -5183,7 +5184,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { reset(mContext.spiedContext); assertThat(dpm.isActivePasswordSufficient()).isFalse(); PasswordMetrics passwordMetricsWithSymbols = computeForPassword("abcd.XY5".getBytes()); PasswordMetrics passwordMetricsWithSymbols = computeForPasswordOrPin( "abcd.XY5".getBytes(), /* isPin */ false); setActivePasswordState(passwordMetricsWithSymbols); assertThat(dpm.isActivePasswordSufficient()).isTrue(); Loading Loading @@ -5237,7 +5239,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM); when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM)) .thenReturn(computeForPassword("184342".getBytes())); .thenReturn(computeForPasswordOrPin("184342".getBytes(), /* isPin */ true)); // Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly // on the parent admin) Loading Loading @@ -6360,7 +6362,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(CALLER_USER_HANDLE); when(getServices().lockSettingsInternal .getUserPasswordMetrics(CALLER_USER_HANDLE)) .thenReturn(computeForPassword("asdf".getBytes())); .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false)); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_MEDIUM); } Loading @@ -6380,10 +6382,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().lockSettingsInternal .getUserPasswordMetrics(CALLER_USER_HANDLE)) .thenReturn(computeForPassword("asdf".getBytes())); .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false)); when(getServices().lockSettingsInternal .getUserPasswordMetrics(parentUser.id)) .thenReturn(computeForPassword("parentUser".getBytes())); .thenReturn(computeForPasswordOrPin("parentUser".getBytes(), /* isPin */ false)); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH); } Loading Loading @@ -7059,13 +7061,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE); reset(mContext.spiedContext); PasswordMetrics passwordMetricsNoSymbols = computeForPassword("1234".getBytes()); PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin( "1234".getBytes(), /* isPin */ true); setActivePasswordState(passwordMetricsNoSymbols); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_LOW); assertThat(dpm.isActivePasswordSufficient()).isFalse(); reset(mContext.spiedContext); passwordMetricsNoSymbols = computeForPassword("84125312943a".getBytes()); passwordMetricsNoSymbols = computeForPasswordOrPin( "84125312943a".getBytes(), /* isPin */ false); setActivePasswordState(passwordMetricsNoSymbols); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH); // using isActivePasswordSufficient Loading Loading
core/java/android/app/admin/PasswordMetrics.java +19 −18 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; 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.PasswordValidationError.CONTAINS_INVALID_CHARACTERS; import static com.android.internal.widget.PasswordValidationError.CONTAINS_SEQUENCE; Loading Loading @@ -74,11 +75,8 @@ public final class PasswordMetrics implements Parcelable { // consider it a complex PIN/password. public static final int MAX_ALLOWED_SEQUENCE = 3; // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN or CREDENTIAL_TYPE_PASSWORD. // Note that this class still uses CREDENTIAL_TYPE_PASSWORD to represent both numeric PIN // and alphabetic password. This is OK as long as this definition is only used internally, // and the value never gets mixed up with credential types from other parts of the framework. // TODO: fix this (ideally after we move logic to PasswordPolicy) // One of CREDENTIAL_TYPE_NONE, CREDENTIAL_TYPE_PATTERN, CREDENTIAL_TYPE_PIN or // CREDENTIAL_TYPE_PASSWORD. public @CredentialType int credType; // Fields below only make sense when credType is PASSWORD. public int length = 0; Loading Loading @@ -192,13 +190,15 @@ public final class PasswordMetrics implements Parcelable { /** * Returns the {@code PasswordMetrics} for a given credential. * * If the credential is a pin or a password, equivalent to {@link #computeForPassword(byte[])}. * {@code credential} cannot be null when {@code type} is * If the credential is a pin or a password, equivalent to * {@link #computeForPasswordOrPin(byte[], boolean)}. {@code credential} cannot be null * when {@code type} is * {@link com.android.internal.widget.LockPatternUtils#CREDENTIAL_TYPE_PASSWORD}. */ public static PasswordMetrics computeForCredential(LockscreenCredential credential) { if (credential.isPassword() || credential.isPin()) { return PasswordMetrics.computeForPassword(credential.getCredential()); return PasswordMetrics.computeForPasswordOrPin(credential.getCredential(), credential.isPin()); } else if (credential.isPattern()) { return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); } else if (credential.isNone()) { Loading @@ -209,9 +209,9 @@ public final class PasswordMetrics implements Parcelable { } /** * Returns the {@code PasswordMetrics} for a given password * Returns the {@code PasswordMetrics} for a given password or pin */ public static PasswordMetrics computeForPassword(@NonNull byte[] password) { public static PasswordMetrics computeForPasswordOrPin(byte[] password, boolean isPin) { // Analyse the characters used int letters = 0; int upperCase = 0; Loading Loading @@ -245,8 +245,9 @@ public final class PasswordMetrics implements Parcelable { } } final int credType = isPin ? CREDENTIAL_TYPE_PIN : CREDENTIAL_TYPE_PASSWORD; final int seqLength = maxLengthSequence(password); return new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD, length, letters, upperCase, lowerCase, return new PasswordMetrics(credType, length, letters, upperCase, lowerCase, numeric, symbols, nonLetter, nonNumeric, seqLength); } Loading Loading @@ -353,7 +354,7 @@ public final class PasswordMetrics implements Parcelable { */ public void maxWith(PasswordMetrics other) { credType = Math.max(credType, other.credType); if (credType != CREDENTIAL_TYPE_PASSWORD) { if (credType != CREDENTIAL_TYPE_PASSWORD && credType != CREDENTIAL_TYPE_PIN) { return; } length = Math.max(length, other.length); Loading Loading @@ -408,7 +409,7 @@ public final class PasswordMetrics implements Parcelable { @Override boolean allowsCredType(int credType) { return credType == CREDENTIAL_TYPE_PASSWORD; return credType == CREDENTIAL_TYPE_PASSWORD || credType == CREDENTIAL_TYPE_PIN; } }, BUCKET_MEDIUM(PASSWORD_COMPLEXITY_MEDIUM) { Loading @@ -424,7 +425,7 @@ public final class PasswordMetrics implements Parcelable { @Override boolean allowsCredType(int credType) { return credType == CREDENTIAL_TYPE_PASSWORD; return credType == CREDENTIAL_TYPE_PASSWORD || credType == CREDENTIAL_TYPE_PIN; } }, BUCKET_LOW(PASSWORD_COMPLEXITY_LOW) { Loading Loading @@ -489,7 +490,7 @@ public final class PasswordMetrics implements Parcelable { if (!bucket.allowsCredType(credType)) { return false; } if (credType != CREDENTIAL_TYPE_PASSWORD) { if (credType != CREDENTIAL_TYPE_PASSWORD && credType != CREDENTIAL_TYPE_PIN) { return true; } return (bucket.canHaveSequence() || seqLength <= MAX_ALLOWED_SEQUENCE) Loading Loading @@ -529,7 +530,7 @@ public final class PasswordMetrics implements Parcelable { new PasswordValidationError(CONTAINS_INVALID_CHARACTERS, 0)); } final PasswordMetrics enteredMetrics = computeForPassword(password); final PasswordMetrics enteredMetrics = computeForPasswordOrPin(password, isPin); return validatePasswordMetrics(adminMetrics, minComplexity, isPin, enteredMetrics); } Loading @@ -555,8 +556,8 @@ public final class PasswordMetrics implements Parcelable { || !bucket.allowsCredType(actualMetrics.credType)) { return Collections.singletonList(new PasswordValidationError(WEAK_CREDENTIAL_TYPE, 0)); } // TODO: this needs to be modified if CREDENTIAL_TYPE_PIN is added. if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD) { if (actualMetrics.credType != CREDENTIAL_TYPE_PASSWORD && actualMetrics.credType != CREDENTIAL_TYPE_PIN) { return Collections.emptyList(); // Nothing to check for pattern or none. } Loading
core/java/android/app/admin/PasswordPolicy.java +12 −4 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; Loading @@ -27,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; /** * {@hide} Loading Loading @@ -58,14 +60,20 @@ public class PasswordPolicy { } else if (quality == PASSWORD_QUALITY_BIOMETRIC_WEAK || quality == PASSWORD_QUALITY_SOMETHING) { return new PasswordMetrics(CREDENTIAL_TYPE_PATTERN); } // quality is NUMERIC or stronger. } else if (quality == PASSWORD_QUALITY_NUMERIC || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) { PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PIN); result.length = length; if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) { result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE; } return result; } // quality is ALPHABETIC or stronger. PasswordMetrics result = new PasswordMetrics(CREDENTIAL_TYPE_PASSWORD); result.length = length; if (quality == PASSWORD_QUALITY_NUMERIC_COMPLEX) { result.seqLength = PasswordMetrics.MAX_ALLOWED_SEQUENCE; } else if (quality == PASSWORD_QUALITY_ALPHABETIC) { if (quality == PASSWORD_QUALITY_ALPHABETIC) { result.nonNumeric = 1; } else if (quality == PASSWORD_QUALITY_ALPHANUMERIC) { result.numeric = 1; Loading
core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +23 −13 Original line number Diff line number Diff line Loading @@ -93,8 +93,8 @@ public class PasswordMetricsTest { @Test public void testComputeForPassword_metrics() { final PasswordMetrics metrics = PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes()); final PasswordMetrics metrics = PasswordMetrics.computeForPasswordOrPin( "6B~0z1Z3*8A".getBytes(), /* isPin */ false); assertEquals(11, metrics.length); assertEquals(4, metrics.letters); assertEquals(3, metrics.upperCase); Loading Loading @@ -133,61 +133,71 @@ public class PasswordMetricsTest { @Test public void testDetermineComplexity_lowNumeric() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("1234".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("1234".getBytes(), /* isPin */true).determineComplexity()); } @Test public void testDetermineComplexity_lowNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("124".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("124".getBytes(), /* isPin */ true).determineComplexity()); } @Test public void testDetermineComplexity_lowAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("a!".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("a!".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_lowAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_LOW, PasswordMetrics.computeForPassword("a!1".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("a!1".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_mediumNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, PasswordMetrics.computeForPassword("1238".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("1238".getBytes(), /* isPin */ true).determineComplexity()); } @Test public void testDetermineComplexity_mediumAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, PasswordMetrics.computeForPassword("ab!c".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("ab!c".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_mediumAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_MEDIUM, PasswordMetrics.computeForPassword("ab!1".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("ab!1".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_highNumericComplex() { assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword("12389647!".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("12389647!".getBytes(), /* isPin */ true).determineComplexity()); } @Test public void testDetermineComplexity_highAlphabetic() { assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword("alphabetic!".getBytes()).determineComplexity()); PasswordMetrics.computeForPasswordOrPin("alphabetic!".getBytes(), /* isPin */ false).determineComplexity()); } @Test public void testDetermineComplexity_highAlphanumeric() { assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword( "alphanumeric123!".getBytes()).determineComplexity()); assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPasswordOrPin("alphanumeric123!".getBytes(), /* isPin */ false).determineComplexity()); } @Test Loading
core/tests/coretests/src/android/app/admin/PasswordPolicyTest.java +3 −2 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_NONE; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN; import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PIN; import static org.junit.Assert.assertEquals; Loading Loading @@ -80,7 +81,7 @@ public class PasswordPolicyTest { public void testGetMinMetrics_numeric() { PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC); PasswordMetrics minMetrics = policy.getMinMetrics(); assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType); assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType); assertEquals(TEST_VALUE, minMetrics.length); assertEquals(0, minMetrics.numeric); // numeric can doesn't really require digits. assertEquals(0, minMetrics.letters); Loading @@ -104,7 +105,7 @@ public class PasswordPolicyTest { public void testGetMinMetrics_numericComplex() { PasswordPolicy policy = testPolicy(PASSWORD_QUALITY_NUMERIC_COMPLEX); PasswordMetrics minMetrics = policy.getMinMetrics(); assertEquals(CREDENTIAL_TYPE_PASSWORD, minMetrics.credType); assertEquals(CREDENTIAL_TYPE_PIN, minMetrics.credType); assertEquals(TEST_VALUE, minMetrics.length); assertEquals(0, minMetrics.numeric); assertEquals(0, minMetrics.letters); Loading
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +13 −9 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ 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.WIPE_EUICC; import static android.app.admin.PasswordMetrics.computeForPassword; import static android.app.admin.PasswordMetrics.computeForPasswordOrPin; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE; import static android.net.InetAddresses.parseNumericAddress; Loading Loading @@ -5156,7 +5156,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { reset(mContext.spiedContext); PasswordMetrics passwordMetricsNoSymbols = computeForPassword("abcdXYZ5".getBytes()); PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin( "abcdXYZ5".getBytes(), /* isPin */ false); setActivePasswordState(passwordMetricsNoSymbols); assertThat(dpm.isActivePasswordSufficient()).isTrue(); Loading @@ -5183,7 +5184,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { reset(mContext.spiedContext); assertThat(dpm.isActivePasswordSufficient()).isFalse(); PasswordMetrics passwordMetricsWithSymbols = computeForPassword("abcd.XY5".getBytes()); PasswordMetrics passwordMetricsWithSymbols = computeForPasswordOrPin( "abcd.XY5".getBytes(), /* isPin */ false); setActivePasswordState(passwordMetricsWithSymbols); assertThat(dpm.isActivePasswordSufficient()).isTrue(); Loading Loading @@ -5237,7 +5239,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { parentDpm.setRequiredPasswordComplexity(PASSWORD_COMPLEXITY_MEDIUM); when(getServices().lockSettingsInternal.getUserPasswordMetrics(UserHandle.USER_SYSTEM)) .thenReturn(computeForPassword("184342".getBytes())); .thenReturn(computeForPasswordOrPin("184342".getBytes(), /* isPin */ true)); // Numeric password is compliant with current requirement (QUALITY_NUMERIC set explicitly // on the parent admin) Loading Loading @@ -6360,7 +6362,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { .thenReturn(CALLER_USER_HANDLE); when(getServices().lockSettingsInternal .getUserPasswordMetrics(CALLER_USER_HANDLE)) .thenReturn(computeForPassword("asdf".getBytes())); .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false)); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_MEDIUM); } Loading @@ -6380,10 +6382,10 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(getServices().lockSettingsInternal .getUserPasswordMetrics(CALLER_USER_HANDLE)) .thenReturn(computeForPassword("asdf".getBytes())); .thenReturn(computeForPasswordOrPin("asdf".getBytes(), /* isPin */ false)); when(getServices().lockSettingsInternal .getUserPasswordMetrics(parentUser.id)) .thenReturn(computeForPassword("parentUser".getBytes())); .thenReturn(computeForPasswordOrPin("parentUser".getBytes(), /* isPin */ false)); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH); } Loading Loading @@ -7059,13 +7061,15 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_NONE); reset(mContext.spiedContext); PasswordMetrics passwordMetricsNoSymbols = computeForPassword("1234".getBytes()); PasswordMetrics passwordMetricsNoSymbols = computeForPasswordOrPin( "1234".getBytes(), /* isPin */ true); setActivePasswordState(passwordMetricsNoSymbols); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_LOW); assertThat(dpm.isActivePasswordSufficient()).isFalse(); reset(mContext.spiedContext); passwordMetricsNoSymbols = computeForPassword("84125312943a".getBytes()); passwordMetricsNoSymbols = computeForPasswordOrPin( "84125312943a".getBytes(), /* isPin */ false); setActivePasswordState(passwordMetricsNoSymbols); assertThat(dpm.getPasswordComplexity()).isEqualTo(PASSWORD_COMPLEXITY_HIGH); // using isActivePasswordSufficient Loading