0

Create wrapper HTTPFetcher to make requests to Phosphor

Responses will be handled by the quiche::BlindSignAuth library. This
is only a wrapper around SimpleURLLoader to make network requests to a
Google owned Auth server (Phosphor). The response is a known format from
an internal Google owned server.
This is not currently in use.

Bug: 1444621
Change-Id: I852c9dd166fa3b20313e35a6f64964ed8b4573f8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4548697
Auto-Submit: Brianna Goldstein <brgoldstein@google.com>
Reviewed-by: Andrew Williams <awillia@chromium.org>
Commit-Queue: Brianna Goldstein <brgoldstein@google.com>
Cr-Commit-Position: refs/heads/main@{#1158572}
This commit is contained in:
Brianna Goldstein
2023-06-16 01:53:44 +00:00
committed by Chromium LUCI CQ
parent ef05107160
commit 7f5ae2160f
7 changed files with 247 additions and 0 deletions

@ -629,6 +629,8 @@ static_library("browser") {
"interstitials/enterprise_util.h",
"invalidation/profile_invalidation_provider_factory.cc",
"invalidation/profile_invalidation_provider_factory.h",
"ip_protection/blind_sign_http_impl.cc",
"ip_protection/blind_sign_http_impl.h",
"ip_protection/ip_protection_auth_token_getter.cc",
"ip_protection/ip_protection_auth_token_getter.h",
"k_anonymity_service/k_anonymity_service_client.cc",
@ -2400,6 +2402,7 @@ static_library("browser") {
"//mojo/public/cpp/bindings",
"//net",
"//net:extras",
"//net/third_party/quiche:blind_sign_auth",
"//ppapi/buildflags",
"//printing/buildflags",
"//rlz/buildflags",

@ -0,0 +1,110 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ip_protection/blind_sign_http_impl.h"
#include <stdio.h>
#include <functional>
#include <string>
#include "base/strings/strcat.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "url/gurl.h"
namespace {
constexpr net::NetworkTrafficAnnotationTag kIpProtectionTrafficAnnotation =
net::DefineNetworkTrafficAnnotation("ip_protection_service_get_token",
R"(
semantics {
sender: "Chrome IP Protection Service Client"
description:
"Request to a Google auth server to obtain an authentication token "
"for Chrome's IP Protection privacy proxies."
trigger:
"The Chrome IP Protection Service is out of proxy authentication "
"tokens."
data:
"Chrome sign-in OAuth Token"
destination: GOOGLE_OWNED_SERVICE
internal {
contacts {
email: "ip-protection-team@google.com"
}
}
user_data {
type: ACCESS_TOKEN
}
last_reviewed: "2023-05-23"
}
policy {
cookies_allowed: NO
policy_exception_justification: "Not implemented."
}
comments:
""
)");
} // namespace
int kIpProtectionRequestMaxBodySize = 1024;
char kIpProtectionContentType[] = "application/x-protobuf";
BlindSignHttpImpl::BlindSignHttpImpl(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: url_loader_factory_(std::move(url_loader_factory)) {
CHECK(url_loader_factory_);
}
BlindSignHttpImpl::~BlindSignHttpImpl() = default;
void BlindSignHttpImpl::DoRequest(
const std::string& path_and_query,
const std::string& authorization_header,
const std::string& body,
std::function<void(absl::StatusOr<quiche::BlindSignHttpResponse>)>
callback) {
callback_ = std::move(callback);
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = GURL(path_and_query);
resource_request->method = net::HttpRequestHeaders::kPostMethod;
resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
resource_request->headers.SetHeader(
net::HttpRequestHeaders::kAuthorization,
base::StrCat({"Bearer ", authorization_header}));
resource_request->headers.SetHeader(net::HttpRequestHeaders::kContentType,
kIpProtectionContentType);
resource_request->headers.SetHeader(net::HttpRequestHeaders::kAccept,
kIpProtectionContentType);
url_loader_ = network::SimpleURLLoader::Create(
std::move(resource_request), kIpProtectionTrafficAnnotation);
url_loader_->AttachStringForUpload(body);
url_loader_->DownloadToString(
url_loader_factory_.get(),
base::BindOnce(&BlindSignHttpImpl::OnRequestCompleted,
weak_ptr_factory_.GetWeakPtr()),
kIpProtectionRequestMaxBodySize);
}
void BlindSignHttpImpl::OnRequestCompleted(
std::unique_ptr<std::string> response) {
int response_code = 0;
if (url_loader_->ResponseInfo() && url_loader_->ResponseInfo()->headers) {
response_code = url_loader_->ResponseInfo()->headers->response_code();
}
url_loader_.reset();
if (!response) {
// TODO (crbug.com/1446863): Indicate why the request to Phosphor failed so
// we can consider not requesting more tokens.
callback_(absl::InternalError("Failed Request to Authentication Server"));
return;
}
quiche::BlindSignHttpResponse bsa_response(response_code,
std::move(*response));
callback_(std::move(bsa_response));
}

@ -0,0 +1,43 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_IP_PROTECTION_BLIND_SIGN_HTTP_IMPL_H_
#define CHROME_BROWSER_IP_PROTECTION_BLIND_SIGN_HTTP_IMPL_H_
#include <functional>
#include <string>
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_http_interface.h"
#include "net/third_party/quiche/src/quiche/blind_sign_auth/blind_sign_http_response.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/url_response_head.mojom.h"
namespace network {
class SimpleURLLoader;
} // namespace network
class BlindSignHttpImpl : public quiche::BlindSignHttpInterface {
public:
explicit BlindSignHttpImpl(
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
~BlindSignHttpImpl() override;
void DoRequest(
const std::string& path_and_query,
const std::string& authorization_header,
const std::string& body,
std::function<void(absl::StatusOr<quiche::BlindSignHttpResponse>)>
callback) override;
private:
void OnRequestCompleted(std::unique_ptr<std::string> response);
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory_;
std::unique_ptr<network::SimpleURLLoader> url_loader_;
std::function<void(absl::StatusOr<quiche::BlindSignHttpResponse>)> callback_;
base::WeakPtrFactory<BlindSignHttpImpl> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_IP_PROTECTION_BLIND_SIGN_HTTP_IMPL_H_

@ -0,0 +1,88 @@
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ip_protection/blind_sign_http_impl.h"
#include "base/test/task_environment.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
#include "services/network/public/mojom/url_response_head.mojom-shared.h"
#include "services/network/test/test_url_loader_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
class BlindSignHttpImplTest : public testing::Test {
protected:
void SetUp() override {
http_fetcher_ = std::make_unique<BlindSignHttpImpl>(
base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
&test_url_loader_factory_));
}
base::test::TaskEnvironment task_environment_;
network::TestURLLoaderFactory test_url_loader_factory_;
std::unique_ptr<BlindSignHttpImpl> http_fetcher_;
std::unique_ptr<IdentityTestEnvironmentProfileAdaptor>
identity_test_env_adaptor_;
};
TEST_F(BlindSignHttpImplTest, DoRequestSendsCorrectRequest) {
std::string path_and_query = "/api/test";
std::string authorization_header = "token";
std::string body = "body";
// Set up the response to return from the mock.
auto head = network::mojom::URLResponseHead::New();
std::string response_body = "Response body";
test_url_loader_factory_.AddResponse(
GURL(path_and_query), std::move(head), response_body,
network::URLLoaderCompletionStatus(net::OK));
absl::StatusOr<quiche::BlindSignHttpResponse> result;
auto callback =
[&result](absl::StatusOr<quiche::BlindSignHttpResponse> response) {
result = std::move(response);
};
http_fetcher_->DoRequest(path_and_query, authorization_header, body,
std::move(callback));
// Use RunUntilIdle to make sure the response has been processed.
task_environment_.RunUntilIdle();
ASSERT_TRUE(result.ok());
EXPECT_EQ("Response body", result->body());
}
TEST_F(BlindSignHttpImplTest, DoRequestFailsToConnectReturnsFailureStatus) {
std::string path_and_query = "/api/test2";
std::string authorization_header = "token";
std::string body = "body";
// Mock no response from Authentication Server.
std::string response_body;
auto head = network::mojom::URLResponseHead::New();
test_url_loader_factory_.AddResponse(
GURL(path_and_query), std::move(head), response_body,
network::URLLoaderCompletionStatus(net::ERR_FAILED));
absl::StatusOr<quiche::BlindSignHttpResponse> result;
auto callback =
[&result](absl::StatusOr<quiche::BlindSignHttpResponse> response) {
result = std::move(response);
};
http_fetcher_->DoRequest(path_and_query, authorization_header, body,
std::move(callback));
// Use RunUntilIdle to make sure the response has been processed.
task_environment_.RunUntilIdle();
EXPECT_EQ("Failed Request to Authentication Server",
result.status().message());
EXPECT_EQ(absl::StatusCode::kInternal, result.status().code());
}

@ -5682,6 +5682,7 @@ test("unit_tests") {
"../browser/history_clusters/history_clusters_tab_helper_unittest.cc",
"../browser/idle/idle_detection_permission_context_unittest.cc",
"../browser/internal_auth_unittest.cc",
"../browser/ip_protection/blind_sign_http_impl_unittest.cc",
"../browser/k_anonymity_service/k_anonymity_service_client_unittest.cc",
"../browser/k_anonymity_service/k_anonymity_service_storage_unittest.cc",
"../browser/k_anonymity_service/k_anonymity_trust_token_getter_unittest.cc",

@ -423,4 +423,5 @@ Refer to README.md for content description and update process.
<item id="iwa_bundle_downloader" added_in_milestone="116" type="completing" content_hash_code="04d2beae" os_list="chromeos" semantics_fields="4,5,7,8,9" policy_fields="-1" file_path="chrome/browser/web_applications/isolated_web_apps/isolated_web_app_downloader.cc" />
<item id="bidding_and_auction_server_key_fetch" added_in_milestone="116" content_hash_code="07667a22" os_list="linux,windows,android,chromeos" file_path="content/browser/interest_group/bidding_and_auction_server_key_fetcher.cc" />
<item id="backdrop_image_link_verification" added_in_milestone="116" content_hash_code="054ed1ab" os_list="linux,windows,chromeos" file_path="chrome/browser/search/background/ntp_background_service.cc" />
<item id="ip_protection_service_get_token" added_in_milestone="116" content_hash_code="03968a1c" os_list="linux,windows,android,chromeos" file_path="chrome/browser/ip_protection/blind_sign_http_impl.cc" />
</annotations>

@ -286,6 +286,7 @@ after discussions on the right group.
<annotation id="glanceables_classroom_integration"/>
<annotation id="promise_app_service_download_icon"/>
<annotation id="backdrop_image_link_verification"/>
<annotation id="ip_protection_service_get_token"/>
</sender>
</group>
<group name="Admin Features" hidden="true">