1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/platform_keys/key_permissions/key_permissions_service_impl.h"
6
7 #include <memory>
8
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/test/gmock_callback_support.h"
12 #include "chrome/browser/chromeos/platform_keys/key_permissions/mock_key_permissions_manager.h"
13 #include "chrome/browser/chromeos/platform_keys/mock_platform_keys_service.h"
14 #include "chrome/browser/chromeos/platform_keys/platform_keys_service.h"
15 #include "chrome/browser/extensions/test_extension_system.h"
16 #include "chrome/test/base/testing_profile.h"
17 #include "components/policy/core/common/mock_policy_service.h"
18 #include "components/prefs/pref_service.h"
19 #include "content/public/test/browser_task_environment.h"
20 #include "extensions/browser/state_store.h"
21 #include "testing/gmock/include/gmock/gmock.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 using ::testing::_;
25
26 namespace chromeos {
27 namespace platform_keys {
28 namespace {
29
30 // A helper that waits until execution of an asynchronous KeyPermissionsService
31 // operation has finished and provides access to the results.
32 template <typename... ResultCallbackArgs>
33 class ExecutionWaiter {
34 public:
35 ExecutionWaiter() = default;
36 ~ExecutionWaiter() = default;
37 ExecutionWaiter(const ExecutionWaiter& other) = delete;
38 ExecutionWaiter& operator=(const ExecutionWaiter& other) = delete;
39
40 // Returns the callback to be passed to the KeyPermissionsService operation
41 // invocation.
42 base::OnceCallback<void(ResultCallbackArgs... result_callback_args)>
GetCallback()43 GetCallback() {
44 return base::BindOnce(&ExecutionWaiter::OnExecutionDone,
45 weak_ptr_factory_.GetWeakPtr());
46 }
47
48 // Waits until the callback returned by GetCallback() has been called.
Wait()49 void Wait() { run_loop_.Run(); }
50
51 protected:
52 // A std::tuple that is capable of storing the arguments passed to the result
53 // callback.
54 using ResultCallbackArgsTuple =
55 std::tuple<std::decay_t<ResultCallbackArgs>...>;
56
57 // Access to the arguments passed to the callback.
result_callback_args() const58 const ResultCallbackArgsTuple& result_callback_args() const {
59 EXPECT_TRUE(done_);
60 return result_callback_args_;
61 }
62
63 private:
OnExecutionDone(ResultCallbackArgs...result_callback_args)64 void OnExecutionDone(ResultCallbackArgs... result_callback_args) {
65 EXPECT_FALSE(done_);
66 done_ = true;
67 result_callback_args_ = ResultCallbackArgsTuple(
68 std::forward<ResultCallbackArgs>(result_callback_args)...);
69 run_loop_.Quit();
70 }
71
72 base::RunLoop run_loop_;
73 bool done_ = false;
74 ResultCallbackArgsTuple result_callback_args_;
75
76 base::WeakPtrFactory<ExecutionWaiter> weak_ptr_factory_{this};
77 };
78
79 // Supports waiting for the result of KeyPermissionsService::IsCorporateKey.
80 class IsCorporateKeyExecutionWaiter : public ExecutionWaiter<bool> {
81 public:
82 IsCorporateKeyExecutionWaiter() = default;
83 ~IsCorporateKeyExecutionWaiter() = default;
84
corporate() const85 bool corporate() const { return std::get<0>(result_callback_args()); }
86 };
87
88 // Supports waiting for the result of KeyPermissionsService::SetCorporateKey.
89 class SetCorporateKeyExecutionWaiter : public ExecutionWaiter<Status> {
90 public:
91 SetCorporateKeyExecutionWaiter() = default;
92 ~SetCorporateKeyExecutionWaiter() = default;
93
status() const94 Status status() const { return std::get<0>(result_callback_args()); }
95 };
96
97 } // namespace
98
99 class KeyPermissionsServiceImplTest : public ::testing::Test {
100 public:
101 KeyPermissionsServiceImplTest() = default;
102 KeyPermissionsServiceImplTest(const KeyPermissionsServiceImplTest&) = delete;
103 KeyPermissionsServiceImplTest& operator=(
104 const KeyPermissionsServiceImplTest&) = delete;
105 ~KeyPermissionsServiceImplTest() override = default;
106
SetUp()107 void SetUp() override {
108 auto mock_policy_service = std::make_unique<policy::MockPolicyService>();
109 policy_service_ = mock_policy_service.get();
110 TestingProfile::Builder builder;
111 builder.SetPolicyService(std::move(mock_policy_service));
112 profile_ = builder.Build();
113
114 extensions::TestExtensionSystem* extension_system =
115 static_cast<extensions::TestExtensionSystem*>(
116 extensions::ExtensionSystem::Get(profile_.get()));
117 extension_system->CreateExtensionService(
118 base::CommandLine::ForCurrentProcess(),
119 /*install_directory=*/base::FilePath(),
120 /*autoupdate_enabled=*/false);
121 extensions_state_store_ = extension_system->state_store();
122
123 platform_keys_service_ = std::make_unique<MockPlatformKeysService>();
124 key_permissions_manager_ = std::make_unique<MockKeyPermissionsManager>();
125
126 key_permissions_service_ = std::make_unique<KeyPermissionsServiceImpl>(
127 /*is_regular_profile=*/true, /*profile_is_managed=*/true,
128 profile_->GetPrefs(), policy_service_, extensions_state_store_,
129 platform_keys_service_.get(), key_permissions_manager_.get());
130 }
131
132 protected:
SetKeyLocations(const std::string & public_key,const std::vector<TokenId> & key_locations)133 void SetKeyLocations(const std::string& public_key,
134 const std::vector<TokenId>& key_locations) {
135 ON_CALL(*platform_keys_service_, GetKeyLocations(public_key, _))
136 .WillByDefault(testing::Invoke(
137 [key_locations](const std::string& public_key_spki_der,
138 GetKeyLocationsCallback callback) {
139 std::move(callback).Run(std::move(key_locations),
140 Status::kSuccess);
141 }));
142 }
143
IsCorporateKey(const std::string & public_key) const144 bool IsCorporateKey(const std::string& public_key) const {
145 IsCorporateKeyExecutionWaiter is_corporate_key_waiter;
146 key_permissions_service_->IsCorporateKey(
147 public_key, is_corporate_key_waiter.GetCallback());
148 is_corporate_key_waiter.Wait();
149 return is_corporate_key_waiter.corporate();
150 }
151
SetCorporateKey(const std::string & public_key)152 void SetCorporateKey(const std::string& public_key) {
153 EXPECT_CALL(*key_permissions_manager_, AllowKeyForUsage(_, _, _))
154 .Times(1)
155 .WillOnce(base::test::RunOnceCallback<0>(Status::kSuccess));
156 SetCorporateKeyExecutionWaiter set_corporate_key_waiter;
157 key_permissions_service_->SetCorporateKey(
158 public_key, set_corporate_key_waiter.GetCallback());
159 set_corporate_key_waiter.Wait();
160 }
161
162 content::BrowserTaskEnvironment task_environment_;
163 std::unique_ptr<TestingProfile> profile_;
164 // Owned by |profile_|.
165 policy::MockPolicyService* policy_service_ = nullptr;
166 // Owned by |profile_|.
167 extensions::StateStore* extensions_state_store_ = nullptr;
168
169 std::unique_ptr<KeyPermissionsServiceImpl> key_permissions_service_;
170 std::unique_ptr<MockPlatformKeysService> platform_keys_service_;
171 std::unique_ptr<MockKeyPermissionsManager> key_permissions_manager_;
172 };
173
TEST_F(KeyPermissionsServiceImplTest,SystemTokenKeyIsImplicitlyCorporate)174 TEST_F(KeyPermissionsServiceImplTest, SystemTokenKeyIsImplicitlyCorporate) {
175 const std::string kPublicKey = "test_public_key";
176
177 SetKeyLocations(kPublicKey, {TokenId::kSystem});
178 EXPECT_TRUE(IsCorporateKey(kPublicKey));
179
180 SetKeyLocations(kPublicKey, {TokenId::kUser, TokenId::kSystem});
181 EXPECT_TRUE(IsCorporateKey(kPublicKey));
182 }
183
TEST_F(KeyPermissionsServiceImplTest,CorporateRoundTrip)184 TEST_F(KeyPermissionsServiceImplTest, CorporateRoundTrip) {
185 const std::string kPublicKey = "test_public_key";
186
187 // By default, user-token keys are not corporate.
188 SetKeyLocations(kPublicKey, {TokenId::kUser});
189 EXPECT_FALSE(IsCorporateKey(kPublicKey));
190
191 SetCorporateKey(kPublicKey);
192 EXPECT_TRUE(IsCorporateKey(kPublicKey));
193
194 // Check that a repeated call doesn't corrupt the stored state.
195 SetCorporateKey(kPublicKey);
196 EXPECT_TRUE(IsCorporateKey(kPublicKey));
197 }
198
199 } // namespace platform_keys
200 } // namespace chromeos
201