blob: 980399c3fa415495ffed927ac6a1c53c2cde4c2b [file] [log] [blame]
// Copyright (c) 2012 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/chromeos/settings/session_manager_operation.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
#include "chrome/browser/chromeos/settings/mock_owner_key_util.h"
#include "components/policy/core/common/cloud/cloud_policy_constants.h"
#include "components/policy/core/common/cloud/cloud_policy_validator.h"
#include "components/policy/core/common/cloud/policy_builder.h"
#include "content/public/test/test_browser_thread.h"
#include "crypto/rsa_private_key.h"
#include "policy/proto/device_management_backend.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace em = enterprise_management;
using testing::Mock;
using testing::_;
namespace chromeos {
class SessionManagerOperationTest : public testing::Test {
public:
SessionManagerOperationTest()
: ui_thread_(content::BrowserThread::UI, &message_loop_),
file_thread_(content::BrowserThread::FILE, &message_loop_),
owner_key_util_(new MockOwnerKeyUtil()),
validated_(false) {}
virtual void SetUp() OVERRIDE {
policy_.payload().mutable_pinned_apps()->add_app_id("fake-app");
policy_.Build();
}
MOCK_METHOD2(OnOperationCompleted,
void(SessionManagerOperation*, DeviceSettingsService::Status));
void CheckSuccessfulValidation(
policy::DeviceCloudPolicyValidator* validator) {
EXPECT_TRUE(validator->success());
EXPECT_TRUE(validator->payload().get());
EXPECT_EQ(validator->payload()->SerializeAsString(),
policy_.payload().SerializeAsString());
validated_ = true;
}
void CheckPublicKeyLoaded(SessionManagerOperation* op) {
ASSERT_TRUE(op->owner_key().get());
ASSERT_TRUE(op->owner_key()->public_key());
std::vector<uint8> public_key;
ASSERT_TRUE(policy_.GetSigningKey()->ExportPublicKey(&public_key));
EXPECT_EQ(public_key, *op->owner_key()->public_key());
}
void CheckPrivateKeyLoaded(SessionManagerOperation* op) {
ASSERT_TRUE(op->owner_key().get());
ASSERT_TRUE(op->owner_key()->private_key());
std::vector<uint8> expected_key;
ASSERT_TRUE(policy_.GetSigningKey()->ExportPrivateKey(&expected_key));
std::vector<uint8> actual_key;
ASSERT_TRUE(op->owner_key()->private_key()->ExportPrivateKey(&actual_key));
EXPECT_EQ(expected_key, actual_key);
}
protected:
base::MessageLoop message_loop_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread file_thread_;
policy::DevicePolicyBuilder policy_;
DeviceSettingsTestHelper device_settings_test_helper_;
scoped_refptr<MockOwnerKeyUtil> owner_key_util_;
bool validated_;
private:
DISALLOW_COPY_AND_ASSIGN(SessionManagerOperationTest);
};
TEST_F(SessionManagerOperationTest, LoadNoPolicyNoKey) {
LoadSettingsOperation op(
base::Bind(&SessionManagerOperationTest::OnOperationCompleted,
base::Unretained(this)));
EXPECT_CALL(*this,
OnOperationCompleted(
&op, DeviceSettingsService::STORE_KEY_UNAVAILABLE));
op.Start(&device_settings_test_helper_, owner_key_util_, NULL);
device_settings_test_helper_.Flush();
Mock::VerifyAndClearExpectations(this);
EXPECT_FALSE(op.policy_data().get());
EXPECT_FALSE(op.device_settings().get());
ASSERT_TRUE(op.owner_key().get());
EXPECT_FALSE(op.owner_key()->public_key());
EXPECT_FALSE(op.owner_key()->private_key());
}
TEST_F(SessionManagerOperationTest, LoadOwnerKey) {
owner_key_util_->SetPublicKeyFromPrivateKey(*policy_.GetSigningKey());
LoadSettingsOperation op(
base::Bind(&SessionManagerOperationTest::OnOperationCompleted,
base::Unretained(this)));
EXPECT_CALL(*this,
OnOperationCompleted(
&op, DeviceSettingsService::STORE_NO_POLICY));
op.Start(&device_settings_test_helper_, owner_key_util_, NULL);
device_settings_test_helper_.Flush();
Mock::VerifyAndClearExpectations(this);
CheckPublicKeyLoaded(&op);
}
TEST_F(SessionManagerOperationTest, LoadPolicy) {
owner_key_util_->SetPublicKeyFromPrivateKey(*policy_.GetSigningKey());
device_settings_test_helper_.set_policy_blob(policy_.GetBlob());
LoadSettingsOperation op(
base::Bind(&SessionManagerOperationTest::OnOperationCompleted,
base::Unretained(this)));
EXPECT_CALL(*this,
OnOperationCompleted(
&op, DeviceSettingsService::STORE_SUCCESS));
op.Start(&device_settings_test_helper_, owner_key_util_, NULL);
device_settings_test_helper_.Flush();
Mock::VerifyAndClearExpectations(this);
ASSERT_TRUE(op.policy_data().get());
EXPECT_EQ(policy_.policy_data().SerializeAsString(),
op.policy_data()->SerializeAsString());
ASSERT_TRUE(op.device_settings().get());
EXPECT_EQ(policy_.payload().SerializeAsString(),
op.device_settings()->SerializeAsString());
}
TEST_F(SessionManagerOperationTest, LoadPrivateOwnerKey) {
owner_key_util_->SetPrivateKey(policy_.GetSigningKey());
LoadSettingsOperation op(
base::Bind(&SessionManagerOperationTest::OnOperationCompleted,
base::Unretained(this)));
EXPECT_CALL(*this,
OnOperationCompleted(
&op, DeviceSettingsService::STORE_NO_POLICY));
op.Start(&device_settings_test_helper_, owner_key_util_, NULL);
device_settings_test_helper_.Flush();
Mock::VerifyAndClearExpectations(this);
CheckPublicKeyLoaded(&op);
CheckPrivateKeyLoaded(&op);
}
TEST_F(SessionManagerOperationTest, RestartLoad) {
owner_key_util_->SetPrivateKey(policy_.GetSigningKey());
device_settings_test_helper_.set_policy_blob(policy_.GetBlob());
LoadSettingsOperation op(
base::Bind(&SessionManagerOperationTest::OnOperationCompleted,
base::Unretained(this)));
EXPECT_CALL(*this, OnOperationCompleted(&op, _)).Times(0);
op.Start(&device_settings_test_helper_, owner_key_util_, NULL);
device_settings_test_helper_.FlushLoops();
device_settings_test_helper_.FlushRetrieve();
EXPECT_TRUE(op.owner_key().get());
EXPECT_TRUE(op.owner_key()->public_key());
Mock::VerifyAndClearExpectations(this);
// Now install a different key and policy and restart the operation.
policy_.SetSigningKey(*policy::PolicyBuilder::CreateTestOtherSigningKey());
policy_.payload().mutable_metrics_enabled()->set_metrics_enabled(true);
policy_.Build();
device_settings_test_helper_.set_policy_blob(policy_.GetBlob());
owner_key_util_->SetPrivateKey(policy_.GetSigningKey());
EXPECT_CALL(*this,
OnOperationCompleted(
&op, DeviceSettingsService::STORE_SUCCESS));
op.RestartLoad(true);
device_settings_test_helper_.Flush();
Mock::VerifyAndClearExpectations(this);
// Check that the new keys have been loaded.
CheckPublicKeyLoaded(&op);
CheckPrivateKeyLoaded(&op);
// Verify the new policy.
ASSERT_TRUE(op.policy_data().get());
EXPECT_EQ(policy_.policy_data().SerializeAsString(),
op.policy_data()->SerializeAsString());
ASSERT_TRUE(op.device_settings().get());
EXPECT_EQ(policy_.payload().SerializeAsString(),
op.device_settings()->SerializeAsString());
}
TEST_F(SessionManagerOperationTest, StoreSettings) {
owner_key_util_->SetPublicKeyFromPrivateKey(*policy_.GetSigningKey());
StoreSettingsOperation op(
base::Bind(&SessionManagerOperationTest::OnOperationCompleted,
base::Unretained(this)),
policy_.GetCopy());
EXPECT_CALL(*this,
OnOperationCompleted(
&op, DeviceSettingsService::STORE_SUCCESS));
op.Start(&device_settings_test_helper_, owner_key_util_, NULL);
device_settings_test_helper_.Flush();
Mock::VerifyAndClearExpectations(this);
EXPECT_EQ(device_settings_test_helper_.policy_blob(),
policy_.GetBlob());
ASSERT_TRUE(op.policy_data().get());
EXPECT_EQ(policy_.policy_data().SerializeAsString(),
op.policy_data()->SerializeAsString());
ASSERT_TRUE(op.device_settings().get());
EXPECT_EQ(policy_.payload().SerializeAsString(),
op.device_settings()->SerializeAsString());
}
TEST_F(SessionManagerOperationTest, SignAndStoreSettings) {
base::Time before(base::Time::NowFromSystemTime());
owner_key_util_->SetPrivateKey(policy_.GetSigningKey());
SignAndStoreSettingsOperation op(
base::Bind(&SessionManagerOperationTest::OnOperationCompleted,
base::Unretained(this)),
scoped_ptr<em::ChromeDeviceSettingsProto>(
new em::ChromeDeviceSettingsProto(policy_.payload())),
policy_.policy_data().username());
EXPECT_CALL(*this,
OnOperationCompleted(
&op, DeviceSettingsService::STORE_SUCCESS));
op.Start(&device_settings_test_helper_, owner_key_util_, NULL);
device_settings_test_helper_.Flush();
Mock::VerifyAndClearExpectations(this);
base::Time after(base::Time::NowFromSystemTime());
// The blob should validate.
scoped_ptr<em::PolicyFetchResponse> policy_response(
new em::PolicyFetchResponse());
ASSERT_TRUE(
policy_response->ParseFromString(
device_settings_test_helper_.policy_blob()));
policy::DeviceCloudPolicyValidator* validator =
policy::DeviceCloudPolicyValidator::Create(
policy_response.Pass(), message_loop_.message_loop_proxy());
validator->ValidateUsername(policy_.policy_data().username());
validator->ValidateTimestamp(
before,
after,
policy::CloudPolicyValidatorBase::TIMESTAMP_REQUIRED);
validator->ValidatePolicyType(policy::dm_protocol::kChromeDevicePolicyType);
validator->ValidatePayload();
std::vector<uint8> public_key;
policy_.GetSigningKey()->ExportPublicKey(&public_key);
validator->ValidateSignature(public_key, false);
validator->StartValidation(
base::Bind(&SessionManagerOperationTest::CheckSuccessfulValidation,
base::Unretained(this)));
message_loop_.RunUntilIdle();
EXPECT_TRUE(validated_);
// Check that the loaded policy_data contains the expected values.
EXPECT_EQ(policy::dm_protocol::kChromeDevicePolicyType,
op.policy_data()->policy_type());
EXPECT_LE((before - base::Time::UnixEpoch()).InMilliseconds(),
op.policy_data()->timestamp());
EXPECT_GE((after - base::Time::UnixEpoch()).InMilliseconds(),
op.policy_data()->timestamp());
EXPECT_FALSE(op.policy_data()->has_request_token());
EXPECT_EQ(policy_.policy_data().username(), op.policy_data()->username());
// Loaded device settings should match what the operation received.
ASSERT_TRUE(op.device_settings().get());
EXPECT_EQ(policy_.payload().SerializeAsString(),
op.device_settings()->SerializeAsString());
}
} // namespace chromeos