Skip to content

Commit

Permalink
[FedCM] Intercept IDP sign-in headers, part 2
Browse files Browse the repository at this point in the history
This intercepts subresources. Part 1 was https://crrev.com/c/3999921

It implements the preferred solution to the timing attack problem
for the federated credential management API as described here:
https://github.com/fedidcg/FedCM/blob/main/meetings/2022/FedCM_%20Options%20for%20the%20Timing%20Attack%20Problem%202022-08-31.pdf

Bug: 1357790
Change-Id: If11d165ac309541c46d27da0d6595edef6e15831
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4006479
Commit-Queue: Nicolás Peña <npm@chromium.org>
Commit-Queue: Christian Biesinger <cbiesinger@chromium.org>
Reviewed-by: Yi Gu <yigu@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1069912}
  • Loading branch information
cbiesinger authored and Chromium LUCI CQ committed Nov 10, 2022
1 parent c5871f8 commit 6f57cbb
Show file tree
Hide file tree
Showing 12 changed files with 173 additions and 7 deletions.
17 changes: 17 additions & 0 deletions chrome/renderer/url_loader_throttle_provider_impl.cc
Expand Up @@ -21,12 +21,15 @@
#include "components/safe_browsing/content/renderer/renderer_url_loader_throttle.h"
#include "components/safe_browsing/core/common/features.h"
#include "content/public/common/content_features.h"
#include "content/public/common/web_identity.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "third_party/blink/public/common/browser_interface_broker_proxy.h"
#include "third_party/blink/public/common/loader/resource_type_util.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-shared.h"
#include "third_party/blink/public/web/modules/credentialmanagement/throttle_helper.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "url/gurl.h"

#if BUILDFLAG(ENABLE_EXTENSIONS)
Expand Down Expand Up @@ -191,6 +194,20 @@ URLLoaderThrottleProviderImpl::CreateThrottles(
->chromeos_listener()));
#endif // BUILDFLAG(IS_CHROMEOS_ASH)

// Workers can call us on a background thread. We don't care about such
// requests because we purposefully only look at resources from frames
// that the user can interact with.
content::RenderFrame* frame =
content::RenderThread::IsMainThread()
? content::RenderFrame::FromRoutingID(render_frame_id)
: nullptr;
if (frame) {
auto throttle = content::MaybeCreateIdentityUrlLoaderThrottle(
base::BindRepeating(blink::SetIdpSigninStatus, frame->GetWebFrame()));
if (throttle)
throttles.push_back(std::move(throttle));
}

return throttles;
}

Expand Down
40 changes: 38 additions & 2 deletions content/browser/webid/webid_browsertest.cc
Expand Up @@ -28,6 +28,7 @@
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
#include "content/shell/browser/shell_federated_permission_context.h"
#include "net/base/features.h"
#include "net/dns/mock_host_resolver.h"
#include "net/http/http_status_code.h"
Expand Down Expand Up @@ -288,9 +289,10 @@ class WebIdIdpSigninStatusBrowserTest : public WebIdBrowserTest {
command_line->AppendSwitch(switches::kIgnoreCertificateErrors);
}

FederatedIdentitySharingPermissionContextDelegate* sharing_context() {
ShellFederatedPermissionContext* sharing_context() {
BrowserContext* context = shell()->web_contents()->GetBrowserContext();
return context->GetFederatedIdentitySharingPermissionContext();
return static_cast<ShellFederatedPermissionContext*>(
context->GetFederatedIdentitySharingPermissionContext());
}
};

Expand Down Expand Up @@ -367,4 +369,38 @@ IN_PROC_BROWSER_TEST_F(WebIdIdpSigninStatusBrowserTest, IdpSignoutToplevel) {
EXPECT_FALSE(*value);
}

// Verify that IDP sign-in/out headers work in subresources.
IN_PROC_BROWSER_TEST_F(WebIdIdpSigninStatusBrowserTest,
IdpSigninAndOutSubresource) {
static constexpr char script[] = R"(
(async () => {
var resp = await fetch('/header/gsign%s');
return resp.status;
}) ();
)";

GURL url_for_origin = https_server().GetURL(kRpHostName, "/header/");
url::Origin origin = url::Origin::Create(url_for_origin);
EXPECT_FALSE(sharing_context()->GetIdpSigninStatus(origin).has_value());
{
base::RunLoop run_loop;
sharing_context()->SetIdpStatusClosureForTesting(run_loop.QuitClosure());
EXPECT_EQ(200, EvalJs(shell(), base::StringPrintf(script, "in")));
run_loop.Run();
}
auto value = sharing_context()->GetIdpSigninStatus(origin);
ASSERT_TRUE(value.has_value());
EXPECT_TRUE(*value);

