blob: 4ae9494aa3627a4db1fba330caa7b90bb0bcc36c [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.app.admin;
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_ALPHABETIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC;
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;
import static android.app.admin.PasswordMetrics.complexityLevelToMinQuality;
import static android.app.admin.PasswordMetrics.getActualRequiredQuality;
import static android.app.admin.PasswordMetrics.getMinimumMetrics;
import static android.app.admin.PasswordMetrics.getTargetQualityMetrics;
import static android.app.admin.PasswordMetrics.sanitizeComplexityLevel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit tests for {@link PasswordMetrics}. */
@RunWith(AndroidJUnit4.class)
@SmallTest
public class PasswordMetricsTest {
@Test
public void testIsDefault() {
final PasswordMetrics metrics = new PasswordMetrics();
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, metrics.quality);
assertEquals(0, metrics.length);
assertEquals(0, metrics.letters);
assertEquals(0, metrics.upperCase);
assertEquals(0, metrics.lowerCase);
assertEquals(0, metrics.numeric);
assertEquals(0, metrics.symbols);
assertEquals(0, metrics.nonLetter);
}
@Test
public void testParceling() {
final int quality = 0;
final int length = 1;
final int letters = 2;
final int upperCase = 3;
final int lowerCase = 4;
final int numeric = 5;
final int symbols = 6;
final int nonLetter = 7;
final Parcel parcel = Parcel.obtain();
final PasswordMetrics metrics;
try {
new PasswordMetrics(
quality, length, letters, upperCase, lowerCase, numeric, symbols, nonLetter)
.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
metrics = PasswordMetrics.CREATOR.createFromParcel(parcel);
} finally {
parcel.recycle();
}
assertEquals(quality, metrics.quality);
assertEquals(length, metrics.length);
assertEquals(letters, metrics.letters);
assertEquals(upperCase, metrics.upperCase);
assertEquals(lowerCase, metrics.lowerCase);
assertEquals(numeric, metrics.numeric);
assertEquals(symbols, metrics.symbols);
assertEquals(nonLetter, metrics.nonLetter);
}
@Test
public void testComputeForPassword_metrics() {
final PasswordMetrics metrics =
PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes());
assertEquals(11, metrics.length);
assertEquals(4, metrics.letters);
assertEquals(3, metrics.upperCase);
assertEquals(1, metrics.lowerCase);
assertEquals(5, metrics.numeric);
assertEquals(2, metrics.symbols);
assertEquals(7, metrics.nonLetter);
}
@Test
public void testComputeForPassword_quality() {
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC,
PasswordMetrics.computeForPassword("a1".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
PasswordMetrics.computeForPassword("a".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
PasswordMetrics.computeForPassword("*~&%$".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,
PasswordMetrics.computeForPassword("1".getBytes()).quality);
// contains a long sequence so isn't complex
assertEquals(PASSWORD_QUALITY_NUMERIC,
PasswordMetrics.computeForPassword("1234".getBytes()).quality);
assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
PasswordMetrics.computeForPassword("".getBytes()).quality);
}
@Test
public void testMaxLengthSequence() {
assertEquals(4, PasswordMetrics.maxLengthSequence("1234".getBytes()));
assertEquals(5, PasswordMetrics.maxLengthSequence("13579".getBytes()));
assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd".getBytes()));
assertEquals(3, PasswordMetrics.maxLengthSequence("aabc".getBytes()));
assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio".getBytes()));
assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC".getBytes()));
// anything that repeats
assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;".getBytes()));
// ordered, but not composed of alphas or digits
assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>".getBytes()));
}
@Test
public void testEquals() {
PasswordMetrics metrics0 = new PasswordMetrics();
PasswordMetrics metrics1 = new PasswordMetrics();
assertNotEquals(metrics0, null);
assertNotEquals(metrics0, new Object());
assertEquals(metrics0, metrics0);
assertEquals(metrics0, metrics1);
assertEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4));
assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 5));
assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4),
new PasswordMetrics(PASSWORD_QUALITY_COMPLEX, 4));
metrics0 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
metrics1 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes());
assertEquals(metrics0, metrics1);
metrics1.letters++;
assertNotEquals(metrics0, metrics1);
metrics1.letters--;
metrics1.upperCase++;
assertNotEquals(metrics0, metrics1);
metrics1.upperCase--;
metrics1.lowerCase++;
assertNotEquals(metrics0, metrics1);
metrics1.lowerCase--;
metrics1.numeric++;
assertNotEquals(metrics0, metrics1);
metrics1.numeric--;
metrics1.symbols++;
assertNotEquals(metrics0, metrics1);
metrics1.symbols--;
metrics1.nonLetter++;
assertNotEquals(metrics0, metrics1);
metrics1.nonLetter--;
assertEquals(metrics0, metrics1);
}
@Test
public void testConstructQuality() {
PasswordMetrics expected = new PasswordMetrics();
expected.quality = PASSWORD_QUALITY_COMPLEX;
PasswordMetrics actual = new PasswordMetrics(PASSWORD_QUALITY_COMPLEX);
assertEquals(expected, actual);
}
@Test
public void testDetermineComplexity_none() {
assertEquals(PASSWORD_COMPLEXITY_NONE,
PasswordMetrics.computeForPassword("".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowSomething() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
new PasswordMetrics(PASSWORD_QUALITY_SOMETHING).determineComplexity());
}
@Test
public void testDetermineComplexity_lowNumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
PasswordMetrics.computeForPassword("1234".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
PasswordMetrics.computeForPassword("124".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
PasswordMetrics.computeForPassword("a!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_lowAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_LOW,
PasswordMetrics.computeForPassword("a!1".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
PasswordMetrics.computeForPassword("1238".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
PasswordMetrics.computeForPassword("ab!c".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_mediumAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_MEDIUM,
PasswordMetrics.computeForPassword("ab!1".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highNumericComplex() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
PasswordMetrics.computeForPassword("12389647!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphabetic() {
assertEquals(PASSWORD_COMPLEXITY_HIGH,
PasswordMetrics.computeForPassword("alphabetic!".getBytes()).determineComplexity());
}
@Test
public void testDetermineComplexity_highAlphanumeric() {
assertEquals(PASSWORD_COMPLEXITY_HIGH, PasswordMetrics.computeForPassword(
"alphanumeric123!".getBytes()).determineComplexity());
}
@Test
public void testSanitizeComplexityLevel_none() {
assertEquals(PASSWORD_COMPLEXITY_NONE, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_NONE));
}
@Test
public void testSanitizeComplexityLevel_low() {
assertEquals(PASSWORD_COMPLEXITY_LOW, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_LOW));
}
@Test
public void testSanitizeComplexityLevel_medium() {
assertEquals(
PASSWORD_COMPLEXITY_MEDIUM, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_MEDIUM));
}
@Test
public void testSanitizeComplexityLevel_high() {
assertEquals(PASSWORD_COMPLEXITY_HIGH, sanitizeComplexityLevel(PASSWORD_COMPLEXITY_HIGH));
}
@Test
public void testSanitizeComplexityLevel_invalid() {
assertEquals(PASSWORD_COMPLEXITY_NONE, sanitizeComplexityLevel(-1));
}
@Test
public void testComplexityLevelToMinQuality_none() {
assertEquals(PASSWORD_QUALITY_UNSPECIFIED,
complexityLevelToMinQuality(PASSWORD_COMPLEXITY_NONE));
}
@Test
public void testComplexityLevelToMinQuality_low() {
assertEquals(PASSWORD_QUALITY_SOMETHING,
complexityLevelToMinQuality(PASSWORD_COMPLEXITY_LOW));
}
@Test
public void testComplexityLevelToMinQuality_medium() {
assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX,
complexityLevelToMinQuality(PASSWORD_COMPLEXITY_MEDIUM));
}
@Test
public void testComplexityLevelToMinQuality_high() {
assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX,
complexityLevelToMinQuality(PASSWORD_COMPLEXITY_HIGH));
}
@Test
public void testComplexityLevelToMinQuality_invalid() {
assertEquals(PASSWORD_QUALITY_UNSPECIFIED, complexityLevelToMinQuality(-1));
}
@Test
public void testGetTargetQualityMetrics_noneComplexityReturnsDefaultMetrics() {
PasswordMetrics metrics =
getTargetQualityMetrics(PASSWORD_COMPLEXITY_NONE, PASSWORD_QUALITY_ALPHANUMERIC);
assertTrue(metrics.isDefault());
}
@Test
public void testGetTargetQualityMetrics_qualityNotAllowedReturnsMinQualityMetrics() {
PasswordMetrics metrics =
getTargetQualityMetrics(PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_NUMERIC);
assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
assertEquals(/* expected= */ 4, metrics.length);
}
@Test
public void testGetTargetQualityMetrics_highComplexityNumericComplex() {
PasswordMetrics metrics = getTargetQualityMetrics(
PASSWORD_COMPLEXITY_HIGH, PASSWORD_QUALITY_NUMERIC_COMPLEX);
assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
assertEquals(/* expected= */ 8, metrics.length);
}
@Test
public void testGetTargetQualityMetrics_mediumComplexityAlphabetic() {
PasswordMetrics metrics = getTargetQualityMetrics(
PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_ALPHABETIC);
assertEquals(PASSWORD_QUALITY_ALPHABETIC, metrics.quality);
assertEquals(/* expected= */ 4, metrics.length);
}
@Test
public void testGetTargetQualityMetrics_lowComplexityAlphanumeric() {
PasswordMetrics metrics = getTargetQualityMetrics(
PASSWORD_COMPLEXITY_MEDIUM, PASSWORD_QUALITY_ALPHANUMERIC);
assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, metrics.quality);
assertEquals(/* expected= */ 4, metrics.length);
}
@Test
public void testGetActualRequiredQuality_nonComplex() {
int actual = getActualRequiredQuality(
PASSWORD_QUALITY_NUMERIC_COMPLEX,
/* requiresNumeric= */ false,
/* requiresLettersOrSymbols= */ false);
assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, actual);
}
@Test
public void testGetActualRequiredQuality_complexRequiresNone() {
int actual = getActualRequiredQuality(
PASSWORD_QUALITY_COMPLEX,
/* requiresNumeric= */ false,
/* requiresLettersOrSymbols= */ false);
assertEquals(PASSWORD_QUALITY_UNSPECIFIED, actual);
}
@Test
public void testGetActualRequiredQuality_complexRequiresNumeric() {
int actual = getActualRequiredQuality(
PASSWORD_QUALITY_COMPLEX,
/* requiresNumeric= */ true,
/* requiresLettersOrSymbols= */ false);
assertEquals(PASSWORD_QUALITY_NUMERIC, actual);
}
@Test
public void testGetActualRequiredQuality_complexRequiresLetters() {
int actual = getActualRequiredQuality(
PASSWORD_QUALITY_COMPLEX,
/* requiresNumeric= */ false,
/* requiresLettersOrSymbols= */ true);
assertEquals(PASSWORD_QUALITY_ALPHABETIC, actual);
}
@Test
public void testGetActualRequiredQuality_complexRequiresNumericAndLetters() {
int actual = getActualRequiredQuality(
PASSWORD_QUALITY_COMPLEX,
/* requiresNumeric= */ true,
/* requiresLettersOrSymbols= */ true);
assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, actual);
}
@Test
public void testGetMinimumMetrics_userInputStricter() {
PasswordMetrics metrics = getMinimumMetrics(
PASSWORD_COMPLEXITY_HIGH,
PASSWORD_QUALITY_ALPHANUMERIC,
PASSWORD_QUALITY_NUMERIC,
/* requiresNumeric= */ false,
/* requiresLettersOrSymbols= */ false);
assertEquals(PASSWORD_QUALITY_ALPHANUMERIC, metrics.quality);
assertEquals(/* expected= */ 6, metrics.length);
}
@Test
public void testGetMinimumMetrics_actualRequiredQualityStricter() {
PasswordMetrics metrics = getMinimumMetrics(
PASSWORD_COMPLEXITY_HIGH,
PASSWORD_QUALITY_UNSPECIFIED,
PASSWORD_QUALITY_NUMERIC,
/* requiresNumeric= */ false,
/* requiresLettersOrSymbols= */ false);
assertEquals(PASSWORD_QUALITY_NUMERIC_COMPLEX, metrics.quality);
assertEquals(/* expected= */ 8, metrics.length);
}
}