Index: content/browser/net/sqlite_persistent_cookie_store_unittest.cc |
diff --git a/content/browser/net/sqlite_persistent_cookie_store_unittest.cc b/content/browser/net/sqlite_persistent_cookie_store_unittest.cc |
index 49ac64be46871059617ba3461b32ddc47f960c15..11c8419673aad48e04ae3eccbc61ffad9c62e2b8 100644 |
--- a/content/browser/net/sqlite_persistent_cookie_store_unittest.cc |
+++ b/content/browser/net/sqlite_persistent_cookie_store_unittest.cc |
@@ -19,10 +19,15 @@ |
#include "base/test/sequenced_worker_pool_owner.h" |
#include "base/threading/sequenced_worker_pool.h" |
#include "base/time/time.h" |
+#include "content/public/browser/cookie_crypto_delegate.h" |
+#include "content/public/browser/cookie_store_factory.h" |
+#include "crypto/encryptor.h" |
+#include "crypto/symmetric_key.h" |
#include "net/cookies/canonical_cookie.h" |
#include "net/cookies/cookie_constants.h" |
#include "sql/connection.h" |
#include "sql/meta_table.h" |
+#include "sql/statement.h" |
#include "testing/gtest/include/gtest/gtest.h" |
#include "url/gurl.h" |
@@ -32,6 +37,36 @@ namespace { |
const base::FilePath::CharType kCookieFilename[] = FILE_PATH_LITERAL("Cookies"); |
+class CookieCryptor : public content::CookieCryptoDelegate { |
+ public: |
+ CookieCryptor(); |
+ virtual bool EncryptString(const std::string& plaintext, |
+ std::string* ciphertext) OVERRIDE; |
+ virtual bool DecryptString(const std::string& ciphertext, |
+ std::string* plaintext) OVERRIDE; |
+ |
+ private: |
+ scoped_ptr<crypto::SymmetricKey> key_; |
+ crypto::Encryptor encryptor_; |
+}; |
+ |
+CookieCryptor::CookieCryptor() : key_( |
+ crypto::SymmetricKey::DeriveKeyFromPassword( |
+ crypto::SymmetricKey::AES, "password", "saltiest", 1000, 256)) { |
+ std::string iv("the iv: 16 bytes"); |
+ encryptor_.Init(key_.get(), crypto::Encryptor::CBC, iv); |
+} |
+ |
+bool CookieCryptor::EncryptString(const std::string& plaintext, |
+ std::string* ciphertext) { |
+ return encryptor_.Encrypt(plaintext, ciphertext); |
+} |
+ |
+bool CookieCryptor::DecryptString(const std::string& ciphertext, |
+ std::string* plaintext) { |
+ return encryptor_.Decrypt(ciphertext, plaintext); |
+} |
+ |
} // namespace |
typedef std::vector<net::CanonicalCookie*> CanonicalCookieVector; |
@@ -90,20 +125,24 @@ class SQLitePersistentCookieStoreTest : public testing::Test { |
pool_owner_.reset(new base::SequencedWorkerPoolOwner(3, "Background Pool")); |
} |
- void CreateAndLoad(bool restore_old_session_cookies, |
+ void CreateAndLoad(bool crypt_cookies, |
+ bool restore_old_session_cookies, |
CanonicalCookieVector* cookies) { |
store_ = new SQLitePersistentCookieStore( |
temp_dir_.path().Append(kCookieFilename), |
client_task_runner(), |
background_task_runner(), |
restore_old_session_cookies, |
- NULL); |
+ NULL, |
+ crypt_cookies ? |
+ scoped_ptr<content::CookieCryptoDelegate>(new CookieCryptor) : |
+ scoped_ptr<content::CookieCryptoDelegate>()); |
Load(cookies); |
} |
- void InitializeStore(bool restore_old_session_cookies) { |
+ void InitializeStore(bool crypt, bool restore_old_session_cookies) { |
CanonicalCookieVector cookies; |
- CreateAndLoad(restore_old_session_cookies, &cookies); |
+ CreateAndLoad(crypt, restore_old_session_cookies, &cookies); |
EXPECT_EQ(0U, cookies.size()); |
} |
@@ -125,6 +164,14 @@ class SQLitePersistentCookieStoreTest : public testing::Test { |
net::COOKIE_PRIORITY_DEFAULT)); |
} |
+ std::string ReadRawDBContents() { |
+ std::string contents; |
+ if (!base::ReadFileToString(temp_dir_.path().Append(kCookieFilename), |
+ &contents)) |
+ return std::string(); |
+ return contents; |
+ } |
+ |
virtual void SetUp() OVERRIDE { |
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
} |
@@ -146,13 +193,13 @@ class SQLitePersistentCookieStoreTest : public testing::Test { |
}; |
TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) { |
- InitializeStore(false); |
+ InitializeStore(false, false); |
AddCookie("A", "B", "foo.bar", "/", base::Time::Now()); |
DestroyStore(); |
// Load up the store and verify that it has good data in it. |
CanonicalCookieVector cookies; |
- CreateAndLoad(false, &cookies); |
+ CreateAndLoad(false, false, &cookies); |
ASSERT_EQ(1U, cookies.size()); |
ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); |
ASSERT_STREQ("A", cookies[0]->Name().c_str()); |
@@ -171,13 +218,13 @@ TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) { |
} |
// Upon loading, the database should be reset to a good, blank state. |
- CreateAndLoad(false, &cookies); |
+ CreateAndLoad(false, false, &cookies); |
ASSERT_EQ(0U, cookies.size()); |
// Verify that, after, recovery, the database persists properly. |
AddCookie("X", "Y", "foo.bar", "/", base::Time::Now()); |
DestroyStore(); |
- CreateAndLoad(false, &cookies); |
+ CreateAndLoad(false, false, &cookies); |
ASSERT_EQ(1U, cookies.size()); |
ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); |
ASSERT_STREQ("X", cookies[0]->Name().c_str()); |
@@ -187,7 +234,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestInvalidMetaTableRecovery) { |
// Test if data is stored as expected in the SQLite database. |
TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) { |
- InitializeStore(false); |
+ InitializeStore(false, false); |
AddCookie("A", "B", "foo.bar", "/", base::Time::Now()); |
// Replace the store effectively destroying the current one and forcing it |
// to write its data to disk. Then we can see if after loading it again it |
@@ -195,7 +242,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) { |
DestroyStore(); |
// Reload and test for persistence |
CanonicalCookieVector cookies; |
- CreateAndLoad(false, &cookies); |
+ CreateAndLoad(false, false, &cookies); |
ASSERT_EQ(1U, cookies.size()); |
ASSERT_STREQ("foo.bar", cookies[0]->Domain().c_str()); |
ASSERT_STREQ("A", cookies[0]->Name().c_str()); |
@@ -207,14 +254,14 @@ TEST_F(SQLitePersistentCookieStoreTest, TestPersistance) { |
STLDeleteElements(&cookies); |
// Reload and check if the cookie has been removed. |
- CreateAndLoad(false, &cookies); |
+ CreateAndLoad(false, false, &cookies); |
ASSERT_EQ(0U, cookies.size()); |
} |
// Test that priority load of cookies for a specfic domain key could be |
// completed before the entire store is loaded |
TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) { |
- InitializeStore(false); |
+ InitializeStore(false, false); |
base::Time t = base::Time::Now(); |
AddCookie("A", "B", "foo.bar", "/", t); |
t += base::TimeDelta::FromInternalValue(10); |
@@ -229,7 +276,9 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) { |
temp_dir_.path().Append(kCookieFilename), |
client_task_runner(), |
background_task_runner(), |
- false, NULL); |
+ false, NULL, |
+ scoped_ptr<content::CookieCryptoDelegate>()); |
+ |
// Posting a blocking task to db_thread_ makes sure that the DB thread waits |
// until both Load and LoadCookiesForKey have been posted to its task queue. |
background_task_runner()->PostTask( |
@@ -284,7 +333,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadCookiesForKey) { |
// Test that we can force the database to be written by calling Flush(). |
TEST_F(SQLitePersistentCookieStoreTest, TestFlush) { |
- InitializeStore(false); |
+ InitializeStore(false, false); |
// File timestamps don't work well on all platforms, so we'll determine |
// whether the DB file has been modified by checking its size. |
base::FilePath path = temp_dir_.path().Append(kCookieFilename); |
@@ -310,7 +359,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestFlush) { |
// Test loading old session cookies from the disk. |
TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) { |
- InitializeStore(true); |
+ InitializeStore(false, true); |
// Add a session cookie. |
store_->AddCookie( |
@@ -325,7 +374,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) { |
// Create a store that loads session cookies and test that the session cookie |
// was loaded. |
CanonicalCookieVector cookies; |
- CreateAndLoad(true, &cookies); |
+ CreateAndLoad(false, true, &cookies); |
ASSERT_EQ(1U, cookies.size()); |
ASSERT_STREQ("sessioncookie.com", cookies[0]->Domain().c_str()); |
@@ -338,7 +387,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestLoadOldSessionCookies) { |
// Test loading old session cookies from the disk. |
TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) { |
- InitializeStore(true); |
+ InitializeStore(false, true); |
// Add a session cookie. |
store_->AddCookie( |
@@ -353,7 +402,7 @@ TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) { |
// Create a store that doesn't load old session cookies and test that the |
// session cookie was not loaded. |
CanonicalCookieVector cookies; |
- CreateAndLoad(false, &cookies); |
+ CreateAndLoad(false, false, &cookies); |
ASSERT_EQ(0U, cookies.size()); |
// The store should also delete the session cookie. Wait until that has been |
@@ -362,12 +411,12 @@ TEST_F(SQLitePersistentCookieStoreTest, TestDontLoadOldSessionCookies) { |
// Create a store that loads old session cookies and test that the session |
// cookie is gone. |
- CreateAndLoad(true, &cookies); |
+ CreateAndLoad(false, true, &cookies); |
ASSERT_EQ(0U, cookies.size()); |
} |
TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) { |
- InitializeStore(true); |
+ InitializeStore(false, true); |
static const char kSessionName[] = "session"; |
static const char kPersistentName[] = "persistent"; |
@@ -392,7 +441,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PersistIsPersistent) { |
// Create a store that loads session cookie and test that the IsPersistent |
// attribute is restored. |
CanonicalCookieVector cookies; |
- CreateAndLoad(true, &cookies); |
+ CreateAndLoad(false, true, &cookies); |
ASSERT_EQ(2U, cookies.size()); |
std::map<std::string, net::CanonicalCookie*> cookie_map; |
@@ -422,7 +471,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) { |
static const char kCookieValue[] = "value"; |
static const char kCookiePath[] = "/"; |
- InitializeStore(true); |
+ InitializeStore(false, true); |
// Add a low-priority persistent cookie. |
store_->AddCookie( |
@@ -457,7 +506,7 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) { |
// Create a store that loads session cookie and test that the priority |
// attribute values are restored. |
CanonicalCookieVector cookies; |
- CreateAndLoad(true, &cookies); |
+ CreateAndLoad(false, true, &cookies); |
ASSERT_EQ(3U, cookies.size()); |
// Put the cookies into a map, by name, so we can easily find them. |
@@ -485,4 +534,74 @@ TEST_F(SQLitePersistentCookieStoreTest, PriorityIsPersistent) { |
STLDeleteElements(&cookies); |
} |
+TEST_F(SQLitePersistentCookieStoreTest, UpdateToEncryption) { |
+ CanonicalCookieVector cookies; |
+ |
+ // Create unencrypted cookie store and write something to it. |
+ InitializeStore(false, false); |
+ AddCookie("name", "value123XYZ", "foo.bar", "/", base::Time::Now()); |
+ DestroyStore(); |
+ |
+ // Verify that "value" is visible in the file. This is necessary in order to |
+ // have confidence in a later test that "encrypted_value" is not visible. |
+ std::string contents = ReadRawDBContents(); |
+ EXPECT_NE(0U, contents.length()); |
+ EXPECT_NE(contents.find("value123XYZ"), std::string::npos); |
+ |
+ // Create encrypted cookie store and ensure old cookie still reads. |
+ STLDeleteElements(&cookies_); |
+ EXPECT_EQ(0U, cookies_.size()); |
+ CreateAndLoad(true, false, &cookies); |
+ EXPECT_EQ(1U, cookies_.size()); |
+ EXPECT_EQ("name", cookies_[0]->Name()); |
+ EXPECT_EQ("value123XYZ", cookies_[0]->Value()); |
+ |
+ // Make sure we can update existing cookie and add new cookie as encrypted. |
+ store_->DeleteCookie(*(cookies_[0])); |
+ AddCookie("name", "encrypted_value123XYZ", "foo.bar", "/", base::Time::Now()); |
+ AddCookie("other", "something456ABC", "foo.bar", "/", |
+ base::Time::Now() + base::TimeDelta::FromInternalValue(10)); |
+ DestroyStore(); |
+ STLDeleteElements(&cookies_); |
+ CreateAndLoad(true, false, &cookies); |
+ EXPECT_EQ(2U, cookies_.size()); |
+ net::CanonicalCookie* cookie_name = NULL; |
+ net::CanonicalCookie* cookie_other = NULL; |
+ if (cookies_[0]->Name() == "name") { |
+ cookie_name = cookies_[0]; |
+ cookie_other = cookies_[1]; |
+ } else { |
+ cookie_name = cookies_[1]; |
+ cookie_other = cookies_[0]; |
+ } |
+ EXPECT_EQ("encrypted_value123XYZ", cookie_name->Value()); |
+ EXPECT_EQ("something456ABC", cookie_other->Value()); |
+ DestroyStore(); |
+ STLDeleteElements(&cookies_); |
+ |
+ // Examine the real record to make sure plaintext version doesn't exist. |
+ sql::Connection db; |
+ sql::Statement smt; |
+ int resultcount = 0; |
+ ASSERT_TRUE(db.Open(temp_dir_.path().Append(kCookieFilename))); |
+ smt.Assign(db.GetCachedStatement(SQL_FROM_HERE, |
+ "SELECT * " |
+ "FROM cookies " |
+ "WHERE host_key = 'foo.bar'")); |
+ while (smt.Step()) { |
+ resultcount++; |
+ for (int i=0; i < smt.ColumnCount(); i++) { |
+ EXPECT_EQ(smt.ColumnString(i).find("value"), std::string::npos); |
+ EXPECT_EQ(smt.ColumnString(i).find("something"), std::string::npos); |
+ } |
+ } |
+ EXPECT_EQ(2, resultcount); |
+ |
+ // Verify that "encrypted_value" is NOT visible in the file. |
+ contents = ReadRawDBContents(); |
+ EXPECT_NE(0U, contents.length()); |
+ EXPECT_EQ(contents.find("encrypted_value123XYZ"), std::string::npos); |
+ EXPECT_EQ(contents.find("something456ABC"), std::string::npos); |
+} |
+ |
} // namespace content |