{
base::RunLoop run_loop;
sharing_context()->SetIdpStatusClosureForTesting(run_loop.QuitClosure());
EXPECT_EQ(200, EvalJs(shell(), base::StringPrintf(script, "out")));
run_loop.Run();
}
value = sharing_context()->GetIdpSigninStatus(origin);
ASSERT_TRUE(value.has_value());
EXPECT_FALSE(*value);
}

} // namespace content
7 changes: 5 additions & 2 deletions content/shell/browser/shell_federated_permission_context.cc
Expand Up @@ -41,8 +41,11 @@ absl::optional<bool> ShellFederatedPermissionContext::GetIdpSigninStatus(
void ShellFederatedPermissionContext::SetIdpSigninStatus(
const url::Origin& idp_origin,
bool idp_signin_status) {
idp_signin_status_.insert(
std::pair(idp_origin.Serialize(), idp_signin_status));
idp_signin_status_[idp_origin.Serialize()] = idp_signin_status;
// TODO(crbug.com/1382989): Find a better way to do this than adding
// explicit helper code to signal completion.
if (idp_signin_status_closure_)
idp_signin_status_closure_.Run();
}

bool ShellFederatedPermissionContext::HasSharingPermission(
Expand Down
7 changes: 7 additions & 0 deletions content/shell/browser/shell_federated_permission_context.h
Expand Up @@ -10,6 +10,7 @@
#include <string>
#include <tuple>

#include "base/functional/callback.h"
#include "content/public/browser/federated_identity_active_session_permission_context_delegate.h"
#include "content/public/browser/federated_identity_api_permission_context_delegate.h"
#include "content/public/browser/federated_identity_sharing_permission_context_delegate.h"
Expand Down Expand Up @@ -62,6 +63,10 @@ class ShellFederatedPermissionContext

bool ShouldCompleteRequestImmediately() const override;

void SetIdpStatusClosureForTesting(base::RepeatingClosure closure) {
idp_signin_status_closure_ = std::move(closure);
}

private:
// Pairs of <RP embedder, IDP>
std::set<std::pair<std::string, std::string>> request_permissions_;
Expand All @@ -72,6 +77,8 @@ class ShellFederatedPermissionContext
std::set<std::tuple<std::string, std::string, std::string>> active_sessions_;
// Map of <IDP, IDPSigninStatus>
std::map<std::string, absl::optional<bool>> idp_signin_status_;

base::RepeatingClosure idp_signin_status_closure_;
};

} // namespace content
Expand Down
43 changes: 43 additions & 0 deletions content/shell/renderer/shell_content_renderer_client.cc
Expand Up @@ -14,6 +14,9 @@
#include "components/cdm/renderer/external_clear_key_key_system_info.h"
#include "components/network_hints/renderer/web_prescient_networking_impl.h"
#include "components/web_cache/renderer/web_cache_impl.h"
#include "content/public/common/web_identity.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/test/test_service.mojom.h"
#include "content/shell/common/main_frame_counter_test_impl.h"
#include "content/shell/common/power_monitor_test_impl.h"
Expand All @@ -26,7 +29,10 @@
#include "net/base/net_errors.h"
#include "ppapi/buildflags/buildflags.h"
#include "sandbox/policy/sandbox.h"
#include "third_party/blink/public/platform/url_loader_throttle_provider.h"
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/web/modules/credentialmanagement/throttle_helper.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_testing_support.h"
#include "third_party/blink/public/web/web_view.h"
#include "v8/include/v8.h"
Expand Down Expand Up @@ -125,6 +131,37 @@ class TestRendererServiceImpl : public mojom::TestService {
mojo::Receiver<mojom::TestService> receiver_;
};

class ShellContentRendererUrlLoaderThrottleProvider
: public blink::URLLoaderThrottleProvider {
public:
std::unique_ptr<URLLoaderThrottleProvider> Clone() override {
return std::make_unique<ShellContentRendererUrlLoaderThrottleProvider>();
}

blink::WebVector<std::unique_ptr<blink::URLLoaderThrottle>> CreateThrottles(
int render_frame_id,
const blink::WebURLRequest& request) override {
blink::WebVector<std::unique_ptr<blink::URLLoaderThrottle>> throttles;
// Workers can call us on a background thread. We don't care about such
// requests because we purposefully only look at resources from frames
// that the user can interact with.`
content::RenderFrame* frame =
RenderThread::IsMainThread()
? content::RenderFrame::FromRoutingID(render_frame_id)
: nullptr;
if (frame) {
auto throttle = content::MaybeCreateIdentityUrlLoaderThrottle(
base::BindRepeating(blink::SetIdpSigninStatus, frame->GetWebFrame()));
if (throttle)
throttles.push_back(std::move(throttle));
}

return throttles;
}

void SetOnline(bool is_online) override {}
};

void CreateRendererTestService(
mojo::PendingReceiver<mojom::TestService> receiver) {
// Owns itself.
Expand Down Expand Up @@ -207,6 +244,12 @@ void ShellContentRendererClient::DidInitializeWorkerContextOnWorkerThread(
}
}

std::unique_ptr<blink::URLLoaderThrottleProvider>
ShellContentRendererClient::CreateURLLoaderThrottleProvider(
blink::URLLoaderThrottleProviderType provider_type) {
return std::make_unique<ShellContentRendererUrlLoaderThrottleProvider>();
}

