Commit 230ea2c9 authored by Pavol Marko's avatar Pavol Marko Committed by Commit Bot

Enable client cert auth for sign-in frame StoragePartition

Enable client certificate authentication in the sign-in profile for
the StoragePartition which is currently used by the sign-in frame.
Additionally, wire up the DeviceLoginScreenAutoSelectCertificateForUrls
policy to content settings on the sign-in screen.

BUG=723849
TEST=browser_tests --gtest_filter=WebViewClientCertsLoginTest.*

Change-Id: Ic5345bc3446c621008088909771c6eca445aa3f3
Reviewed-on: https://chromium-review.googlesource.com/790295
Commit-Queue: Pavol Marko <pmarko@chromium.org>
Reviewed-by: default avatarRyan Sleevi <rsleevi@chromium.org>
Reviewed-by: default avatarMaksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarRyan Hamilton <rch@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#521232}
parent 97461ea2
...@@ -270,8 +270,10 @@ ...@@ -270,8 +270,10 @@
#include "chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.h" #include "chrome/browser/chromeos/fileapi/mtp_file_system_backend_delegate.h"
#include "chrome/browser/chromeos/login/signin/merge_session_navigation_throttle.h" #include "chrome/browser/chromeos/login/signin/merge_session_navigation_throttle.h"
#include "chrome/browser/chromeos/login/signin/merge_session_throttling_utils.h" #include "chrome/browser/chromeos/login/signin/merge_session_throttling_utils.h"
#include "chrome/browser/chromeos/login/signin_partition_manager.h"
#include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/chromeos/system/input_device_settings.h"
#include "chrome/browser/metrics/leak_detector/leak_detector_remote_controller.h" #include "chrome/browser/metrics/leak_detector/leak_detector_remote_controller.h"
#include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_dialogs.h"
...@@ -2373,8 +2375,40 @@ void ChromeContentBrowserClient::SelectClientCertificate( ...@@ -2373,8 +2375,40 @@ void ChromeContentBrowserClient::SelectClientCertificate(
<< "Invalid URL string: https://" << "Invalid URL string: https://"
<< cert_request_info->host_and_port.ToString(); << cert_request_info->host_and_port.ToString();
bool may_show_cert_selection = true;
Profile* profile = Profile* profile =
Profile::FromBrowserContext(web_contents->GetBrowserContext()); Profile::FromBrowserContext(web_contents->GetBrowserContext());
#if defined(OS_CHROMEOS)
if (chromeos::ProfileHelper::IsSigninProfile(profile)) {
// TODO(pmarko): crbug.com/723849: Set |may_show_cert_selection| to false
// and remove the command-line flag after prototype phase when the
// DeviceLoginScreenAutoSelectCertificateForUrls policy is live.
may_show_cert_selection =
chromeos::switches::IsSigninFrameClientCertUserSelectionEnabled();
content::StoragePartition* storage_partition =
content::BrowserContext::GetStoragePartition(
profile, web_contents->GetSiteInstance());
chromeos::login::SigninPartitionManager* signin_partition_manager =
chromeos::login::SigninPartitionManager::Factory::GetForBrowserContext(
profile);
// On the sign-in profile, only allow client certs in the context of the
// sign-in frame.
if (!signin_partition_manager->IsCurrentSigninStoragePartition(
storage_partition)) {
LOG(WARNING)
<< "Client cert requested in sign-in profile in wrong context.";
// Continue without client certificate. We do this to mimic the case of no
// client certificate being present in the profile's certificate store.
delegate->ContinueWithCertificate(nullptr, nullptr);
return;
}
VLOG(1) << "Client cert requested in sign-in profile.";
}
#endif // defined(OS_CHROMEOS)
std::unique_ptr<base::Value> filter = std::unique_ptr<base::Value> filter =
HostContentSettingsMapFactory::GetForProfile(profile)->GetWebsiteSetting( HostContentSettingsMapFactory::GetForProfile(profile)->GetWebsiteSetting(
requesting_url, requesting_url, requesting_url, requesting_url,
...@@ -2406,6 +2440,15 @@ void ChromeContentBrowserClient::SelectClientCertificate( ...@@ -2406,6 +2440,15 @@ void ChromeContentBrowserClient::SelectClientCertificate(
} }
} }
if (!may_show_cert_selection) {
LOG(WARNING) << "No client cert matched by policy and user selection is "
"not allowed.";
// Continue without client certificate. We do this to mimic the case of no
// client certificate being present in the profile's certificate store.
delegate->ContinueWithCertificate(nullptr, nullptr);
return;
}
chrome::ShowSSLClientCertificateSelector(web_contents, cert_request_info, chrome::ShowSSLClientCertificateSelector(web_contents, cert_request_info,
std::move(client_certs), std::move(client_certs),
std::move(delegate)); std::move(delegate));
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/guid.h" #include "base/guid.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/incognito_helpers.h"
#include "chromeos/chromeos_switches.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h" #include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
...@@ -70,13 +71,9 @@ void SigninPartitionManager::StartSigninSession( ...@@ -70,13 +71,9 @@ void SigninPartitionManager::StartSigninSession(
GURL guest_site = GetGuestSiteURL(storage_partition_domain_, GURL guest_site = GetGuestSiteURL(storage_partition_domain_,
current_storage_partition_name_); current_storage_partition_name_);
// Prepare the StoragePartition
current_storage_partition_ = current_storage_partition_ =
content::BrowserContext::GetStoragePartitionForSite(browser_context_, content::BrowserContext::GetStoragePartitionForSite(browser_context_,
guest_site, true); guest_site, true);
// TODO(pmarko): crbug.com/723849: Set UserData on |current_storage_partition|
// to allow client certificates.
} }
void SigninPartitionManager::CloseCurrentSigninSession( void SigninPartitionManager::CloseCurrentSigninSession(
...@@ -112,6 +109,11 @@ SigninPartitionManager::GetCurrentStoragePartition() { ...@@ -112,6 +109,11 @@ SigninPartitionManager::GetCurrentStoragePartition() {
return current_storage_partition_; return current_storage_partition_;
} }
bool SigninPartitionManager::IsCurrentSigninStoragePartition(
const content::StoragePartition* storage_partition) const {
return IsInSigninSession() && storage_partition == current_storage_partition_;
}
SigninPartitionManager::Factory::Factory() SigninPartitionManager::Factory::Factory()
: BrowserContextKeyedServiceFactory( : BrowserContextKeyedServiceFactory(
"SigninPartitionManager", "SigninPartitionManager",
......
...@@ -54,12 +54,16 @@ class SigninPartitionManager : public KeyedService { ...@@ -54,12 +54,16 @@ class SigninPartitionManager : public KeyedService {
// that is between StartSigninSession and CloseCurrentSigninSession calls. // that is between StartSigninSession and CloseCurrentSigninSession calls.
const std::string& GetCurrentStoragePartitionName() const; const std::string& GetCurrentStoragePartitionName() const;
// Returns the current StoragePartition. May only be called after // Returns the current StoragePartition. May only be called when a sign-in
// StartSigninSession has been called. May only be called when a sign-in
// session is active, that is between StartSigninSession and // session is active, that is between StartSigninSession and
// CloseCurrentSigninSession calls. // CloseCurrentSigninSession calls.
content::StoragePartition* GetCurrentStoragePartition(); content::StoragePartition* GetCurrentStoragePartition();
// Returns true if |storage_partition| is the partition in use by the current
// sign-in session. Returns false if no sign-in session is active.
bool IsCurrentSigninStoragePartition(
const content::StoragePartition* storage_partition) const;
void SetClearStoragePartitionTaskForTesting( void SetClearStoragePartitionTaskForTesting(
ClearStoragePartitionTask clear_storage_partition_task); ClearStoragePartitionTask clear_storage_partition_task);
......
...@@ -2,21 +2,41 @@ ...@@ -2,21 +2,41 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/callback.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/login/helper.h" #include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/signin_partition_manager.h" #include "chrome/browser/chromeos/login/signin_partition_manager.h"
#include "chrome/browser/chromeos/login/test/oobe_base_test.h" #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
#include "chrome/browser/chromeos/login/ui/webui_login_display.h" #include "chrome/browser/chromeos/login/ui/webui_login_display.h"
#include "chrome/browser/chromeos/policy/device_policy_cros_browser_test.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/ui/webui/signin/signin_utils.h"
#include "chromeos/chromeos_switches.h" #include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/guest_view/browser/guest_view_manager.h" #include "components/guest_view/browser/guest_view_manager.h"
#include "components/policy/proto/chrome_device_policy.pb.h"
#include "components/prefs/pref_change_registrar.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
#include "crypto/nss_util_internal.h"
#include "crypto/scoped_test_system_nss_key_slot.h"
#include "media/base/media_switches.h" #include "media/base/media_switches.h"
#include "net/cookies/canonical_cookie.h" #include "net/cookies/canonical_cookie.h"
#include "net/test/cert_test_util.h"
#include "net/test/spawned_test_server/spawned_test_server.h"
#include "net/test/test_data_directory.h"
#include "services/network/public/interfaces/cookie_manager.mojom.h" #include "services/network/public/interfaces/cookie_manager.mojom.h"
namespace em = enterprise_management;
namespace chromeos { namespace chromeos {
namespace { namespace {
...@@ -70,6 +90,43 @@ std::string GetAllCookies(content::StoragePartition* storage_partition) { ...@@ -70,6 +90,43 @@ std::string GetAllCookies(content::StoragePartition* storage_partition) {
return cookies; return cookies;
} }
// Spins the loop until a notification is received from |prefs| that the value
// of |pref_name| has changed. If the notification is received before Wait()
// has been called, Wait() returns immediately and no loop is spun.
class PrefChangeWatcher {
public:
PrefChangeWatcher(const std::string& pref_name, PrefService* prefs);
void Wait();
private:
void OnPrefChange();
bool pref_changed_ = false;
base::RunLoop run_loop_;
PrefChangeRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(PrefChangeWatcher);
};
PrefChangeWatcher::PrefChangeWatcher(const std::string& pref_name,
PrefService* prefs) {
registrar_.Init(prefs);
registrar_.Add(pref_name, base::Bind(&PrefChangeWatcher::OnPrefChange,
base::Unretained(this)));
}
void PrefChangeWatcher::Wait() {
if (!pref_changed_)
run_loop_.Run();
}
void PrefChangeWatcher::OnPrefChange() {
pref_changed_ = true;
run_loop_.Quit();
}
} // namespace } // namespace
class WebviewLoginTest : public OobeBaseTest { class WebviewLoginTest : public OobeBaseTest {
...@@ -313,4 +370,241 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, RequestCamera) { ...@@ -313,4 +370,241 @@ IN_PROC_BROWSER_TEST_F(WebviewLoginTest, RequestCamera) {
EXPECT_FALSE(getUserMediaSuccess); EXPECT_FALSE(getUserMediaSuccess);
} }
class WebviewClientCertsLoginTest : public WebviewLoginTest {
public:
WebviewClientCertsLoginTest() {}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(
switches::kDisableSigninFrameClientCertUserSelection);
WebviewLoginTest::SetUpCommandLine(command_line);
}
void SetUpInProcessBrowserTestFixture() override {
auto fake_session_manager_client =
std::make_unique<FakeSessionManagerClient>();
fake_session_manager_client_ = fake_session_manager_client.get();
DBusThreadManager::GetSetterForTesting()->SetSessionManagerClient(
std::move(fake_session_manager_client));
device_policy_test_helper_.InstallOwnerKey();
device_policy_test_helper_.MarkAsEnterpriseOwned();
WebviewLoginTest::SetUpInProcessBrowserTestFixture();
}
// Installs a testing system slot and imports a client certificate into it.
void SetUpClientCertInSystemSlot() {
{
bool system_slot_constructed_successfully = false;
base::RunLoop loop;
content::BrowserThread::PostTaskAndReply(
content::BrowserThread::IO, FROM_HERE,
base::BindOnce(&WebviewClientCertsLoginTest::SetUpTestSystemSlotOnIO,
base::Unretained(this),
&system_slot_constructed_successfully),
loop.QuitClosure());
loop.Run();
ASSERT_TRUE(system_slot_constructed_successfully);
}
// Import a second client cert signed by another CA than client_1 into the
// system wide key slot.
client_cert_ = net::ImportClientCertAndKeyFromFile(
net::GetTestCertsDirectory(), "client_1.pem", "client_1.pk8",
test_system_slot_->slot());
ASSERT_TRUE(client_cert_.get());
}
// Sets up the DeviceLoginScreenAutoSelectCertificateForUrls policy.
void SetAutoSelectCertificatePattern(const std::string& autoselect_pattern) {
em::ChromeDeviceSettingsProto& proto(
device_policy_test_helper_.device_policy()->payload());
proto.mutable_device_login_screen_auto_select_certificate_for_urls()
->add_login_screen_auto_select_certificate_rules(autoselect_pattern);
device_policy_test_helper_.device_policy()->Build();
fake_session_manager_client_->set_device_policy(
device_policy_test_helper_.device_policy()->GetBlob());
PrefChangeWatcher watcher(prefs::kManagedAutoSelectCertificateForUrls,
ProfileHelper::GetSigninProfile()->GetPrefs());
fake_session_manager_client_->OnPropertyChangeComplete(true);
watcher.Wait();
}
// Starts the Test HTTPS server with |ssl_options|.
void StartHttpsServer(const net::SpawnedTestServer::SSLOptions& ssl_options) {
https_server_ = std::make_unique<net::SpawnedTestServer>(
net::SpawnedTestServer::TYPE_HTTPS, ssl_options, base::FilePath());
ASSERT_TRUE(https_server_->Start());
}
// Requests |http_server_|'s client-cert test page in the webview with the id
// |webview_id|. Returns the content of the client-cert test page. If
// |watch_new_webcontents| is true, this function will watch for newly-created
// WebContents when determining if the navigation to the test page has
// finished. This can be used for webviews which have not navigated yet, as
// their WebContents will be created on-demand.
std::string RequestClientCertTestPageInFrame(std::string webview_id,
bool watch_new_webcontents) {
const GURL url = https_server_->GetURL("client-cert");
content::TestNavigationObserver navigation_observer(url);
if (watch_new_webcontents)
navigation_observer.StartWatchingNewWebContents();
else
navigation_observer.WatchExistingWebContents();
JS().Evaluate(base::StringPrintf("$('%s').src='%s'", webview_id.c_str(),
url.spec().c_str()));
navigation_observer.Wait();
content::WebContents* main_web_contents = GetLoginUI()->GetWebContents();
content::WebContents* frame_web_contents =
signin::GetAuthFrameWebContents(main_web_contents, webview_id);
test::JSChecker frame_js_checker(frame_web_contents);
const std::string https_reply_content =
frame_js_checker.GetString("document.body.textContent");
return https_reply_content;
}
void ShowEulaScreen() {
LoginDisplayHost::default_host()->StartWizard(OobeScreen::SCREEN_OOBE_EULA);
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
}
private:
void SetUpTestSystemSlotOnIO(bool* out_system_slot_constructed_successfully) {
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
test_system_slot_ = std::make_unique<crypto::ScopedTestSystemNSSKeySlot>();
*out_system_slot_constructed_successfully =
test_system_slot_->ConstructedSuccessfully();
}
policy::DevicePolicyCrosTestHelper device_policy_test_helper_;
// Unowned pointer - owned by DBusThreadManager.
FakeSessionManagerClient* fake_session_manager_client_;
std::unique_ptr<crypto::ScopedTestSystemNSSKeySlot> test_system_slot_;
scoped_refptr<net::X509Certificate> client_cert_;
std::unique_ptr<net::SpawnedTestServer> https_server_;
DISALLOW_COPY_AND_ASSIGN(WebviewClientCertsLoginTest);
};
// Test that client certificate authentication using certificates from the
// system slot is enabled in the sign-in frame. The server does not request
// certificates signed by a specific authority.
IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
SigninFrameNoAuthorityGiven) {
ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
net::SpawnedTestServer::SSLOptions ssl_options;
ssl_options.request_client_certificate = true;
ASSERT_NO_FATAL_FAILURE(StartHttpsServer(ssl_options));
const std::string autoselect_pattern =
R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})";
SetAutoSelectCertificatePattern(autoselect_pattern);
WaitForGaiaPageLoad();
std::string https_reply_content = RequestClientCertTestPageInFrame(
gaia_frame_parent_, false /* watch_new_webcontents */);
EXPECT_EQ(
"got client cert with fingerprint: "
"c66145f49caca4d1325db96ace0f12f615ba4981",
https_reply_content);
}
// Test that if no client certificate is auto-selected using policy on the
// sign-in frame, the client does not send up any client certificate.
IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
SigninFrameCertNotAutoSelected) {
ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
net::SpawnedTestServer::SSLOptions ssl_options;
ssl_options.request_client_certificate = true;
ASSERT_NO_FATAL_FAILURE(StartHttpsServer(ssl_options));
WaitForGaiaPageLoad();
std::string https_reply_content = RequestClientCertTestPageInFrame(
gaia_frame_parent_, false /* watch_new_webcontents */);
EXPECT_EQ("got no client cert", https_reply_content);
}
// Test that client certificate authentication using certificates from the
// system slot is enabled in the sign-in frame. The server requests
// a certificate signed by a specific authority.
IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest, SigninFrameAuthorityGiven) {
ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
net::SpawnedTestServer::SSLOptions ssl_options;
ssl_options.request_client_certificate = true;
base::FilePath ca_path =
net::GetTestCertsDirectory().Append(FILE_PATH_LITERAL("client_1_ca.pem"));
ssl_options.client_authorities.push_back(ca_path);
ASSERT_NO_FATAL_FAILURE(StartHttpsServer(ssl_options));
const std::string autoselect_pattern =
R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})";
SetAutoSelectCertificatePattern(autoselect_pattern);
WaitForGaiaPageLoad();
std::string https_reply_content = RequestClientCertTestPageInFrame(
gaia_frame_parent_, false /* watch_new_webcontents */);
EXPECT_EQ(
"got client cert with fingerprint: "
"c66145f49caca4d1325db96ace0f12f615ba4981",
https_reply_content);
}
// Test that client certificate authentication using certificates from the
// system slot is enabled in the sign-in frame. The server requests
// a certificate signed by a specific authority. The client doesn't have a
// matching certificate.
IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
SigninFrameAuthorityGivenNoMatchingCert) {
ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
net::SpawnedTestServer::SSLOptions ssl_options;
ssl_options.request_client_certificate = true;
base::FilePath ca_path =
net::GetTestCertsDirectory().Append(FILE_PATH_LITERAL("client_2_ca.pem"));
ssl_options.client_authorities.push_back(ca_path);
ASSERT_NO_FATAL_FAILURE(StartHttpsServer(ssl_options));
const std::string autoselect_pattern =
R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})";
SetAutoSelectCertificatePattern(autoselect_pattern);
WaitForGaiaPageLoad();
std::string https_reply_content = RequestClientCertTestPageInFrame(
gaia_frame_parent_, false /* watch_new_webcontents */);
EXPECT_EQ("got no client cert", https_reply_content);
}
// Tests that client certificate authentication is not enabled in a webview on
// the sign-in screen which is not the sign-in frame. In this case, the EULA
// webview is used.
IN_PROC_BROWSER_TEST_F(WebviewClientCertsLoginTest,
ClientCertRequestedInOtherWebView) {
ASSERT_NO_FATAL_FAILURE(SetUpClientCertInSystemSlot());
net::SpawnedTestServer::SSLOptions ssl_options;
ssl_options.request_client_certificate = true;
ASSERT_NO_FATAL_FAILURE(StartHttpsServer(ssl_options));
const std::string autoselect_pattern =
R"({"pattern": "*", "filter": {"ISSUER": {"CN": "B CA"}}})";
SetAutoSelectCertificatePattern(autoselect_pattern);
ShowEulaScreen();
// Use |watch_new_webcontents| because the EULA webview has not navigated yet.
std::string https_reply_content = RequestClientCertTestPageInFrame(
"cros-eula-frame", true /* watch_new_webcontents */);
EXPECT_EQ("got no client cert", https_reply_content);
}
} // namespace chromeos } // namespace chromeos
...@@ -377,12 +377,26 @@ void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy, ...@@ -377,12 +377,26 @@ void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy,
const em::LoginScreenInputMethodsProto& login_screen_input_methods( const em::LoginScreenInputMethodsProto& login_screen_input_methods(
policy.login_screen_input_methods()); policy.login_screen_input_methods());
for (const auto& input_method : for (const auto& input_method :
login_screen_input_methods.login_screen_input_methods()) login_screen_input_methods.login_screen_input_methods()) {
input_methods->AppendString(input_method); input_methods->AppendString(input_method);
}
policies->Set(key::kDeviceLoginScreenInputMethods, POLICY_LEVEL_MANDATORY, policies->Set(key::kDeviceLoginScreenInputMethods, POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD, POLICY_SCOPE_MACHINE, POLICY_SOURCE_CLOUD,
std::move(input_methods), nullptr); std::move(input_methods), nullptr);
} }
if (policy.has_device_login_screen_auto_select_certificate_for_urls()) {
std::unique_ptr<base::ListValue> rules(new base::ListValue);
const em::DeviceLoginScreenAutoSelectCertificateForUrls& proto_rules(
policy.device_login_screen_auto_select_certificate_for_urls());
for (const auto& rule :
proto_rules.login_screen_auto_select_certificate_rules()) {
rules->AppendString(rule);
}
policies->Set(key::kDeviceLoginScreenAutoSelectCertificateForUrls,
POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
POLICY_SOURCE_CLOUD, std::move(rules), nullptr);
}
} }
void DecodeNetworkPolicies(const em::ChromeDeviceSettingsProto& policy, void DecodeNetworkPolicies(const em::ChromeDeviceSettingsProto& policy,
......
...@@ -79,6 +79,17 @@ void ApplyValueAsMandatoryPolicy(const base::Value* value, ...@@ -79,6 +79,17 @@ void ApplyValueAsMandatoryPolicy(const base::Value* value,
} }
} }
// Applies the value of |device_policy| in |device_policy_map| as the
// mandatory value of |user_policy| in |user_policy_map|. If the value of
// |device_policy| is unset, does nothing.
void ApplyDevicePolicyAsMandatoryPolicy(const std::string& device_policy,
const std::string& user_policy,
const PolicyMap& device_policy_map,
PolicyMap* user_policy_map) {
const base::Value* value = device_policy_map.GetValue(device_policy);
ApplyValueAsMandatoryPolicy(value, user_policy, user_policy_map);
}
} // namespace } // namespace
LoginProfilePolicyProvider::LoginProfilePolicyProvider( LoginProfilePolicyProvider::LoginProfilePolicyProvider(
...@@ -162,6 +173,10 @@ void LoginProfilePolicyProvider::UpdateFromDevicePolicy() { ...@@ -162,6 +173,10 @@ void LoginProfilePolicyProvider::UpdateFromDevicePolicy() {
key::kVirtualKeyboardEnabled, key::kVirtualKeyboardEnabled,
device_policy_map, &user_policy_map); device_policy_map, &user_policy_map);
ApplyDevicePolicyAsMandatoryPolicy(
key::kDeviceLoginScreenAutoSelectCertificateForUrls,
key::kAutoSelectCertificateForUrls, device_policy_map, &user_policy_map);
const base::Value* value = const base::Value* value =
device_policy_map.GetValue(key::kDeviceLoginScreenPowerManagement); device_policy_map.GetValue(key::kDeviceLoginScreenPowerManagement);
const base::DictionaryValue* dict = NULL; const base::DictionaryValue* dict = NULL;
......
...@@ -146,6 +146,7 @@ ...@@ -146,6 +146,7 @@
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/net/nss_context.h" #include "chrome/browser/net/nss_context.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/cryptohome_client.h" #include "chromeos/dbus/cryptohome_client.h"
#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/settings/cros_settings_names.h" #include "chromeos/settings/cros_settings_names.h"
...@@ -463,6 +464,18 @@ void ProfileIOData::InitializeOnUIThread(Profile* profile) { ...@@ -463,6 +464,18 @@ void ProfileIOData::InitializeOnUIThread(Profile* profile) {
#endif #endif
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
// Enable client certificates for the Chrome OS sign-in frame, if this feature
// is not disabled by a flag.
// Note that while this applies to the whole sign-in profile, client
// certificates will only be selected for the StoragePartition currently used
// in the sign-in frame (see SigninPartitionManager).
if (chromeos::switches::IsSigninFrameClientCertsEnabled() &&
chromeos::ProfileHelper::IsSigninProfile(profile)) {
// We only need the system slot for client certificates, not in NSS context
// (the sign-in profile's NSS context is not initialized).
params->system_key_slot_use_type = SystemKeySlotUseType::kUseForClientAuth;
}
user_manager::UserManager* user_manager = user_manager::UserManager::Get(); user_manager::UserManager* user_manager = user_manager::UserManager::Get();
if (user_manager) { if (user_manager) {
const user_manager::User* user = const user_manager::User* user =
...@@ -481,7 +494,10 @@ void ProfileIOData::InitializeOnUIThread(Profile* profile) { ...@@ -481,7 +494,10 @@ void ProfileIOData::InitializeOnUIThread(Profile* profile) {
// Use the device-wide system key slot only if the user is affiliated on // Use the device-wide system key slot only if the user is affiliated on
// the device. // the device.
params->use_system_key_slot = user->IsAffiliated(); if (user->IsAffiliated()) {
params->system_key_slot_use_type =
SystemKeySlotUseType::kUseForClientAuthAndCertManagement;
}
} }
} }
...@@ -644,7 +660,7 @@ ProfileIOData::AppRequestContext::~AppRequestContext() { ...@@ -644,7 +660,7 @@ ProfileIOData::AppRequestContext::~AppRequestContext() {
ProfileIOData::ProfileParams::ProfileParams() ProfileIOData::ProfileParams::ProfileParams()
: io_thread(NULL), : io_thread(NULL),
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
use_system_key_slot(false), system_key_slot_use_type(SystemKeySlotUseType::kNone),
#endif #endif
profile(NULL) { profile(NULL) {
} }
...@@ -654,7 +670,7 @@ ProfileIOData::ProfileParams::~ProfileParams() {} ...@@ -654,7 +670,7 @@ ProfileIOData::ProfileParams::~ProfileParams() {}
ProfileIOData::ProfileIOData(Profile::ProfileType profile_type) ProfileIOData::ProfileIOData(Profile::ProfileType profile_type)
: initialized_(false), : initialized_(false),
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
use_system_key_slot_(false), system_key_slot_use_type_(SystemKeySlotUseType::kNone),
#endif #endif
main_request_context_(nullptr), main_request_context_(nullptr),
resource_context_(new ResourceContext(this)), resource_context_(new ResourceContext(this)),
...@@ -974,11 +990,15 @@ std::unique_ptr<net::ClientCertStore> ProfileIOData::CreateClientCertStore() { ...@@ -974,11 +990,15 @@ std::unique_ptr<net::ClientCertStore> ProfileIOData::CreateClientCertStore() {
if (!client_cert_store_factory_.is_null()) if (!client_cert_store_factory_.is_null())
return client_cert_store_factory_.Run(); return client_cert_store_factory_.Run();
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
bool use_system_key_slot =
system_key_slot_use_type_ == SystemKeySlotUseType::kUseForClientAuth ||
system_key_slot_use_type_ ==
SystemKeySlotUseType::kUseForClientAuthAndCertManagement;
return std::unique_ptr<net::ClientCertStore>( return std::unique_ptr<net::ClientCertStore>(
new chromeos::ClientCertStoreChromeOS( new chromeos::ClientCertStoreChromeOS(
certificate_provider_ ? certificate_provider_->Copy() : nullptr, certificate_provider_ ? certificate_provider_->Copy() : nullptr,
base::MakeUnique<chromeos::ClientCertFilterChromeOS>( base::MakeUnique<chromeos::ClientCertFilterChromeOS>(
use_system_key_slot_, username_hash_), use_system_key_slot, username_hash_),
base::Bind(&CreateCryptoModuleBlockingPasswordDelegate, base::Bind(&CreateCryptoModuleBlockingPasswordDelegate,
kCryptoModulePasswordClientAuth))); kCryptoModulePasswordClientAuth)));
#elif defined(USE_NSS_CERTS) #elif defined(USE_NSS_CERTS)
...@@ -1123,9 +1143,16 @@ void ProfileIOData::Init( ...@@ -1123,9 +1143,16 @@ void ProfileIOData::Init(
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
username_hash_ = profile_params_->username_hash; username_hash_ = profile_params_->username_hash;
use_system_key_slot_ = profile_params_->use_system_key_slot; system_key_slot_use_type_ = profile_params_->system_key_slot_use_type;
if (use_system_key_slot_) // If we're using the system slot for certificate management, we also must
// have access to the user's slots.
DCHECK(!(username_hash_.empty() &&
system_key_slot_use_type_ ==
SystemKeySlotUseType::kUseForClientAuthAndCertManagement));
if (system_key_slot_use_type_ ==
SystemKeySlotUseType::kUseForClientAuthAndCertManagement) {
EnableNSSSystemKeySlotForResourceContext(resource_context_.get()); EnableNSSSystemKeySlotForResourceContext(resource_context_.get());
}
certificate_provider_ = std::move(profile_params_->certificate_provider); certificate_provider_ = std::move(profile_params_->certificate_provider);
#endif #endif
......
...@@ -259,6 +259,20 @@ class ProfileIOData { ...@@ -259,6 +259,20 @@ class ProfileIOData {
std::unique_ptr<net::ClientCertStore> CreateClientCertStore(); std::unique_ptr<net::ClientCertStore> CreateClientCertStore();
protected: protected:
#if defined(OS_CHROMEOS)
// Defines possible ways in which a profile may use the Chrome OS system
// token.
enum class SystemKeySlotUseType {
// This profile does not use the system key slot.
kNone,
// This profile only uses the system key slot for client certiticates.
kUseForClientAuth,
// This profile uses the system key slot for client certificates and for
// certificate management.
kUseForClientAuthAndCertManagement
};
#endif
// A URLRequestContext for media that owns its HTTP factory, to ensure // A URLRequestContext for media that owns its HTTP factory, to ensure
// it is deleted. // it is deleted.
class MediaRequestContext : public net::URLRequestContext { class MediaRequestContext : public net::URLRequestContext {
...@@ -343,7 +357,7 @@ class ProfileIOData { ...@@ -343,7 +357,7 @@ class ProfileIOData {
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
std::unique_ptr<policy::PolicyCertVerifier> policy_cert_verifier; std::unique_ptr<policy::PolicyCertVerifier> policy_cert_verifier;
std::string username_hash; std::string username_hash;
bool use_system_key_slot; SystemKeySlotUseType system_key_slot_use_type;
std::unique_ptr<chromeos::CertificateProvider> certificate_provider; std::unique_ptr<chromeos::CertificateProvider> certificate_provider;
#endif #endif
...@@ -583,7 +597,7 @@ class ProfileIOData { ...@@ -583,7 +597,7 @@ class ProfileIOData {
mutable std::unique_ptr<ChromeExpectCTReporter> expect_ct_reporter_; mutable std::unique_ptr<ChromeExpectCTReporter> expect_ct_reporter_;
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
mutable std::string username_hash_; mutable std::string username_hash_;
mutable bool use_system_key_slot_; mutable SystemKeySlotUseType system_key_slot_use_type_;
mutable std::unique_ptr<chromeos::CertificateProvider> certificate_provider_; mutable std::unique_ptr<chromeos::CertificateProvider> certificate_provider_;
#endif #endif
......
...@@ -532,6 +532,22 @@ const char kDisablePerUserTimezone[] = "disable-per-user-timezone"; ...@@ -532,6 +532,22 @@ const char kDisablePerUserTimezone[] = "disable-per-user-timezone";
const char kDisableFineGrainedTimeZoneDetection[] = const char kDisableFineGrainedTimeZoneDetection[] =
"disable-fine-grained-time-zone-detection"; "disable-fine-grained-time-zone-detection";
// Disables client certificate authentication on the sign-in frame on the Chrome
// OS sign-in profile.
// TODO(pmarko): Remove this flag in M-66 if no issues are found
// (crbug.com/723849).
const char kDisableSigninFrameClientCerts[] =
"disable-signin-frame-client-certs";
// Disables user selection of client certificate on the sign-in frame on the
// Chrome OS sign-in profile.
// TODO(pmarko): Remove this flag in M-65 when the
// DeviceLoginScreenAutoSelectCertificateForUrls policy is enabled on the server
// side (crbug.com/723849) and completely disable user selection of certificates
// on the sign-in frame.
const char kDisableSigninFrameClientCertUserSelection[] =
"disable-signin-frame-client-cert-user-selection";
bool WakeOnWifiEnabled() { bool WakeOnWifiEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableWakeOnWifi); return !base::CommandLine::ForCurrentProcess()->HasSwitch(kDisableWakeOnWifi);
} }
...@@ -630,5 +646,15 @@ bool IsZipArchiverUnpackerEnabled() { ...@@ -630,5 +646,15 @@ bool IsZipArchiverUnpackerEnabled() {
kEnableZipArchiverUnpacker); kEnableZipArchiverUnpacker);
} }
bool IsSigninFrameClientCertsEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
kDisableSigninFrameClientCerts);
}
bool IsSigninFrameClientCertUserSelectionEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
kDisableSigninFrameClientCertUserSelection);
}
} // namespace switches } // namespace switches
} // namespace chromeos } // namespace chromeos
...@@ -99,6 +99,8 @@ CHROMEOS_EXPORT extern const char kEnableTouchpadThreeFingerClick[]; ...@@ -99,6 +99,8 @@ CHROMEOS_EXPORT extern const char kEnableTouchpadThreeFingerClick[];
CHROMEOS_EXPORT extern const char kEnableFileManagerTouchMode[]; CHROMEOS_EXPORT extern const char kEnableFileManagerTouchMode[];
CHROMEOS_EXPORT extern const char kDisableFileManagerTouchMode[]; CHROMEOS_EXPORT extern const char kDisableFileManagerTouchMode[];
CHROMEOS_EXPORT extern const char kDisableFineGrainedTimeZoneDetection[]; CHROMEOS_EXPORT extern const char kDisableFineGrainedTimeZoneDetection[];
CHROMEOS_EXPORT extern const char kDisableSigninFrameClientCerts[];
CHROMEOS_EXPORT extern const char kDisableSigninFrameClientCertUserSelection[];
CHROMEOS_EXPORT extern const char kEnableVideoPlayerChromecastSupport[]; CHROMEOS_EXPORT extern const char kEnableVideoPlayerChromecastSupport[];
CHROMEOS_EXPORT extern const char kEnableVoiceInteraction[]; CHROMEOS_EXPORT extern const char kEnableVoiceInteraction[];
CHROMEOS_EXPORT extern const char kEnableZipArchiverPacker[]; CHROMEOS_EXPORT extern const char kEnableZipArchiverPacker[];
...@@ -180,6 +182,14 @@ CHROMEOS_EXPORT bool IsVoiceInteractionEnabled(); ...@@ -180,6 +182,14 @@ CHROMEOS_EXPORT bool IsVoiceInteractionEnabled();
// Returns true if Zip Archiver is enabled for unpacking files. // Returns true if Zip Archiver is enabled for unpacking files.
CHROMEOS_EXPORT bool IsZipArchiverUnpackerEnabled(); CHROMEOS_EXPORT bool IsZipArchiverUnpackerEnabled();
// Returns true if client certificate authentication for the sign-in frame on
// the Chrome OS sign-in screen is enabled.
CHROMEOS_EXPORT bool IsSigninFrameClientCertsEnabled();
// Returns true if user selection of certificates is enabled for the sign-in
// frame on the Chrome OS sign-in screen.
CHROMEOS_EXPORT bool IsSigninFrameClientCertUserSelectionEnabled();
} // namespace switches } // namespace switches
} // namespace chromeos } // namespace chromeos
......
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