1 // Copyright (c) 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/chromeos/policy/system_proxy_manager.h"
6 
7 #include "base/bind.h"
8 #include "base/strings/string16.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
13 #include "chrome/browser/chromeos/profiles/profile_helper.h"
14 #include "chrome/browser/chromeos/ui/request_system_proxy_credentials_view.h"
15 #include "chrome/browser/chromeos/ui/system_proxy_notification.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_finder.h"
19 #include "chrome/browser/ui/browser_window.h"
20 #include "chrome/common/pref_names.h"
21 #include "chromeos/dbus/system_proxy/system_proxy_client.h"
22 #include "chromeos/network/network_event_log.h"
23 #include "chromeos/network/network_state.h"
24 #include "chromeos/network/network_state_handler.h"
25 #include "chromeos/network/proxy/proxy_config_service_impl.h"
26 #include "chromeos/network/proxy/ui_proxy_config_service.h"
27 #include "chromeos/settings/cros_settings_names.h"
28 #include "chromeos/settings/cros_settings_provider.h"
29 #include "components/arc/arc_prefs.h"
30 #include "components/prefs/pref_change_registrar.h"
31 #include "components/prefs/pref_registry_simple.h"
32 #include "components/prefs/pref_service.h"
33 #include "components/proxy_config/proxy_config_pref_names.h"
34 #include "components/user_manager/user.h"
35 #include "components/user_manager/user_manager.h"
36 #include "content/public/browser/storage_partition.h"
37 #include "net/base/host_port_pair.h"
38 #include "net/base/proxy_server.h"
39 #include "net/http/http_auth_scheme.h"
40 #include "net/http/http_util.h"
41 #include "services/network/public/mojom/network_context.mojom.h"
42 #include "ui/aura/window.h"
43 #include "ui/gfx/native_widget_types.h"
44 #include "ui/views/widget/widget.h"
45 #include "ui/views/window/dialog_delegate.h"
46 
47 namespace {
48 const char kSystemProxyService[] = "system-proxy-service";
49 }  // namespace
50 
51 namespace policy {
52 
SystemProxyManager(chromeos::CrosSettings * cros_settings,PrefService * local_state)53 SystemProxyManager::SystemProxyManager(chromeos::CrosSettings* cros_settings,
54                                        PrefService* local_state)
55     : cros_settings_(cros_settings),
56       system_proxy_subscription_(cros_settings_->AddSettingsObserver(
57           chromeos::kSystemProxySettings,
58           base::BindRepeating(
59               &SystemProxyManager::OnSystemProxySettingsPolicyChanged,
60               base::Unretained(this)))) {
61   // Connect to System-proxy signals.
62   chromeos::SystemProxyClient::Get()->SetWorkerActiveSignalCallback(
63       base::BindRepeating(&SystemProxyManager::OnWorkerActive,
64                           weak_factory_.GetWeakPtr()));
65   chromeos::SystemProxyClient::Get()->SetAuthenticationRequiredSignalCallback(
66       base::BindRepeating(&SystemProxyManager::OnAuthenticationRequired,
67                           weak_factory_.GetWeakPtr()));
68   chromeos::SystemProxyClient::Get()->ConnectToWorkerSignals();
69   local_state_ = local_state;
70 
71   // Listen to pref changes.
72   local_state_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
73   local_state_pref_change_registrar_->Init(local_state_);
74   local_state_pref_change_registrar_->Add(
75       prefs::kKerberosEnabled,
76       base::BindRepeating(&SystemProxyManager::OnKerberosEnabledChanged,
77                           weak_factory_.GetWeakPtr()));
78   DCHECK(chromeos::NetworkHandler::IsInitialized());
79   chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver(
80       this, FROM_HERE);
81   // Fire it once so we're sure we get an invocation on startup.
82   OnSystemProxySettingsPolicyChanged();
83 }
84 
~SystemProxyManager()85 SystemProxyManager::~SystemProxyManager() {
86   DCHECK(chromeos::NetworkHandler::IsInitialized());
87   chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver(
88       this, FROM_HERE);
89 }
90 
SystemServicesProxyPacString() const91 std::string SystemProxyManager::SystemServicesProxyPacString() const {
92   return system_proxy_enabled_ && !system_services_address_.empty()
93              ? "PROXY " + system_services_address_
94              : std::string();
95 }
96 
StartObservingPrimaryProfilePrefs(Profile * profile)97 void SystemProxyManager::StartObservingPrimaryProfilePrefs(Profile* profile) {
98   primary_profile_ = profile;
99   extension_prefs_util_ = std::make_unique<extensions::PrefsUtil>(profile);
100   // Listen to pref changes.
101   profile_pref_change_registrar_ = std::make_unique<PrefChangeRegistrar>();
102   profile_pref_change_registrar_->Init(primary_profile_->GetPrefs());
103   profile_pref_change_registrar_->Add(
104       prefs::kKerberosActivePrincipalName,
105       base::BindRepeating(&SystemProxyManager::OnKerberosAccountChanged,
106                           base::Unretained(this)));
107   profile_pref_change_registrar_->Add(
108       arc::prefs::kArcEnabled,
109       base::BindRepeating(&SystemProxyManager::OnArcEnabledChanged,
110                           weak_factory_.GetWeakPtr()));
111   profile_pref_change_registrar_->Add(
112       proxy_config::prefs::kProxy,
113       base::BindRepeating(&SystemProxyManager::OnProxyConfigChanged,
114                           base::Unretained(this)));
115   if (system_proxy_enabled_) {
116     OnProxyConfigChanged();
117     OnKerberosAccountChanged();
118     OnArcEnabledChanged();
119   }
120 }
121 
StopObservingPrimaryProfilePrefs()122 void SystemProxyManager::StopObservingPrimaryProfilePrefs() {
123   profile_pref_change_registrar_->RemoveAll();
124   profile_pref_change_registrar_.reset();
125   extension_prefs_util_.reset();
126   primary_profile_ = nullptr;
127 }
128 
ClearUserCredentials()129 void SystemProxyManager::ClearUserCredentials() {
130   if (!system_proxy_enabled_) {
131     return;
132   }
133 
134   system_proxy::ClearUserCredentialsRequest request;
135   chromeos::SystemProxyClient::Get()->ClearUserCredentials(
136       request, base::BindOnce(&SystemProxyManager::OnClearUserCredentials,
137                               weak_factory_.GetWeakPtr()));
138 }
139 
OnSystemProxySettingsPolicyChanged()140 void SystemProxyManager::OnSystemProxySettingsPolicyChanged() {
141   chromeos::CrosSettingsProvider::TrustedStatus status =
142       cros_settings_->PrepareTrustedValues(base::BindOnce(
143           &SystemProxyManager::OnSystemProxySettingsPolicyChanged,
144           base::Unretained(this)));
145   if (status != chromeos::CrosSettingsProvider::TRUSTED)
146     return;
147 
148   const base::Value* proxy_settings =
149       cros_settings_->GetPref(chromeos::kSystemProxySettings);
150 
151   if (!proxy_settings)
152     return;
153 
154   system_proxy_enabled_ =
155       proxy_settings->FindBoolKey(chromeos::kSystemProxySettingsKeyEnabled)
156           .value_or(false);
157   // System-proxy is inactive by default.
158   if (!system_proxy_enabled_) {
159     // Send a shut-down command to the daemon. Since System-proxy is started via
160     // dbus activation, if the daemon is inactive, this command will start the
161     // daemon and tell it to exit.
162     // TODO(crbug.com/1055245,acostinas): Do not send shut-down command if
163     // System-proxy is inactive.
164     system_proxy::ShutDownRequest request;
165     request.set_traffic_type(system_proxy::TrafficOrigin::ALL);
166     chromeos::SystemProxyClient::Get()->ShutDownProcess(
167         request, base::BindOnce(&SystemProxyManager::OnShutDownProcess,
168                                 weak_factory_.GetWeakPtr()));
169     system_services_address_.clear();
170     SetUserTrafficProxyPref(std::string());
171     CloseAuthenticationUI();
172     return;
173   }
174   const std::string* username = proxy_settings->FindStringKey(
175       chromeos::kSystemProxySettingsKeySystemServicesUsername);
176 
177   const std::string* password = proxy_settings->FindStringKey(
178       chromeos::kSystemProxySettingsKeySystemServicesPassword);
179 
180   const base::Value* auth_schemes =
181       proxy_settings->FindListKey(chromeos::kSystemProxySettingsKeyAuthSchemes);
182 
183   policy_credentials_auth_schemes_.clear();
184   if (auth_schemes) {
185     for (const auto& auth_scheme : auth_schemes->GetList())
186       policy_credentials_auth_schemes_.push_back(auth_scheme.GetString());
187   }
188 
189   if (!username || username->empty() || !password || password->empty()) {
190     NET_LOG(DEBUG) << "Proxy credentials for system traffic not set: "
191                    << kSystemProxyService;
192   } else {
193     system_services_username_ = *username;
194     system_services_password_ = *password;
195   }
196   if (IsManagedProxyConfigured()) {
197     // Force send the configuration in case the credentials hand't changed, but
198     // `policy_credentials_auth_schemes_` has.
199     SendPolicyAuthenticationCredentials(system_services_username_,
200                                         system_services_password_,
201                                         /*force_send=*/true);
202   } else {
203     // To avoid leaking the policy set credentials, don't send them to
204     // System-proxy if there's no managed proxy on the network.
205     // Note: When SystemProxyManager is starting, the credentials are empty and
206     // they were never sent before. We need to force send them, otherwise
207     // `SendPolicyAuthenticationCredentials` will detect that no change to the
208     // credentials occurred and will not trigger a D-Bus request. This means the
209     // worker service for Chrome OS system services will not be started.
210     SendPolicyAuthenticationCredentials(/*username=*/"",
211                                         /*password=*/"",
212                                         /*force_send=*/true);
213   }
214 
215   // Fire once to cover the case where the SystemProxySetting policy is set
216   // during a user session.
217   if (IsArcEnabled()) {
218     OnArcEnabledChanged();
219   }
220 }
221 
OnKerberosEnabledChanged()222 void SystemProxyManager::OnKerberosEnabledChanged() {
223   SendKerberosAuthenticationDetails();
224 }
225 
OnKerberosAccountChanged()226 void SystemProxyManager::OnKerberosAccountChanged() {
227   if (!local_state_->GetBoolean(prefs::kKerberosEnabled)) {
228     return;
229   }
230   SendKerberosAuthenticationDetails();
231 }
232 
OnArcEnabledChanged()233 void SystemProxyManager::OnArcEnabledChanged() {
234   if (!system_proxy_enabled_) {
235     return;
236   }
237 
238   if (!IsArcEnabled()) {
239     system_proxy::ShutDownRequest request;
240     request.set_traffic_type(system_proxy::TrafficOrigin::USER);
241     chromeos::SystemProxyClient::Get()->ShutDownProcess(
242         request, base::BindOnce(&SystemProxyManager::OnShutDownProcess,
243                                 weak_factory_.GetWeakPtr()));
244     return;
245   }
246 
247   if (local_state_->GetBoolean(prefs::kKerberosEnabled)) {
248     SendKerberosAuthenticationDetails();
249     return;
250   }
251 
252   system_proxy::SetAuthenticationDetailsRequest request;
253   request.set_traffic_type(system_proxy::TrafficOrigin::USER);
254   chromeos::SystemProxyClient::Get()->SetAuthenticationDetails(
255       request, base::BindOnce(&SystemProxyManager::OnSetAuthenticationDetails,
256                               weak_factory_.GetWeakPtr()));
257 }
258 
IsArcEnabled() const259 bool SystemProxyManager::IsArcEnabled() const {
260   return primary_profile_ &&
261          primary_profile_->GetPrefs()->GetBoolean(arc::prefs::kArcEnabled);
262 }
263 
SendUserAuthenticationCredentials(const system_proxy::ProtectionSpace & protection_space,const std::string & username,const std::string & password)264 void SystemProxyManager::SendUserAuthenticationCredentials(
265     const system_proxy::ProtectionSpace& protection_space,
266     const std::string& username,
267     const std::string& password) {
268   // System-proxy is started via d-bus activation, meaning the first d-bus call
269   // will start the daemon. Check that System-proxy was not disabled by policy
270   // while looking for credentials so we don't accidentally restart it.
271   if (!system_proxy_enabled_) {
272     return;
273   }
274 
275   system_proxy::Credentials user_credentials;
276   user_credentials.set_username(username);
277   user_credentials.set_password(password);
278 
279   system_proxy::SetAuthenticationDetailsRequest request;
280   request.set_traffic_type(IsArcEnabled()
281                                ? system_proxy::TrafficOrigin::ALL
282                                : system_proxy::TrafficOrigin::SYSTEM);
283   *request.mutable_credentials() = user_credentials;
284   *request.mutable_protection_space() = protection_space;
285 
286   chromeos::SystemProxyClient::Get()->SetAuthenticationDetails(
287       request, base::BindOnce(&SystemProxyManager::OnSetAuthenticationDetails,
288                               weak_factory_.GetWeakPtr()));
289 }
290 
SendPolicyAuthenticationCredentials(const std::string & username,const std::string & password,bool force_send)291 void SystemProxyManager::SendPolicyAuthenticationCredentials(
292     const std::string& username,
293     const std::string& password,
294     bool force_send) {
295   if (!system_proxy_enabled_)
296     return;
297 
298   if (!force_send &&
299       (last_sent_username_ == username && last_sent_password_ == password)) {
300     // Credentials were already sent.
301     return;
302   }
303 
304   last_sent_username_ = username;
305   last_sent_password_ = password;
306 
307   system_proxy::SetAuthenticationDetailsRequest request;
308   system_proxy::Credentials credentials;
309   credentials.set_username(username);
310   credentials.set_password(password);
311   for (const auto& auth_scheme : policy_credentials_auth_schemes_) {
312     credentials.add_policy_credentials_auth_schemes(auth_scheme);
313   }
314   *request.mutable_credentials() = credentials;
315 
316   request.set_traffic_type(system_proxy::TrafficOrigin::SYSTEM);
317 
318   chromeos::SystemProxyClient::Get()->SetAuthenticationDetails(
319       request, base::BindOnce(&SystemProxyManager::OnSetAuthenticationDetails,
320                               weak_factory_.GetWeakPtr()));
321 }
322 
SendKerberosAuthenticationDetails()323 void SystemProxyManager::SendKerberosAuthenticationDetails() {
324   if (!system_proxy_enabled_) {
325     return;
326   }
327 
328   system_proxy::SetAuthenticationDetailsRequest request;
329   request.set_traffic_type(IsArcEnabled()
330                                ? system_proxy::TrafficOrigin::ALL
331                                : system_proxy::TrafficOrigin::SYSTEM);
332   request.set_kerberos_enabled(
333       local_state_->GetBoolean(prefs::kKerberosEnabled));
334   if (primary_profile_) {
335     request.set_active_principal_name(
336         primary_profile_->GetPrefs()
337             ->Get(prefs::kKerberosActivePrincipalName)
338             ->GetString());
339   }
340   chromeos::SystemProxyClient::Get()->SetAuthenticationDetails(
341       request, base::BindOnce(&SystemProxyManager::OnSetAuthenticationDetails,
342                               weak_factory_.GetWeakPtr()));
343 }
344 
SendEmptyCredentials(const system_proxy::ProtectionSpace & protection_space)345 void SystemProxyManager::SendEmptyCredentials(
346     const system_proxy::ProtectionSpace& protection_space) {
347   SendUserAuthenticationCredentials(protection_space,
348                                     /*username=*/std::string(),
349                                     /*password=*/std::string());
350 }
351 
SetSystemProxyEnabledForTest(bool enabled)352 void SystemProxyManager::SetSystemProxyEnabledForTest(bool enabled) {
353   system_proxy_enabled_ = enabled;
354 }
355 
SetSystemServicesProxyUrlForTest(const std::string & local_proxy_url)356 void SystemProxyManager::SetSystemServicesProxyUrlForTest(
357     const std::string& local_proxy_url) {
358   system_proxy_enabled_ = true;
359   system_services_address_ = local_proxy_url;
360 }
361 
SetSendAuthDetailsClosureForTest(base::RepeatingClosure closure)362 void SystemProxyManager::SetSendAuthDetailsClosureForTest(
363     base::RepeatingClosure closure) {
364   send_auth_details_closure_for_test_ = closure;
365 }
366 
367 chromeos::RequestSystemProxyCredentialsView*
GetActiveAuthDialogForTest()368 SystemProxyManager::GetActiveAuthDialogForTest() {
369   return active_auth_dialog_;
370 }
371 
CloseAuthDialogForTest()372 void SystemProxyManager::CloseAuthDialogForTest() {
373   DCHECK(auth_widget_);
374   auth_widget_->CloseNow();
375 }
376 
377 // static
RegisterProfilePrefs(PrefRegistrySimple * registry)378 void SystemProxyManager::RegisterProfilePrefs(PrefRegistrySimple* registry) {
379   registry->RegisterStringPref(prefs::kSystemProxyUserTrafficHostAndPort,
380                                /*default_value=*/std::string());
381 }
382 
OnSetAuthenticationDetails(const system_proxy::SetAuthenticationDetailsResponse & response)383 void SystemProxyManager::OnSetAuthenticationDetails(
384     const system_proxy::SetAuthenticationDetailsResponse& response) {
385   if (response.has_error_message()) {
386     NET_LOG(ERROR)
387         << "Failed to set system traffic credentials for system proxy: "
388         << kSystemProxyService << ", Error: " << response.error_message();
389   }
390   if (send_auth_details_closure_for_test_)
391     send_auth_details_closure_for_test_.Run();
392 }
393 
394 // This function is called when the default network changes or when any of its
395 // properties change.
DefaultNetworkChanged(const chromeos::NetworkState * network)396 void SystemProxyManager::DefaultNetworkChanged(
397     const chromeos::NetworkState* network) {
398   if (!network)
399     return;
400   OnProxyConfigChanged();
401 }
402 
OnProxyConfigChanged()403 void SystemProxyManager::OnProxyConfigChanged() {
404   if (!IsManagedProxyConfigured()) {
405     SendPolicyAuthenticationCredentials(/*username=*/"", /*password=*/"",
406                                         /*force_send=*/false);
407     return;
408   }
409   SendPolicyAuthenticationCredentials(system_services_username_,
410                                       system_services_password_,
411                                       /*force_send=*/false);
412 }
413 
IsManagedProxyConfigured()414 bool SystemProxyManager::IsManagedProxyConfigured() {
415   DCHECK(chromeos::NetworkHandler::IsInitialized());
416   chromeos::NetworkHandler* network_handler = chromeos::NetworkHandler::Get();
417   base::Value proxy_settings(base::Value::Type::DICTIONARY);
418 
419   // |ui_proxy_config_service| may be missing in tests. If the device is offline
420   // (no network connected) the |DefaultNetwork| is null.
421   if (chromeos::NetworkHandler::HasUiProxyConfigService() &&
422       network_handler->network_state_handler()->DefaultNetwork()) {
423     // Check if proxy is enforced by user policy, force installed extension or
424     // ONC policies. This will only read managed settings.
425     chromeos::NetworkHandler::GetUiProxyConfigService()
426         ->MergeEnforcedProxyConfig(
427             network_handler->network_state_handler()->DefaultNetwork()->guid(),
428             &proxy_settings);
429   }
430   if (proxy_settings.DictEmpty())
431     return false;  // no managed proxy set
432 
433   if (IsProxyConfiguredByUserViaExtension())
434     return false;
435 
436   // Proxy was configured by the admin
437   return true;
438 }
439 
IsProxyConfiguredByUserViaExtension()440 bool SystemProxyManager::IsProxyConfiguredByUserViaExtension() {
441   if (!extension_prefs_util_)
442     return false;
443 
444   std::unique_ptr<extensions::api::settings_private::PrefObject> pref =
445       extension_prefs_util_->GetPref(proxy_config::prefs::kProxy);
446   return pref && pref->extension_can_be_disabled &&
447          *pref->extension_can_be_disabled;
448 }
449 
OnShutDownProcess(const system_proxy::ShutDownResponse & response)450 void SystemProxyManager::OnShutDownProcess(
451     const system_proxy::ShutDownResponse& response) {
452   if (response.has_error_message() && !response.error_message().empty()) {
453     NET_LOG(ERROR) << "Failed to shutdown system proxy process: "
454                    << kSystemProxyService
455                    << ", error: " << response.error_message();
456   }
457 }
458 
OnClearUserCredentials(const system_proxy::ClearUserCredentialsResponse & response)459 void SystemProxyManager::OnClearUserCredentials(
460     const system_proxy::ClearUserCredentialsResponse& response) {
461   if (response.has_error_message() && !response.error_message().empty()) {
462     NET_LOG(ERROR) << "Failed to clear user credentials: "
463                    << kSystemProxyService
464                    << ", error: " << response.error_message();
465   }
466 }
467 
OnWorkerActive(const system_proxy::WorkerActiveSignalDetails & details)468 void SystemProxyManager::OnWorkerActive(
469     const system_proxy::WorkerActiveSignalDetails& details) {
470   if (details.traffic_origin() == system_proxy::TrafficOrigin::SYSTEM) {
471     system_services_address_ = details.local_proxy_url();
472     return;
473   }
474   SetUserTrafficProxyPref(details.local_proxy_url());
475 }
476 
SetUserTrafficProxyPref(const std::string & user_traffic_address)477 void SystemProxyManager::SetUserTrafficProxyPref(
478     const std::string& user_traffic_address) {
479   if (!primary_profile_) {
480     return;
481   }
482   primary_profile_->GetPrefs()->SetString(
483       prefs::kSystemProxyUserTrafficHostAndPort, user_traffic_address);
484 }
485 
OnAuthenticationRequired(const system_proxy::AuthenticationRequiredDetails & details)486 void SystemProxyManager::OnAuthenticationRequired(
487     const system_proxy::AuthenticationRequiredDetails& details) {
488   system_proxy::ProtectionSpace protection_space =
489       details.proxy_protection_space();
490 
491   if (!primary_profile_) {
492     SendEmptyCredentials(protection_space);
493     return;
494   }
495 
496   // The previous authentication attempt failed.
497   if (details.has_bad_cached_credentials() &&
498       details.bad_cached_credentials()) {
499     ShowAuthenticationNotification(protection_space,
500                                    details.bad_cached_credentials());
501     return;
502   }
503 
504   // TODO(acostinas,chromium:1104818) |protection_space.origin()| is in a
505   // URI-like format which may be incompatible between Chrome and libcurl, which
506   // is used on the Chrome OS side. We should change |origin()| to be a PAC
507   // string (a more "standard" way of representing proxies) and call
508   // |FromPacString()| to create |proxy_server|.
509   net::ProxyServer proxy_server = net::ProxyServer::FromURI(
510       protection_space.origin(), net::ProxyServer::Scheme::SCHEME_HTTP);
511 
512   if (!proxy_server.is_valid()) {
513     SendEmptyCredentials(protection_space);
514     return;
515   }
516   content::BrowserContext::GetDefaultStoragePartition(primary_profile_)
517       ->GetNetworkContext()
518       ->LookupProxyAuthCredentials(
519           proxy_server, protection_space.scheme(),
520           net::HttpUtil::Unquote(protection_space.realm()),
521           base::BindOnce(
522               &SystemProxyManager::LookupProxyAuthCredentialsCallback,
523               weak_factory_.GetWeakPtr(), protection_space));
524 }
525 
LookupProxyAuthCredentialsCallback(const system_proxy::ProtectionSpace & protection_space,const base::Optional<net::AuthCredentials> & credentials)526 void SystemProxyManager::LookupProxyAuthCredentialsCallback(
527     const system_proxy::ProtectionSpace& protection_space,
528     const base::Optional<net::AuthCredentials>& credentials) {
529   if (!credentials) {
530     // Ask the user for credentials
531     ShowAuthenticationNotification(protection_space, /*show_error=*/false);
532     return;
533   }
534 
535   std::string username;
536   std::string password;
537   if (credentials) {
538     username = base::UTF16ToUTF8(credentials->username());
539     password = base::UTF16ToUTF8(credentials->password());
540 
541     // If there's a dialog requesting credentials for this proxy, close it.
542     if (notification_handler_ ||
543         (active_auth_dialog_ &&
544          active_auth_dialog_->GetProxyServer() == protection_space.origin())) {
545       CloseAuthenticationUI();
546     }
547   }
548   SendUserAuthenticationCredentials(protection_space, username, password);
549 }
550 
ShowAuthenticationNotification(const system_proxy::ProtectionSpace & protection_space,bool show_error)551 void SystemProxyManager::ShowAuthenticationNotification(
552     const system_proxy::ProtectionSpace& protection_space,
553     bool show_error) {
554   if (active_auth_dialog_)
555     return;
556   notification_handler_ = std::make_unique<chromeos::SystemProxyNotification>(
557       protection_space, show_error,
558       base::BindOnce(&SystemProxyManager::ShowAuthenticationDialog,
559                      weak_factory_.GetWeakPtr()));
560   notification_handler_->Show();
561 }
562 
ShowAuthenticationDialog(const system_proxy::ProtectionSpace & protection_space,bool show_error_label)563 void SystemProxyManager::ShowAuthenticationDialog(
564     const system_proxy::ProtectionSpace& protection_space,
565     bool show_error_label) {
566   if (active_auth_dialog_)
567     return;
568 
569   if (notification_handler_)
570     notification_handler_->Close();
571 
572   active_auth_dialog_ = new chromeos::RequestSystemProxyCredentialsView(
573       protection_space.origin(), show_error_label,
574       base::BindOnce(&SystemProxyManager::OnDialogClosed,
575                      weak_factory_.GetWeakPtr(), protection_space));
576 
577   active_auth_dialog_->SetAcceptCallback(
578       base::BindRepeating(&SystemProxyManager::OnDialogAccepted,
579                           weak_factory_.GetWeakPtr(), protection_space));
580   active_auth_dialog_->SetCancelCallback(
581       base::BindRepeating(&SystemProxyManager::OnDialogCanceled,
582                           weak_factory_.GetWeakPtr(), protection_space));
583 
584   auth_widget_ = views::DialogDelegate::CreateDialogWidget(
585       active_auth_dialog_, /*context=*/nullptr, /*parent=*/nullptr);
586   auth_widget_->Show();
587 }
588 
OnDialogAccepted(const system_proxy::ProtectionSpace & protection_space)589 void SystemProxyManager::OnDialogAccepted(
590     const system_proxy::ProtectionSpace& protection_space) {
591   SendUserAuthenticationCredentials(
592       protection_space, base::UTF16ToUTF8(active_auth_dialog_->GetUsername()),
593       base::UTF16ToUTF8(active_auth_dialog_->GetPassword()));
594 }
595 
OnDialogCanceled(const system_proxy::ProtectionSpace & protection_space)596 void SystemProxyManager::OnDialogCanceled(
597     const system_proxy::ProtectionSpace& protection_space) {
598   SendEmptyCredentials(protection_space);
599 }
600 
OnDialogClosed(const system_proxy::ProtectionSpace & protection_space)601 void SystemProxyManager::OnDialogClosed(
602     const system_proxy::ProtectionSpace& protection_space) {
603   active_auth_dialog_ = nullptr;
604   auth_widget_ = nullptr;
605 }
606 
CloseAuthenticationUI()607 void SystemProxyManager::CloseAuthenticationUI() {
608   // Closes the notification if shown.
609   if (notification_handler_) {
610     notification_handler_->Close();
611     notification_handler_.reset();
612   }
613   if (!auth_widget_)
614     return;
615   // Also deletes the |auth_widget_| instance.
616   auth_widget_->CloseWithReason(views::Widget::ClosedReason::kUnspecified);
617 }
618 
619 }  // namespace policy
620