blob: 923b0651180819b7839a5423d5d40fb9862a67f5 [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/browsing_data/access_context_audit_service.h"
#include "base/files/scoped_temp_dir.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_simple_task_runner.h"
#include "chrome/browser/browsing_data/access_context_audit_service_factory.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/testing_profile.h"
#include "components/browsing_data/content/local_shared_objects_container.h"
#include "content/public/browser/cookie_access_details.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/test/browser_task_environment.h"
#include "services/network/test/test_cookie_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// Checks that info in |record| matches both |cookie| and |top_frame_origin|.
void CheckCookieMatchesRecord(
net::CanonicalCookie* cookie,
GURL top_frame_origin,
const AccessContextAuditDatabase::AccessRecord& record) {
EXPECT_EQ(top_frame_origin.GetOrigin(), record.top_frame_origin);
EXPECT_EQ(AccessContextAuditDatabase::StorageAPIType::kCookie, record.type);
EXPECT_EQ(cookie->Name(), record.name);
EXPECT_EQ(cookie->Domain(), record.domain);
EXPECT_EQ(cookie->Path(), record.path);
}
} // namespace
class TestCookieManager : public network::TestCookieManager {
public:
void AddGlobalChangeListener(
mojo::PendingRemote<network::mojom::CookieChangeListener>
notification_pointer) override {
listener_registered_ = true;
}
bool ListenerRegistered() { return listener_registered_; }
protected:
bool listener_registered_ = false;
};
class AccessContextAuditServiceTest : public testing::Test {
public:
AccessContextAuditServiceTest() = default;
std::unique_ptr<KeyedService> BuildTestContextAuditService(
content::BrowserContext* context) {
std::unique_ptr<AccessContextAuditService> service(
new AccessContextAuditService());
service->SetTaskRunnerForTesting(
browser_task_environment_.GetMainThreadTaskRunner());
service->Init(temp_directory_.GetPath(), cookie_manager());
return service;
}
void SetUp() override {
feature_list_.InitWithFeatures(
{features::kClientStorageAccessContextAuditing}, {});
ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
task_runner_ = scoped_refptr<base::TestSimpleTaskRunner>(
new base::TestSimpleTaskRunner);
TestingProfile::Builder builder;
builder.AddTestingFactory(
AccessContextAuditServiceFactory::GetInstance(),
base::BindRepeating(
&AccessContextAuditServiceTest::BuildTestContextAuditService,
base::Unretained(this)));
builder.SetPath(temp_directory_.GetPath());
profile_ = builder.Build();
browser_task_environment_.RunUntilIdle();
}
void AccessRecordCallback(
std::vector<AccessContextAuditDatabase::AccessRecord> records) {
records_ = records;
}
std::vector<AccessContextAuditDatabase::AccessRecord> GetReturnedRecords() {
return records_;
}
void ClearReturnedRecords() { records_.clear(); }
TestCookieManager* cookie_manager() { return &cookie_manager_; }
TestingProfile* profile() { return profile_.get(); }
AccessContextAuditService* service() {
return AccessContextAuditServiceFactory::GetForProfile(profile());
}
protected:
content::BrowserTaskEnvironment browser_task_environment_;
std::unique_ptr<TestingProfile> profile_;
base::ScopedTempDir temp_directory_;
TestCookieManager cookie_manager_;
base::test::ScopedFeatureList feature_list_;
scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
std::vector<AccessContextAuditDatabase::AccessRecord> records_;
};
TEST_F(AccessContextAuditServiceTest, RegisterDeletionObservers) {
// Check that the service correctly registers observers for deletion.
EXPECT_TRUE(cookie_manager_.ListenerRegistered());
}
TEST_F(AccessContextAuditServiceTest, CookieRecords) {
// Check that cookie access records are successfully stored and deleted.
GURL kTestCookieURL("https://example.com");
std::string kTestCookieName = "test";
auto test_cookie = net::CanonicalCookie::Create(
kTestCookieURL, kTestCookieName + "=1", base::Time::Now(),
base::nullopt /* server_time */);
content::CookieAccessDetails test_access_details(
content::CookieAccessDetails::Type::kRead, kTestCookieURL, kTestCookieURL,
{*test_cookie});
browsing_data::LocalSharedObjectsContainer test_container(
profile(), {}, base::NullCallback());
test_container.cookies()->AddCookies(test_access_details);
// Record access to this cookie against a URL.
GURL kTopFrameURL("https://test.com");
service()->RecordAccess(test_container, kTopFrameURL);
// Ensure that the record of this access is correctly returned.
service()->GetAllAccessRecords(
base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
base::Unretained(this)));
browser_task_environment_.RunUntilIdle();
EXPECT_EQ(1u, GetReturnedRecords().size());
CheckCookieMatchesRecord(test_cookie.get(), kTopFrameURL,
GetReturnedRecords()[0]);
// Check that informing the service of access to the cookie is a no-op.
service()->OnCookieChange(
net::CookieChangeInfo(*test_cookie, net::CookieAccessSemantics::UNKNOWN,
net::CookieChangeCause::OVERWRITE));
ClearReturnedRecords();
service()->GetAllAccessRecords(
base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
base::Unretained(this)));
browser_task_environment_.RunUntilIdle();
EXPECT_EQ(1u, GetReturnedRecords().size());
CheckCookieMatchesRecord(test_cookie.get(), kTopFrameURL,
GetReturnedRecords()[0]);
// Inform the service the cookie has been deleted and check it is no longer
// returned.
service()->OnCookieChange(
net::CookieChangeInfo(*test_cookie, net::CookieAccessSemantics::UNKNOWN,
net::CookieChangeCause::EXPLICIT));
ClearReturnedRecords();
service()->GetAllAccessRecords(
base::BindOnce(&AccessContextAuditServiceTest::AccessRecordCallback,
base::Unretained(this)));
browser_task_environment_.RunUntilIdle();
EXPECT_EQ(0u, GetReturnedRecords().size());
}