0

Exempt YouTube infrastructure endpoints from being thottled.

Supervised user features require some of YouTube APIs to be available
to get information about eg. sign-in status, that in turn allows
correct exchange of cookies.

Minor: Prevent name collisions and ODR violations with other test compilation units by wrapping the entirety in anonymous namespace.

Bug: 374246913
Change-Id: I65ef5e04f2182866abc1b1317037da9968278376
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6087807
Reviewed-by: Alex Ilin <alexilin@chromium.org>
Commit-Queue: Tomek Jurkiewicz <tju@google.com>
Cr-Commit-Position: refs/heads/main@{#1395377}
This commit is contained in:
Tomasz Jurkiewicz
2024-12-12 06:02:07 -08:00
committed by Chromium LUCI CQ
parent 24aba9c411
commit c89be15ee6
4 changed files with 120 additions and 8 deletions

@ -39,6 +39,17 @@
#include "chrome/browser/supervised_user/supervised_user_verification_page.h"
#endif
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
namespace {
bool IsYouTubeInfrastructureSubframe(content::NavigationHandle* handle) {
if (handle->GetNavigatingFrameType() != content::FrameType::kSubframe) {
return false;
}
return handle->GetURL().DomainIs("accounts.youtube.com");
}
} // namespace
#endif
// static
std::unique_ptr<SupervisedUserGoogleAuthNavigationThrottle>
SupervisedUserGoogleAuthNavigationThrottle::MaybeCreate(
@ -170,6 +181,13 @@ SupervisedUserGoogleAuthNavigationThrottle::ShouldProceed() {
return content::NavigationThrottle::PROCEED;
}
if (base::FeatureList::IsEnabled(
supervised_user::kExemptYouTubeInfrastructureFromBlocking) &&
IsYouTubeInfrastructureSubframe(navigation_handle())) {
// Controls integration between google.com and youtube.com.
return content::NavigationThrottle::PROCEED;
}
// We only show the interstitial for the primary main frame and subframes.
// Navigation is allowed otherwise;
switch (navigation_handle()->GetNavigatingFrameType()) {

@ -27,12 +27,17 @@
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr char kExampleURL[] = "http://www.example1.com/123";
constexpr char kGoogleSearchURL[] = "https://www.google.com/search?q=test";
constexpr char kGoogleHomeURL[] = "https://www.google.com";
constexpr char kYoutubeDomain[] = "https://www.youtube.com";
constexpr char kChildTestEmail[] = "child@example.com";
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
constexpr char kYoutubeAccountsDomain[] = "https://accounts.youtube.com";
#endif
std::unique_ptr<KeyedService> BuildTestSigninClient(
content::BrowserContext* context) {
Profile* profile = Profile::FromBrowserContext(context);
@ -44,12 +49,23 @@ std::unique_ptr<KeyedService> CreateMockSyncService(
return std::make_unique<syncer::MockSyncService>();
}
} // namespace
class MockNavigationSubframeHandle : public content::MockNavigationHandle {
public:
MockNavigationSubframeHandle(const GURL& url,
content::RenderFrameHost* render_frame_host)
: content::MockNavigationHandle(url, render_frame_host) {}
content::FrameType GetNavigatingFrameType() const override {
return content::FrameType::kSubframe;
}
};
class SupervisedUserGoogleAuthNavigationThrottleTest
: public ChromeRenderViewHostTestHarness {
public:
void SetUp() override { ChromeRenderViewHostTestHarness::SetUp(); }
void TearDown() final {
subframe_ = nullptr;
ChromeRenderViewHostTestHarness::TearDown();
}
signin::IdentityManager* identity_manager() {
return IdentityManagerFactory::GetForProfile(profile());
@ -72,12 +88,25 @@ class SupervisedUserGoogleAuthNavigationThrottleTest
}
std::unique_ptr<SupervisedUserGoogleAuthNavigationThrottle>
CreateNavigationThrottle(const GURL& url, bool skip_jni_call = true) {
handle =
std::make_unique<::testing::NiceMock<content::MockNavigationHandle>>(
url, main_rfh());
CreateNavigationThrottle(const GURL& url,
bool skip_jni_call = true,
bool for_subframe = false) {
if (for_subframe) {
content::RenderFrameHostTester::For(main_rfh())
->InitializeRenderFrameIfNeeded();
subframe_ = content::RenderFrameHostTester::For(main_rfh())
->AppendChild("subframe");
handle_ =
std::make_unique<::testing::NiceMock<MockNavigationSubframeHandle>>(
url, subframe_);
} else {
handle_ =
std::make_unique<::testing::NiceMock<content::MockNavigationHandle>>(
url, main_rfh());
}
std::unique_ptr<SupervisedUserGoogleAuthNavigationThrottle> throttle =
SupervisedUserGoogleAuthNavigationThrottle::MaybeCreate(handle.get());
SupervisedUserGoogleAuthNavigationThrottle::MaybeCreate(handle_.get());
if (skip_jni_call) {
throttle->set_skip_jni_call_for_testing(true);
@ -98,7 +127,8 @@ class SupervisedUserGoogleAuthNavigationThrottleTest
}
private:
std::unique_ptr<content::MockNavigationHandle> handle;
std::unique_ptr<content::MockNavigationHandle> handle_;
raw_ptr<content::RenderFrameHost> subframe_;
};
TEST_F(SupervisedUserGoogleAuthNavigationThrottleTest,
@ -222,6 +252,60 @@ TEST_F(SupervisedUserGoogleAuthNavigationThrottleTest,
prenderedThrottle->WillStartRequest());
}
// In order to correctly perform authentication to youtube.com, its
// infrastructure (accounts.youtube.com) must be allowed.
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
TEST_F(
SupervisedUserGoogleAuthNavigationThrottleTest,
NavigationForPendingSignedInSupervisedUsersAllowsYouTubeInfrastructureInSubframes) {
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(
supervised_user::kForceSupervisedUserReauthenticationForYouTube);
SetUserAsSupervised();
SetInvalidRefreshTokenForPrimaryAccount(
identity_manager(),
signin_metrics::SourceForRefreshTokenOperation::kUnknown);
// An invalid, signed-in account is not authenticated.
signin::SetListAccountsResponseOneAccountWithParams(
{kChildTestEmail,
identity_manager()
->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin)
.gaia,
/*valid=*/false,
/*is_signed_out=*/false,
/*verified=*/true},
GetTestURLLoaderFactory());
identity_manager()->GetAccountsCookieMutator()->TriggerCookieJarUpdate();
content::RunAllTasksUntilIdle();
// Regular youtube content is not allowed, neither in subframe nor in main
// frame.
EXPECT_EQ(
content::NavigationThrottle::CANCEL,
CreateNavigationThrottle(GURL(kYoutubeDomain), /*skip_jni_call=*/true,
/*for_subframe=*/true)
->WillStartRequest());
EXPECT_EQ(
content::NavigationThrottle::CANCEL,
CreateNavigationThrottle(GURL(kYoutubeDomain), /*skip_jni_call=*/true,
/*for_subframe=*/false)
->WillStartRequest());
// But youtube accounts infrastructure is allowed (only in subframes).
EXPECT_EQ(content::NavigationThrottle::PROCEED,
CreateNavigationThrottle(GURL(kYoutubeAccountsDomain),
/*skip_jni_call=*/true,
/*for_subframe=*/true)
->WillStartRequest());
EXPECT_EQ(content::NavigationThrottle::CANCEL,
CreateNavigationThrottle(GURL(kYoutubeAccountsDomain),
/*skip_jni_call=*/true,
/*for_subframe=*/false)
->WillStartRequest());
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
TEST_F(SupervisedUserGoogleAuthNavigationThrottleTest,
NavigationForNotFreshSupervisedUsers) {
SetUserAsSupervised();
@ -255,3 +339,5 @@ TEST_F(SupervisedUserGoogleAuthNavigationThrottleTest, NavigationForNonUsers) {
// Throttling is not required for non supervised accounts.
EXPECT_EQ(nullptr, CreateNavigationThrottle(GURL(kExampleURL), false));
}
} // namespace

@ -137,6 +137,10 @@ BASE_FEATURE(kCloseSignTabsFromReauthenticationInterstitial,
BASE_FEATURE(kAllowSupervisedUserReauthenticationForSubframes,
"EnableSupervisedUserReauthenticationForSubframes",
base::FEATURE_ENABLED_BY_DEFAULT);
BASE_FEATURE(kExemptYouTubeInfrastructureFromBlocking,
"ExemptYouTubeInfrastructureFromBlocking",
base::FEATURE_ENABLED_BY_DEFAULT);
#endif
// TODO: crbug.com/378636321 - Clean up the

@ -96,6 +96,10 @@ BASE_DECLARE_FEATURE(kCloseSignTabsFromReauthenticationInterstitial);
// `kForceSupervisedUserReauthenticationForYouTube` or
// `kForceSupervisedUserReauthenticationForBlockedSites` is enabled.
BASE_DECLARE_FEATURE(kAllowSupervisedUserReauthenticationForSubframes);
// Specifies if infrastructure-related YouTube endpoints should be still
// reachable even if parental controls related restrict YouTube access.
BASE_DECLARE_FEATURE(kExemptYouTubeInfrastructureFromBlocking);
#endif
// Fallback to sending un-credentialed filtering requests for supervised users