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