blob: 0743140f05fe743e345c4b20c0b961f860a96248 [file] [log] [blame]
// Copyright (c) 2011 The Chromium OS 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 "policy_service.h"
#include <algorithm>
#include <string>
#include <vector>
#include <base/message_loop.h>
#include <base/message_loop_proxy.h>
#include <base/threading/thread.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "login_manager/bindings/device_management_backend.pb.h"
#include "login_manager/mock_owner_key.h"
#include "login_manager/mock_policy_service.h"
#include "login_manager/mock_policy_store.h"
namespace em = enterprise_management;
using ::testing::DoAll;
using ::testing::InvokeWithoutArgs;
using ::testing::Mock;
using ::testing::Return;
using ::testing::ReturnRef;
using ::testing::Sequence;
using ::testing::SetArgumentPointee;
using ::testing::StrictMock;
using ::testing::_;
namespace {
MATCHER_P(CastEq, str, "") {
return std::equal(str.begin(), str.end(), reinterpret_cast<const char*>(arg));
}
MATCHER_P(VectorEq, str, "") {
return str.size() == arg.size() &&
std::equal(str.begin(), str.end(), arg.begin());
}
MATCHER_P(PolicyEq, str, "") {
std::string arg_policy;
return arg.SerializeToString(&arg_policy) && arg_policy == str;
}
} // namespace
namespace login_manager {
class PolicyServiceTest : public testing::Test {
public:
PolicyServiceTest()
: fake_data_("fake_data"),
fake_sig_("fake_signature"),
fake_key_("fake_key"),
fake_key_sig_("fake_key_signature") {
}
virtual void SetUp() {
key_ = new StrictMock<MockOwnerKey>;
store_ = new StrictMock<MockPolicyStore>;
scoped_refptr<base::MessageLoopProxy> message_loop(
base::MessageLoopProxy::CreateForCurrentThread());
service_ = new PolicyService(store_, key_, message_loop, message_loop);
service_->set_delegate(&delegate_);
}
void InitPolicy(const std::string& data,
const std::string& signature,
const std::string& key,
const std::string& key_signature) {
policy_proto_.Clear();
if (!data.empty())
policy_proto_.set_policy_data(data);
if (!signature.empty())
policy_proto_.set_policy_data_signature(signature);
if (!key.empty())
policy_proto_.set_new_public_key(key);
if (!key_signature.empty())
policy_proto_.set_new_public_key_signature(key_signature);
ASSERT_TRUE(policy_proto_.SerializeToString(&policy_str_));
policy_data_ = reinterpret_cast<const uint8*>(policy_str_.c_str());
policy_len_ = policy_str_.size();
}
void ExpectVerifyAndSetPolicy(Sequence& sequence) {
EXPECT_CALL(*key_, Verify(CastEq(fake_data_), fake_data_.size(),
CastEq(fake_sig_), fake_sig_.size()))
.InSequence(sequence)
.WillOnce(Return(true));
EXPECT_CALL(*store_, Set(PolicyEq(policy_str_))).Times(1)
.InSequence(sequence);
}
void ExpectPersistKey(Sequence& sequence) {
EXPECT_CALL(*key_, Persist())
.InSequence(sequence)
.WillOnce(Return(true));
EXPECT_CALL(delegate_, OnKeyPersisted(true));
}
void ExpectPersistPolicy(Sequence& sequence) {
EXPECT_CALL(*store_, Persist())
.InSequence(sequence)
.WillOnce(Return(true));
EXPECT_CALL(completion_, Success()).Times(1);
EXPECT_CALL(delegate_, OnPolicyPersisted(true));
}
void ExpectKeyEqualsFalse(Sequence& sequence) {
EXPECT_CALL(*key_, Equals(_))
.InSequence(sequence)
.WillRepeatedly(Return(false));
}
void ExpectKeyPopulated(Sequence& sequence, bool return_value) {
EXPECT_CALL(*key_, IsPopulated())
.InSequence(sequence)
.WillRepeatedly(Return(return_value));
}
void ExpectStoreFail(int flags, ChromeOSLoginError code) {
EXPECT_CALL(*key_, Persist()).Times(0);
EXPECT_CALL(*store_, Set(_)).Times(0);
EXPECT_CALL(*store_, Persist()).Times(0);
EXPECT_CALL(completion_, Success()).Times(0);
EXPECT_CALL(completion_, Failure(_)).Times(1);
EXPECT_FALSE(service_->Store(policy_data_, policy_len_, &completion_,
flags));
loop_.RunAllPending();
}
PolicyStore* store() { return service_->store(); }
OwnerKey* key() { return service_->key(); }
static const int kAllKeyFlags;
static const char kSignalSuccess[];
static const char kSignalFailure[];
std::string fake_data_;
std::string fake_sig_;
std::string fake_key_;
std::string fake_key_sig_;
// Various representations of the policy protobuf.
em::PolicyFetchResponse policy_proto_;
std::string policy_str_;
const uint8* policy_data_;
uint32 policy_len_;
MessageLoop loop_;
// Use StrictMock to make sure that no unexpected policy or key mutations can
// occur without the test failing.
StrictMock<MockOwnerKey>* key_;
StrictMock<MockPolicyStore>* store_;
MockPolicyServiceDelegate delegate_;
MockPolicyServiceCompletion completion_;
scoped_refptr<PolicyService> service_;
};
const int PolicyServiceTest::kAllKeyFlags = PolicyService::KEY_ROTATE |
PolicyService::KEY_INSTALL_NEW |
PolicyService::KEY_CLOBBER;
const char PolicyServiceTest::kSignalSuccess[] = "success";
const char PolicyServiceTest::kSignalFailure[] = "failure";
TEST_F(PolicyServiceTest, Initialize) {
EXPECT_CALL(*key_, PopulateFromDiskIfPossible())
.WillOnce(Return(true));
EXPECT_CALL(*key_, IsPopulated())
.WillOnce(Return(true));
EXPECT_CALL(*store_, LoadOrCreate())
.WillOnce(Return(true));
EXPECT_TRUE(service_->Initialize());
}
TEST_F(PolicyServiceTest, Store) {
InitPolicy(fake_data_, fake_sig_, "", "");
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, true);
EXPECT_CALL(*key_, Verify(CastEq(fake_data_), fake_data_.size(),
CastEq(fake_sig_), fake_sig_.size()))
.InSequence(s1, s2)
.WillRepeatedly(Return(true));
ExpectKeyPopulated(s1, true);
ExpectVerifyAndSetPolicy(s2);
EXPECT_TRUE(service_->Store(policy_data_, policy_len_, &completion_,
kAllKeyFlags));
Mock::VerifyAndClearExpectations(key_);
Mock::VerifyAndClearExpectations(store_);
ExpectPersistPolicy(s2);
loop_.RunAllPending();
}
TEST_F(PolicyServiceTest, StoreWrongSignature) {
InitPolicy(fake_data_, fake_sig_, "", "");
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, true);
EXPECT_CALL(*key_, Verify(CastEq(fake_data_), fake_data_.size(),
CastEq(fake_sig_), fake_sig_.size()))
.InSequence(s1, s2)
.WillRepeatedly(Return(false));
ExpectStoreFail(kAllKeyFlags, CHROMEOS_LOGIN_ERROR_VERIFY_FAIL);
}
TEST_F(PolicyServiceTest, StoreNoData) {
InitPolicy("", "", "", "");
ExpectStoreFail(kAllKeyFlags, CHROMEOS_LOGIN_ERROR_DECODE_FAIL);
}
TEST_F(PolicyServiceTest, StoreNoSignature) {
InitPolicy(fake_data_, "", "", "");
ExpectStoreFail(kAllKeyFlags, CHROMEOS_LOGIN_ERROR_DECODE_FAIL);
}
TEST_F(PolicyServiceTest, StoreNoKey) {
InitPolicy(fake_data_, fake_sig_, "", "");
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, false);
EXPECT_CALL(*key_, Verify(CastEq(fake_data_), fake_data_.size(),
CastEq(fake_sig_), fake_sig_.size()))
.InSequence(s1, s2)
.WillRepeatedly(Return(false));
ExpectStoreFail(kAllKeyFlags, CHROMEOS_LOGIN_ERROR_VERIFY_FAIL);
}
TEST_F(PolicyServiceTest, StoreNewKey) {
InitPolicy(fake_data_, fake_sig_, fake_key_, "");
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, false);
EXPECT_CALL(*key_, PopulateFromBuffer(VectorEq(fake_key_)))
.InSequence(s1, s2)
.WillOnce(Return(true));
ExpectKeyPopulated(s1, true);
ExpectVerifyAndSetPolicy(s2);
EXPECT_TRUE(service_->Store(policy_data_, policy_len_, &completion_,
kAllKeyFlags));
Mock::VerifyAndClearExpectations(key_);
Mock::VerifyAndClearExpectations(store_);
ExpectPersistKey(s1);
ExpectPersistPolicy(s2);
loop_.RunAllPending();
}
TEST_F(PolicyServiceTest, StoreNewKeyClobber) {
InitPolicy(fake_data_, fake_sig_, fake_key_, "");
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, false);
EXPECT_CALL(*key_, ClobberCompromisedKey(VectorEq(fake_key_)))
.InSequence(s1, s2)
.WillOnce(Return(true));
ExpectKeyPopulated(s1, true);
ExpectVerifyAndSetPolicy(s2);
EXPECT_TRUE(service_->Store(policy_data_, policy_len_, &completion_,
PolicyService::KEY_CLOBBER));
Mock::VerifyAndClearExpectations(key_);
Mock::VerifyAndClearExpectations(store_);
ExpectPersistKey(s1);
ExpectPersistPolicy(s2);
loop_.RunAllPending();
}
TEST_F(PolicyServiceTest, StoreNewKeySame) {
InitPolicy(fake_data_, fake_sig_, fake_key_, "");
Sequence s1, s2, s3;
EXPECT_CALL(*key_, Equals(fake_key_))
.InSequence(s1)
.WillRepeatedly(Return(true));
ExpectKeyPopulated(s2, true);
ExpectVerifyAndSetPolicy(s3);
EXPECT_TRUE(service_->Store(policy_data_, policy_len_, &completion_,
kAllKeyFlags));
Mock::VerifyAndClearExpectations(key_);
Mock::VerifyAndClearExpectations(store_);
ExpectPersistPolicy(s2);
loop_.RunAllPending();
}
TEST_F(PolicyServiceTest, StoreNewKeyNotAllowed) {
InitPolicy(fake_data_, fake_sig_, fake_key_, "");
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, false);
ExpectStoreFail(0, CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY);
}
TEST_F(PolicyServiceTest, StoreRotation) {
InitPolicy(fake_data_, fake_sig_, fake_key_, fake_key_sig_);
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, true);
EXPECT_CALL(*key_, Rotate(VectorEq(fake_key_), VectorEq(fake_key_sig_)))
.InSequence(s1, s2)
.WillOnce(Return(true));
ExpectKeyPopulated(s1, true);
ExpectVerifyAndSetPolicy(s2);
EXPECT_TRUE(service_->Store(policy_data_, policy_len_, &completion_,
kAllKeyFlags));
Mock::VerifyAndClearExpectations(key_);
Mock::VerifyAndClearExpectations(store_);
ExpectPersistKey(s1);
ExpectPersistPolicy(s2);
loop_.RunAllPending();
}
TEST_F(PolicyServiceTest, StoreRotationClobber) {
InitPolicy(fake_data_, fake_sig_, fake_key_, fake_key_sig_);
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, false);
EXPECT_CALL(*key_, ClobberCompromisedKey(VectorEq(fake_key_)))
.InSequence(s1, s2)
.WillOnce(Return(true));
ExpectKeyPopulated(s1, true);
ExpectVerifyAndSetPolicy(s2);
EXPECT_TRUE(service_->Store(policy_data_, policy_len_, &completion_,
PolicyService::KEY_CLOBBER));
Mock::VerifyAndClearExpectations(key_);
Mock::VerifyAndClearExpectations(store_);
ExpectPersistKey(s1);
ExpectPersistPolicy(s2);
loop_.RunAllPending();
}
TEST_F(PolicyServiceTest, StoreRotationNoSignature) {
InitPolicy(fake_data_, fake_sig_, fake_key_, "");
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, true);
ExpectStoreFail(PolicyService::KEY_ROTATE,
CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY);
}
TEST_F(PolicyServiceTest, StoreRotationBadSignature) {
InitPolicy(fake_data_, fake_sig_, fake_key_, fake_key_sig_);
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, true);
EXPECT_CALL(*key_, Rotate(VectorEq(fake_key_), VectorEq(fake_key_sig_)))
.InSequence(s1, s2)
.WillOnce(Return(false));
ExpectStoreFail(PolicyService::KEY_ROTATE,
CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY);
}
TEST_F(PolicyServiceTest, StoreRotationNotAllowed) {
InitPolicy(fake_data_, fake_sig_, fake_key_, fake_key_sig_);
Sequence s1, s2;
ExpectKeyEqualsFalse(s1);
ExpectKeyPopulated(s2, true);
ExpectStoreFail(0, CHROMEOS_LOGIN_ERROR_ILLEGAL_PUBKEY);
}
TEST_F(PolicyServiceTest, Retrieve) {
InitPolicy(fake_data_, fake_sig_, fake_key_, fake_key_sig_);
EXPECT_CALL(*store_, Get())
.WillOnce(ReturnRef(policy_proto_));
std::vector<uint8> policy_data;
EXPECT_TRUE(service_->Retrieve(&policy_data));
ASSERT_EQ(policy_str_.size(), policy_data.size());
EXPECT_TRUE(std::equal(policy_str_.begin(), policy_str_.end(),
policy_data.begin()));
}
class PolicyServiceThreadTest : public testing::Test {
public:
PolicyServiceThreadTest()
: io_thread_("policy service test IO thread") {
io_thread_.Start();
}
virtual void SetUp() {
key_ = new StrictMock<MockOwnerKey>;
store_ = new StrictMock<MockPolicyStore>;
service_ =
new PolicyService(store_, key_,
base::MessageLoopProxy::CreateForCurrentThread(),
io_thread_.message_loop_proxy());
service_->set_delegate(&delegate_);
}
void QuitMainLoop() {
main_loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask());
}
MessageLoop main_loop_;
base::Thread io_thread_;
// Use StrictMock to make sure that no unexpected policy or key mutations can
// occur without the test failing.
StrictMock<MockOwnerKey>* key_;
StrictMock<MockPolicyStore>* store_;
MockPolicyServiceDelegate delegate_;
scoped_refptr<PolicyService> service_;
private:
DISALLOW_COPY_AND_ASSIGN(PolicyServiceThreadTest);
};
TEST_F(PolicyServiceThreadTest, PersistPolicySyncSuccess) {
EXPECT_CALL(*store_, Persist())
.WillOnce(Return(true));
service_->PersistPolicySync();
EXPECT_CALL(delegate_, OnPolicyPersisted(true))
.WillOnce(InvokeWithoutArgs(this,
&PolicyServiceThreadTest::QuitMainLoop));
main_loop_.Run();
}
TEST_F(PolicyServiceThreadTest, PersistPolicySyncFailure) {
EXPECT_CALL(*store_, Persist())
.WillOnce(Return(false));
service_->PersistPolicySync();
EXPECT_CALL(delegate_, OnPolicyPersisted(false))
.WillOnce(InvokeWithoutArgs(this,
&PolicyServiceThreadTest::QuitMainLoop));
main_loop_.Run();
}
} // namespace login_manager