Commit 0a4d70a2 authored by Andreea Costinas's avatar Andreea Costinas Committed by Commit Bot

system-proxy: Ask user for proxy credentials

Currently, if System-proxy requires credentials to authenticate to a
remote proxy, it will send a request to the Browser to fetch credentials
from the Network Service authentication cache. If the user didn't
authenticate in the Browser yet, System-proxy will receive empty
credentials.

This CL changes the flow to notify the user that System-proxy requires
credentials and allows the user to enter the credentials in a dedicated
dialogue, without needing to go through the Browser.

Bug: 1112722
Test: unittests, manually on DUT
Change-Id: I0bb1e0e2d0a644b47dd022a87664cab1bb4e5205
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2356204Reviewed-by: default avatarAndreea-Elena Costinas <acostinas@google.com>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarOmar Morsi <omorsi@google.com>
Reviewed-by: default avatarEvan Stade <estade@chromium.org>
Commit-Queue: Andreea-Elena Costinas <acostinas@google.com>
Cr-Commit-Position: refs/heads/master@{#799641}
parent e4a6e8a2
...@@ -5725,4 +5725,15 @@ You can manage this account’s settings by installing the Family Link app on yo ...@@ -5725,4 +5725,15 @@ You can manage this account’s settings by installing the Family Link app on yo
<message name="IDS_SYSTEM_PROXY_AUTH_DIALOG_ERROR_LABEL" desc="Text for the error label that informs users that the authentication attempt failed."> <message name="IDS_SYSTEM_PROXY_AUTH_DIALOG_ERROR_LABEL" desc="Text for the error label that informs users that the authentication attempt failed.">
Unable to connect to the proxy Unable to connect to the proxy
</message> </message>
<!-- Strings for the System-proxy notifications informing the user that System-proxy required credentials-->
<message name="IDS_SYSTEM_PROXY_AUTH_REQUIRED_NOTIFICATION_TITLE" desc="Title of notification displayed when System-proxy requires user credentials to authenticate to a remote web proxy.">
Sign in to connect to the proxy
</message>
<message name="IDS_SYSTEM_PROXY_AUTH_REQUIRED_NOTIFICATION_BODY" desc="Body of notification informing user that they need to provide username and password for System-proxy to connect to a remote web proxy.">
The proxy <ph name="PROXY">$1<ex>http://localhost:3128</ex></ph> requires you to authenticate with a username and password
</message>
<message name="IDS_SYSTEM_PROXY_AUTH_REQUIRED_NOTIFICATION_ERROR_TITLE" desc="Title of notification displayed when System-proxy requires new user credentials because the previous ones were incorrect.">
Unable to connect to the proxy, please try again
</message>
</grit-part> </grit-part>
2377dbafa091cc07ad9291f7cdf6d0759357d6a5
\ No newline at end of file
5887c20fc72eff381f7eca93ff12f61d590632d2
\ No newline at end of file
2377dbafa091cc07ad9291f7cdf6d0759357d6a5
\ No newline at end of file
...@@ -188,6 +188,7 @@ aggregate_vector_icons("chrome_vector_icons") { ...@@ -188,6 +188,7 @@ aggregate_vector_icons("chrome_vector_icons") {
"notification_storage_full.icon", "notification_storage_full.icon",
"notification_vpn.icon", "notification_vpn.icon",
"notification_wifi_off.icon", "notification_wifi_off.icon",
"notification_wifi.icon",
"shutdown_guest_os.icon", "shutdown_guest_os.icon",
"warning_badge_circle.icon", "warning_badge_circle.icon",
] ]
......
// 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.
CANVAS_DIMENSIONS, 18,
MOVE_TO, 9.01f, 13.99f,
LINE_TO, 17.81f, 3.03f,
CUBIC_TO, 17.47f, 2.77f, 14.08f, 0, 9, 0,
CUBIC_TO, 3.92f, 0, 0.53f, 2.77f, 0.19f, 3.03f,
LINE_TO, 8.99f, 13.99f,
LINE_TO, 9.01f, 13.99f,
LINE_TO, 9.01f, 13.99f,
CLOSE
...@@ -2634,6 +2634,8 @@ source_set("chromeos") { ...@@ -2634,6 +2634,8 @@ source_set("chromeos") {
"ui/request_system_proxy_credentials_view.h", "ui/request_system_proxy_credentials_view.h",
"ui/screen_capture_notification_ui_chromeos.cc", "ui/screen_capture_notification_ui_chromeos.cc",
"ui/screen_capture_notification_ui_chromeos.h", "ui/screen_capture_notification_ui_chromeos.h",
"ui/system_proxy_notification.cc",
"ui/system_proxy_notification.h",
"ui/tpm_auto_update_notification.cc", "ui/tpm_auto_update_notification.cc",
"ui/tpm_auto_update_notification.h", "ui/tpm_auto_update_notification.h",
"ui/update_required_notification.cc", "ui/update_required_notification.cc",
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/ui/request_system_proxy_credentials_view.h" #include "chrome/browser/chromeos/ui/request_system_proxy_credentials_view.h"
#include "chrome/browser/chromeos/ui/system_proxy_notification.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_finder.h"
...@@ -84,7 +85,6 @@ std::string SystemProxyManager::SystemServicesProxyPacString() const { ...@@ -84,7 +85,6 @@ std::string SystemProxyManager::SystemServicesProxyPacString() const {
void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) { void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) {
primary_profile_ = profile; primary_profile_ = profile;
// Listen to pref changes. // Listen to pref changes.
profile_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>(); profile_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
profile_pref_change_registrar_->Init(primary_profile_->GetPrefs()); profile_pref_change_registrar_->Init(primary_profile_->GetPrefs());
...@@ -105,7 +105,9 @@ void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) { ...@@ -105,7 +105,9 @@ void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) {
void SystemProxyManager::StopObservingPrimaryProfilePrefs() { void SystemProxyManager::StopObservingPrimaryProfilePrefs() {
profile_pref_change_registrar_->RemoveAll(); profile_pref_change_registrar_->RemoveAll();
profile_pref_change_registrar_.reset(); profile_pref_change_registrar_.reset();
primary_profile_ = nullptr;
} }
void SystemProxyManager::ClearUserCredentials() { void SystemProxyManager::ClearUserCredentials() {
if (!system_proxy_enabled_) { if (!system_proxy_enabled_) {
return; return;
...@@ -148,10 +150,9 @@ void SystemProxyManager::OnSystemProxySettingsPolicyChanged() { ...@@ -148,10 +150,9 @@ void SystemProxyManager::OnSystemProxySettingsPolicyChanged() {
weak_factory_.GetWeakPtr())); weak_factory_.GetWeakPtr()));
system_services_address_.clear(); system_services_address_.clear();
SetUserTrafficProxyPref(std::string()); SetUserTrafficProxyPref(std::string());
CloseAuthenticationDialog(); CloseAuthenticationUI();
return; return;
} }
system_proxy::SetAuthenticationDetailsRequest request; system_proxy::SetAuthenticationDetailsRequest request;
system_proxy::Credentials credentials; system_proxy::Credentials credentials;
const std::string* username = proxy_settings->FindStringKey( const std::string* username = proxy_settings->FindStringKey(
...@@ -280,6 +281,21 @@ void SystemProxyManager::SetSystemServicesProxyUrlForTest( ...@@ -280,6 +281,21 @@ void SystemProxyManager::SetSystemServicesProxyUrlForTest(
system_services_address_ = local_proxy_url; system_services_address_ = local_proxy_url;
} }
void SystemProxyManager::SetSendAuthDetailsClosureForTest(
base::RepeatingClosure closure) {
send_auth_details_closure_for_test_ = closure;
}
chromeos::RequestSystemProxyCredentialsView*
SystemProxyManager::GetActiveAuthDialogForTest() {
return active_auth_dialog_;
}
void SystemProxyManager::CloseAuthDialogForTest() {
DCHECK(auth_widget_);
auth_widget_->CloseNow();
}
// static // static
void SystemProxyManager::RegisterProfilePrefs(PrefRegistrySimple* registry) { void SystemProxyManager::RegisterProfilePrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kSystemProxyUserTrafficHostAndPort, registry->RegisterStringPref(prefs::kSystemProxyUserTrafficHostAndPort,
...@@ -293,6 +309,8 @@ void SystemProxyManager::OnSetAuthenticationDetails( ...@@ -293,6 +309,8 @@ void SystemProxyManager::OnSetAuthenticationDetails(
<< "Failed to set system traffic credentials for system proxy: " << "Failed to set system traffic credentials for system proxy: "
<< kSystemProxyService << ", Error: " << response.error_message(); << kSystemProxyService << ", Error: " << response.error_message();
} }
if (send_auth_details_closure_for_test_)
send_auth_details_closure_for_test_.Run();
} }
void SystemProxyManager::OnShutDownProcess( void SystemProxyManager::OnShutDownProcess(
...@@ -335,11 +353,20 @@ void SystemProxyManager::OnAuthenticationRequired( ...@@ -335,11 +353,20 @@ void SystemProxyManager::OnAuthenticationRequired(
const system_proxy::AuthenticationRequiredDetails& details) { const system_proxy::AuthenticationRequiredDetails& details) {
system_proxy::ProtectionSpace protection_space = system_proxy::ProtectionSpace protection_space =
details.proxy_protection_space(); details.proxy_protection_space();
if (!primary_profile_) { if (!primary_profile_) {
SendEmptyCredentials(protection_space); SendEmptyCredentials(protection_space);
return; return;
} }
// The previous authentication attempt failed.
if (details.has_bad_cached_credentials() &&
details.bad_cached_credentials()) {
ShowAuthenticationNotification(protection_space,
details.bad_cached_credentials());
return;
}
// TODO(acostinas,chromium:1104818) |protection_space.origin()| is in a // TODO(acostinas,chromium:1104818) |protection_space.origin()| is in a
// URI-like format which may be incompatible between Chrome and libcurl, which // URI-like format which may be incompatible between Chrome and libcurl, which
// is used on the Chrome OS side. We should change |origin()| to be a PAC // is used on the Chrome OS side. We should change |origin()| to be a PAC
...@@ -365,32 +392,49 @@ void SystemProxyManager::OnAuthenticationRequired( ...@@ -365,32 +392,49 @@ void SystemProxyManager::OnAuthenticationRequired(
void SystemProxyManager::LookupProxyAuthCredentialsCallback( void SystemProxyManager::LookupProxyAuthCredentialsCallback(
const system_proxy::ProtectionSpace& protection_space, const system_proxy::ProtectionSpace& protection_space,
const base::Optional<net::AuthCredentials>& credentials) { const base::Optional<net::AuthCredentials>& credentials) {
// System-proxy is started via d-bus activation, meaning the first d-bus call if (!credentials) {
// will start the daemon. Check that System-proxy was not disabled by policy // Ask the user for credentials
// while looking for credentials so we don't accidentally restart it. ShowAuthenticationNotification(protection_space, /*show_error=*/false);
if (!system_proxy_enabled_) {
return; return;
} }
std::string username; std::string username;
std::string password; std::string password;
if (credentials) { if (credentials) {
username = base::UTF16ToUTF8(credentials->username()); username = base::UTF16ToUTF8(credentials->username());
password = base::UTF16ToUTF8(credentials->password()); password = base::UTF16ToUTF8(credentials->password());
// If there's a dialog requesting credentials for this proxy, close it. // If there's a dialog requesting credentials for this proxy, close it.
if (active_auth_dialog_ && if (notification_handler_ ||
active_auth_dialog_->GetProxyServer() == protection_space.origin()) { (active_auth_dialog_ &&
CloseAuthenticationDialog(); active_auth_dialog_->GetProxyServer() == protection_space.origin())) {
CloseAuthenticationUI();
} }
} }
SendUserAuthenticationCredentials(protection_space, username, password); SendUserAuthenticationCredentials(protection_space, username, password);
} }
void SystemProxyManager::ShowAuthenticationNotification(
const system_proxy::ProtectionSpace& protection_space,
bool show_error) {
if (active_auth_dialog_)
return;
notification_handler_ = std::make_unique<chromeos::SystemProxyNotification>(
protection_space, show_error,
base::BindOnce(&SystemProxyManager::ShowAuthenticationDialog,
weak_factory_.GetWeakPtr()));
notification_handler_->Show();
}
void SystemProxyManager::ShowAuthenticationDialog( void SystemProxyManager::ShowAuthenticationDialog(
const system_proxy::ProtectionSpace& protection_space, const system_proxy::ProtectionSpace& protection_space,
bool show_error_label) { bool show_error_label) {
if (active_auth_dialog_) if (active_auth_dialog_)
return; return;
if (notification_handler_)
notification_handler_->Close();
active_auth_dialog_ = new chromeos::RequestSystemProxyCredentialsView( active_auth_dialog_ = new chromeos::RequestSystemProxyCredentialsView(
protection_space.origin(), show_error_label, protection_space.origin(), show_error_label,
base::BindOnce(&SystemProxyManager::OnDialogClosed, base::BindOnce(&SystemProxyManager::OnDialogClosed,
...@@ -426,7 +470,12 @@ void SystemProxyManager::OnDialogClosed( ...@@ -426,7 +470,12 @@ void SystemProxyManager::OnDialogClosed(
auth_widget_ = nullptr; auth_widget_ = nullptr;
} }
void SystemProxyManager::CloseAuthenticationDialog() { void SystemProxyManager::CloseAuthenticationUI() {
// Closes the notification if shown.
if (notification_handler_) {
notification_handler_->Close();
notification_handler_.reset();
}
if (!auth_widget_) if (!auth_widget_)
return; return;
// Also deletes the |auth_widget_| instance. // Also deletes the |auth_widget_| instance.
......
...@@ -18,7 +18,8 @@ ...@@ -18,7 +18,8 @@
namespace chromeos { namespace chromeos {
class RequestSystemProxyCredentialsView; class RequestSystemProxyCredentialsView;
} class SystemProxyNotification;
} // namespace chromeos
namespace system_proxy { namespace system_proxy {
class SetAuthenticationDetailsResponse; class SetAuthenticationDetailsResponse;
...@@ -67,6 +68,9 @@ class SystemProxyManager { ...@@ -67,6 +68,9 @@ class SystemProxyManager {
void SetSystemProxyEnabledForTest(bool enabled); void SetSystemProxyEnabledForTest(bool enabled);
void SetSystemServicesProxyUrlForTest(const std::string& local_proxy_url); void SetSystemServicesProxyUrlForTest(const std::string& local_proxy_url);
void SetSendAuthDetailsClosureForTest(base::RepeatingClosure closure);
chromeos::RequestSystemProxyCredentialsView* GetActiveAuthDialogForTest();
void CloseAuthDialogForTest();
// Registers prefs stored in user profiles. // Registers prefs stored in user profiles.
static void RegisterProfilePrefs(PrefRegistrySimple* registry); static void RegisterProfilePrefs(PrefRegistrySimple* registry);
...@@ -123,6 +127,10 @@ class SystemProxyManager { ...@@ -123,6 +127,10 @@ class SystemProxyManager {
const system_proxy::ProtectionSpace& protection_space, const system_proxy::ProtectionSpace& protection_space,
const base::Optional<net::AuthCredentials>& credentials); const base::Optional<net::AuthCredentials>& credentials);
void ShowAuthenticationNotification(
const system_proxy::ProtectionSpace& protection_space,
bool show_error);
// Shows a dialog which prompts the user to introduce proxy authentication // Shows a dialog which prompts the user to introduce proxy authentication
// credentials for OS level traffic. If |show_error_label| is true, the // credentials for OS level traffic. If |show_error_label| is true, the
// dialog will show a label that indicates the previous attempt to // dialog will show a label that indicates the previous attempt to
...@@ -134,8 +142,8 @@ class SystemProxyManager { ...@@ -134,8 +142,8 @@ class SystemProxyManager {
void OnDialogCanceled(const system_proxy::ProtectionSpace& protection_space); void OnDialogCanceled(const system_proxy::ProtectionSpace& protection_space);
void OnDialogClosed(const system_proxy::ProtectionSpace& protection_space); void OnDialogClosed(const system_proxy::ProtectionSpace& protection_space);
// Closes the authentication dialog if shown. // Closes the authentication notification or dialog if shown.
void CloseAuthenticationDialog(); void CloseAuthenticationUI();
chromeos::CrosSettings* cros_settings_; chromeos::CrosSettings* cros_settings_;
std::unique_ptr<chromeos::CrosSettings::ObserverSubscription> std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>
...@@ -149,6 +157,10 @@ class SystemProxyManager { ...@@ -149,6 +157,10 @@ class SystemProxyManager {
// Local state prefs, not owned. // Local state prefs, not owned.
PrefService* local_state_ = nullptr; PrefService* local_state_ = nullptr;
// Notification which informs the user that System-proxy requires credentials
// for authentication to the remote proxy.
std::unique_ptr<chromeos::SystemProxyNotification> notification_handler_;
// Owned by |auth_widget_|. // Owned by |auth_widget_|.
chromeos::RequestSystemProxyCredentialsView* active_auth_dialog_ = nullptr; chromeos::RequestSystemProxyCredentialsView* active_auth_dialog_ = nullptr;
// Owned by the UI code (NativeWidget). // Owned by the UI code (NativeWidget).
...@@ -161,6 +173,8 @@ class SystemProxyManager { ...@@ -161,6 +173,8 @@ class SystemProxyManager {
std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_; std::unique_ptr<PrefChangeRegistrar> local_state_pref_change_registrar_;
std::unique_ptr<PrefChangeRegistrar> profile_pref_change_registrar_; std::unique_ptr<PrefChangeRegistrar> profile_pref_change_registrar_;
base::RepeatingClosure send_auth_details_closure_for_test_;
base::WeakPtrFactory<SystemProxyManager> weak_factory_{this}; base::WeakPtrFactory<SystemProxyManager> weak_factory_{this};
}; };
......
// 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 "base/bind.h"
#include "base/run_loop.h"
#include "base/task/current_thread.h"
#include "base/test/bind_test_util.h"
#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/system_proxy_manager.h"
#include "chrome/browser/chromeos/ui/request_system_proxy_credentials_view.h"
#include "chrome/browser/notifications/notification_display_service_tester.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/dbus/system_proxy/system_proxy_client.h"
#include "chromeos/dbus/system_proxy/system_proxy_service.pb.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/textfield/textfield.h"
namespace policy {
namespace {
constexpr char kRealm[] = "My proxy";
constexpr char kScheme[] = "dIgEsT";
constexpr char kProxyAuthUrl[] = "http://example.com:3128";
constexpr char kSystemProxyNotificationId[] = "system-proxy.auth_required";
constexpr char kUsername[] = "testuser";
constexpr char kPassword[] = "testpwd";
} // namespace
class SystemProxyManagerBrowserTest : public InProcessBrowserTest {
public:
SystemProxyManagerBrowserTest() = default;
SystemProxyManagerBrowserTest(const SystemProxyManagerBrowserTest&) = delete;
SystemProxyManagerBrowserTest& operator=(
const SystemProxyManagerBrowserTest&) = delete;
~SystemProxyManagerBrowserTest() override = default;
void SetUpOnMainThread() override {
GetSystemProxyManager()->StartObservingPrimaryProfilePrefs(
browser()->profile());
display_service_tester_ =
std::make_unique<NotificationDisplayServiceTester>(/*profile=*/nullptr);
GetSystemProxyManager()->SetSystemProxyEnabledForTest(true);
}
void TearDownOnMainThread() override {
GetSystemProxyManager()->SetSystemProxyEnabledForTest(false);
}
protected:
SystemProxyManager* GetSystemProxyManager() {
return g_browser_process->platform_part()
->browser_policy_connector_chromeos()
->GetSystemProxyManager();
}
chromeos::RequestSystemProxyCredentialsView* dialog() {
return GetSystemProxyManager()->GetActiveAuthDialogForTest();
}
chromeos::SystemProxyClient::TestInterface* client_test_interface() {
return chromeos::SystemProxyClient::Get()->GetTestInterface();
}
void SendAuthenticationRequest(bool bad_cached_credentials) {
system_proxy::ProtectionSpace protection_space;
protection_space.set_origin(kProxyAuthUrl);
protection_space.set_scheme(kScheme);
protection_space.set_realm(kRealm);
system_proxy::AuthenticationRequiredDetails details;
details.set_bad_cached_credentials(bad_cached_credentials);
*details.mutable_proxy_protection_space() = protection_space;
client_test_interface()->SendAuthenticationRequiredSignal(details);
}
void WaitForNotification() {
base::RunLoop run_loop;
display_service_tester_->SetNotificationAddedClosure(
run_loop.QuitClosure());
run_loop.Run();
}
std::unique_ptr<NotificationDisplayServiceTester> display_service_tester_;
};
// Tests the flow for setting user credentials for System-proxy:
// - Receiving an authentication request prompts a notification;
// - Clicking on the notification opens a dialog;
// - Credentials introduced in the dialog are sent via D-Bus to System-proxy.
IN_PROC_BROWSER_TEST_F(SystemProxyManagerBrowserTest, AuthenticationDialog) {
base::RunLoop run_loop;
GetSystemProxyManager()->SetSendAuthDetailsClosureForTest(
run_loop.QuitClosure());
EXPECT_FALSE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
SendAuthenticationRequest(/* bad_cached_credentials = */ false);
WaitForNotification();
EXPECT_TRUE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
display_service_tester_->SimulateClick(
NotificationHandler::Type::TRANSIENT, kSystemProxyNotificationId,
/*action_index=*/base::nullopt, /*reply=*/base::nullopt);
// Dialog is created.
ASSERT_TRUE(dialog());
// Expect warning is not shown.
ASSERT_FALSE(dialog()->error_label_for_testing()->GetVisible());
dialog()->username_textfield_for_testing()->SetText(
base::ASCIIToUTF16(kUsername));
dialog()->password_textfield_for_testing()->SetText(
base::ASCIIToUTF16(kPassword));
// Simulate clicking on "OK" button.
dialog()->Accept();
// Wait for the callback set via |SetSendAuthDetailsClosureForTest| to be
// called. The callback will be called when SystemProxyManager calls the D-Bus
// method |SetAuthenticationDetails|
run_loop.Run();
system_proxy::SetAuthenticationDetailsRequest request =
client_test_interface()->GetLastAuthenticationDetailsRequest();
ASSERT_TRUE(request.has_credentials());
EXPECT_EQ(request.credentials().username(), kUsername);
EXPECT_EQ(request.credentials().password(), kPassword);
// Verify that the UI elements are reset.
GetSystemProxyManager()->CloseAuthDialogForTest();
EXPECT_FALSE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
EXPECT_FALSE(dialog());
}
// Tests that canceling the authentication dialog sends empty credentials to
// System-proxy.
IN_PROC_BROWSER_TEST_F(SystemProxyManagerBrowserTest,
CancelAuthenticationDialog) {
EXPECT_FALSE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
SendAuthenticationRequest(/* bad_cached_credentials = */ false);
WaitForNotification();
EXPECT_TRUE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
display_service_tester_->SimulateClick(
NotificationHandler::Type::TRANSIENT, kSystemProxyNotificationId,
/*action_index=*/base::nullopt, /*reply=*/base::nullopt);
// Dialog is created.
ASSERT_TRUE(dialog());
// Expect warning is not shown.
ASSERT_FALSE(dialog()->error_label_for_testing()->GetVisible());
dialog()->username_textfield_for_testing()->SetText(
base::ASCIIToUTF16(kUsername));
dialog()->password_textfield_for_testing()->SetText(
base::ASCIIToUTF16(kPassword));
base::RunLoop run_loop;
GetSystemProxyManager()->SetSendAuthDetailsClosureForTest(
run_loop.QuitClosure());
// Simulate clicking on "Cancel" button.
dialog()->Cancel();
run_loop.Run();
system_proxy::SetAuthenticationDetailsRequest request =
client_test_interface()->GetLastAuthenticationDetailsRequest();
ASSERT_TRUE(request.has_credentials());
EXPECT_EQ(request.credentials().username(), "");
EXPECT_EQ(request.credentials().password(), "");
// Verify that the UI elements are reset.
GetSystemProxyManager()->CloseAuthDialogForTest();
EXPECT_FALSE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
EXPECT_FALSE(dialog());
}
// Tests that the warning informing the user that the previous credentials are
// incorrect is shown in the UI.
IN_PROC_BROWSER_TEST_F(SystemProxyManagerBrowserTest,
BadCachedCredentialsWarning) {
EXPECT_FALSE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
SendAuthenticationRequest(/* bad_cached_credentials = */ true);
WaitForNotification();
EXPECT_TRUE(
display_service_tester_->GetNotification(kSystemProxyNotificationId));
display_service_tester_->SimulateClick(
NotificationHandler::Type::TRANSIENT, kSystemProxyNotificationId,
/*action_index=*/base::nullopt, /*reply=*/base::nullopt);
ASSERT_TRUE(dialog());
// Expect warning is shown.
EXPECT_TRUE(dialog()->error_label_for_testing()->GetVisible());
}
} // namespace policy
...@@ -195,13 +195,14 @@ TEST_F(SystemProxyManagerTest, KerberosConfig) { ...@@ -195,13 +195,14 @@ TEST_F(SystemProxyManagerTest, KerberosConfig) {
TEST_F(SystemProxyManagerTest, UserCredentialsRequiredNoUser) { TEST_F(SystemProxyManagerTest, UserCredentialsRequiredNoUser) {
SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */, SetPolicy(true /* system_proxy_enabled */, "" /* system_services_username */,
"" /* system_services_password */); "" /* system_services_password */);
system_proxy_manager_->StopObservingPrimaryProfilePrefs();
system_proxy::ProtectionSpace protection_space; system_proxy::ProtectionSpace protection_space;
protection_space.set_origin(kProxyAuthUrl); protection_space.set_origin(kProxyAuthUrl);
protection_space.set_scheme(kScheme); protection_space.set_scheme(kScheme);
protection_space.set_realm(kRealm); protection_space.set_realm(kRealm);
system_proxy::AuthenticationRequiredDetails details; system_proxy::AuthenticationRequiredDetails details;
details.set_bad_cached_credentials(false);
*details.mutable_proxy_protection_space() = protection_space; *details.mutable_proxy_protection_space() = protection_space;
client_test_interface()->SendAuthenticationRequiredSignal(details); client_test_interface()->SendAuthenticationRequiredSignal(details);
...@@ -219,6 +220,7 @@ TEST_F(SystemProxyManagerTest, UserCredentialsRequiredNoUser) { ...@@ -219,6 +220,7 @@ TEST_F(SystemProxyManagerTest, UserCredentialsRequiredNoUser) {
ASSERT_TRUE(request.has_credentials()); ASSERT_TRUE(request.has_credentials());
EXPECT_EQ("", request.credentials().username()); EXPECT_EQ("", request.credentials().username());
EXPECT_EQ("", request.credentials().password()); EXPECT_EQ("", request.credentials().password());
system_proxy_manager_->StartObservingPrimaryProfilePrefs(profile_.get());
} }
// Tests that credential requests are resolved to a D-Bus call which sends back // Tests that credential requests are resolved to a D-Bus call which sends back
......
// 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/ui/system_proxy_notification.h"
#include "ash/public/cpp/notification_utils.h"
#include "base/location.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/notifications/notification_display_service.h"
#include "chrome/browser/notifications/notification_display_service_factory.h"
#include "chrome/browser/notifications/system_notification_helper.h"
#include "chrome/grit/generated_resources.h"
#include "components/vector_icons/vector_icons.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/message_center/public/cpp/notification.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
#include "ui/message_center/public/cpp/notification_types.h"
#include "ui/message_center/public/cpp/notifier_id.h"
namespace {
constexpr char kNotificationId[] = "system-proxy.auth_required";
constexpr char kNotifierId[] = "system-proxy";
} // namespace
namespace chromeos {
SystemProxyNotification::SystemProxyNotification(
const system_proxy::ProtectionSpace& protection_space,
bool show_error,
OnClickCallback callback)
: protection_space_(protection_space),
show_error_(show_error),
on_click_callback_(std::move(callback)),
weak_ptr_factory_(this) {}
SystemProxyNotification::~SystemProxyNotification() = default;
void SystemProxyNotification::Show() {
const base::string16 title =
show_error_ ? l10n_util::GetStringUTF16(
IDS_SYSTEM_PROXY_AUTH_REQUIRED_NOTIFICATION_ERROR_TITLE)
: l10n_util::GetStringUTF16(
IDS_SYSTEM_PROXY_AUTH_REQUIRED_NOTIFICATION_TITLE);
const base::string16 body = l10n_util::GetStringFUTF16(
IDS_SYSTEM_PROXY_AUTH_REQUIRED_NOTIFICATION_BODY,
base::ASCIIToUTF16(protection_space_.origin()));
std::unique_ptr<message_center::Notification> notification =
ash::CreateSystemNotification(
message_center::NOTIFICATION_TYPE_SIMPLE, kNotificationId, title,
body, base::string16() /*display_source=*/, GURL() /*origin_url=*/,
message_center::NotifierId(
message_center::NotifierType::SYSTEM_COMPONENT, kNotifierId),
message_center::RichNotificationData(),
base::MakeRefCounted<message_center::HandleNotificationClickDelegate>(
base::BindRepeating(&SystemProxyNotification::OnClick,
weak_ptr_factory_.GetWeakPtr())),
kNotificationWifiIcon,
message_center::SystemNotificationWarningLevel::WARNING);
notification->set_pinned(true);
SystemNotificationHelper::GetInstance()->Display(*notification);
}
void SystemProxyNotification::SystemProxyNotification::OnClick() {
DCHECK(!on_click_callback_.is_null());
std::move(on_click_callback_).Run(protection_space_, show_error_);
}
void SystemProxyNotification::Close() {
SystemNotificationHelper::GetInstance()->Close(kNotificationId);
}
} // 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.
#ifndef CHROME_BROWSER_CHROMEOS_UI_SYSTEM_PROXY_NOTIFICATION_H_
#define CHROME_BROWSER_CHROMEOS_UI_SYSTEM_PROXY_NOTIFICATION_H_
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/dbus/system_proxy/system_proxy_service.pb.h"
namespace message_center {
class Notification;
}
namespace chromeos {
// SystemProxyNotification manages the notification informing the user that
// System-proxy requires user credentials to authenticate to the remote web
// proxy.
class SystemProxyNotification {
public:
using OnClickCallback =
base::OnceCallback<void(const system_proxy::ProtectionSpace&, bool)>;
SystemProxyNotification(const system_proxy::ProtectionSpace& protection_space,
bool show_error,
OnClickCallback callback);
SystemProxyNotification(const SystemProxyNotification&) = delete;
SystemProxyNotification& operator=(const SystemProxyNotification&) = delete;
~SystemProxyNotification();
void Show();
void Close();
private:
void OnClick();
const system_proxy::ProtectionSpace protection_space_;
const bool show_error_;
OnClickCallback on_click_callback_;
std::unique_ptr<message_center::Notification> notification_;
base::WeakPtrFactory<SystemProxyNotification> weak_ptr_factory_{this};
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_UI_SYSTEM_PROXY_NOTIFICATION_H_
...@@ -2476,6 +2476,7 @@ if (!is_android) { ...@@ -2476,6 +2476,7 @@ if (!is_android) {
"../browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc", "../browser/chromeos/policy/site_isolation_flag_handling_browsertest.cc",
"../browser/chromeos/policy/status_collector/child_status_collector_browsertest.cc", "../browser/chromeos/policy/status_collector/child_status_collector_browsertest.cc",
"../browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc", "../browser/chromeos/policy/status_collector/device_status_collector_browsertest.cc",
"../browser/chromeos/policy/system_proxy_manager_browsertest.cc",
"../browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc", "../browser/chromeos/policy/unaffiliated_arc_allowed_browsertest.cc",
"../browser/chromeos/policy/user_affiliation_browsertest.cc", "../browser/chromeos/policy/user_affiliation_browsertest.cc",
"../browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc", "../browser/chromeos/policy/user_cloud_external_data_manager_browsertest.cc",
......
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