Commit c142dce8 authored by Findit's avatar Findit

Revert "Reland Add browser tests for smart card SAML login"

This reverts commit d5274dbb.

Reason for revert:

Findit (https://goo.gl/kROfz5) identified CL at revision 735947 as the
culprit for flakes in the build cycles as shown on:
https://analysis.chromium.org/p/chromium/flake-portal/analysis/culprit?key=ag9zfmZpbmRpdC1mb3ItbWVyQwsSDEZsYWtlQ3VscHJpdCIxY2hyb21pdW0vZDUyNzRkYmI0OGZlMDU2ZGRmNmFlMWNmZjQ2YjQ3OTVkNTU1NDFmOQw

Sample Failed Build: https://ci.chromium.org/b/8889996165162517568

Sample Failed Step: browser_tests

Sample Flaky Test: SecurityTokenSamlTest.Basic

Original change's description:
> Reland Add browser tests for smart card SAML login
> 
> This relands the commit 8fd76b23 that
> got reverted in commit 319c9b41 due to
> failing on official trybots.
> 
> The fix in the reland is to suppress the sync consent screen that is
> normally enabled on the "branded" builds and that was breaking test
> expectations (the test expected the user session to start straight away
> after the successful authentication without any extra screens).
> 
> Original change's description:
> > Add browser tests for smart card SAML login
> >
> > Provide test coverage for the scenario where a new user authenticates
> > via SAML using a smart card (or, generally speaking, using a security
> > token via an extension using the chrome.certificateProvider API).
> >
> > This also provides some test coverage for the <security-token-pin>
> > Polymer element used on the Login Screen.
> >
> > Bug: 1033936
> > Change-Id: I5ded32e0570eb7227c77b954c33d12c1a8a62914
> > Reviewed-on:
> https://chromium-review.googlesource.com/c/chromium/src/+/1968989
> > Reviewed-by: Alexander Alekseev <alemate@chromium.org>
> > Reviewed-by: Denis Kuznetsov [CET] <antrim@chromium.org>
> > Reviewed-by: Alexander Hendrich <hendrich@chromium.org>
> > Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
> > Cr-Commit-Position: refs/heads/master@{#734510}
> 
> Bug: 1033936
> Tbr: alemate@chromium.org, hendrich@chromium.org
> Test: run the test locally with is_chrome_branded=true
> Change-Id: I0e8394bb78030137c7570d58c2462a773c13ce06
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2017430
> Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
> Reviewed-by: Denis Kuznetsov [CET] <antrim@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#735947}


Change-Id: Ifc621efff2f069cd90b25f9fff6d778a6732c2c3
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1033936
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2025885
Cr-Commit-Position: refs/heads/master@{#736083}
parent c7d8cda0
......@@ -1630,8 +1630,6 @@ source_set("chromeos") {
"login/users/supervised_user_manager.h",
"login/users/supervised_user_manager_impl.cc",
"login/users/supervised_user_manager_impl.h",
"login/users/test_users.cc",
"login/users/test_users.h",
"login/users/user_manager_interface.h",
"login/version_info_updater.cc",
"login/version_info_updater.h",
......
......@@ -14,7 +14,9 @@
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "base/optional.h"
#include "base/strings/string_piece.h"
#include "base/values.h"
#include "chrome/common/extensions/api/certificate_provider.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/notification_details.h"
......@@ -101,11 +103,6 @@ bool RsaSignPrehashed(const EVP_PKEY& key,
return true;
}
void SendReplyToJs(extensions::TestSendMessageFunction* function,
const base::Value& response) {
function->Reply(ConvertValueToJson(response));
}
} // namespace
TestCertificateProviderExtension::TestCertificateProviderExtension(
......@@ -143,50 +140,39 @@ void TestCertificateProviderExtension::Observe(
return;
}
const auto typed_details =
content::Details<std::pair<std::string, bool*>>(details);
const std::string& message = typed_details->first;
bool* const listener_will_respond = typed_details->second;
// Handle the request and reply to it (possibly, asynchronously).
const std::string& message =
content::Details<std::pair<std::string, bool*>>(details)->first;
base::Value message_value = ParseJsonToValue(message);
CHECK(message_value.is_list());
CHECK(message_value.GetList().size());
CHECK(message_value.GetList()[0].is_string());
const std::string& request_type = message_value.GetList()[0].GetString();
ReplyToJsCallback send_reply_to_js_callback =
base::BindOnce(&SendReplyToJs, base::Unretained(function));
*listener_will_respond = true;
base::Value response;
if (request_type == "onCertificatesRequested") {
CHECK_EQ(message_value.GetList().size(), 1U);
HandleCertificatesRequest(std::move(send_reply_to_js_callback));
} else if (request_type == "onSignatureRequested") {
CHECK_EQ(message_value.GetList().size(), 3U);
HandleSignatureRequest(
/*sign_request=*/message_value.GetList()[1],
/*pin_user_input=*/message_value.GetList()[2],
std::move(send_reply_to_js_callback));
response = HandleCertificatesRequest();
} else if (request_type == "onSignDigestRequested") {
CHECK_EQ(message_value.GetList().size(), 2U);
response =
HandleSignDigestRequest(/*sign_request=*/message_value.GetList()[1]);
} else {
LOG(FATAL) << "Unexpected JS message type: " << request_type;
}
function->Reply(ConvertValueToJson(response));
}
void TestCertificateProviderExtension::HandleCertificatesRequest(
ReplyToJsCallback callback) {
base::Value TestCertificateProviderExtension::HandleCertificatesRequest() {
base::Value cert_info_values(base::Value::Type::LIST);
if (!should_fail_certificate_requests_)
cert_info_values.Append(MakeCertInfoValue(*certificate_));
std::move(callback).Run(cert_info_values);
return cert_info_values;
}
void TestCertificateProviderExtension::HandleSignatureRequest(
const base::Value& sign_request,
const base::Value& pin_user_input,
ReplyToJsCallback callback) {
base::Value TestCertificateProviderExtension::HandleSignDigestRequest(
const base::Value& sign_request) {
CHECK_EQ(*sign_request.FindKey("certificate"),
ConvertBytesToValue(GetCertDer(*certificate_)));
const int sign_request_id = sign_request.FindKey("signRequestId")->GetInt();
const std::vector<uint8_t> digest =
ExtractBytesFromValue(*sign_request.FindKey("digest"));
......@@ -201,42 +187,10 @@ void TestCertificateProviderExtension::HandleSignatureRequest(
else
LOG(FATAL) << "Unexpected signature request hash: " << hash;
if (should_fail_sign_digest_requests_) {
// Simulate a failure.
std::move(callback).Run(/*response=*/base::Value());
return;
}
base::Value response(base::Value::Type::DICTIONARY);
if (required_pin_.has_value()) {
if (pin_user_input.is_none()) {
// The PIN is required but not specified yet, so request it via the JS
// side before generating the signature.
base::Value pin_request_parameters(base::Value::Type::DICTIONARY);
pin_request_parameters.SetIntKey("signRequestId", sign_request_id);
response.SetKey("requestPin", std::move(pin_request_parameters));
std::move(callback).Run(response);
return;
}
if (pin_user_input.GetString() != *required_pin_) {
// The PIN is wrong, so retry the PIN request with displaying an error.
base::Value pin_request_parameters(base::Value::Type::DICTIONARY);
pin_request_parameters.SetIntKey("signRequestId", sign_request_id);
pin_request_parameters.SetStringKey("errorType", "INVALID_PIN");
response.SetKey("requestPin", std::move(pin_request_parameters));
std::move(callback).Run(response);
return;
}
// The entered PIN is correct. Stop the PIN request and proceed to
// generating the signature.
base::Value stop_pin_request_parameters(base::Value::Type::DICTIONARY);
stop_pin_request_parameters.SetIntKey("signRequestId", sign_request_id);
response.SetKey("stopPinRequest", std::move(stop_pin_request_parameters));
}
// Generate and return a valid signature.
if (should_fail_sign_digest_requests_)
return base::Value();
std::vector<uint8_t> signature;
CHECK(
RsaSignPrehashed(*private_key_, openssl_digest_type, digest, &signature));
response.SetKey("signature", ConvertBytesToValue(signature));
std::move(callback).Run(response);
return ConvertBytesToValue(signature);
}
......@@ -8,11 +8,8 @@
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/scoped_refptr.h"
#include "base/optional.h"
#include "base/values.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "third_party/boringssl/src/include/openssl/base.h"
......@@ -50,10 +47,6 @@ class TestCertificateProviderExtension final
return certificate_;
}
// Sets the PIN that will be required when doing every signature request.
// (By default, no PIN is requested.)
void set_require_pin(const std::string& pin) { required_pin_ = pin; }
// Sets whether the extension should respond with a failure to the
// onCertificatesRequested requests.
void set_should_fail_certificate_requests(
......@@ -69,26 +62,18 @@ class TestCertificateProviderExtension final
}
private:
using ReplyToJsCallback =
base::OnceCallback<void(const base::Value& response)>;
// content::NotificationObserver implementation:
void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) override;
void HandleCertificatesRequest(ReplyToJsCallback callback);
void HandleSignatureRequest(const base::Value& sign_request,
const base::Value& pin_user_input,
ReplyToJsCallback callback);
base::Value HandleCertificatesRequest();
base::Value HandleSignDigestRequest(const base::Value& sign_request);
content::BrowserContext* const browser_context_;
const std::string extension_id_;
const scoped_refptr<net::X509Certificate> certificate_;
const bssl::UniquePtr<EVP_PKEY> private_key_;
// When non-empty, contains the expected PIN; the implementation will request
// the PIN on every signature request in this case.
base::Optional<std::string> required_pin_;
bool should_fail_certificate_requests_ = false;
bool should_fail_sign_digest_requests_ = false;
content::NotificationRegistrar notification_registrar_;
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <iterator>
#include <string>
#include "base/bind.h"
#include "base/command_line.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/values.h"
#include "chrome/browser/chromeos/certificate_provider/test_certificate_provider_extension.h"
#include "chrome/browser/chromeos/certificate_provider/test_certificate_provider_extension_login_screen_mixin.h"
#include "chrome/browser/chromeos/login/saml/test_client_cert_saml_idp_mixin.h"
#include "chrome/browser/chromeos/login/test/device_state_mixin.h"
#include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
#include "chrome/browser/chromeos/login/test/https_forwarder.h"
#include "chrome/browser/chromeos/login/test/js_checker.h"
#include "chrome/browser/chromeos/login/test/oobe_base_test.h"
#include "chrome/browser/chromeos/login/test/scoped_policy_update.h"
#include "chrome/browser/chromeos/login/test/session_manager_state_waiter.h"
#include "chrome/browser/chromeos/login/ui/login_display_host.h"
#include "chrome/browser/chromeos/login/users/test_users.h"
#include "chrome/browser/chromeos/scoped_test_system_nss_key_slot_mixin.h"
#include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
#include "chromeos/constants/chromeos_switches.h"
#include "components/account_id/account_id.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_ui.h"
#include "google_apis/gaia/fake_gaia.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace chromeos {
namespace {
// Pattern for the DeviceLoginScreenAutoSelectCertificateForUrls admin policy
// that automatically selects the certificate exposed by the test certificate
// provider extension.
constexpr char kClientCertAutoSelectPolicyValue[] =
R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})";
// The DER-encoded "CN=B CA" DistinguishedName value, which represents the
// issuer of the certificate exposed by the test certificate provider extension.
constexpr uint8_t kClientCertCaName[] = {0x30, 0x0f, 0x31, 0x0d, 0x30, 0x0b,
0x06, 0x03, 0x55, 0x04, 0x03, 0x0c,
0x04, 0x42, 0x20, 0x43, 0x41};
// The PIN code that the test certificate provider extension is configured to
// expect.
constexpr char kCorrectPin[] = "17093";
std::string GetClientCertCaName() {
return std::string(std::begin(kClientCertCaName),
std::end(kClientCertCaName));
}
std::string GetActiveUserEmail() {
const user_manager::User* user =
user_manager::UserManager::Get()->GetActiveUser();
if (!user)
return std::string();
return user->GetAccountId().GetUserEmail();
}
} // namespace
// Tests the challenge-response type of SAML login (e.g., the smart card based
// user login).
//
// The rough sequence of steps in the correct scenario:
// 1. the user e-mail is entered into the Gaia form;
// 2. the browser is redirected to the (first) SAML page;
// 3. the browser is redirected to the second SAML page, which requests a client
// certificate during the TLS handshake;
// 4. the test certificate provider extension returns the client certificate;
// 5. the TLS handshake with the SAML server continues, and the server makes a
// challenge request;
// 6. the test certificate provider extension receives the challenge and
// requests the PIN, for which the PIN dialog is shown on top of the SAML
// page frame;
// 7. the PIN is entered;
// 8. the test certificate provider extension receives the PIN and generates the
// signature of the challenge, which is forwarded to the SAML server;
// 9. the TLS handshake with the SAML server completes, and the SAML page
// redirects back to Gaia to signal about the successful authentication;
// 10. the user session starts.
class SecurityTokenSamlTest : public OobeBaseTest {
protected:
SecurityTokenSamlTest() {
// Allow the forced installation of extensions in the background.
needs_background_networking_ = true;
SetClientCertAutoSelectPolicy();
ConfigureFakeGaia();
}
SecurityTokenSamlTest(const SecurityTokenSamlTest&) = delete;
SecurityTokenSamlTest& operator=(const SecurityTokenSamlTest&) = delete;
void SetUpCommandLine(base::CommandLine* command_line) override {
OobeBaseTest::SetUpCommandLine(command_line);
// Skip OOBE post-login screens (like the sync consent screen in branded
// builders) to make the test simpler by directly proceeding to user session
// after the sign-in.
command_line->AppendSwitch(switches::kOobeSkipPostLogin);
// Avoid aborting the user sign-in due to the user policy requests not being
// faked in the test.
command_line->AppendSwitch(
chromeos::switches::kAllowFailedPolicyFetchForTest);
}
void SetUpOnMainThread() override {
OobeBaseTest::SetUpOnMainThread();
cert_provider_extension_mixin_.test_certificate_provider_extension()
->set_require_pin(kCorrectPin);
gaia_mixin_.fake_gaia()->RegisterSamlUser(
saml_test_users::kFirstUserCorpExampleComEmail,
saml_idp_mixin_.GetSamlPageUrl());
StartObservingLoginUiMessages();
}
int pin_dialog_shown_count() const { return pin_dialog_shown_count_; }
void StartSignIn() {
LoginDisplayHost::default_host()
->GetOobeUI()
->GetView<GaiaScreenHandler>()
->ShowSigninScreenForTest(
saml_test_users::kFirstUserCorpExampleComEmail,
/*password=*/std::string(),
/*services=*/"[]");
}
// Waits until the security token PIN dialog appears on the login screen.
void WaitForPinDialog() {
if (pin_dialog_shown_count_)
return;
base::RunLoop run_loop;
pin_dialog_shown_run_loop_ = &run_loop;
// Quit() will be called from OnPinDialogShownMessage().
run_loop.Run();
pin_dialog_shown_run_loop_ = nullptr;
}
// Enters the security token PIN by simulating click events on the on-screen
// keypad.
void InputPinByClickingKeypad(const std::string& pin) {
for (char pin_character : pin) {
const std::string digit_button_id =
std::string("digitButton") + pin_character;
test::OobeJS().ClickOnPath(
{"gaia-signin", "pinDialog", "pinKeyboard", digit_button_id});
}
}
private:
// Sets up the client certificate to be automatically selected for the SAML
// page (by default a certificate selector needs to be shown).
void SetClientCertAutoSelectPolicy() {
device_state_mixin_.RequestDevicePolicyUpdate()
->policy_payload()
->mutable_device_login_screen_auto_select_certificate_for_urls()
->add_login_screen_auto_select_certificate_rules(
kClientCertAutoSelectPolicyValue);
}
void ConfigureFakeGaia() {
// FakeGaia uses the fake merge session parameters for preparing the result
// of the SAML sign-in.
gaia_mixin_.set_initialize_fake_merge_session(false);
gaia_mixin_.fake_gaia()->SetFakeMergeSessionParams(
saml_test_users::kFirstUserCorpExampleComEmail,
/*auth_sid_cookie=*/std::string(),
/*auth_lsid_cookie=*/std::string());
}
// Subscribes for the notifications from the Login Screen UI,
void StartObservingLoginUiMessages() {
GetLoginUI()->RegisterMessageCallback(
"securityTokenPinDialogShownForTest",
base::BindRepeating(&SecurityTokenSamlTest::OnPinDialogShownMessage,
weak_factory_.GetWeakPtr()));
}
// Called when the Login Screen UI notifies that the PIN dialog is shown.
void OnPinDialogShownMessage(const base::ListValue*) {
++pin_dialog_shown_count_;
if (pin_dialog_shown_run_loop_)
pin_dialog_shown_run_loop_->Quit();
}
ScopedTestSystemNSSKeySlotMixin system_nss_key_slot_mixin_{&mixin_host_};
FakeGaiaMixin gaia_mixin_{&mixin_host_, embedded_test_server()};
DeviceStateMixin device_state_mixin_{
&mixin_host_, DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED};
TestClientCertSamlIdpMixin saml_idp_mixin_{
&mixin_host_, &gaia_mixin_,
/*client_cert_authorities=*/{GetClientCertCaName()}};
TestCertificateProviderExtensionLoginScreenMixin
cert_provider_extension_mixin_{&mixin_host_, &device_state_mixin_};
int pin_dialog_shown_count_ = 0;
base::RunLoop* pin_dialog_shown_run_loop_ = nullptr;
base::WeakPtrFactory<SecurityTokenSamlTest> weak_factory_{this};
};
// Tests the successful login scenario with the correct PIN.
IN_PROC_BROWSER_TEST_F(SecurityTokenSamlTest, Basic) {
WaitForSigninScreen();
test::OobeJS().ExpectHiddenPath({"gaia-signin", "pinDialog"});
StartSignIn();
WaitForPinDialog();
test::OobeJS().ExpectVisiblePath({"gaia-signin", "pinDialog"});
InputPinByClickingKeypad(kCorrectPin);
test::OobeJS().ClickOnPath({"gaia-signin", "pinDialog", "submit"});
test::WaitForPrimaryUserSessionStart();
EXPECT_EQ(saml_test_users::kFirstUserCorpExampleComEmail,
GetActiveUserEmail());
EXPECT_EQ(1, pin_dialog_shown_count());
}
} // namespace chromeos
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/login/saml/test_client_cert_saml_idp_mixin.h"
#include "base/bind.h"
#include "base/strings/string_util.h"
#include "chrome/browser/chromeos/login/test/fake_gaia_mixin.h"
#include "chrome/browser/chromeos/login/test/https_forwarder.h"
#include "net/base/url_util.h"
#include "net/http/http_status_code.h"
#include "net/ssl/ssl_config.h"
#include "net/ssl/ssl_server_config.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace chromeos {
namespace {
// Name of the "RelayState" URL parameter from the SAML specification.
constexpr char kSamlRelayStateUrlParam[] = "RelayState";
// URL path of the first SAML page. The FakeGaia will redirect the browser to
// this page when the sign-in for |kUserEmail| is started. This page will
// redirect to the second SAML page (see below).
constexpr char kSamlPageUrlPath[] = "saml-page";
// URL path of the second SAML page. This page is configured to authenticate the
// client via a client certificate.
constexpr char kSamlWithClientCertsPageUrlPath[] = "saml-client-cert-page";
// The response passed by the second SAML page to Gaia after successful
// authentication.
constexpr char kSamlResponse[] = "saml-response";
} // namespace
TestClientCertSamlIdpMixin::TestClientCertSamlIdpMixin(
InProcessBrowserTestMixinHost* host,
FakeGaiaMixin* gaia_mixin,
const std::vector<std::string>& client_cert_authorities)
: InProcessBrowserTestMixin(host), gaia_mixin_(gaia_mixin) {
saml_server_.RegisterRequestHandler(
base::BindRepeating(&TestClientCertSamlIdpMixin::HandleSamlServerRequest,
base::Unretained(this)));
// Set up |saml_with_client_certs_server_| to request a client certificate.
net::SSLServerConfig ssl_config;
ssl_config.client_cert_type =
net::SSLServerConfig::ClientCertType::REQUIRE_CLIENT_CERT;
// TODO(crbug.com/792204): Enable TLS 1.3 after the
// chrome.certificateProvider API supports it.
ssl_config.version_max = net::SSL_PROTOCOL_VERSION_TLS1_2;
ssl_config.cert_authorities = client_cert_authorities;
saml_with_client_certs_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_OK,
ssl_config);
saml_with_client_certs_server_.RegisterRequestHandler(base::BindRepeating(
&TestClientCertSamlIdpMixin::HandleSamlWithClientCertsServerRequest,
base::Unretained(this)));
}
TestClientCertSamlIdpMixin::~TestClientCertSamlIdpMixin() = default;
GURL TestClientCertSamlIdpMixin::GetSamlPageUrl() const {
EXPECT_TRUE(saml_server_.Started());
return saml_server_.GetURL(std::string("/") + kSamlPageUrlPath);
}
void TestClientCertSamlIdpMixin::SetUpOnMainThread() {
ASSERT_TRUE(saml_server_.Start());
ASSERT_TRUE(saml_with_client_certs_server_.Start());
}
std::unique_ptr<net::test_server::HttpResponse>
TestClientCertSamlIdpMixin::HandleSamlServerRequest(
const net::test_server::HttpRequest& request) {
if (request.GetURL().ExtractFileName() != kSamlPageUrlPath)
return nullptr;
// Extract the RelayState parameter specified by Gaia, so that we can pass
// this value to subsequent SAML pages and finally back to Gaia.
std::string saml_relay_state;
EXPECT_TRUE(net::GetValueForKeyInQuery(
request.GetURL(), kSamlRelayStateUrlParam, &saml_relay_state));
// Redirect to the second SAML page.
// TODO(crbug.com/1034451): Remove this HTML-based redirect (or even the
// whole first SAML page) from the test once the Login Screen implementation
// is fixed to support the client certificates on the very first SAML page.
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
GURL redirect_url = saml_with_client_certs_server_.GetURL(
std::string("/") + kSamlWithClientCertsPageUrlPath);
redirect_url = net::AppendQueryParameter(
redirect_url, kSamlRelayStateUrlParam, saml_relay_state);
response->set_content(base::ReplaceStringPlaceholders(
R"(<!doctype html><html><head>
<meta http-equiv="refresh" content="0; URL=$1" /></head></html>)",
{redirect_url.spec()}, /*offsets=*/nullptr));
return response;
}
std::unique_ptr<net::test_server::HttpResponse>
TestClientCertSamlIdpMixin::HandleSamlWithClientCertsServerRequest(
const net::test_server::HttpRequest& request) {
if (request.GetURL().ExtractFileName() != kSamlWithClientCertsPageUrlPath)
return nullptr;
// Obtain the RelayState parameter that was originally specified by Gaia.
std::string saml_relay_state;
EXPECT_TRUE(net::GetValueForKeyInQuery(
request.GetURL(), kSamlRelayStateUrlParam, &saml_relay_state));
// Redirect to the Gaia SAML assertion page.
auto response = std::make_unique<net::test_server::BasicHttpResponse>();
response->set_code(net::HTTP_TEMPORARY_REDIRECT);
response->AddCustomHeader("Location",
GetGaiaSamlAssertionUrl(saml_relay_state).spec());
return response;
}
// Returns the URL to be used by the SAML page to redirect back to Gaia after
// the authentication completion.
GURL TestClientCertSamlIdpMixin::GetGaiaSamlAssertionUrl(
const std::string& saml_relay_state) {
GURL assertion_url =
gaia_mixin_->gaia_https_forwarder()->GetURLForSSLHost("").Resolve("/SSO");
assertion_url =
net::AppendQueryParameter(assertion_url, "SAMLResponse", kSamlResponse);
assertion_url = net::AppendQueryParameter(
assertion_url, kSamlRelayStateUrlParam, saml_relay_state);
return assertion_url;
}
} // namespace chromeos
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SAML_TEST_CLIENT_CERT_SAML_IDP_MIXIN_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_SAML_TEST_CLIENT_CERT_SAML_IDP_MIXIN_H_
#include <memory>
#include <string>
#include <vector>
#include "chrome/test/base/mixin_based_in_process_browser_test.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
class GURL;
namespace net {
namespace test_server {
struct HttpRequest;
class HttpResponse;
} // namespace test_server
} // namespace net
namespace chromeos {
class FakeGaiaMixin;
class TestClientCertSamlIdpMixin final : public InProcessBrowserTestMixin {
public:
// |client_cert_authorities| is the list of DER-encoded X.509
// DistinguishedName of certificate authorities that should be requested by
// the SAML server during the client authentication.
TestClientCertSamlIdpMixin(
InProcessBrowserTestMixinHost* host,
FakeGaiaMixin* gaia_mixin,
const std::vector<std::string>& client_cert_authorities);
TestClientCertSamlIdpMixin(const TestClientCertSamlIdpMixin&) = delete;
TestClientCertSamlIdpMixin& operator=(const TestClientCertSamlIdpMixin&) =
delete;
~TestClientCertSamlIdpMixin() override;
// Returns the SAML IdP initial page URL, which should be configured in the
// (fake) Gaia as the redirect endpoint for the tested users.
GURL GetSamlPageUrl() const;
// InProcessBrowserTestMixin:
void SetUpOnMainThread() override;
private:
// Handles requests to |saml_server_|.
std::unique_ptr<net::test_server::HttpResponse> HandleSamlServerRequest(
const net::test_server::HttpRequest& request);
// Handles requests to |saml_with_client_certs_server_|.
std::unique_ptr<net::test_server::HttpResponse>
HandleSamlWithClientCertsServerRequest(
const net::test_server::HttpRequest& request);
// Returns the URL to be used by the SAML page to redirect back to Gaia after
// the authentication completion.
GURL GetGaiaSamlAssertionUrl(const std::string& saml_relay_state);
FakeGaiaMixin* const gaia_mixin_;
net::EmbeddedTestServer saml_server_{net::EmbeddedTestServer::TYPE_HTTPS};
net::EmbeddedTestServer saml_with_client_certs_server_{
net::EmbeddedTestServer::TYPE_HTTPS};
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SAML_TEST_CLIENT_CERT_SAML_IDP_MIXIN_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/login/users/test_users.h"
namespace chromeos {
namespace saml_test_users {
const char kFirstUserCorpExampleComEmail[] = "alice@corp.example.com";
const char kSecondUserCorpExampleComEmail[] = "bob@corp.example.com";
const char kThirdUserCorpExampleComEmail[] = "carol@corp.example.com";
const char kFourthUserCorpExampleTestEmail[] = "dan@corp.example.test";
const char kFifthUserExampleTestEmail[] = "eve@example.test";
} // namespace saml_test_users
} // namespace chromeos
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Constants for Chrome OS test user accounts.
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_USERS_TEST_USERS_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_USERS_TEST_USERS_H_
namespace chromeos {
namespace saml_test_users {
// Note that the "corp.example.com" and the "example.test" domains are
// important, since they're hardcoded in embedded_setup_chromeos.html.
extern const char kFirstUserCorpExampleComEmail[];
extern const char kSecondUserCorpExampleComEmail[];
extern const char kThirdUserCorpExampleComEmail[];
extern const char kFourthUserCorpExampleTestEmail[];
extern const char kFifthUserExampleTestEmail[];
} // namespace saml_test_users
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_USERS_TEST_USERS_H_
......@@ -1494,8 +1494,6 @@ Polymer({
// initialization.
return;
}
if (oldValue === null && newValue !== null)
chrome.send('securityTokenPinDialogShownForTest');
if ((oldValue !== null && newValue === null) ||
(oldValue !== null && newValue !== null &&
!this.pinDialogResultReported_)) {
......
......@@ -40,7 +40,7 @@
</div>
<div slot="bottom-buttons" class="layout horizontal justified">
<oobe-back-button on-tap="onBackClicked_"></oobe-back-button>
<oobe-next-button id="submit" on-tap="onSubmit_"
<oobe-next-button on-tap="onSubmit_"
disabled="[[!canSubmit_]]"></oobe-next-button>
</div>
</oobe-dialog>
......
......@@ -166,10 +166,7 @@ Polymer({
this.processingCompletion_ = false;
this.hasValue_ = false;
this.userEdited_ = false;
// Note: setting the focus synchronously, to avoid flakiness in tests due to
// racing between the asynchronous caret positioning and the PIN characters
// input.
this.$.pinKeyboard.focusInputSynchronously();
this.$.pinKeyboard.focusInput();
},
/**
......
......@@ -884,8 +884,6 @@ if (!is_android) {
"../browser/chrome_worker_browsertest.cc",
"../browser/chromeos/certificate_provider/test_certificate_provider_extension_login_screen_mixin.cc",
"../browser/chromeos/certificate_provider/test_certificate_provider_extension_login_screen_mixin.h",
"../browser/chromeos/login/saml/test_client_cert_saml_idp_mixin.cc",
"../browser/chromeos/login/saml/test_client_cert_saml_idp_mixin.h",
"../browser/chromeos/scoped_test_system_nss_key_slot_mixin.cc",
"../browser/chromeos/scoped_test_system_nss_key_slot_mixin.h",
"../browser/client_hints/client_hints_browsertest.cc",
......@@ -2228,7 +2226,6 @@ if (!is_android) {
"../browser/chromeos/login/reset_browsertest.cc",
"../browser/chromeos/login/saml/password_change_success_detection_browsertest.cc",
"../browser/chromeos/login/saml/saml_browsertest.cc",
"../browser/chromeos/login/saml/security_token_saml_browsertest.cc",
"../browser/chromeos/login/screens/app_downloading_screen_browsertest.cc",
"../browser/chromeos/login/screens/assistant_optin_flow_screen_browsertest.cc",
"../browser/chromeos/login/screens/fingerprint_setup_browsertest.cc",
......
......@@ -30,79 +30,34 @@ function jsonifiableFromSignRequest(signRequest) {
return transformedSignRequest;
}
// Listener for the chrome.certificateProvider.onCertificatesRequested event.
function onCertificatesRequested(reportCallback) {
requestCertificatesFromCpp(reportCallback);
}
// Listener for the chrome.certificateProvider.onSignDigestRequested event.
function onSignDigestRequested(request, reportCallback) {
requestSignatureFromCpp(request, /*pinUserInput=*/ null, reportCallback);
}
function requestCertificatesFromCpp(reportCertificatesCallback) {
chrome.test.sendMessage(
JSON.stringify(['onCertificatesRequested']),
onCertificatesResponseFromCpp.bind(null, reportCertificatesCallback));
}
function onCertificatesResponseFromCpp(reportCertificatesCallback, response) {
const certInfoList = certInfoListFromParsedJson(JSON.parse(response));
reportCertificatesCallback(certInfoList, rejectedCertificates => {
if (rejectedCertificates && rejectedCertificates.length) {
console.error(
'Rejected certificates: ' + JSON.stringify(rejectedCertificates));
}
});
}
function requestSignatureFromCpp(
signDigestRequest, pinUserInput, reportSignatureCallback) {
chrome.test.sendMessage(
JSON.stringify([
'onSignatureRequested', jsonifiableFromSignRequest(signDigestRequest),
pinUserInput
]),
onSignatureResponseFromCpp.bind(
null, signDigestRequest, reportSignatureCallback));
}
function onSignatureResponseFromCpp(
signDigestRequest, reportSignatureCallback, response) {
const parsedResponse = JSON.parse(response);
if (parsedResponse === null) {
// The C++ handler signaled an error.
reportSignatureCallback();
return;
}
if (parsedResponse.stopPinRequest) {
// The C++ handler asked to stop the PIN request.
chrome.certificateProvider.stopPinRequest(
parsedResponse.stopPinRequest, function() {});
// Note that we're not returning here, since the parsed response may contain
// the signature as well.
}
if (parsedResponse.signature) {
// Forward the signature generated by the C++ handler.
reportSignatureCallback(arrayBufferFromByteList(parsedResponse.signature));
}
if (parsedResponse.requestPin) {
// The C++ handler asked to request the PIN. After the PIN is obtained,
// we'll request the signature from the C++ handler again.
chrome.certificateProvider.requestPin(
parsedResponse.requestPin, requestPinResponse => {
const pinUserInput =
requestPinResponse && requestPinResponse.userInput ?
requestPinResponse.userInput :
'pin-request-failed';
requestSignatureFromCpp(
signDigestRequest, pinUserInput, reportSignatureCallback);
});
}
}
chrome.certificateProvider.onCertificatesRequested.addListener(
onCertificatesRequested);
reportCallback => {
// Forward the request to the C++ handler.
chrome.test.sendMessage(
JSON.stringify(['onCertificatesRequested']), response => {
const certInfoList =
certInfoListFromParsedJson(JSON.parse(response));
reportCallback(certInfoList, rejectedCertificates => {
if (rejectedCertificates && rejectedCertificates.length) {
console.error(
'Rejected certificates: ' +
JSON.stringify(rejectedCertificates));
}
});
});
});
chrome.certificateProvider.onSignDigestRequested.addListener(
onSignDigestRequested);
(request, reportCallback) => {
// Forward the request to the C++ handler.
chrome.test.sendMessage(
JSON.stringify(
['onSignDigestRequested', jsonifiableFromSignRequest(request)]),
response => {
const parsedResponse = JSON.parse(response);
const signature = (parsedResponse === null) ?
undefined :
arrayBufferFromByteList(parsedResponse);
reportCallback(signature);
});
});
......@@ -199,19 +199,19 @@
<div id="rowsContainer" on-mousedown="onRowContainerMousedown_">
<div class="row">
<cr-button class="digit-button" on-tap="onNumberTap_" value="1"
id="digitButton1" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard1')]]</inner-text>
<inner-text class="letter empty"
hidden="[[!enableLetters]]">ABC</inner-text>
</cr-button>
<cr-button class="digit-button" on-tap="onNumberTap_" value="2"
id="digitButton2" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard2')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">ABC</inner-text>
</cr-button>
<cr-button class="digit-button" on-tap="onNumberTap_" value="3"
id="digitButton3" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard3')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">DEF</inner-text>
......@@ -219,19 +219,19 @@
</div>
<div class="row">
<cr-button class="digit-button" on-tap="onNumberTap_" value="4"
id="digitButton4" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard4')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">GHI</inner-text>
</cr-button>
<cr-button class="digit-button" on-tap="onNumberTap_" value="5"
id="digitButton5" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard5')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">JKL</inner-text>
</cr-button>
<cr-button class="digit-button" on-tap="onNumberTap_" value="6"
id="digitButton6" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard6')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">MNO</inner-text>
......@@ -239,19 +239,19 @@
</div>
<div class="row">
<cr-button class="digit-button" on-tap="onNumberTap_" value="7"
id="digitButton7" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard7')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">PQRS</inner-text>
</cr-button>
<cr-button class="digit-button" on-tap="onNumberTap_" value="8"
id="digitButton8" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard8')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">TUV</inner-text>
</cr-button>
<cr-button class="digit-button" on-tap="onNumberTap_" value="9"
id="digitButton9" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard9')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">WXYZ</inner-text>
......@@ -260,7 +260,7 @@
<div class="row bottom-row">
<div class="digit-button"></div>
<cr-button class="digit-button" on-tap="onNumberTap_" value="0"
id="digitButton0" disabled="[[disabled]]" circle-ripple>
disabled="[[disabled]]" circle-ripple>
<inner-text class="number">[[i18n('pinKeyboard0')]]</inner-text>
<inner-text class="letter"
hidden="[[!enableLetters]]">+</inner-text>
......
......@@ -214,18 +214,6 @@ Polymer({
this.passwordElement_().blur();
},
/**
* Schedules a call to focusInputSynchronously().
* @param {number=} opt_selectionStart
* @param {number=} opt_selectionEnd
*/
focusInput(opt_selectionStart, opt_selectionEnd) {
setTimeout(
() =>
this.focusInputSynchronously(opt_selectionStart, opt_selectionEnd),
0);
},
/**
* Transfers focus to the input element. This should not bring up the virtual
* keyboard, if it is enabled. After focus, moves the caret to the correct
......@@ -233,10 +221,12 @@ Polymer({
* @param {number=} opt_selectionStart
* @param {number=} opt_selectionEnd
*/
focusInputSynchronously(opt_selectionStart, opt_selectionEnd) {
this.passwordElement_().focus();
this.selectionStart_ = opt_selectionStart || 0;
this.selectionEnd_ = opt_selectionEnd || 0;
focusInput(opt_selectionStart, opt_selectionEnd) {
setTimeout(function() {
this.passwordElement_().focus();
this.selectionStart_ = opt_selectionStart || 0;
this.selectionEnd_ = opt_selectionEnd || 0;
}.bind(this), 0);
},
/**
......
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