From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jeremy Apthorp <nornagon@nornagon.net>
Date: Tue, 12 Nov 2019 11:50:16 -0800
Subject: add TrustedAuthClient to URLLoaderFactory

This allows intercepting authentication requests for the 'net' module.
Without this, the 'login' event for electron.net.ClientRequest can't be
implemented, because the existing path checks for the presence of a
WebContents, and cancels the authentication if there's no WebContents
available, which there isn't in the case of the 'net' module.

diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 737fc3c70ed0962fa1123c5665706762d7a8238b..9e894008fe949b756d3ee7d28a168c815e5dbcf2 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -228,6 +228,25 @@ struct CTPolicy {
   array<string> excluded_legacy_spkis;
 };
 
+interface TrustedAuthClient {
+  OnAuthRequired(
+      mojo_base.mojom.UnguessableToken? window_id,
+      uint32 process_id,
+      uint32 routing_id,
+      uint32 request_id,
+      url.mojom.Url url,
+      bool first_auth_attempt,
+      AuthChallengeInfo auth_info,
+      URLResponseHead? head,
+      pending_remote<AuthChallengeResponder> auth_challenge_responder);
+};
+interface TrustedURLLoaderAuthClient {
+  // When a new URLLoader is created, this will be called to pass a
+  // corresponding |auth_client|.
+  OnLoaderCreated(int32 request_id,
+                  pending_receiver<TrustedAuthClient> auth_client);
+};
+
 interface CertVerifierClient {
   Verify(
     int32 default_error,
@@ -660,6 +679,8 @@ struct URLLoaderFactoryParams {
   // impact because of the extra process hops, so use should be minimized.
   pending_remote<TrustedURLLoaderHeaderClient>? header_client;
 
+  pending_remote<TrustedURLLoaderAuthClient>? auth_client;
+
   // |factory_bound_access_patterns| are used for CORS checks in addition to
   // the per-context allow patterns that is managed via NetworkContext
   // interface. This still respects the per-context block lists.
diff --git a/services/network/url_loader.cc b/services/network/url_loader.cc
index c02cabc51eb5a99c9857b8cb5a57e0793e04b863..4c87980dbad41372f3f23a9493877801ab4ed3d8 100644
--- a/services/network/url_loader.cc
+++ b/services/network/url_loader.cc
@@ -461,6 +461,7 @@ URLLoader::URLLoader(
     base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
     base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
     mojom::TrustedURLLoaderHeaderClient* url_loader_header_client,
+    mojom::TrustedURLLoaderAuthClient* url_loader_auth_client,
     mojom::OriginPolicyManager* origin_policy_manager,
     std::unique_ptr<TrustTokenRequestHelperFactory> trust_token_helper_factory,
     const cors::OriginAccessList* origin_access_list,
@@ -525,6 +526,11 @@ URLLoader::URLLoader(
     header_client_.set_disconnect_handler(
         base::BindOnce(&URLLoader::OnMojoDisconnect, base::Unretained(this)));
   }
+  if (url_loader_auth_client) {
+    url_loader_auth_client->OnLoaderCreated(request_id_, auth_client_.BindNewPipeAndPassReceiver());
+    auth_client_.set_disconnect_handler(
+        base::BindOnce(&URLLoader::OnMojoDisconnect, base::Unretained(this)));
+  }
   if (want_raw_headers_) {
     options_ |= mojom::kURLLoadOptionSendSSLInfoWithResponse |
                 mojom::kURLLoadOptionSendSSLInfoForCertificateError;
@@ -1170,7 +1176,7 @@ void URLLoader::OnAuthRequired(net::URLRequest* url_request,
     // |this| may have been deleted.
     return;
   }
-  if (!network_context_client_) {
+  if (!network_context_client_ && !auth_client_) {
     OnAuthCredentials(base::nullopt);
     return;
   }
@@ -1186,11 +1192,20 @@ void URLLoader::OnAuthRequired(net::URLRequest* url_request,
   if (url_request->response_headers())
     head->headers = url_request->response_headers();
   head->auth_challenge_info = auth_info;
-  network_context_client_->OnAuthRequired(
-      fetch_window_id_, factory_params_->process_id, render_frame_id_,
-      request_id_, url_request_->url(), first_auth_attempt_, auth_info,
-      std::move(head),
-      auth_challenge_responder_receiver_.BindNewPipeAndPassRemote());
+
+  if (auth_client_) {
+    auth_client_->OnAuthRequired(
+        fetch_window_id_, factory_params_->process_id, render_frame_id_,
+        request_id_, url_request_->url(), first_auth_attempt_, auth_info,
+        std::move(head),
+        auth_challenge_responder_receiver_.BindNewPipeAndPassRemote());
+  } else {
+    network_context_client_->OnAuthRequired(
+        fetch_window_id_, factory_params_->process_id, render_frame_id_,
+        request_id_, url_request_->url(), first_auth_attempt_, auth_info,
+        std::move(head),
+        auth_challenge_responder_receiver_.BindNewPipeAndPassRemote());
+  }
 
   auth_challenge_responder_receiver_.set_disconnect_handler(
       base::BindOnce(&URLLoader::DeleteSelf, base::Unretained(this)));
diff --git a/services/network/url_loader.h b/services/network/url_loader.h
index 193733544750f8cdb07d76be80170f752947cec6..e2fcaeea674b3012d428911637748bb819aaf3e8 100644
--- a/services/network/url_loader.h
+++ b/services/network/url_loader.h
@@ -129,6 +129,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
       base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder,
       base::WeakPtr<NetworkUsageAccumulator> network_usage_accumulator,
       mojom::TrustedURLLoaderHeaderClient* url_loader_header_client,
+      mojom::TrustedURLLoaderAuthClient* url_loader_auth_client,
       mojom::OriginPolicyManager* origin_policy_manager,
       std::unique_ptr<TrustTokenRequestHelperFactory>
           trust_token_helper_factory,
@@ -494,6 +495,7 @@ class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
   base::Optional<base::UnguessableToken> fetch_window_id_;
 
   mojo::Remote<mojom::TrustedHeaderClient> header_client_;
+  mojo::Remote<mojom::TrustedAuthClient> auth_client_;
 
   std::unique_ptr<FileOpenerForUpload> file_opener_for_upload_;
 
diff --git a/services/network/url_loader_factory.cc b/services/network/url_loader_factory.cc
index adf7d7e9df186f032cb85d2aeba301c551442c78..07b3c4a219ecefa142efa10ba0b7efda16d755d6 100644
--- a/services/network/url_loader_factory.cc
+++ b/services/network/url_loader_factory.cc
@@ -77,6 +77,7 @@ URLLoaderFactory::URLLoaderFactory(
       resource_scheduler_client_(std::move(resource_scheduler_client)),
       header_client_(std::move(params_->header_client)),
       coep_reporter_(std::move(params_->coep_reporter)),
+      auth_client_(std::move(params_->auth_client)),
       cors_url_loader_factory_(cors_url_loader_factory),
       cookie_observer_(std::move(params_->cookie_observer)) {
   DCHECK(context);
@@ -297,6 +298,7 @@ void URLLoaderFactory::CreateLoaderAndStart(
       std::move(keepalive_statistics_recorder),
       std::move(network_usage_accumulator),
       header_client_.is_bound() ? header_client_.get() : nullptr,
+      auth_client_.is_bound() ? auth_client_.get() : nullptr,
       context_->origin_policy_manager(), std::move(trust_token_factory),
       context_->cors_origin_access_list(), std::move(cookie_observer));
 
diff --git a/services/network/url_loader_factory.h b/services/network/url_loader_factory.h
index 182b26816da9e82d83c47c3c73ecfdcf3003b967..903a3ad083201ed85e82169698041152278697fa 100644
--- a/services/network/url_loader_factory.h
+++ b/services/network/url_loader_factory.h
@@ -74,6 +74,7 @@ class URLLoaderFactory : public mojom::URLLoaderFactory {
   scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
   mojo::Remote<mojom::TrustedURLLoaderHeaderClient> header_client_;
   mojo::Remote<mojom::CrossOriginEmbedderPolicyReporter> coep_reporter_;
+  mojo::Remote<mojom::TrustedURLLoaderAuthClient> auth_client_;
 
   // |cors_url_loader_factory_| owns this.
   cors::CorsURLLoaderFactory* cors_url_loader_factory_;
