blob: 5034830b42d80293233a4b26efb7381e9f8b9522 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/device_bound_sessions/session_inclusion_rules.h"
#include <initializer_list>
#include "base/strings/string_util.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/device_bound_sessions/proto/storage.pb.h"
#include "net/device_bound_sessions/session_error.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace net::device_bound_sessions {
namespace {
using Result = SessionInclusionRules::InclusionResult;
using RuleType = SessionParams::Scope::Specification::Type;
// These tests depend on the registry_controlled_domains code, so assert ahead
// of time that the eTLD+1 is what we expect, for clarity and to avoid confusing
// test failures.
void AssertDomainAndRegistry(const url::Origin& origin,
const std::string& expected_domain_and_registry) {
ASSERT_EQ(
registry_controlled_domains::GetDomainAndRegistry(
origin, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES),
expected_domain_and_registry)
<< "Unexpected domain and registry.";
}
} // namespace
class SessionInclusionRulesTest : public ::testing::Test {
public:
struct EvaluateUrlTestCase {
const char* url;
Result expected_result;
};
struct AddUrlRuleTestCase {
RuleType rule_type;
const char* host_pattern;
const char* path_prefix;
// This is kSuccess if there is no error expected when adding.
SessionError::ErrorType expected_is_added_result;
};
SessionInclusionRulesTest() = default;
void SetOrigin(const url::Origin& origin) { origin_ = origin; }
void SetIncludeSite(bool include_site) {
params_.include_site = include_site;
}
void CheckMayIncludeSite(bool expected_may_include_site) {
auto inclusion_rules_or_error =
SessionInclusionRules::Create(origin_, params_, GURL());
ASSERT_TRUE(inclusion_rules_or_error.has_value());
SessionInclusionRules& rules = *inclusion_rules_or_error;
EXPECT_EQ(rules.may_include_site_for_testing(), expected_may_include_site);
}
void CheckEvaluateUrlTestCases(
std::initializer_list<EvaluateUrlTestCase> test_cases) {
auto inclusion_rules_or_error =
SessionInclusionRules::Create(origin_, params_, GURL());
ASSERT_TRUE(inclusion_rules_or_error.has_value());
SessionInclusionRules& rules = *inclusion_rules_or_error;
for (const auto& test_case : test_cases) {
SCOPED_TRACE(test_case.url);
EXPECT_EQ(rules.EvaluateRequestUrl(GURL(test_case.url)),
test_case.expected_result);
}
}
void CheckAddUrlRuleTestCases(
std::initializer_list<AddUrlRuleTestCase> test_cases) {
auto inclusion_rules_or_error =
SessionInclusionRules::Create(origin_, params_, GURL());
ASSERT_TRUE(inclusion_rules_or_error.has_value());
for (const auto& test_case : test_cases) {
SCOPED_TRACE(base::JoinString(
{test_case.host_pattern, test_case.path_prefix}, ", "));
params_.specifications.emplace_back(
test_case.rule_type, test_case.host_pattern, test_case.path_prefix);
inclusion_rules_or_error =
SessionInclusionRules::Create(origin_, params_, GURL());
EXPECT_EQ(inclusion_rules_or_error.has_value(),
test_case.expected_is_added_result == SessionError::kSuccess);
if (test_case.expected_is_added_result != SessionError::kSuccess &&
!inclusion_rules_or_error.has_value()) {
EXPECT_EQ(inclusion_rules_or_error.error().type,
test_case.expected_is_added_result);
}
if (!inclusion_rules_or_error.has_value()) {
// Forget about this rule so that future rules can be evaluated.
params_.specifications.pop_back();
}
}
}
const SessionParams::Scope& params() { return params_; }
private:
SessionParams::Scope params_;
url::Origin origin_;
};
TEST_F(SessionInclusionRulesTest, DefaultIncludeOriginMayNotIncludeSite) {
url::Origin subdomain_origin =
url::Origin::Create(GURL("https://some.site.test"));
AssertDomainAndRegistry(subdomain_origin, "site.test");
SetOrigin(subdomain_origin);
CheckMayIncludeSite(false);
CheckEvaluateUrlTestCases(
{// URL not valid.
{"", Result::kExclude},
// Origins match.
{"https://some.site.test", Result::kInclude},
// Path is allowed.
{"https://some.site.test/path", Result::kInclude},
// Not same scheme.
{"http://some.site.test", Result::kExclude},
// Not same host (same-site subdomain).
{"https://some.other.site.test", Result::kExclude},
// Not same host (superdomain).
{"https://site.test", Result::kExclude},
// Unrelated site.
{"https://unrelated.test", Result::kExclude},
// Not same port.
{"https://some.site.test:8888", Result::kExclude}});
}
TEST_F(SessionInclusionRulesTest, DefaultIncludeOriginThoughMayIncludeSite) {
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
AssertDomainAndRegistry(root_site_origin, "site.test");
SetOrigin(root_site_origin);
CheckMayIncludeSite(true);
// All expectations are as above. Even though including the site is allowed,
// because the origin's host is its root eTLD+1, it is still limited to a
// default origin inclusion_rules because it did not set include_site.
CheckEvaluateUrlTestCases({// URL not valid.
{"", Result::kExclude},
// Origins match.
{"https://site.test", Result::kInclude},
// Path is allowed.
{"https://site.test/path", Result::kInclude},
// Not same scheme.
{"http://site.test", Result::kExclude},
// Not same host (same-site subdomain).
{"https://other.site.test", Result::kExclude},
// Not same host (superdomain).
{"https://test", Result::kExclude},
// Unrelated site.
{"https://unrelated.test", Result::kExclude},
// Not same port.
{"https://site.test:8888", Result::kExclude}});
}
TEST_F(SessionInclusionRulesTest, IncludeSiteAttemptedButNotAllowed) {
url::Origin subdomain_origin =
url::Origin::Create(GURL("https://some.site.test"));
AssertDomainAndRegistry(subdomain_origin, "site.test");
SessionParams::Scope params;
params.include_site = true;
auto rules_or_error = SessionInclusionRules::Create(
subdomain_origin, params, GURL("https://some.site.test/refresh"));
ASSERT_FALSE(rules_or_error.has_value());
EXPECT_EQ(rules_or_error.error().type,
SessionError::kInvalidScopeIncludeSite);
}
TEST_F(SessionInclusionRulesTest, IncludeSite) {
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
AssertDomainAndRegistry(root_site_origin, "site.test");
SetOrigin(root_site_origin);
CheckMayIncludeSite(true);
SetIncludeSite(true);
CheckEvaluateUrlTestCases(
{// URL not valid.
{"", Result::kExclude},
// Origins match.
{"https://site.test", Result::kInclude},
// Path is allowed.
{"https://site.test/path", Result::kInclude},
// Not same scheme (site is schemeful).
{"http://site.test", Result::kExclude},
// Same-site subdomain is allowed.
{"https://some.site.test", Result::kInclude},
{"https://some.other.site.test", Result::kInclude},
// Not same host (superdomain).
{"https://test", Result::kExclude},
// Unrelated site.
{"https://unrelated.test", Result::kExclude},
// Other port is allowed because whole site is included.
{"https://site.test:8888", Result::kInclude}});
}
TEST_F(SessionInclusionRulesTest, AddUrlRuleToOriginOnly) {
url::Origin subdomain_origin =
url::Origin::Create(GURL("https://some.site.test"));
AssertDomainAndRegistry(subdomain_origin, "site.test");
SetOrigin(subdomain_origin);
CheckMayIncludeSite(false);
CheckAddUrlRuleTestCases(
{// Host pattern equals origin's host. Path is valid.
{RuleType::kExclude, "some.site.test", "/static",
SessionError::kSuccess},
// Add an opposite rule to check later.
{RuleType::kInclude, "some.site.test", "/static/included",
SessionError::kSuccess},
// Path not valid.
{RuleType::kExclude, "some.site.test", "NotAPath",
SessionError::kInvalidScopeRulePath},
// Has a valid wildcard, but the origin scoping ensures it will
// only match some.site.test.
{RuleType::kInclude, "*.site.test", "/static/wildcard_match/",
SessionError::kSuccess},
// Other host patterns are not accepted.
{RuleType::kInclude, "unrelated.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kInclude, "site.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kInclude, "other.site.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kInclude, "https://some.site.test", "/static/https_rule/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kInclude, "some.site.test:8000", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch}});
EXPECT_EQ(params().specifications.size(), 3u);
CheckEvaluateUrlTestCases(
{// Matches the rule.
{"https://some.site.test/static", Result::kExclude},
// A path under the rule's path prefix is subject to the rule.
{"https://some.site.test/static/some/thing", Result::kExclude},
// These do not match the rule, so are subject to the basic rules (the
// origin).
{"https://some.site.test/staticcccccccc", Result::kInclude},
{"https://other.site.test/static", Result::kExclude},
// The more recently added rule wins out.
{"https://some.site.test/static/included", Result::kInclude},
{"https://some.site.test/valid_path", Result::kInclude},
// The wildcard matching is valid, but only matches the origin.
{"https://some.site.test/static/wildcard_match/", Result::kInclude},
// The origin scoping takes precedence over the rule.
{"https://subdomain.site.test/static/wildcard_match/", Result::kExclude},
{"https://unrelated.test/", Result::kExclude},
{"https://site.test/", Result::kExclude},
{"https://other.test/", Result::kExclude},
{"https://some.site.test/static/https_rule/", Result::kExclude},
{"https://some.site.test:8000/", Result::kExclude}});
// Note that what matters is when the rule was added, not how specific the URL
// path prefix is. Let's add another rule now to show that.
CheckAddUrlRuleTestCases(
{{RuleType::kExclude, "some.site.test", "/", SessionError::kSuccess}});
CheckEvaluateUrlTestCases(
{{"https://some.site.test/static/included", Result::kExclude}});
}
TEST_F(SessionInclusionRulesTest, AddUrlRuleToOriginThatMayIncludeSite) {
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
AssertDomainAndRegistry(root_site_origin, "site.test");
SetOrigin(root_site_origin);
CheckMayIncludeSite(true);
// Without any rules yet, the basic rules is just the origin, because
// include_site was not set.
CheckEvaluateUrlTestCases({{"https://site.test/static", Result::kInclude},
{"https://other.site.test", Result::kExclude}});
CheckAddUrlRuleTestCases(
{{RuleType::kExclude, "excluded.site.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kInclude, "included.site.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "site.test", "/static", SessionError::kSuccess},
{RuleType::kInclude, "unrelated.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch}});
EXPECT_EQ(params().specifications.size(), 1u);
CheckEvaluateUrlTestCases(
{// Path is excluded by rule.
{"https://site.test/static", Result::kExclude},
// Session is origin-scoped, so this rule is ignored.
{"https://excluded.site.test", Result::kExclude},
// Session is origin-scoped, so this rule is ignored.
{"https://included.site.test", Result::kExclude},
// Rule does not apply to wrong scheme.
{"http://included.site.test", Result::kExclude},
// No rules applies to these URLs, so the basic
// rules (origin) applies.
{"https://other.site.test", Result::kExclude},
{"https://site.test/stuff", Result::kInclude},
// Origin scoping takes precedence over rule.
{"https://unrelated.test/", Result::kExclude}});
}
TEST_F(SessionInclusionRulesTest, AddUrlRuleToRulesIncludingSite) {
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
AssertDomainAndRegistry(root_site_origin, "site.test");
SetOrigin(root_site_origin);
CheckMayIncludeSite(true);
SetIncludeSite(true);
// Without any rules yet, the basic rules is the site.
CheckEvaluateUrlTestCases({{"https://site.test/static", Result::kInclude},
{"https://other.site.test", Result::kInclude}});
// Since the origin's host is the root eTLD+1, it is allowed to set rules that
// affect URLs other than the setting origin (but still within the site).
CheckAddUrlRuleTestCases(
{{RuleType::kExclude, "excluded.site.test", "/", SessionError::kSuccess},
{RuleType::kInclude, "included.site.test", "/", SessionError::kSuccess},
{RuleType::kExclude, "site.test", "/static", SessionError::kSuccess},
{RuleType::kInclude, "unrelated.test", "/",
SessionError::kScopeRuleSiteScopedHostPatternMismatch}});
EXPECT_EQ(params().specifications.size(), 3u);
CheckEvaluateUrlTestCases(
{// Path is excluded by rule.
{"https://site.test/static", Result::kExclude},
// Rule excludes URL explicitly.
{"https://excluded.site.test", Result::kExclude},
// Rule includes URL explicitly.
{"https://included.site.test", Result::kInclude},
// Rule does not apply to wrong scheme.
{"http://included.site.test", Result::kExclude},
// No rule applies to these URLs, so the basic rules (site) applies.
{"https://other.site.test", Result::kInclude},
{"https://site.test/stuff", Result::kInclude},
// Site scoping takes precedence over rule.
{"https://unrelated.test/", Result::kExclude}});
}
TEST_F(SessionInclusionRulesTest, AddUrlRuleToRulesIncludingOrigin) {
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
AssertDomainAndRegistry(root_site_origin, "site.test");
SetOrigin(root_site_origin);
CheckMayIncludeSite(true);
SetIncludeSite(false);
CheckAddUrlRuleTestCases(
{{RuleType::kExclude, "excluded.site.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kInclude, "included.site.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "site.test", "/static", SessionError::kSuccess},
{RuleType::kInclude, "unrelated.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch}});
EXPECT_EQ(params().specifications.size(), 1u);
CheckEvaluateUrlTestCases({// Path is excluded by rule.
{"https://site.test/static", Result::kExclude},
// Rejected rules
{"https://excluded.site.test", Result::kExclude},
{"https://included.site.test", Result::kExclude},
// No rules applies to these URLs, so the basic
// rules (which is only the origin) applies.
{"https://other.site.test", Result::kExclude},
{"https://site.test/stuff", Result::kInclude},
// Site scoping takes precedence over rule.
{"https://unrelated.test/", Result::kExclude}});
}
TEST_F(SessionInclusionRulesTest, UrlRuleParsing) {
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
AssertDomainAndRegistry(root_site_origin, "site.test");
// Use the most permissive type of inclusion_rules, to hit the interesting
// edge cases.
SetOrigin(root_site_origin);
CheckMayIncludeSite(true);
CheckAddUrlRuleTestCases(
{// Empty host pattern not permitted.
{RuleType::kExclude, "", "/",
SessionError::kInvalidScopeRuleHostPattern},
// Host pattern that is only whitespace is not permitted.
{RuleType::kExclude, " ", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Forbidden characters in host_pattern.
{RuleType::kExclude, "https://site.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "site.test:8888", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "site.test,other.test", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Non-IPv6-allowable characters within the brackets.
{RuleType::kExclude, "[*.:abcd::3:4:ff]", "/",
SessionError::kInvalidScopeRuleHostPattern},
{RuleType::kExclude, "[1:ab+cd::3:4:ff]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "[[1:abcd::3:4:ff]]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Internal wildcard characters are forbidden in the host pattern.
{RuleType::kExclude, "sub.*.site.test", "/",
SessionError::kInvalidScopeRuleHostPattern},
// Multiple wildcard characters are forbidden in the host pattern.
{RuleType::kExclude, "*.sub.*.site.test", "/",
SessionError::kInvalidScopeRuleHostPattern},
// Wildcard must be followed by a dot.
{RuleType::kExclude, "*site.test", "/",
SessionError::kInvalidScopeRuleHostPattern},
// Wildcard may be followed by an eTLD, but will only match
// for requests matching the scope origin or requests that are
// subdomains of the site (depending on `include_site`).
{RuleType::kExclude, "*.test", "/", SessionError::kSuccess},
// Other sites are not allowed.
{RuleType::kExclude, "unrelated.site", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "4.31.198.44", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "[1:abcd::3:4:ff]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "co.uk", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "com", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch}});
}
TEST_F(SessionInclusionRulesTest, UrlRuleParsingTopLevelDomain) {
url::Origin tld_origin = url::Origin::Create(GURL("https://com"));
AssertDomainAndRegistry(tld_origin, "");
SetOrigin(tld_origin);
CheckMayIncludeSite(false);
CheckAddUrlRuleTestCases(
{// Exact host is allowed.
{RuleType::kExclude, "com", "/", SessionError::kSuccess},
// Wildcards are not permitted.
{RuleType::kExclude, "*.com", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Other hosts with no registrable domain are not allowed.
{RuleType::kExclude, "4.31.198.44", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "[1:abcd::3:4:ff]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "co.uk", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch}});
}
TEST_F(SessionInclusionRulesTest, UrlRuleParsingIPv4Address) {
url::Origin ip_origin = url::Origin::Create(GURL("https://4.31.198.44"));
AssertDomainAndRegistry(ip_origin, "");
SetOrigin(ip_origin);
CheckMayIncludeSite(false);
CheckAddUrlRuleTestCases(
{// Exact host is allowed.
{RuleType::kExclude, "4.31.198.44", "/", SessionError::kSuccess},
// Wildcards are not permitted for IPv4 addresses.
{RuleType::kExclude, "*.31.198.44", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "*.4.31.198.44", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Other hosts with no registrable domain are not allowed.
{RuleType::kExclude, "[1:abcd::3:4:ff]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "co.uk", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "com", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch}});
}
TEST_F(SessionInclusionRulesTest, UrlRuleParsingIPv6Address) {
url::Origin ipv6_origin =
url::Origin::Create(GURL("https://[1:abcd::3:4:ff]"));
AssertDomainAndRegistry(ipv6_origin, "");
SetOrigin(ipv6_origin);
CheckMayIncludeSite(false);
CheckAddUrlRuleTestCases(
{// Exact host is allowed.
{RuleType::kExclude, "[1:abcd::3:4:ff]", "/", SessionError::kSuccess},
// Wildcards are not permitted.
{RuleType::kExclude, "*.[1:abcd::3:4:ff]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Brackets mismatched is not allowed.
{RuleType::kExclude, "[1:abcd::3:4:ff", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "1:abcd::3:4:ff]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Non-IPv6-allowable characters within the brackets is not allowed.
{RuleType::kExclude, "[*.:abcd::3:4:ff]", "/",
SessionError::kInvalidScopeRuleHostPattern},
{RuleType::kExclude, "[1:ab+cd::3:4:ff]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "[[1:abcd::3:4:ff]]", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
// Other hosts with no registrable domain are not allowed.
{RuleType::kExclude, "4.31.198.44", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "co.uk", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch},
{RuleType::kExclude, "com", "/",
SessionError::kScopeRuleOriginScopedHostPatternMismatch}});
}
// This test is more to document the current behavior than anything else. We may
// discover a need for more comprehensive support for port numbers in the
// future.
TEST_F(SessionInclusionRulesTest, NonstandardPort) {
url::Origin nonstandard_port_origin =
url::Origin::Create(GURL("https://site.test:8888"));
AssertDomainAndRegistry(nonstandard_port_origin, "site.test");
SetOrigin(nonstandard_port_origin);
CheckMayIncludeSite(true);
// Without any URL rules, the default origin rule allows only the same origin.
CheckEvaluateUrlTestCases({{"https://site.test", Result::kExclude},
{"https://site.test:8888", Result::kInclude},
{"https://other.site.test", Result::kExclude}});
// If we include_site, then same-site URLs regardless of port number are
// included.
SetIncludeSite(true);
CheckEvaluateUrlTestCases({{"https://site.test", Result::kInclude},
{"https://site.test:8888", Result::kInclude},
{"https://site.test:1234", Result::kInclude},
{"https://other.site.test", Result::kInclude}});
// However, adding URL rules to an inclusion_rules based on such an origin may
// lead to unintuitive outcomes. It is not possible to specify a rule that
// applies to the same origin as the setting origin if the setting origin has
// a nonstandard port.
CheckAddUrlRuleTestCases(
{// The pattern is not accepted
{RuleType::kInclude, "site.test:8888", "/",
SessionError::kScopeRuleSiteScopedHostPatternMismatch},
// A rule with the same host without port specified is accepted.
// This rule applies to any URL with the specified host.
{RuleType::kExclude, "site.test", "/", SessionError::kSuccess},
// The pattern is not accepted
{RuleType::kInclude, "site.test:443", "/",
SessionError::kScopeRuleSiteScopedHostPatternMismatch}});
EXPECT_EQ(params().specifications.size(), 1u);
CheckEvaluateUrlTestCases(
{// This is same-origin but gets caught in the "site.test" rule because
// the rule didn't specify a port.
{"https://site.test:8888", Result::kExclude},
// This is same-site but gets caught in the "site.test" rule because
// the rule didn't specify a port.
{"https://site.test:1234", Result::kExclude},
// Same-site is included by basic rules.
{"https://other.site.test", Result::kInclude},
// Also excluded explicitly by rule.
{"https://site.test", Result::kExclude},
{"https://site.test:443", Result::kExclude}});
}
TEST_F(SessionInclusionRulesTest, ToFromProto) {
// Create a valid SessionInclusionRules object with default inclusion rule and
// a couple of additional URL rules.
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
AssertDomainAndRegistry(root_site_origin, "site.test");
SessionParams::Scope params;
params.include_site = true;
params.specifications = {{RuleType::kExclude, "excluded.site.test", "/"},
{RuleType::kInclude, "included.site.test", "/"}};
auto inclusion_rules_or_error = SessionInclusionRules::Create(
root_site_origin, std::move(params), GURL());
ASSERT_TRUE(inclusion_rules_or_error.has_value());
SessionInclusionRules& rules = *inclusion_rules_or_error;
// Create a corresponding proto object and validate.
proto::SessionInclusionRules proto = rules.ToProto();
EXPECT_EQ(root_site_origin.Serialize(), proto.origin());
EXPECT_TRUE(proto.do_include_site());
ASSERT_EQ(proto.url_rules().size(), 2);
{
const auto& rule = proto.url_rules(0);
EXPECT_EQ(rule.rule_type(), proto::RuleType::EXCLUDE);
EXPECT_EQ(rule.host_pattern(), "excluded.site.test");
EXPECT_EQ(rule.path_prefix(), "/");
}
{
const auto& rule = proto.url_rules(1);
EXPECT_EQ(rule.rule_type(), proto::RuleType::INCLUDE);
EXPECT_EQ(rule.host_pattern(), "included.site.test");
EXPECT_EQ(rule.path_prefix(), "/");
}
// Create a SessionInclusionRules object from the proto and verify
// that it is the same as the original.
std::optional<SessionInclusionRules> restored_inclusion_rules =
SessionInclusionRules::CreateFromProto(proto);
ASSERT_TRUE(restored_inclusion_rules.has_value());
EXPECT_EQ(*restored_inclusion_rules, rules);
}
TEST_F(SessionInclusionRulesTest, FailCreateFromInvalidProto) {
// Empty proto.
{
proto::SessionInclusionRules proto;
EXPECT_FALSE(SessionInclusionRules::CreateFromProto(proto));
}
// Opaque origin.
{
proto::SessionInclusionRules proto;
proto.set_origin("about:blank");
proto.set_do_include_site(false);
EXPECT_FALSE(SessionInclusionRules::CreateFromProto(proto));
}
// Create a fully populated proto.
url::Origin root_site_origin = url::Origin::Create(GURL("https://site.test"));
SessionParams::Scope params;
params.include_site = true;
params.specifications = {{RuleType::kExclude, "excluded.site.test", "/"},
{RuleType::kInclude, "included.site.test", "/"}};
auto inclusion_rules_or_error = SessionInclusionRules::Create(
root_site_origin, std::move(params), GURL());
ASSERT_TRUE(inclusion_rules_or_error.has_value());
SessionInclusionRules& rules = *inclusion_rules_or_error;
proto::SessionInclusionRules proto = rules.ToProto();
// The proto must actually be valid, or none of the following tests will be
// validating anything.
ASSERT_TRUE(SessionInclusionRules::CreateFromProto(proto).has_value());
// Test for missing proto fields by clearing the fields one at a time.
{
proto::SessionInclusionRules p(proto);
p.clear_origin();
EXPECT_FALSE(SessionInclusionRules::CreateFromProto(p));
}
{
proto::SessionInclusionRules p(proto);
p.clear_do_include_site();
EXPECT_FALSE(SessionInclusionRules::CreateFromProto(p));
}
// URL rules with missing parameters.
{
proto::SessionInclusionRules p(proto);
p.mutable_url_rules(0)->clear_rule_type();
EXPECT_FALSE(SessionInclusionRules::CreateFromProto(p));
}
{
proto::SessionInclusionRules p(proto);
p.mutable_url_rules(0)->clear_host_pattern();
EXPECT_FALSE(SessionInclusionRules::CreateFromProto(p));
}
{
proto::SessionInclusionRules p(proto);
p.mutable_url_rules(0)->clear_path_prefix();
EXPECT_FALSE(SessionInclusionRules::CreateFromProto(p));
}
}
} // namespace net::device_bound_sessions