Commit 0de33520 authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Test Ash smart card login PIN lockout failure

Provide test coverage for the scenario when the PIN dialog, triggered
during the challenge-response login (a.k.a. smart card based login),
receives a wrong PIN several times until the lockout happens.

Bug: 1033936
Change-Id: Ibe90e48fd2a32fb990e22357704afab2bdd6e3b0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2317230
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarFabian Sommer <fabiansommer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#792232}
parent f650fe63
...@@ -266,10 +266,19 @@ void TestCertificateProviderExtension::HandleSignatureRequest( ...@@ -266,10 +266,19 @@ void TestCertificateProviderExtension::HandleSignatureRequest(
// side before generating the signature. // side before generating the signature.
base::Value pin_request_parameters(base::Value::Type::DICTIONARY); base::Value pin_request_parameters(base::Value::Type::DICTIONARY);
pin_request_parameters.SetIntKey("signRequestId", sign_request_id); pin_request_parameters.SetIntKey("signRequestId", sign_request_id);
if (remaining_pin_attempts_ == 0) {
pin_request_parameters.SetStringKey("errorType",
"MAX_ATTEMPTS_EXCEEDED");
}
response.SetKey("requestPin", std::move(pin_request_parameters)); response.SetKey("requestPin", std::move(pin_request_parameters));
std::move(callback).Run(response); std::move(callback).Run(response);
return; return;
} }
if (remaining_pin_attempts_ == 0) {
// The error about the lockout is already displayed, so fail immediately.
std::move(callback).Run(/*response=*/base::Value());
return;
}
if (pin_status_string == "canceled" || if (pin_status_string == "canceled" ||
base::StartsWith(pin_status_string, base::StartsWith(pin_status_string,
"failed:", base::CompareCase::SENSITIVE)) { "failed:", base::CompareCase::SENSITIVE)) {
...@@ -281,10 +290,19 @@ void TestCertificateProviderExtension::HandleSignatureRequest( ...@@ -281,10 +290,19 @@ void TestCertificateProviderExtension::HandleSignatureRequest(
} }
DCHECK_EQ(pin_status_string, "ok"); DCHECK_EQ(pin_status_string, "ok");
if (pin_string != *required_pin_) { if (pin_string != *required_pin_) {
// The PIN is wrong, so retry the PIN request with displaying an error. // The entered PIN is wrong, so decrement the remaining attempt count, and
// update the PIN dialog with displaying an error.
if (remaining_pin_attempts_ > 0)
--remaining_pin_attempts_;
base::Value pin_request_parameters(base::Value::Type::DICTIONARY); base::Value pin_request_parameters(base::Value::Type::DICTIONARY);
pin_request_parameters.SetIntKey("signRequestId", sign_request_id); pin_request_parameters.SetIntKey("signRequestId", sign_request_id);
pin_request_parameters.SetStringKey("errorType", "INVALID_PIN"); pin_request_parameters.SetStringKey(
"errorType", remaining_pin_attempts_ == 0 ? "MAX_ATTEMPTS_EXCEEDED"
: "INVALID_PIN");
if (remaining_pin_attempts_ > 0) {
pin_request_parameters.SetIntKey("attemptsLeft",
remaining_pin_attempts_);
}
response.SetKey("requestPin", std::move(pin_request_parameters)); response.SetKey("requestPin", std::move(pin_request_parameters));
std::move(callback).Run(response); std::move(callback).Run(response);
return; return;
......
...@@ -58,6 +58,14 @@ class TestCertificateProviderExtension final ...@@ -58,6 +58,14 @@ class TestCertificateProviderExtension final
// (By default, no PIN is requested.) // (By default, no PIN is requested.)
void set_require_pin(const std::string& pin) { required_pin_ = pin; } void set_require_pin(const std::string& pin) { required_pin_ = pin; }
// Sets the number of remaining PIN attempts.
// Zero number means the lockout state, when no attempts are allowed anymore.
// A negative number denotes infinite number of attempts, which is the default
// behavior.
void set_remaining_pin_attempts(int remaining_pin_attempts) {
remaining_pin_attempts_ = remaining_pin_attempts;
}
// Sets whether the extension should respond with a failure to the // Sets whether the extension should respond with a failure to the
// onCertificatesRequested requests. // onCertificatesRequested requests.
void set_should_fail_certificate_requests( void set_should_fail_certificate_requests(
...@@ -94,6 +102,10 @@ class TestCertificateProviderExtension final ...@@ -94,6 +102,10 @@ class TestCertificateProviderExtension final
// When non-empty, contains the expected PIN; the implementation will request // When non-empty, contains the expected PIN; the implementation will request
// the PIN on every signature request in this case. // the PIN on every signature request in this case.
base::Optional<std::string> required_pin_; base::Optional<std::string> required_pin_;
// The number of remaining PIN attempts.
// When equal to zero, signature requests will be failed immediately; when is
// negative, infinite number of attempts is allowed.
int remaining_pin_attempts_ = -1;
bool should_fail_certificate_requests_ = false; bool should_fail_certificate_requests_ = false;
bool should_fail_sign_digest_requests_ = false; bool should_fail_sign_digest_requests_ = false;
content::NotificationRegistrar notification_registrar_; content::NotificationRegistrar notification_registrar_;
......
...@@ -64,6 +64,13 @@ constexpr char kChallengeResponseErrorLabel[] = ...@@ -64,6 +64,13 @@ constexpr char kChallengeResponseErrorLabel[] =
"Couldn’t recognize your smart card. Try again."; "Couldn’t recognize your smart card. Try again.";
constexpr char kPinDialogDefaultTitle[] = "Smart card PIN"; constexpr char kPinDialogDefaultTitle[] = "Smart card PIN";
constexpr char kPinDialogInvalidPinTitle[] = "Invalid PIN."; constexpr char kPinDialogInvalidPinTitle[] = "Invalid PIN.";
constexpr char kPinDialogInvalidPin2AttemptsTitle[] =
"Invalid PIN. 2 attempts left";
// TODO(crbug.com/1060695): Fix the incorrect plural in the message.
constexpr char kPinDialogInvalidPin1AttemptTitle[] =
"Invalid PIN. 1 attempts left";
constexpr char kPinDialogNoAttemptsLeftTitle[] =
"Maximum allowed attempts exceeded.";
constexpr char kChallengeData[] = "challenge"; constexpr char kChallengeData[] = "challenge";
...@@ -330,6 +337,29 @@ IN_PROC_BROWSER_TEST_F(SecurityTokenLoginTest, WrongPinThenCorrect) { ...@@ -330,6 +337,29 @@ IN_PROC_BROWSER_TEST_F(SecurityTokenLoginTest, WrongPinThenCorrect) {
WaitForActiveSession(); WaitForActiveSession();
} }
// Test the login failure scenario when the wrong PIN is entered several times
// until there's no more attempt left (simulating, e.g., a smart card lockout).
IN_PROC_BROWSER_TEST_F(SecurityTokenLoginTest, WrongPinUntilLockout) {
test_certificate_provider_extension()->set_remaining_pin_attempts(3);
StartLoginAndWaitForPinDialog();
// A wrong PIN is entered several times, causing a corresponding error
// displayed in the PIN dialog.
LoginScreenTestApi::SubmitPinRequestWidget(kWrongPin);
WaitForPinDialogTitle(kPinDialogInvalidPin2AttemptsTitle);
LoginScreenTestApi::SubmitPinRequestWidget(kWrongPin);
WaitForPinDialogTitle(kPinDialogInvalidPin1AttemptTitle);
LoginScreenTestApi::SubmitPinRequestWidget(kWrongPin);
WaitForPinDialogTitle(kPinDialogNoAttemptsLeftTitle);
// After closing the PIN dialog with the fatal error, the login fails.
AuthFailureWaiter auth_failure_waiter;
LoginScreenTestApi::CancelPinRequestWidget();
EXPECT_EQ(auth_failure_waiter.Wait(),
AuthFailure::COULD_NOT_MOUNT_CRYPTOHOME);
}
// Test the login failure scenario when the extension fails to sign the // Test the login failure scenario when the extension fails to sign the
// challenge. // challenge.
IN_PROC_BROWSER_TEST_F(SecurityTokenLoginTest, SigningFailure) { IN_PROC_BROWSER_TEST_F(SecurityTokenLoginTest, SigningFailure) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment