Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(388)

Unified Diff: components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc

Issue 116273002: Added support for signed policy blobs on desktop. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix for ios. Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc
diff --git a/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc b/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc
index c7378c74806925da7ab9cde9da2e3fa3b82f0aae..0162e0a67eac62447f5a41c84714600b415ace57 100644
--- a/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc
+++ b/components/policy/core/common/cloud/user_cloud_policy_store_unittest.cc
@@ -9,6 +9,7 @@
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_loop_proxy.h"
#include "base/run_loop.h"
+#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/core/common/cloud/mock_cloud_external_data_manager.h"
#include "components/policy/core/common/cloud/mock_cloud_policy_store.h"
#include "components/policy/core/common/cloud/policy_builder.h"
@@ -32,6 +33,8 @@ void RunUntilIdle() {
run_loop.RunUntilIdle();
}
+} // namespace
+
class UserCloudPolicyStoreTest : public testing::Test {
public:
UserCloudPolicyStoreTest() {}
@@ -39,15 +42,21 @@ class UserCloudPolicyStoreTest : public testing::Test {
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
store_.reset(
- new UserCloudPolicyStore(policy_file(), loop_.message_loop_proxy()));
+ new UserCloudPolicyStore(policy_file(),
+ key_file(),
+ GetPolicyVerificationKey(),
+ loop_.message_loop_proxy()));
external_data_manager_.reset(new MockCloudExternalDataManager);
external_data_manager_->SetPolicyStore(store_.get());
store_->SetSigninUsername(PolicyBuilder::kFakeUsername);
store_->AddObserver(&observer_);
- policy_.payload().mutable_passwordmanagerenabled()->set_value(true);
- policy_.payload().mutable_urlblacklist()->mutable_value()->add_entries(
- "chromium.org");
+ // Install an initial public key, so that by default the validation of
+ // the stored/loaded policy blob succeeds (it looks like a new key
+ // provision).
+ policy_.SetDefaultInitialSigningKey();
+
+ InitPolicyPayload(&policy_.payload());
policy_.Build();
}
@@ -59,10 +68,20 @@ class UserCloudPolicyStoreTest : public testing::Test {
RunUntilIdle();
}
+ void InitPolicyPayload(enterprise_management::CloudPolicySettings* payload) {
+ payload->mutable_passwordmanagerenabled()->set_value(true);
+ payload->mutable_urlblacklist()->mutable_value()->add_entries(
+ "chromium.org");
+ }
+
base::FilePath policy_file() {
return tmp_dir_.path().AppendASCII("policy");
}
+ base::FilePath key_file() {
+ return tmp_dir_.path().AppendASCII("policy_key");
+ }
+
// Verifies that store_->policy_map() has the appropriate entries.
void VerifyPolicyMap(CloudPolicyStore* store) {
EXPECT_EQ(2U, store->policy_map().size());
@@ -81,6 +100,18 @@ class UserCloudPolicyStoreTest : public testing::Test {
Eq(error)))));
}
+ void StorePolicyAndEnsureLoaded(
+ const enterprise_management::PolicyFetchResponse& policy) {
+ Sequence s;
+ EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s);
+ EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s);
+ store_->Store(policy);
+ RunUntilIdle();
+ Mock::VerifyAndClearExpectations(external_data_manager_.get());
+ Mock::VerifyAndClearExpectations(&observer_);
+ ASSERT_TRUE(store_->policy());
+ }
+
UserPolicyBuilder policy_;
MockCloudPolicyStoreObserver observer_;
scoped_ptr<UserCloudPolicyStore> store_;
@@ -162,20 +193,54 @@ TEST_F(UserCloudPolicyStoreTest, LoadImmediatelyWithInvalidFile) {
EXPECT_TRUE(store_->policy_map().empty());
}
+// Load file from cache with no key data, then migrate to have a key.
+TEST_F(UserCloudPolicyStoreTest, Migration) {
+ UserPolicyBuilder unsigned_builder;
+ unsigned_builder.UnsetSigningKey();
+ InitPolicyPayload(&unsigned_builder.payload());
+ unsigned_builder.Build();
+ // Policy should be unsigned.
+ EXPECT_FALSE(unsigned_builder.policy().has_policy_data_signature());
+
+ // Write policy to disk.
+ std::string data;
+ ASSERT_TRUE(unsigned_builder.policy().SerializeToString(&data));
+ ASSERT_TRUE(base::CreateDirectory(policy_file().DirName()));
+ int size = data.size();
+ ASSERT_EQ(size, file_util::WriteFile(policy_file(), data.c_str(), size));
+
+ // Now make sure the data can get loaded.
+ Sequence s;
+ EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s);
+ EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s);
+ store_->LoadImmediately(); // Should load without running the message loop.
+ Mock::VerifyAndClearExpectations(external_data_manager_.get());
+ Mock::VerifyAndClearExpectations(&observer_);
+
+ ASSERT_TRUE(store_->policy());
+ EXPECT_EQ(unsigned_builder.policy_data().SerializeAsString(),
+ store_->policy()->SerializeAsString());
+ VerifyPolicyMap(store_.get());
+ EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
+ EXPECT_TRUE(store_->policy_key().empty());
+ EXPECT_FALSE(base::PathExists(key_file()));
+
+ // Now mimic a new policy coming down - this should result in a new key
+ // being installed.
+ StorePolicyAndEnsureLoaded(policy_.policy());
+ EXPECT_EQ(policy_.policy().new_public_key(), store_->policy_key());
+ EXPECT_TRUE(base::PathExists(key_file()));
+}
+
TEST_F(UserCloudPolicyStoreTest, Store) {
EXPECT_FALSE(store_->policy());
EXPECT_TRUE(store_->policy_map().empty());
// Store a simple policy and make sure it ends up as the currently active
// policy.
- Sequence s;
- EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s);
- EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s);
- store_->Store(policy_.policy());
- RunUntilIdle();
+ StorePolicyAndEnsureLoaded(policy_.policy());
// Policy should be decoded and stored.
- ASSERT_TRUE(store_->policy());
EXPECT_EQ(policy_.policy_data().SerializeAsString(),
store_->policy()->SerializeAsString());
VerifyPolicyMap(store_.get());
@@ -188,18 +253,9 @@ TEST_F(UserCloudPolicyStoreTest, StoreThenClear) {
// Store a simple policy and make sure the file exists.
// policy.
- Sequence s1;
- EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s1);
- EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s1);
- store_->Store(policy_.policy());
- RunUntilIdle();
-
- EXPECT_TRUE(store_->policy());
+ StorePolicyAndEnsureLoaded(policy_.policy());
EXPECT_FALSE(store_->policy_map().empty());
- Mock::VerifyAndClearExpectations(external_data_manager_.get());
- Mock::VerifyAndClearExpectations(&observer_);
-
// Policy file should exist.
ASSERT_TRUE(base::PathExists(policy_file()));
@@ -218,6 +274,47 @@ TEST_F(UserCloudPolicyStoreTest, StoreThenClear) {
EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
}
+TEST_F(UserCloudPolicyStoreTest, StoreRotatedKey) {
+ EXPECT_FALSE(store_->policy());
+ EXPECT_TRUE(store_->policy_map().empty());
+
+ // Store a simple policy and make sure it ends up as the currently active
+ // policy.
+ StorePolicyAndEnsureLoaded(policy_.policy());
+ EXPECT_FALSE(policy_.policy().has_new_public_key_signature());
+ std::string original_policy_key = policy_.policy().new_public_key();
+ EXPECT_EQ(original_policy_key, store_->policy_key());
+
+ // Now do key rotation.
+ policy_.SetDefaultSigningKey();
+ policy_.SetDefaultNewSigningKey();
+ policy_.Build();
+ EXPECT_TRUE(policy_.policy().has_new_public_key_signature());
+ EXPECT_NE(original_policy_key, policy_.policy().new_public_key());
+ StorePolicyAndEnsureLoaded(policy_.policy());
+ EXPECT_EQ(policy_.policy().new_public_key(), store_->policy_key());
+}
+
+TEST_F(UserCloudPolicyStoreTest, ProvisionKeyTwice) {
+ EXPECT_FALSE(store_->policy());
+ EXPECT_TRUE(store_->policy_map().empty());
+
+ // Store a simple policy and make sure it ends up as the currently active
+ // policy.
+ StorePolicyAndEnsureLoaded(policy_.policy());
+
+ // Now try sending down policy signed with a different key (i.e. do key
+ // rotation with a key not signed with the original signing key).
+ policy_.UnsetSigningKey();
+ policy_.SetDefaultNewSigningKey();
+ policy_.Build();
+ EXPECT_FALSE(policy_.policy().has_new_public_key_signature());
+
+ ExpectError(store_.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR);
+ store_->Store(policy_.policy());
+ RunUntilIdle();
+}
+
TEST_F(UserCloudPolicyStoreTest, StoreTwoTimes) {
EXPECT_FALSE(store_->policy());
EXPECT_TRUE(store_->policy_map().empty());
@@ -225,28 +322,20 @@ TEST_F(UserCloudPolicyStoreTest, StoreTwoTimes) {
// Store a simple policy then store a second policy before the first one
// finishes validating, and make sure the second policy ends up as the active
// policy.
- Sequence s1;
- EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s1);
- EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s1);
-
UserPolicyBuilder first_policy;
+ first_policy.SetDefaultInitialSigningKey();
first_policy.payload().mutable_passwordmanagerenabled()->set_value(false);
first_policy.Build();
- store_->Store(first_policy.policy());
- RunUntilIdle();
-
- Mock::VerifyAndClearExpectations(external_data_manager_.get());
- Mock::VerifyAndClearExpectations(&observer_);
-
- Sequence s2;
- EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s2);
- EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s2);
+ StorePolicyAndEnsureLoaded(first_policy.policy());
- store_->Store(policy_.policy());
- RunUntilIdle();
+ // Rebuild policy with the same signing key as |first_policy| (no rotation).
+ policy_.UnsetNewSigningKey();
+ policy_.SetDefaultSigningKey();
+ policy_.Build();
+ ASSERT_FALSE(policy_.policy().has_new_public_key());
+ StorePolicyAndEnsureLoaded(policy_.policy());
// Policy should be decoded and stored.
- ASSERT_TRUE(store_->policy());
EXPECT_EQ(policy_.policy_data().SerializeAsString(),
store_->policy()->SerializeAsString());
VerifyPolicyMap(store_.get());
@@ -256,15 +345,15 @@ TEST_F(UserCloudPolicyStoreTest, StoreTwoTimes) {
TEST_F(UserCloudPolicyStoreTest, StoreThenLoad) {
// Store a simple policy and make sure it can be read back in.
// policy.
- Sequence s;
- EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s);
- EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s);
- store_->Store(policy_.policy());
- RunUntilIdle();
+ StorePolicyAndEnsureLoaded(policy_.policy());
+ EXPECT_FALSE(store_->policy_key().empty());
// Now, make sure the policy can be read back in from a second store.
scoped_ptr<UserCloudPolicyStore> store2(
- new UserCloudPolicyStore(policy_file(), loop_.message_loop_proxy()));
+ new UserCloudPolicyStore(policy_file(),
+ key_file(),
+ GetPolicyVerificationKey(),
+ loop_.message_loop_proxy()));
store2->SetSigninUsername(PolicyBuilder::kFakeUsername);
store2->AddObserver(&observer_);
EXPECT_CALL(observer_, OnStoreLoaded(store2.get()));
@@ -277,20 +366,21 @@ TEST_F(UserCloudPolicyStoreTest, StoreThenLoad) {
VerifyPolicyMap(store2.get());
EXPECT_EQ(CloudPolicyStore::STATUS_OK, store2->status());
store2->RemoveObserver(&observer_);
+ // Make sure that we properly resurrected the keys.
+ EXPECT_EQ(store2->policy_key(), store_->policy_key());
}
TEST_F(UserCloudPolicyStoreTest, StoreThenLoadImmediately) {
// Store a simple policy and make sure it can be read back in.
// policy.
- Sequence s;
- EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s);
- EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s);
- store_->Store(policy_.policy());
- RunUntilIdle();
+ StorePolicyAndEnsureLoaded(policy_.policy());
// Now, make sure the policy can be read back in from a second store.
scoped_ptr<UserCloudPolicyStore> store2(
- new UserCloudPolicyStore(policy_file(), loop_.message_loop_proxy()));
+ new UserCloudPolicyStore(policy_file(),
+ key_file(),
+ GetPolicyVerificationKey(),
+ loop_.message_loop_proxy()));
store2->SetSigninUsername(PolicyBuilder::kFakeUsername);
store2->AddObserver(&observer_);
EXPECT_CALL(observer_, OnStoreLoaded(store2.get()));
@@ -316,18 +406,28 @@ TEST_F(UserCloudPolicyStoreTest, StoreValidationError) {
ASSERT_FALSE(store_->policy());
}
-TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
- // Force a validation error by changing the username after policy is stored.
- Sequence s;
- EXPECT_CALL(*external_data_manager_, OnPolicyStoreLoaded()).InSequence(s);
- EXPECT_CALL(observer_, OnStoreLoaded(store_.get())).InSequence(s);
+TEST_F(UserCloudPolicyStoreTest, StoreUnsigned) {
+ // Create unsigned policy, try to store it, should get a validation error.
+ policy_.policy().mutable_policy_data_signature()->clear();
+
+ // Store policy.
+ ExpectError(store_.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR);
store_->Store(policy_.policy());
RunUntilIdle();
+ ASSERT_FALSE(store_->policy());
+}
+
+TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
+ // Force a validation error by changing the username after policy is stored.
+ StorePolicyAndEnsureLoaded(policy_.policy());
// Sign out, and sign back in as a different user, and try to load the profile
// data (should fail due to mismatched username).
scoped_ptr<UserCloudPolicyStore> store2(
- new UserCloudPolicyStore(policy_file(), loop_.message_loop_proxy()));
+ new UserCloudPolicyStore(policy_file(),
+ key_file(),
+ GetPolicyVerificationKey(),
+ loop_.message_loop_proxy()));
store2->SetSigninUsername("foobar@foobar.com");
store2->AddObserver(&observer_);
ExpectError(store2.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR);
@@ -340,7 +440,10 @@ TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
// Sign out - we should be able to load the policy (don't check usernames
// when signed out).
scoped_ptr<UserCloudPolicyStore> store3(
- new UserCloudPolicyStore(policy_file(), loop_.message_loop_proxy()));
+ new UserCloudPolicyStore(policy_file(),
+ key_file(),
+ GetPolicyVerificationKey(),
+ loop_.message_loop_proxy()));
store3->AddObserver(&observer_);
EXPECT_CALL(observer_, OnStoreLoaded(store3.get()));
store3->Load();
@@ -351,7 +454,10 @@ TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
// Now start a signin as a different user - this should fail validation.
scoped_ptr<UserCloudPolicyStore> store4(
- new UserCloudPolicyStore(policy_file(), loop_.message_loop_proxy()));
+ new UserCloudPolicyStore(policy_file(),
+ key_file(),
+ GetPolicyVerificationKey(),
+ loop_.message_loop_proxy()));
store4->SetSigninUsername("foobar@foobar.com");
store4->AddObserver(&observer_);
ExpectError(store4.get(), CloudPolicyStore::STATUS_VALIDATION_ERROR);
@@ -362,6 +468,8 @@ TEST_F(UserCloudPolicyStoreTest, LoadValidationError) {
store4->RemoveObserver(&observer_);
}
-} // namespace
+// TODO(atwilson): Add a test to detect tampered policy
+// (new_public_key_verification_signature() doesn't match the right key -
+// http://crbug.com/275291).
} // namespace policy

Powered by Google App Engine
This is Rietveld 408576698