Index: chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc |
diff --git a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc |
index b97b51a4116eaa15a80684c327af073db9df4918..9488f74425b7e3c4f270c354c3c86ec0fc19f655 100644 |
--- a/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc |
+++ b/chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api_unittest.cc |
@@ -6,6 +6,8 @@ |
#include "chrome/browser/chromeos/extensions/quick_unlock_private/quick_unlock_private_api.h" |
+#include <algorithm> |
+ |
#include "base/bind.h" |
#include "base/memory/ptr_util.h" |
#include "chrome/browser/chromeos/login/quick_unlock/pin_storage.h" |
@@ -14,12 +16,16 @@ |
#include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h" |
#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" |
#include "chrome/browser/extensions/extension_api_unittest.h" |
+#include "chrome/common/pref_names.h" |
#include "chromeos/login/auth/fake_extended_authenticator.h" |
#include "extensions/browser/api_test_utils.h" |
#include "extensions/browser/extension_function_dispatcher.h" |
using namespace extensions; |
namespace quick_unlock_private = extensions::api::quick_unlock_private; |
+using CredentialCheck = quick_unlock_private::CredentialCheck; |
+using CredentialProblem = quick_unlock_private::CredentialProblem; |
+using CredentialRequirements = quick_unlock_private::CredentialRequirements; |
using QuickUnlockMode = quick_unlock_private::QuickUnlockMode; |
using QuickUnlockModeList = std::vector<QuickUnlockMode>; |
using CredentialList = std::vector<std::string>; |
@@ -50,6 +56,15 @@ void FailIfCalled(const QuickUnlockModeList& modes) { |
FAIL(); |
} |
+enum ExpectedPinState { |
+ PIN_GOOD = 1 << 0, |
+ PIN_TOO_SHORT = 1 << 1, |
+ PIN_TOO_LONG = 1 << 2, |
+ PIN_WEAK_ERROR = 1 << 3, |
+ PIN_WEAK_WARNING = 1 << 4, |
+ PIN_CONTAINS_NONDIGIT = 1 << 5 |
+}; |
+ |
} // namespace |
class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest { |
@@ -129,6 +144,72 @@ class QuickUnlockPrivateUnitTest : public ExtensionApiUnittest { |
return modes; |
} |
+ // Returns true if |problem| is contained in |problems|. |
+ bool HasProblem(CredentialProblem problem, |
+ const std::vector<CredentialProblem> problems) { |
+ return std::find(problems.begin(), problems.end(), problem) != |
+ problems.end(); |
+ } |
+ |
+ bool HasFlag(int outcome, int flag) { return (outcome & flag) != 0; } |
+ |
+ // Helper function for checking whether |IsCredentialUsableUsingPin| will |
+ // return the right message given a pin. |
+ void CheckPin(int expected_outcome, const std::string& pin) { |
+ CredentialCheck result = CheckCredentialUsingPin(pin); |
+ const std::vector<CredentialProblem> errors(result.errors); |
+ const std::vector<CredentialProblem> warnings(result.warnings); |
+ |
+ // A pin is considered good if it emits no errors or warnings. |
+ EXPECT_EQ(HasFlag(expected_outcome, PIN_GOOD), |
+ errors.empty() && warnings.empty()); |
+ EXPECT_EQ( |
+ HasFlag(expected_outcome, PIN_TOO_SHORT), |
+ HasProblem(CredentialProblem::CREDENTIAL_PROBLEM_TOO_SHORT, errors)); |
+ EXPECT_EQ( |
+ HasFlag(expected_outcome, PIN_TOO_LONG), |
+ HasProblem(CredentialProblem::CREDENTIAL_PROBLEM_TOO_LONG, errors)); |
+ EXPECT_EQ( |
+ HasFlag(expected_outcome, PIN_WEAK_WARNING), |
+ HasProblem(CredentialProblem::CREDENTIAL_PROBLEM_TOO_WEAK, warnings)); |
+ EXPECT_EQ( |
+ HasFlag(expected_outcome, PIN_WEAK_ERROR), |
+ HasProblem(CredentialProblem::CREDENTIAL_PROBLEM_TOO_WEAK, errors)); |
+ EXPECT_EQ( |
+ HasFlag(expected_outcome, PIN_CONTAINS_NONDIGIT), |
+ HasProblem(CredentialProblem::CREDENTIAL_PROBLEM_CONTAINS_NONDIGIT, |
+ errors)); |
+ } |
+ |
+ CredentialCheck CheckCredentialUsingPin(const std::string& pin) { |
+ auto params = base::MakeUnique<base::ListValue>(); |
+ params->AppendString(ToString(QuickUnlockMode::QUICK_UNLOCK_MODE_PIN)); |
+ params->AppendString(pin); |
+ |
+ std::unique_ptr<base::Value> result = RunFunction( |
+ new QuickUnlockPrivateCheckCredentialFunction(), std::move(params)); |
+ |
+ CredentialCheck function_result; |
+ EXPECT_TRUE(CredentialCheck::Populate(*result, &function_result)); |
+ return function_result; |
+ } |
+ |
+ void CheckGetCredentialRequirements(int expected_pin_min_length, |
+ int expected_pin_max_length) { |
+ auto params = base::MakeUnique<base::ListValue>(); |
+ params->AppendString(ToString(QuickUnlockMode::QUICK_UNLOCK_MODE_PIN)); |
+ |
+ std::unique_ptr<base::Value> result = |
+ RunFunction(new QuickUnlockPrivateGetCredentialRequirementsFunction(), |
+ std::move(params)); |
+ |
+ CredentialRequirements function_result; |
+ EXPECT_TRUE(CredentialRequirements::Populate(*result, &function_result)); |
+ |
+ EXPECT_EQ(function_result.min_length, expected_pin_min_length); |
+ EXPECT_EQ(function_result.max_length, expected_pin_max_length); |
+ } |
+ |
// Wrapper for chrome.quickUnlockPrivate.setModes that automatically uses a |
// valid password. |
bool SetModes(const QuickUnlockModeList& modes, |
@@ -245,7 +326,7 @@ TEST_F(QuickUnlockPrivateUnitTest, SetModesFailsWithInvalidPassword) { |
FailIfModesChanged(); |
EXPECT_FALSE(SetModesUsingPassword( |
kInvalidPassword, |
- QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"})); |
+ QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"1111"})); |
EXPECT_EQ(GetActiveModes(), QuickUnlockModeList{}); |
} |
@@ -263,10 +344,10 @@ TEST_F(QuickUnlockPrivateUnitTest, ModeChangeEventOnlyRaisedWhenModesChange) { |
ExpectModesChanged( |
QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}); |
EXPECT_TRUE(SetModes( |
- QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"})); |
+ QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"1111"})); |
FailIfModesChanged(); |
EXPECT_TRUE(SetModes( |
- QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"22"})); |
+ QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"2222"})); |
EXPECT_TRUE(SetModes( |
QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {""})); |
} |
@@ -280,7 +361,7 @@ TEST_F(QuickUnlockPrivateUnitTest, SetModesAndGetActiveModes) { |
ExpectModesChanged( |
QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}); |
EXPECT_TRUE(SetModes( |
- QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"})); |
+ QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"1111"})); |
EXPECT_EQ(GetActiveModes(), |
QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}); |
EXPECT_TRUE(pin_storage->IsPinSet()); |
@@ -300,13 +381,13 @@ TEST_F(QuickUnlockPrivateUnitTest, VerifyAuthenticationAgainstPIN) { |
EXPECT_FALSE(pin_storage->IsPinSet()); |
EXPECT_TRUE(SetModes( |
- QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"11"})); |
+ QuickUnlockModeList{QuickUnlockMode::QUICK_UNLOCK_MODE_PIN}, {"1111"})); |
EXPECT_TRUE(pin_storage->IsPinSet()); |
pin_storage->MarkStrongAuth(); |
pin_storage->ResetUnlockAttemptCount(); |
- EXPECT_TRUE(pin_storage->TryAuthenticatePin("11")); |
- EXPECT_FALSE(pin_storage->TryAuthenticatePin("00")); |
+ EXPECT_TRUE(pin_storage->TryAuthenticatePin("1111")); |
+ EXPECT_FALSE(pin_storage->TryAuthenticatePin("0000")); |
} |
// Verifies that the number of modes and the number of passwords given must be |
@@ -316,4 +397,97 @@ TEST_F(QuickUnlockPrivateUnitTest, ThrowErrorOnMismatchedParameterCount) { |
EXPECT_FALSE(SetModesWithError("[\"valid\", [], [\"11\"]]").empty()); |
} |
+// Validates PIN error checking in conjuction with policy-related prefs. |
+TEST_F(QuickUnlockPrivateUnitTest, CheckCredentialProblemReporting) { |
+ PrefService* pref_service = profile()->GetPrefs(); |
+ |
+ // Verify the pin checks work with the default preferences which are minimum |
+ // length of 4, maximum length of 0 (no maximum) and no easy to guess check. |
+ CheckPin(PIN_GOOD, "1112"); |
+ CheckPin(PIN_GOOD, "11112"); |
+ CheckPin(PIN_GOOD, "1111111111111112"); |
+ CheckPin(PIN_WEAK_WARNING, "1111"); |
+ CheckPin(PIN_TOO_SHORT, "1"); |
+ CheckPin(PIN_TOO_SHORT, "11"); |
+ CheckPin(PIN_TOO_SHORT | PIN_WEAK_WARNING, "111"); |
+ CheckPin(PIN_TOO_SHORT | PIN_CONTAINS_NONDIGIT, "a"); |
+ CheckPin(PIN_CONTAINS_NONDIGIT, "aaab"); |
+ CheckPin(PIN_CONTAINS_NONDIGIT | PIN_WEAK_WARNING, "aaaa"); |
+ CheckPin(PIN_CONTAINS_NONDIGIT | PIN_WEAK_WARNING, "abcd"); |
+ |
+ // Verify that now if the minimum length is set to 3, PINs of length 3 are |
+ // accepted. |
+ pref_service->SetInteger(prefs::kPinUnlockMinimumLength, 3); |
+ CheckPin(PIN_WEAK_WARNING, "111"); |
+ |
+ // Verify setting a nonzero maximum length that is less than the minimum |
+ // length results in the pin only accepting PINs of length minimum length. |
+ pref_service->SetInteger(prefs::kPinUnlockMaximumLength, 2); |
+ pref_service->SetInteger(prefs::kPinUnlockMinimumLength, 4); |
+ CheckPin(PIN_GOOD, "1112"); |
+ CheckPin(PIN_TOO_SHORT, "112"); |
+ CheckPin(PIN_TOO_LONG, "11112"); |
+ |
+ // Verify that now if the maximum length is set to 5, PINs longer than 5 are |
+ // considered too long and cannot be used. |
+ pref_service->SetInteger(prefs::kPinUnlockMaximumLength, 5); |
+ CheckPin(PIN_TOO_LONG | PIN_WEAK_WARNING, "111111"); |
+ CheckPin(PIN_TOO_LONG | PIN_WEAK_WARNING, "1111111"); |
+ |
+ // Verify that if both the minimum length and maximum length is set to 4, only |
+ // 4 digit PINs can be used. |
+ pref_service->SetInteger(prefs::kPinUnlockMinimumLength, 4); |
+ pref_service->SetInteger(prefs::kPinUnlockMaximumLength, 4); |
+ CheckPin(PIN_TOO_SHORT, "122"); |
+ CheckPin(PIN_TOO_LONG, "12222"); |
+ CheckPin(PIN_GOOD, "1222"); |
+ |
+ // Set the PINs minimum/maximum lengths back to their defaults. |
+ pref_service->SetInteger(prefs::kPinUnlockMinimumLength, 4); |
+ pref_service->SetInteger(prefs::kPinUnlockMaximumLength, 0); |
+ |
+ // Verify that PINs that are weak are flagged as such. See |
+ // IsPinDifficultEnough in quick_unlock_private_api.cc for the description of |
+ // a weak pin. |
+ pref_service->SetBoolean(prefs::kPinUnlockWeakPinsAllowed, false); |
+ // Good. |
+ CheckPin(PIN_GOOD, "1112"); |
+ CheckPin(PIN_GOOD, "7890"); |
+ CheckPin(PIN_GOOD, "0987"); |
+ // Same digits. |
+ CheckPin(PIN_WEAK_ERROR, "1111"); |
+ // Increasing. |
+ CheckPin(PIN_WEAK_ERROR, "0123"); |
+ CheckPin(PIN_WEAK_ERROR, "3456789"); |
+ // Decreasing. |
+ CheckPin(PIN_WEAK_ERROR, "3210"); |
+ CheckPin(PIN_WEAK_ERROR, "987654"); |
+ // Too common. |
+ CheckPin(PIN_WEAK_ERROR, "1212"); |
+ |
+ // Verify that if a PIN has more than one error, both are returned. |
+ CheckPin(PIN_TOO_SHORT | PIN_WEAK_ERROR, "111"); |
+ CheckPin(PIN_TOO_SHORT | PIN_WEAK_ERROR, "234"); |
+} |
+ |
+TEST_F(QuickUnlockPrivateUnitTest, GetCredentialRequirements) { |
+ PrefService* pref_service = profile()->GetPrefs(); |
+ |
+ // Verify that trying out PINs under the minimum/maximum lengths will send the |
+ // minimum/maximum lengths as additional information for display purposes. |
+ pref_service->SetInteger(prefs::kPinUnlockMinimumLength, 6); |
+ pref_service->SetInteger(prefs::kPinUnlockMaximumLength, 8); |
+ CheckGetCredentialRequirements(6, 8); |
+ |
+ // Verify that by setting a maximum length to be nonzero and smaller than the |
+ // minimum length, the resulting maxium length will be equal to the minimum |
+ // length pref. |
+ pref_service->SetInteger(prefs::kPinUnlockMaximumLength, 4); |
+ CheckGetCredentialRequirements(6, 6); |
+ |
+ // Verify that the values received from policy are sanitized. |
+ pref_service->SetInteger(prefs::kPinUnlockMinimumLength, -3); |
+ pref_service->SetInteger(prefs::kPinUnlockMaximumLength, -3); |
+ CheckGetCredentialRequirements(1, 0); |
+} |
} // namespace chromeos |