blob: 4ac1cdb52689ad11ecdfa11aacaa1d61b8d7afb9 [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 "login_manager/device_policy_service.h"
#include <algorithm>
#include <set>
#include <string>
#include <vector>
#include <base/basictypes.h>
#include <base/message_loop.h>
#include <base/message_loop_proxy.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "login_manager/bindings/chrome_device_policy.pb.h"
#include "login_manager/bindings/device_management_backend.pb.h"
#include "login_manager/mock_mitigator.h"
#include "login_manager/mock_nss_util.h"
#include "login_manager/mock_owner_key.h"
#include "login_manager/mock_policy_store.h"
namespace em = enterprise_management;
using google::protobuf::RepeatedPtrField;
using testing::AtLeast;
using testing::DoAll;
using testing::Expectation;
using testing::Mock;
using testing::Return;
using testing::ReturnRef;
using testing::Sequence;
using testing::StrictMock;
using testing::WithArg;
using testing::_;
ACTION_P(AssignVector, str) {
arg0->assign(str.begin(), str.end());
}
namespace login_manager {
class DevicePolicyServiceTest : public ::testing::Test {
public:
DevicePolicyServiceTest()
: owner_("user@somewhere"),
fake_sig_("fake_signature"),
fake_key_("fake_key"),
new_fake_sig_("new_fake_signature"),
key_(NULL),
store_(NULL) {
fake_key_vector_.assign(fake_key_.begin(), fake_key_.end());
}
void InitPolicy(const em::ChromeDeviceSettingsProto& settings,
const std::string& owner,
const std::string& signature,
const std::string& request_token) {
std::string settings_str;
ASSERT_TRUE(settings.SerializeToString(&settings_str));
em::PolicyData policy_data;
policy_data.set_policy_type(DevicePolicyService::kDevicePolicyType);
policy_data.set_policy_value(settings_str);
if (!owner.empty())
policy_data.set_username(owner);
if (!request_token.empty())
policy_data.set_request_token(request_token);
std::string policy_data_str;
ASSERT_TRUE(policy_data.SerializeToString(&policy_data_str));
policy_proto_.Clear();
policy_proto_.set_policy_data(policy_data_str);
policy_proto_.set_policy_data_signature(signature);
ASSERT_TRUE(policy_proto_.SerializeToString(&policy_str_));
}
void InitEmptyPolicy(const std::string& owner,
const std::string& signature,
const std::string& request_token) {
em::ChromeDeviceSettingsProto settings;
InitPolicy(settings, owner, signature, request_token);
}
void InitService(NssUtil* nss) {
key_ = new StrictMock<MockOwnerKey>;
store_ = new StrictMock<MockPolicyStore>;
mitigator_.reset(new MockMitigator);
scoped_refptr<base::MessageLoopProxy> message_loop(
base::MessageLoopProxy::CreateForCurrentThread());
service_ = new DevicePolicyService(store_, key_,
message_loop, message_loop,
nss,
mitigator_.get());
// Allow the key to be read any time.
EXPECT_CALL(*key_, public_key_der())
.WillRepeatedly(ReturnRef(fake_key_vector_));
}
void RecordNewPolicy(const em::PolicyFetchResponse& policy) {
new_policy_proto_.CopyFrom(policy);
}
// Checks that the recorded |new_policy_| has been modified accordingly from
// |policy_proto_| while logging in |owner_| as a device owner.
void CheckNewOwnerSettings(
const em::ChromeDeviceSettingsProto& old_settings) {
// Check PolicyFetchResponse wrapper.
ASSERT_EQ(new_fake_sig_, new_policy_proto_.policy_data_signature());
ASSERT_EQ(fake_key_, new_policy_proto_.new_public_key());
ASSERT_EQ(std::string(), new_policy_proto_.new_public_key_signature());
ASSERT_TRUE(new_policy_proto_.has_policy_data());
// Check signed policy data.
em::PolicyData policy_data;
ASSERT_TRUE(policy_data.ParseFromString(new_policy_proto_.policy_data()));
ASSERT_EQ(DevicePolicyService::kDevicePolicyType,
policy_data.policy_type());
ASSERT_FALSE(policy_data.has_request_token());
ASSERT_TRUE(policy_data.has_policy_value());
ASSERT_EQ(policy_data.username(), owner_);
// Check the device settings.
em::ChromeDeviceSettingsProto settings;
ASSERT_TRUE(settings.ParseFromString(policy_data.policy_value()));
ASSERT_TRUE(settings.has_user_whitelist());
const RepeatedPtrField<std::string>& old_whitelist(
old_settings.user_whitelist().user_whitelist());
const RepeatedPtrField<std::string>& whitelist(
settings.user_whitelist().user_whitelist());
ASSERT_LE(old_whitelist.size(), whitelist.size());
ASSERT_GE(old_whitelist.size() + 1, whitelist.size());
std::set<std::string> old_whitelist_set(old_whitelist.begin(),
old_whitelist.end());
old_whitelist_set.insert(owner_);
std::set<std::string> whitelist_set(whitelist.begin(),
whitelist.end());
ASSERT_EQ(old_whitelist_set.size(), whitelist_set.size());
ASSERT_TRUE(std::equal(whitelist_set.begin(), whitelist_set.end(),
old_whitelist_set.begin()));
ASSERT_TRUE(settings.has_allow_new_users());
// Make sure no other fields have been touched.
settings.clear_user_whitelist();
settings.clear_allow_new_users();
em::ChromeDeviceSettingsProto blank_settings;
ASSERT_EQ(settings.SerializeAsString(), blank_settings.SerializeAsString());
}
void ExpectMitigating(bool mitigating) {
EXPECT_CALL(*mitigator_, Mitigating())
.WillRepeatedly(Return(mitigating));
}
void ExpectGetPolicy(Sequence sequence,
const em::PolicyFetchResponse& policy) {
EXPECT_CALL(*store_, Get())
.InSequence(sequence)
.WillRepeatedly(ReturnRef(policy));
}
void ExpectInstallNewOwnerPolicy(Sequence sequence) {
Expectation get_policy =
EXPECT_CALL(*store_, Get())
.WillRepeatedly(ReturnRef(policy_proto_));
Expectation compare_keys =
EXPECT_CALL(*key_, Equals(_))
.WillRepeatedly(Return(false));
Expectation sign =
EXPECT_CALL(*key_, Sign(_, _, _))
.After(get_policy)
.WillOnce(DoAll(WithArg<2>(AssignVector(new_fake_sig_)),
Return(true)));
Expectation set_policy = EXPECT_CALL(*store_, Set(_))
.InSequence(sequence)
.After(sign)
.WillOnce(Invoke(this, &DevicePolicyServiceTest::RecordNewPolicy));
}
void ExpectPersistKeyAndPolicy() {
Mock::VerifyAndClearExpectations(key_);
Mock::VerifyAndClearExpectations(store_);
EXPECT_CALL(*key_, Persist())
.WillOnce(Return(true));
EXPECT_CALL(*store_, Persist())
.WillOnce(Return(true));
loop_.RunAllPending();
}
em::PolicyFetchResponse policy_proto_;
std::string policy_str_;
em::PolicyFetchResponse new_policy_proto_;
std::string owner_;
std::string fake_sig_;
std::string fake_key_;
std::vector<uint8> fake_key_vector_;
std::string new_fake_sig_;
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_;
scoped_ptr<MockMitigator> mitigator_;
scoped_refptr<DevicePolicyService> service_;
};
TEST_F(DevicePolicyServiceTest, CheckAndHandleOwnerLogin_SuccessEmptyPolicy) {
InitService(new KeyCheckUtil);
em::ChromeDeviceSettingsProto settings;
ASSERT_NO_FATAL_FAILURE(InitPolicy(settings, owner_, fake_sig_, ""));
Sequence s;
ExpectGetPolicy(s, policy_proto_);
ExpectInstallNewOwnerPolicy(s);
ExpectGetPolicy(s, new_policy_proto_);
EXPECT_CALL(*mitigator_, Mitigate(_))
.Times(0);
PolicyService::Error error;
bool is_owner = false;
EXPECT_TRUE(service_->CheckAndHandleOwnerLogin(owner_,
&is_owner,
&error));
EXPECT_TRUE(is_owner);
EXPECT_NO_FATAL_FAILURE(CheckNewOwnerSettings(settings));
}
TEST_F(DevicePolicyServiceTest, CheckAndHandleOwnerLogin_SuccessAddOwner) {
InitService(new KeyCheckUtil);
em::ChromeDeviceSettingsProto settings;
settings.mutable_user_whitelist()->add_user_whitelist("a@b");
settings.mutable_user_whitelist()->add_user_whitelist("c@d");
ASSERT_NO_FATAL_FAILURE(InitPolicy(settings, owner_, fake_sig_, ""));
Sequence s;
ExpectGetPolicy(s, policy_proto_);
ExpectInstallNewOwnerPolicy(s);
ExpectGetPolicy(s, new_policy_proto_);
EXPECT_CALL(*mitigator_, Mitigate(_))
.Times(0);
PolicyService::Error error;
bool is_owner = false;
EXPECT_TRUE(service_->CheckAndHandleOwnerLogin(owner_,
&is_owner,
&error));
EXPECT_TRUE(is_owner);
EXPECT_NO_FATAL_FAILURE(CheckNewOwnerSettings(settings));
}
TEST_F(DevicePolicyServiceTest, CheckAndHandleOwnerLogin_SuccessOwnerPresent) {
InitService(new KeyCheckUtil);
em::ChromeDeviceSettingsProto settings;
settings.mutable_user_whitelist()->add_user_whitelist("a@b");
settings.mutable_user_whitelist()->add_user_whitelist("c@d");
settings.mutable_user_whitelist()->add_user_whitelist(owner_);
settings.mutable_allow_new_users()->set_allow_new_users(true);
ASSERT_NO_FATAL_FAILURE(InitPolicy(settings, owner_, fake_sig_, ""));
Sequence s;
ExpectGetPolicy(s, policy_proto_);
ExpectInstallNewOwnerPolicy(s);
ExpectGetPolicy(s, new_policy_proto_);
EXPECT_CALL(*mitigator_, Mitigate(_))
.Times(0);
PolicyService::Error error;
bool is_owner = false;
EXPECT_TRUE(service_->CheckAndHandleOwnerLogin(owner_,
&is_owner,
&error));
EXPECT_TRUE(is_owner);
EXPECT_NO_FATAL_FAILURE(CheckNewOwnerSettings(settings));
}
TEST_F(DevicePolicyServiceTest, CheckAndHandleOwnerLogin_NotOwner) {
InitService(new KeyFailUtil);
ASSERT_NO_FATAL_FAILURE(InitEmptyPolicy(owner_, fake_sig_, ""));
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*mitigator_, Mitigate(_))
.Times(0);
PolicyService::Error error;
bool is_owner = true;
EXPECT_TRUE(service_->CheckAndHandleOwnerLogin("regular_user@somewhere",
&is_owner,
&error));
EXPECT_FALSE(is_owner);
}
TEST_F(DevicePolicyServiceTest, CheckAndHandleOwnerLogin_EnterpriseDevice) {
InitService(new KeyFailUtil);
ASSERT_NO_FATAL_FAILURE(InitEmptyPolicy(owner_, fake_sig_, "fake_token"));
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*mitigator_, Mitigate(_))
.Times(0);
PolicyService::Error error;
bool is_owner = true;
EXPECT_TRUE(service_->CheckAndHandleOwnerLogin(owner_,
&is_owner,
&error));
EXPECT_FALSE(is_owner);
}
TEST_F(DevicePolicyServiceTest, CheckAndHandleOwnerLogin_MissingKey) {
InitService(new KeyFailUtil);
ASSERT_NO_FATAL_FAILURE(InitEmptyPolicy(owner_, fake_sig_, ""));
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*mitigator_, Mitigate(_))
.InSequence(s)
.WillOnce(Return(true));
PolicyService::Error error;
bool is_owner = false;
EXPECT_TRUE(service_->CheckAndHandleOwnerLogin(owner_,
&is_owner,
&error));
EXPECT_TRUE(is_owner);
}
TEST_F(DevicePolicyServiceTest, CheckAndHandleOwnerLogin_MitigationFailure) {
InitService(new KeyFailUtil);
ASSERT_NO_FATAL_FAILURE(InitEmptyPolicy(owner_, fake_sig_, ""));
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*mitigator_, Mitigate(_))
.InSequence(s)
.WillOnce(Return(false));
PolicyService::Error error;
bool is_owner = false;
EXPECT_FALSE(service_->CheckAndHandleOwnerLogin(owner_,
&is_owner,
&error));
}
TEST_F(DevicePolicyServiceTest, ValidateAndStoreOwnerKey_SuccessNewKey) {
InitService(new KeyCheckUtil);
ExpectMitigating(false);
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*key_, PopulateFromBuffer(fake_key_vector_))
.InSequence(s)
.WillOnce(Return(true));
ExpectInstallNewOwnerPolicy(s);
service_->ValidateAndStoreOwnerKey(owner_, fake_key_);
ExpectPersistKeyAndPolicy();
}
TEST_F(DevicePolicyServiceTest, ValidateAndStoreOwnerKey_SuccessMitigating) {
InitService(new KeyCheckUtil);
ExpectMitigating(true);
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*key_, ClobberCompromisedKey(fake_key_vector_))
.InSequence(s)
.WillOnce(Return(true));
ExpectInstallNewOwnerPolicy(s);
service_->ValidateAndStoreOwnerKey(owner_, fake_key_);
ExpectPersistKeyAndPolicy();
}
TEST_F(DevicePolicyServiceTest, ValidateAndStoreOwnerKey_SuccessAddOwner) {
InitService(new KeyCheckUtil);
em::ChromeDeviceSettingsProto settings;
settings.mutable_user_whitelist()->add_user_whitelist("a@b");
settings.mutable_user_whitelist()->add_user_whitelist("c@d");
ASSERT_NO_FATAL_FAILURE(InitPolicy(settings, owner_, fake_sig_, ""));
ExpectMitigating(false);
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*key_, PopulateFromBuffer(fake_key_vector_))
.InSequence(s)
.WillOnce(Return(true));
ExpectInstallNewOwnerPolicy(s);
service_->ValidateAndStoreOwnerKey(owner_, fake_key_);
ExpectPersistKeyAndPolicy();
}
TEST_F(DevicePolicyServiceTest, ValidateAndStoreOwnerKey_NoPrivateKey) {
InitService(new KeyFailUtil);
service_->ValidateAndStoreOwnerKey(owner_, fake_key_);
}
TEST_F(DevicePolicyServiceTest, ValidateAndStoreOwnerKey_NewKeyInstallFails) {
InitService(new KeyCheckUtil);
ExpectMitigating(false);
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*key_, PopulateFromBuffer(fake_key_vector_))
.InSequence(s)
.WillOnce(Return(false));
service_->ValidateAndStoreOwnerKey(owner_, fake_key_);
}
TEST_F(DevicePolicyServiceTest, ValidateAndStoreOwnerKey_KeyClobberFails) {
InitService(new KeyCheckUtil);
ExpectMitigating(true);
Sequence s;
ExpectGetPolicy(s, policy_proto_);
EXPECT_CALL(*key_, ClobberCompromisedKey(fake_key_vector_))
.InSequence(s)
.WillOnce(Return(false));
service_->ValidateAndStoreOwnerKey(owner_, fake_key_);
}
TEST_F(DevicePolicyServiceTest, ValidateAndStoreOwnerKey_NssFailure) {
InitService(new SadNssUtil);
service_->ValidateAndStoreOwnerKey(owner_, fake_key_);
}
TEST_F(DevicePolicyServiceTest, KeyMissing_Present) {
InitService(new MockNssUtil);
EXPECT_CALL(*key_, HaveCheckedDisk())
.WillRepeatedly(Return(true));
EXPECT_CALL(*key_, IsPopulated())
.WillRepeatedly(Return(true));
EXPECT_FALSE(service_->KeyMissing());
}
TEST_F(DevicePolicyServiceTest, KeyMissing_NoDiskCheck) {
InitService(new MockNssUtil);
EXPECT_CALL(*key_, HaveCheckedDisk())
.WillRepeatedly(Return(false));
EXPECT_CALL(*key_, IsPopulated())
.WillRepeatedly(Return(false));
EXPECT_FALSE(service_->KeyMissing());
}
TEST_F(DevicePolicyServiceTest, KeyMissing_CheckedAndMissing) {
InitService(new MockNssUtil);
EXPECT_CALL(*key_, HaveCheckedDisk())
.WillRepeatedly(Return(true));
EXPECT_CALL(*key_, IsPopulated())
.WillRepeatedly(Return(false));
EXPECT_TRUE(service_->KeyMissing());
}
} // namespace login_manager