user_cloud_policy_store_chromeos_unittest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/chromeos/policy/user_cloud_policy_store_chromeos.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
75c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include <vector>
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
95c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/basictypes.h"
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/bind.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/file_util.h"
125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/files/scoped_temp_dir.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu#include "base/message_loop.h"
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/threading/sequenced_worker_pool.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/policy/cloud/policy_builder.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chrome/browser/policy/proto/cloud/device_management_local.pb.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chromeos/dbus/mock_cryptohome_client.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "chromeos/dbus/mock_session_manager_client.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "content/public/test/test_browser_thread.h"
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "policy/policy_constants.h"
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "policy/proto/cloud_policy.pb.h"
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gmock/include/gmock/gmock.h"
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace em = enterprise_management;
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)using testing::AllOf;
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)using testing::AnyNumber;
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing testing::Eq;
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing testing::Mock;
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing testing::Property;
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing testing::SaveArg;
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuusing testing::_;
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace policy {
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liunamespace {
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kLegacyDeviceId[] = "legacy-device-id";
435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kLegacyToken[] = "legacy-token";
445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kSanitizedUsername[] = "0123456789ABCDEF0123456789ABCDEF012345678";
455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuconst char kDefaultHomepage[] = "http://chromium.org";
465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuACTION_P2(SendSanitizedUsername, call_status, sanitized_username) {
485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  MessageLoop::current()->PostTask(
495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      FROM_HERE, base::Bind(arg1, call_status, sanitized_username));
505c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
515c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
525c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass UserCloudPolicyStoreChromeOSTest : public testing::Test {
535c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu protected:
545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  UserCloudPolicyStoreChromeOSTest()
555c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : loop_(MessageLoop::TYPE_UI),
565c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        ui_thread_(content::BrowserThread::UI, &loop_),
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        file_thread_(content::BrowserThread::FILE, &loop_) {}
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void SetUp() OVERRIDE {
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(cryptohome_client_,
615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                GetSanitizedUsername(PolicyBuilder::kFakeUsername, _))
625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        .Times(AnyNumber())
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        .WillRepeatedly(
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            SendSanitizedUsername(chromeos::DBUS_METHOD_CALL_SUCCESS,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  kSanitizedUsername));
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    store_.reset(new UserCloudPolicyStoreChromeOS(&cryptohome_client_,
690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                  &session_manager_client_,
700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                  PolicyBuilder::kFakeUsername,
710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                  user_policy_dir(),
720529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                  token_file(),
730529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                  policy_file()));
740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    store_->AddObserver(&observer_);
750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
760529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Install the initial public key, so that by default the validation of
770529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // the stored/loaded policy blob succeeds.
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    std::vector<uint8> public_key;
795c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    ASSERT_TRUE(policy_.signing_key()->ExportPublicKey(&public_key));
805c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    StoreUserPolicyKey(public_key);
815c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
825c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    policy_.payload().mutable_homepagelocation()->set_value(kDefaultHomepage);
835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    policy_.Build();
845c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
855c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
865c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void TearDown() OVERRIDE {
87010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    store_->RemoveObserver(&observer_);
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    store_.reset();
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RunUntilIdle();
90010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Install an expectation on |observer_| for an error code.
93010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void ExpectError(CloudPolicyStore::Status error) {
94010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_CALL(observer_,
95010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                OnStoreError(AllOf(Eq(store_.get()),
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                   Property(&CloudPolicyStore::status,
97010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                            Eq(error)))));
98010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
99010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
100010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Triggers a store_->Load() operation, handles the expected call to
101010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // |session_manager_client_| and sends |response|.
102010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void PerformPolicyLoad(const std::string& response) {
103010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Issue a load command.
104010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    chromeos::SessionManagerClient::RetrievePolicyCallback retrieve_callback;
105010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_CALL(session_manager_client_, RetrieveUserPolicy(_))
106010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        .WillOnce(SaveArg<0>(&retrieve_callback));
107010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    store_->Load();
108010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RunUntilIdle();
109010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    Mock::VerifyAndClearExpectations(&session_manager_client_);
110010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    ASSERT_FALSE(retrieve_callback.is_null());
111010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
112010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Run the callback.
113010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    retrieve_callback.Run(response);
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RunUntilIdle();
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Verifies that store_->policy_map() has the HomepageLocation entry with
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // the |expected_value|.
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void VerifyPolicyMap(const char* expected_value) {
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(1U, store_->policy_map().size());
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const PolicyMap::Entry* entry =
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        store_->policy_map().Get(key::kHomepageLocation);
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(entry);
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    EXPECT_TRUE(base::StringValue(expected_value).Equals(entry->value));
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
127010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void StoreUserPolicyKey(const std::vector<uint8>& public_key) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(file_util::CreateDirectory(user_policy_key_file().DirName()));
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ASSERT_TRUE(
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        file_util::WriteFile(user_policy_key_file(),
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             reinterpret_cast<const char*>(public_key.data()),
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                             public_key.size()));
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Stores the current |policy_| and verifies that it is published.
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If |new_public_key| is set then it will be persisted after storing but
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // before loading the policy, so that the signature validation can succeed.
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // If |previous_value| is set then a previously existing policy with that
139010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // value will be expected; otherwise no previous policy is expected.
140010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // If |new_value| is set then a new policy with that value is expected after
141010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // storing the |policy_| blob.
142010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  void PerformStorePolicy(const std::vector<uint8>* new_public_key,
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const char* previous_value,
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                          const char* new_value) {
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    chromeos::SessionManagerClient::StorePolicyCallback store_callback;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _))
1470529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        .WillOnce(SaveArg<1>(&store_callback));
1480529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    store_->Store(policy_.policy());
1490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    RunUntilIdle();
1500529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    Mock::VerifyAndClearExpectations(&session_manager_client_);
1510529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    ASSERT_FALSE(store_callback.is_null());
1520529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1530529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // The new policy shouldn't be present yet.
1540529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    PolicyMap previous_policy;
1550529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    EXPECT_EQ(previous_value != NULL, store_->policy() != NULL);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (previous_value) {
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      previous_policy.Set(key::kHomepageLocation,
1580529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          POLICY_LEVEL_MANDATORY,
1590529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          POLICY_SCOPE_USER,
1600529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                          base::Value::CreateStringValue(previous_value));
1610529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1620529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    EXPECT_TRUE(previous_policy.Equals(store_->policy_map()));
1630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
1640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Store the new public key so that the validation after the retrieve
1660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // operation completes can verify the signature.
1670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    if (new_public_key)
1680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      StoreUserPolicyKey(*new_public_key);
1690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
1700529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    // Let the store operation complete.
1710529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    chromeos::SessionManagerClient::RetrievePolicyCallback retrieve_callback;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_CALL(session_manager_client_, RetrieveUserPolicy(_))
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        .WillOnce(SaveArg<0>(&retrieve_callback));
1740529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    store_callback.Run(true);
1750529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    RunUntilIdle();
176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_TRUE(previous_policy.Equals(store_->policy_map()));
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    Mock::VerifyAndClearExpectations(&session_manager_client_);
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ASSERT_FALSE(retrieve_callback.is_null());
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Finish the retrieve callback.
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_CALL(observer_, OnStoreLoaded(store_.get()));
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    retrieve_callback.Run(policy_.GetBlob());
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    RunUntilIdle();
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    ASSERT_TRUE(store_->policy());
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(policy_.policy_data().SerializeAsString(),
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              store_->policy()->SerializeAsString());
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    VerifyPolicyMap(new_value);
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void VerifyStoreHasValidationError() {
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_FALSE(store_->policy());
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_TRUE(store_->policy_map().empty());
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(CloudPolicyStore::STATUS_VALIDATION_ERROR, store_->status());
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RunUntilIdle() {
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    loop_.RunUntilIdle();
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    content::BrowserThread::GetBlockingPool()->FlushForTesting();
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    loop_.RunUntilIdle();
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::FilePath user_policy_dir() {
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return tmp_dir_.path().AppendASCII("var_run_user_policy");
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  base::FilePath user_policy_key_file() {
2095c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return user_policy_dir().AppendASCII(kSanitizedUsername)
2105c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                            .AppendASCII("policy.pub");
2115c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2125c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2135c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::FilePath token_file() {
2145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return tmp_dir_.path().AppendASCII("token");
2155c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2165c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2175c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::FilePath policy_file() {
2185c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    return tmp_dir_.path().AppendASCII("policy");
2195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
2205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  MessageLoop loop_;
2225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  chromeos::MockCryptohomeClient cryptohome_client_;
2235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  chromeos::MockSessionManagerClient session_manager_client_;
2245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  UserPolicyBuilder policy_;
2255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  MockCloudPolicyStoreObserver observer_;
2265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  scoped_ptr<UserCloudPolicyStoreChromeOS> store_;
2275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
2295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  content::TestBrowserThread ui_thread_;
2305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  content::TestBrowserThread file_thread_;
2315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  base::ScopedTempDir tmp_dir_;
2325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreChromeOSTest);
2345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
2355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(UserCloudPolicyStoreChromeOSTest, InitialStore) {
2375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Start without any public key to trigger the initial key checks.
2385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false));
2395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  // Make the policy blob contain a new public key.
2405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey());
2415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  policy_.Build();
2425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  std::vector<uint8> new_public_key;
2435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_TRUE(policy_.new_signing_key()->ExportPublicKey(&new_public_key));
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_NO_FATAL_FAILURE(
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      PerformStorePolicy(&new_public_key, NULL, kDefaultHomepage));
2465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
2475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
2485c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithExistingKey) {
2495c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ASSERT_NO_FATAL_FAILURE(
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      PerformStorePolicy(NULL, NULL, kDefaultHomepage));
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithRotation) {
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make the policy blob contain a new public key.
255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey());
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  policy_.Build();
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<uint8> new_public_key;
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(policy_.new_signing_key()->ExportPublicKey(&new_public_key));
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      PerformStorePolicy(&new_public_key, NULL, kDefaultHomepage));
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(UserCloudPolicyStoreChromeOSTest, StoreFail) {
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Store policy.
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  chromeos::SessionManagerClient::StorePolicyCallback store_callback;
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _))
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      .WillOnce(SaveArg<1>(&store_callback));
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  store_->Store(policy_.policy());
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  Mock::VerifyAndClearExpectations(&session_manager_client_);
271  ASSERT_FALSE(store_callback.is_null());
272
273  // Let the store operation complete.
274  ExpectError(CloudPolicyStore::STATUS_STORE_ERROR);
275  store_callback.Run(false);
276  RunUntilIdle();
277  EXPECT_FALSE(store_->policy());
278  EXPECT_TRUE(store_->policy_map().empty());
279  EXPECT_EQ(CloudPolicyStore::STATUS_STORE_ERROR, store_->status());
280}
281
282TEST_F(UserCloudPolicyStoreChromeOSTest, StoreValidationError) {
283  policy_.policy_data().clear_policy_type();
284  policy_.Build();
285
286  // Store policy.
287  chromeos::SessionManagerClient::StorePolicyCallback store_callback;
288  ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR);
289  EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _))
290      .Times(0);
291  store_->Store(policy_.policy());
292  RunUntilIdle();
293  Mock::VerifyAndClearExpectations(&session_manager_client_);
294}
295
296TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithoutPolicyKey) {
297  // Make the dbus call to cryptohome fail.
298  Mock::VerifyAndClearExpectations(&cryptohome_client_);
299  EXPECT_CALL(cryptohome_client_,
300              GetSanitizedUsername(PolicyBuilder::kFakeUsername, _))
301      .Times(AnyNumber())
302      .WillRepeatedly(SendSanitizedUsername(chromeos::DBUS_METHOD_CALL_FAILURE,
303                                            std::string()));
304
305  // Store policy.
306  chromeos::SessionManagerClient::StorePolicyCallback store_callback;
307  ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR);
308  EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _))
309      .Times(0);
310  store_->Store(policy_.policy());
311  RunUntilIdle();
312  Mock::VerifyAndClearExpectations(&session_manager_client_);
313}
314
315TEST_F(UserCloudPolicyStoreChromeOSTest, StoreWithInvalidSignature) {
316  // Break the signature.
317  policy_.policy().mutable_policy_data_signature()->append("garbage");
318
319  // Store policy.
320  chromeos::SessionManagerClient::StorePolicyCallback store_callback;
321  ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR);
322  EXPECT_CALL(session_manager_client_, StoreUserPolicy(policy_.GetBlob(), _))
323      .Times(0);
324  store_->Store(policy_.policy());
325  RunUntilIdle();
326  Mock::VerifyAndClearExpectations(&session_manager_client_);
327}
328
329TEST_F(UserCloudPolicyStoreChromeOSTest, Load) {
330  EXPECT_CALL(observer_, OnStoreLoaded(store_.get()));
331  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob()));
332  Mock::VerifyAndClearExpectations(&observer_);
333
334  // Verify that the policy has been loaded.
335  ASSERT_TRUE(store_->policy());
336  EXPECT_EQ(policy_.policy_data().SerializeAsString(),
337            store_->policy()->SerializeAsString());
338  VerifyPolicyMap(kDefaultHomepage);
339  EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
340}
341
342TEST_F(UserCloudPolicyStoreChromeOSTest, LoadNoPolicy) {
343  EXPECT_CALL(observer_, OnStoreLoaded(store_.get()));
344  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(""));
345  Mock::VerifyAndClearExpectations(&observer_);
346
347  // Verify no policy has been installed.
348  EXPECT_FALSE(store_->policy());
349  EXPECT_TRUE(store_->policy_map().empty());
350  EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
351}
352
353TEST_F(UserCloudPolicyStoreChromeOSTest, LoadInvalidPolicy) {
354  ExpectError(CloudPolicyStore::STATUS_PARSE_ERROR);
355  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad("invalid"));
356
357  // Verify no policy has been installed.
358  EXPECT_FALSE(store_->policy());
359  EXPECT_TRUE(store_->policy_map().empty());
360  EXPECT_EQ(CloudPolicyStore::STATUS_PARSE_ERROR, store_->status());
361}
362
363TEST_F(UserCloudPolicyStoreChromeOSTest, LoadValidationError) {
364  policy_.policy_data().clear_policy_type();
365  policy_.Build();
366
367  ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR);
368  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob()));
369  VerifyStoreHasValidationError();
370}
371
372TEST_F(UserCloudPolicyStoreChromeOSTest, LoadNoKey) {
373  // The loaded policy can't be verified without the public key.
374  ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false));
375  ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR);
376  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob()));
377  VerifyStoreHasValidationError();
378}
379
380TEST_F(UserCloudPolicyStoreChromeOSTest, LoadInvalidSignature) {
381  // Break the signature.
382  policy_.policy().mutable_policy_data_signature()->append("garbage");
383  ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR);
384  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(policy_.GetBlob()));
385  VerifyStoreHasValidationError();
386}
387
388TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationFull) {
389  std::string data;
390
391  em::DeviceCredentials credentials;
392  credentials.set_device_token(kLegacyToken);
393  credentials.set_device_id(kLegacyDeviceId);
394  ASSERT_TRUE(credentials.SerializeToString(&data));
395  ASSERT_NE(-1, file_util::WriteFile(token_file(), data.c_str(), data.size()));
396
397  em::CachedCloudPolicyResponse cached_policy;
398  cached_policy.mutable_cloud_policy()->CopyFrom(policy_.policy());
399  ASSERT_TRUE(cached_policy.SerializeToString(&data));
400  ASSERT_NE(-1, file_util::WriteFile(policy_file(), data.c_str(), data.size()));
401
402  EXPECT_CALL(observer_, OnStoreLoaded(store_.get()));
403  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(""));
404  Mock::VerifyAndClearExpectations(&observer_);
405
406  // Verify that legacy user policy and token have been loaded.
407  em::PolicyData expected_policy_data;
408  EXPECT_TRUE(expected_policy_data.ParseFromString(
409                  cached_policy.cloud_policy().policy_data()));
410  expected_policy_data.clear_public_key_version();
411  expected_policy_data.set_request_token(kLegacyToken);
412  expected_policy_data.set_device_id(kLegacyDeviceId);
413  ASSERT_TRUE(store_->policy());
414  EXPECT_EQ(expected_policy_data.SerializeAsString(),
415            store_->policy()->SerializeAsString());
416  VerifyPolicyMap(kDefaultHomepage);
417  EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
418}
419
420TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationNoToken) {
421  std::string data;
422  testing::Sequence seq;
423
424  em::CachedCloudPolicyResponse cached_policy;
425  cached_policy.mutable_cloud_policy()->CopyFrom(policy_.policy());
426  ASSERT_TRUE(cached_policy.SerializeToString(&data));
427  ASSERT_NE(-1, file_util::WriteFile(policy_file(), data.c_str(), data.size()));
428
429  EXPECT_CALL(observer_, OnStoreLoaded(store_.get()));
430  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(""));
431  Mock::VerifyAndClearExpectations(&observer_);
432
433  // Verify the legacy cache has been loaded.
434  em::PolicyData expected_policy_data;
435  EXPECT_TRUE(expected_policy_data.ParseFromString(
436                  cached_policy.cloud_policy().policy_data()));
437  expected_policy_data.clear_public_key_version();
438  ASSERT_TRUE(store_->policy());
439  EXPECT_EQ(expected_policy_data.SerializeAsString(),
440            store_->policy()->SerializeAsString());
441  VerifyPolicyMap(kDefaultHomepage);
442  EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
443}
444
445TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationNoPolicy) {
446  std::string data;
447
448  em::DeviceCredentials credentials;
449  credentials.set_device_token(kLegacyToken);
450  credentials.set_device_id(kLegacyDeviceId);
451  ASSERT_TRUE(credentials.SerializeToString(&data));
452  ASSERT_NE(-1, file_util::WriteFile(token_file(), data.c_str(), data.size()));
453
454  EXPECT_CALL(observer_, OnStoreLoaded(store_.get()));
455  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(""));
456  Mock::VerifyAndClearExpectations(&observer_);
457
458  // Verify that legacy user policy and token have been loaded.
459  em::PolicyData expected_policy_data;
460  expected_policy_data.set_request_token(kLegacyToken);
461  expected_policy_data.set_device_id(kLegacyDeviceId);
462  ASSERT_TRUE(store_->policy());
463  EXPECT_EQ(expected_policy_data.SerializeAsString(),
464            store_->policy()->SerializeAsString());
465  EXPECT_TRUE(store_->policy_map().empty());
466  EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
467}
468
469TEST_F(UserCloudPolicyStoreChromeOSTest, MigrationAndStoreNew) {
470  // Start without an existing public key.
471  ASSERT_TRUE(file_util::Delete(user_policy_key_file(), false));
472
473  std::string data;
474  em::CachedCloudPolicyResponse cached_policy;
475  cached_policy.mutable_cloud_policy()->CopyFrom(policy_.policy());
476  ASSERT_TRUE(cached_policy.SerializeToString(&data));
477  ASSERT_NE(-1, file_util::WriteFile(policy_file(), data.c_str(), data.size()));
478
479  EXPECT_CALL(observer_, OnStoreLoaded(store_.get()));
480  ASSERT_NO_FATAL_FAILURE(PerformPolicyLoad(""));
481  Mock::VerifyAndClearExpectations(&observer_);
482
483  // Verify the legacy cache has been loaded.
484  em::PolicyData expected_policy_data;
485  EXPECT_TRUE(expected_policy_data.ParseFromString(
486                  cached_policy.cloud_policy().policy_data()));
487  expected_policy_data.clear_public_key_version();
488  ASSERT_TRUE(store_->policy());
489  EXPECT_EQ(expected_policy_data.SerializeAsString(),
490            store_->policy()->SerializeAsString());
491  VerifyPolicyMap(kDefaultHomepage);
492  EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status());
493  EXPECT_TRUE(file_util::PathExists(policy_file()));
494
495  // Now store a new policy using the new homepage location.
496  const char kNewHomepage[] = "http://google.com";
497  policy_.payload().mutable_homepagelocation()->set_value(kNewHomepage);
498  policy_.set_new_signing_key(PolicyBuilder::CreateTestNewSigningKey());
499  policy_.Build();
500  std::vector<uint8> new_public_key;
501  ASSERT_TRUE(policy_.new_signing_key()->ExportPublicKey(&new_public_key));
502  ASSERT_NO_FATAL_FAILURE(
503      PerformStorePolicy(&new_public_key, kDefaultHomepage, kNewHomepage));
504  VerifyPolicyMap(kNewHomepage);
505
506  // Verify that the legacy cache has been removed.
507  EXPECT_FALSE(file_util::PathExists(policy_file()));
508}
509
510}  // namespace
511
512}  // namespace policy
513