#if BUILDFLAG(ENABLE_MOJO_CDM)
void ShellContentRendererClient::GetSupportedKeySystems(
media::GetSupportedKeySystemsCB cb) {
Expand Down
9 changes: 9 additions & 0 deletions content/shell/renderer/shell_content_renderer_client.h
Expand Up @@ -13,6 +13,11 @@
#include "content/public/renderer/content_renderer_client.h"
#include "media/mojo/buildflags.h"

namespace blink {
class URLLoaderThrottleProvider;
enum class URLLoaderThrottleProviderType;
} // namespace blink

namespace web_cache {
class WebCacheImpl;
}
Expand Down Expand Up @@ -46,6 +51,10 @@ class ShellContentRendererClient : public ContentRendererClient {
void DidInitializeWorkerContextOnWorkerThread(
v8::Local<v8::Context> context) override;

std::unique_ptr<blink::URLLoaderThrottleProvider>
CreateURLLoaderThrottleProvider(
blink::URLLoaderThrottleProviderType provider_type) override;

#if BUILDFLAG(ENABLE_MOJO_CDM)
void GetSupportedKeySystems(media::GetSupportedKeySystemsCB cb) override;
#endif
Expand Down
1 change: 1 addition & 0 deletions third_party/blink/public/BUILD.gn
Expand Up @@ -282,6 +282,7 @@ source_set("blink_headers") {
"web/modules/autofill/web_form_element_observer.h",
"web/modules/autofill_assistant/node_signals.h",
"web/modules/canvas/canvas_test_utils.h",
"web/modules/credentialmanagement/throttle_helper.h",
"web/modules/media/audio/audio_device_factory.h",
"web/modules/media/audio/audio_input_ipc_factory.h",
"web/modules/media/audio/audio_output_ipc_factory.h",
Expand Down
@@ -0,0 +1 @@
file://content/browser/webid/OWNERS
@@ -0,0 +1,30 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_CREDENTIALMANAGEMENT_THROTTLE_HELPER_H_
#define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_CREDENTIALMANAGEMENT_THROTTLE_HELPER_H_

#include "third_party/blink/public/platform/web_common.h"

namespace url {
class Origin;
}

namespace blink {

namespace mojom {
enum class IdpSigninStatus;
} // namespace mojom

class WebLocalFrame;

// Sets the identity provider (IDP) signin state of the given |origin| to
// |status|. This is meant for use with IdentityUrlLoaderThrottle.
BLINK_MODULES_EXPORT void SetIdpSigninStatus(WebLocalFrame* frame,
const url::Origin& origin,
mojom::IdpSigninStatus status);

} // namespace blink

#endif // THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_CREDENTIALMANAGEMENT_THROTTLE_HELPER_H_
Expand Up @@ -119,11 +119,15 @@ CredentialManagerProxy* CredentialManagerProxy::From(
ScriptState* script_state) {
DCHECK(script_state->ContextIsValid());
LocalDOMWindow& window = *LocalDOMWindow::From(script_state);
return From(&window);
}

CredentialManagerProxy* CredentialManagerProxy::From(LocalDOMWindow* window) {
auto* supplement =
Supplement<LocalDOMWindow>::From<CredentialManagerProxy>(window);
Supplement<LocalDOMWindow>::From<CredentialManagerProxy>(*window);
if (!supplement) {
supplement = MakeGarbageCollected<CredentialManagerProxy>(window);
ProvideTo(window, supplement);
supplement = MakeGarbageCollected<CredentialManagerProxy>(*window);
ProvideTo(*window, supplement);
}
return supplement;
}
Expand Down
Expand Up @@ -60,6 +60,8 @@ class MODULES_EXPORT CredentialManagerProxy
// context corresponding to an attached window.
static CredentialManagerProxy* From(ScriptState*);

static CredentialManagerProxy* From(LocalDOMWindow*);

private:
template <typename Interface>
void BindRemoteForFedCm(HeapMojoRemote<Interface>& remote,
Expand Down
Expand Up @@ -5,6 +5,9 @@
#include "third_party/blink/renderer/modules/credentialmanagement/federated_credential.h"

#include "base/metrics/histogram_macros.h"
#include "third_party/blink/public/web/modules/credentialmanagement/throttle_helper.h"
#include "third_party/blink/public/web/web_frame.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_credential_request_options.h"
#include "third_party/blink/renderer/bindings/modules/v8/v8_federated_credential_init.h"
Expand Down Expand Up @@ -75,4 +78,14 @@ bool FederatedCredential::IsFederatedCredential() const {
return true;
}

void SetIdpSigninStatus(WebLocalFrame* frame,
const url::Origin& origin,
mojom::blink::IdpSigninStatus status) {
LocalFrame* local_frame = To<LocalFrame>(WebFrame::ToCoreFrame(*frame));
auto* auth_request = CredentialManagerProxy::From(local_frame->DomWindow())
->FederatedAuthRequest();
auth_request->SetIdpSigninStatus(SecurityOrigin::CreateFromUrlOrigin(origin),
status);
}

} // namespace blink

0 comments on commit 6f57cbb

Please sign in to comment.