Commit b8e3aa3e authored by Bruno Kim Medeiros Cesar's avatar Bruno Kim Medeiros Cesar Committed by Commit Bot

Return MANUAL reason for host patterns that match default behavior.

This change enable parents to override SafeSearch with host patterns,
like "*.sex.*".
Currently "allow" patterns are not considered for the "try to block
mature sites" setting, so the URL is allowed by DEFAULT but blocked
by the SafeSearch check. By returning a MANUAL reason, instead, then it
will be honored.

This may introduce a conflict when different patterns match the same URL,
but have different defaults, say, "www.google.*" and "*.google.com" both
match "www.google.com". In this case, we prefer to honor a blacklist over
a whitelist.

parent settings.

Bug: 880909
Test: Built a Chrome APK and verified different combinations for
Change-Id: Ia8a2e8c9261c9ea0a539c32a2ca8fe5e3e576fae
Reviewed-on: https://chromium-review.googlesource.com/1207573
Commit-Queue: Bruno Kim Medeiros Cesar <brunokim@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Cr-Commit-Position: refs/heads/master@{#590297}
parent cbf43767
...@@ -333,25 +333,11 @@ SupervisedUserURLFilter::GetFilteringBehaviorForURL( ...@@ -333,25 +333,11 @@ SupervisedUserURLFilter::GetFilteringBehaviorForURL(
if (base::ContainsKey(*kWhitelistedOrigins, effective_url.GetOrigin())) if (base::ContainsKey(*kWhitelistedOrigins, effective_url.GetOrigin()))
return ALLOW; return ALLOW;
// Check manual overrides for the exact URL. // Check manual blacklists and whitelists.
auto url_it = url_map_.find(policy::url_util::Normalize(effective_url)); FilteringBehavior manual_result =
if (url_it != url_map_.end()) GetManualFilteringBehaviorForURL(effective_url);
return url_it->second ? ALLOW : BLOCK; if (manual_result != INVALID)
return manual_result;
// Check manual overrides for the hostname.
const std::string host = effective_url.host();
auto host_it = host_map_.find(host);
if (host_it != host_map_.end())
return host_it->second ? ALLOW : BLOCK;
// Look for patterns matching the hostname, with a value that is different
// from the default (a value of true in the map meaning allowed).
for (const auto& host_entry : host_map_) {
if ((host_entry.second == (default_behavior_ == BLOCK)) &&
HostMatchesPattern(host, host_entry.first)) {
return host_entry.second ? ALLOW : BLOCK;
}
}
// Check the list of URL patterns. // Check the list of URL patterns.
std::set<URLMatcherConditionSet::ID> matching_ids = std::set<URLMatcherConditionSet::ID> matching_ids =
...@@ -363,7 +349,7 @@ SupervisedUserURLFilter::GetFilteringBehaviorForURL( ...@@ -363,7 +349,7 @@ SupervisedUserURLFilter::GetFilteringBehaviorForURL(
} }
// Check the list of hostname hashes. // Check the list of hostname hashes.
if (contents_->hostname_hashes.count(HostnameHash(host))) { if (contents_->hostname_hashes.count(HostnameHash(effective_url.host()))) {
*reason = supervised_user_error_page::WHITELIST; *reason = supervised_user_error_page::WHITELIST;
return ALLOW; return ALLOW;
} }
...@@ -380,6 +366,46 @@ SupervisedUserURLFilter::GetFilteringBehaviorForURL( ...@@ -380,6 +366,46 @@ SupervisedUserURLFilter::GetFilteringBehaviorForURL(
return default_behavior_; return default_behavior_;
} }
// There may be conflicting patterns, say, "allow *.google.com" and "block
// www.google.*". To break the tie, we prefer blacklists over whitelists, by
// returning early if there is a BLOCK and evaluating all manual overrides
// before returning an ALLOW. If there are no applicable manual overrides,
// return INVALID.
SupervisedUserURLFilter::FilteringBehavior
SupervisedUserURLFilter::GetManualFilteringBehaviorForURL(
const GURL& url) const {
FilteringBehavior result = INVALID;
// Check manual overrides for the exact URL.
auto url_it = url_map_.find(policy::url_util::Normalize(url));
if (url_it != url_map_.end()) {
if (!url_it->second)
return BLOCK;
result = ALLOW;
}
// Check manual overrides for the hostname.
const std::string host = url.host();
auto host_it = host_map_.find(host);
if (host_it != host_map_.end()) {
if (!host_it->second)
return BLOCK;
result = ALLOW;
}
// Look for patterns matching the hostname, with a value that is different
// from the default (a value of true in the map meaning allowed).
for (const auto& host_entry : host_map_) {
if (HostMatchesPattern(host, host_entry.first)) {
if (!host_entry.second)
return BLOCK;
result = ALLOW;
}
}
return result;
}
bool SupervisedUserURLFilter::GetFilteringBehaviorForURLWithAsyncChecks( bool SupervisedUserURLFilter::GetFilteringBehaviorForURLWithAsyncChecks(
const GURL& url, const GURL& url,
FilteringBehaviorCallback callback) const { FilteringBehaviorCallback callback) const {
......
...@@ -180,6 +180,7 @@ class SupervisedUserURLFilter { ...@@ -180,6 +180,7 @@ class SupervisedUserURLFilter {
const GURL& url, const GURL& url,
bool manual_only, bool manual_only,
supervised_user_error_page::FilteringBehaviorReason* reason) const; supervised_user_error_page::FilteringBehaviorReason* reason) const;
FilteringBehavior GetManualFilteringBehaviorForURL(const GURL& url) const;
void CheckCallback(FilteringBehaviorCallback callback, void CheckCallback(FilteringBehaviorCallback callback,
const GURL& url, const GURL& url,
......
...@@ -29,6 +29,13 @@ class SupervisedUserURLFilterTest : public ::testing::Test, ...@@ -29,6 +29,13 @@ class SupervisedUserURLFilterTest : public ::testing::Test,
// SupervisedUserURLFilter::Observer: // SupervisedUserURLFilter::Observer:
void OnSiteListUpdated() override { run_loop_.Quit(); } void OnSiteListUpdated() override { run_loop_.Quit(); }
void OnURLChecked(const GURL& url,
SupervisedUserURLFilter::FilteringBehavior behavior,
supervised_user_error_page::FilteringBehaviorReason reason,
bool uncertain) override {
behavior_ = behavior;
reason_ = reason;
}
protected: protected:
bool IsURLWhitelisted(const std::string& url) { bool IsURLWhitelisted(const std::string& url) {
...@@ -36,9 +43,45 @@ class SupervisedUserURLFilterTest : public ::testing::Test, ...@@ -36,9 +43,45 @@ class SupervisedUserURLFilterTest : public ::testing::Test,
SupervisedUserURLFilter::ALLOW; SupervisedUserURLFilter::ALLOW;
} }
void ExpectURLInDefaultWhitelist(const std::string& url) {
ExpectURLCheckMatches(url, SupervisedUserURLFilter::ALLOW,
supervised_user_error_page::DEFAULT);
}
void ExpectURLInDefaultBlacklist(const std::string& url) {
ExpectURLCheckMatches(url, SupervisedUserURLFilter::BLOCK,
supervised_user_error_page::DEFAULT);
}
void ExpectURLInManualWhitelist(const std::string& url) {
ExpectURLCheckMatches(url, SupervisedUserURLFilter::ALLOW,
supervised_user_error_page::MANUAL);
}
void ExpectURLInManualBlacklist(const std::string& url) {
ExpectURLCheckMatches(url, SupervisedUserURLFilter::BLOCK,
supervised_user_error_page::MANUAL);
}
base::test::ScopedTaskEnvironment scoped_task_environment_; base::test::ScopedTaskEnvironment scoped_task_environment_;
base::RunLoop run_loop_; base::RunLoop run_loop_;
SupervisedUserURLFilter filter_; SupervisedUserURLFilter filter_;
SupervisedUserURLFilter::FilteringBehavior behavior_;
supervised_user_error_page::FilteringBehaviorReason reason_;
private:
void ExpectURLCheckMatches(
const std::string& url,
SupervisedUserURLFilter::FilteringBehavior expected_behavior,
supervised_user_error_page::FilteringBehaviorReason expected_reason) {
bool called_synchronously =
filter_.GetFilteringBehaviorForURLWithAsyncChecks(GURL(url),
base::DoNothing());
ASSERT_TRUE(called_synchronously);
EXPECT_EQ(behavior_, expected_behavior);
EXPECT_EQ(reason_, expected_reason);
}
}; };
TEST_F(SupervisedUserURLFilterTest, Basic) { TEST_F(SupervisedUserURLFilterTest, Basic) {
...@@ -399,30 +442,85 @@ TEST_F(SupervisedUserURLFilterTest, HostMatchesPattern) { ...@@ -399,30 +442,85 @@ TEST_F(SupervisedUserURLFilterTest, HostMatchesPattern) {
"www.*.google.com")); "www.*.google.com"));
} }
TEST_F(SupervisedUserURLFilterTest, Patterns) { TEST_F(SupervisedUserURLFilterTest, PatternsWithoutConflicts) {
std::map<std::string, bool> hosts; std::map<std::string, bool> hosts;
// Initally, the second rule is ignored because has the same value as the // The third rule is redundant with the first, but it's not a conflict
// default (block). When we change the default to allow, the first rule is // since they have the same value (allow).
// ignored instead.
hosts["*.google.com"] = true; hosts["*.google.com"] = true;
hosts["www.google.*"] = false;
hosts["accounts.google.com"] = false; hosts["accounts.google.com"] = false;
hosts["mail.google.com"] = true; hosts["mail.google.com"] = true;
filter_.SetManualHosts(std::move(hosts)); filter_.SetManualHosts(std::move(hosts));
filter_.SetDefaultFilteringBehavior(SupervisedUserURLFilter::BLOCK);
// Initially, the default filtering behavior is BLOCK.
EXPECT_TRUE(IsURLWhitelisted("http://www.google.com/foo/")); EXPECT_TRUE(IsURLWhitelisted("http://www.google.com/foo/"));
EXPECT_FALSE(IsURLWhitelisted("http://accounts.google.com/bar/")); EXPECT_FALSE(IsURLWhitelisted("http://accounts.google.com/bar/"));
EXPECT_FALSE(IsURLWhitelisted("http://www.google.co.uk/blurp/"));
EXPECT_TRUE(IsURLWhitelisted("http://mail.google.com/moose/")); EXPECT_TRUE(IsURLWhitelisted("http://mail.google.com/moose/"));
EXPECT_FALSE(IsURLWhitelisted("http://www.google.co.uk/blurp/"));
filter_.SetDefaultFilteringBehavior(SupervisedUserURLFilter::ALLOW); filter_.SetDefaultFilteringBehavior(SupervisedUserURLFilter::ALLOW);
EXPECT_TRUE(IsURLWhitelisted("http://www.google.com/foo/"));
EXPECT_FALSE(IsURLWhitelisted("http://accounts.google.com/bar/"));
EXPECT_TRUE(IsURLWhitelisted("http://mail.google.com/moose/"));
EXPECT_TRUE(IsURLWhitelisted("http://www.google.co.uk/blurp/"));
}
TEST_F(SupervisedUserURLFilterTest, PatternsWithConflicts) {
std::map<std::string, bool> hosts;
// The fourth rule conflicts with the first for "www.google.com" host.
// Blocking then takes precedence.
hosts["*.google.com"] = true;
hosts["accounts.google.com"] = false;
hosts["mail.google.com"] = true;
hosts["www.google.*"] = false;
filter_.SetManualHosts(std::move(hosts));
filter_.SetDefaultFilteringBehavior(SupervisedUserURLFilter::BLOCK);
EXPECT_FALSE(IsURLWhitelisted("http://www.google.com/foo/")); EXPECT_FALSE(IsURLWhitelisted("http://www.google.com/foo/"));
EXPECT_FALSE(IsURLWhitelisted("http://accounts.google.com/bar/")); EXPECT_FALSE(IsURLWhitelisted("http://accounts.google.com/bar/"));
EXPECT_TRUE(IsURLWhitelisted("http://mail.google.com/moose/"));
EXPECT_FALSE(IsURLWhitelisted("http://www.google.co.uk/blurp/")); EXPECT_FALSE(IsURLWhitelisted("http://www.google.co.uk/blurp/"));
filter_.SetDefaultFilteringBehavior(SupervisedUserURLFilter::ALLOW);
EXPECT_FALSE(IsURLWhitelisted("http://www.google.com/foo/"));
EXPECT_FALSE(IsURLWhitelisted("http://accounts.google.com/bar/"));
EXPECT_TRUE(IsURLWhitelisted("http://mail.google.com/moose/")); EXPECT_TRUE(IsURLWhitelisted("http://mail.google.com/moose/"));
EXPECT_FALSE(IsURLWhitelisted("http://www.google.co.uk/blurp/"));
}
TEST_F(SupervisedUserURLFilterTest, Reason) {
std::map<std::string, bool> hosts;
std::map<GURL, bool> urls;
hosts["youtube.com"] = true;
hosts["*.google.*"] = true;
urls[GURL("https://youtube.com/robots.txt")] = false;
urls[GURL("https://google.co.uk/robots.txt")] = false;
filter_.SetManualHosts(std::move(hosts));
filter_.SetManualURLs(std::move(urls));
filter_.SetDefaultFilteringBehavior(SupervisedUserURLFilter::BLOCK);
ExpectURLInDefaultBlacklist("https://m.youtube.com/feed/trending");
ExpectURLInDefaultBlacklist("https://com.google");
ExpectURLInManualWhitelist("https://youtube.com/feed/trending");
ExpectURLInManualWhitelist("https://google.com/humans.txt");
ExpectURLInManualBlacklist("https://youtube.com/robots.txt");
ExpectURLInManualBlacklist("https://google.co.uk/robots.txt");
filter_.SetDefaultFilteringBehavior(SupervisedUserURLFilter::ALLOW);
ExpectURLInDefaultWhitelist("https://m.youtube.com/feed/trending");
ExpectURLInDefaultWhitelist("https://com.google");
ExpectURLInManualWhitelist("https://youtube.com/feed/trending");
ExpectURLInManualWhitelist("https://google.com/humans.txt");
ExpectURLInManualBlacklist("https://youtube.com/robots.txt");
ExpectURLInManualBlacklist("https://google.co.uk/robots.txt");
} }
TEST_F(SupervisedUserURLFilterTest, WhitelistsPatterns) { TEST_F(SupervisedUserURLFilterTest, WhitelistsPatterns) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment