1 // Copyright 2019 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/policy/tpm_auto_update_mode_policy_handler.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/callback_helpers.h"
11 #include "base/memory/ptr_util.h"
12 #include "base/run_loop.h"
13 #include "base/timer/mock_timer.h"
14 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
15 #include "chrome/browser/chromeos/settings/scoped_testing_cros_settings.h"
16 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
17 #include "chrome/browser/chromeos/tpm_firmware_update.h"
18 #include "chrome/browser/prefs/browser_prefs.h"
19 #include "chrome/common/pref_names.h"
20 #include "chrome/test/base/scoped_testing_local_state.h"
21 #include "chrome/test/base/testing_browser_process.h"
22 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
24 #include "chromeos/settings/cros_settings_names.h"
25 #include "chromeos/tpm/stub_install_attributes.h"
26 #include "components/account_id/account_id.h"
27 #include "components/prefs/pref_service.h"
28 #include "components/prefs/testing_pref_service.h"
29 #include "components/user_manager/fake_user_manager.h"
30 #include "components/user_manager/scoped_user_manager.h"
31 #include "content/public/test/browser_task_environment.h"
32 #include "testing/gtest/include/gtest/gtest.h"
33 
34 namespace {
35 constexpr char kFakeUserName[] = "test@example.com";
36 constexpr char kFakeGaiaId[] = "1234567890";
37 }  // namespace
38 
39 namespace policy {
40 
41 class TPMAutoUpdateModePolicyHandlerTest : public testing::Test {
42  public:
TPMAutoUpdateModePolicyHandlerTest()43   TPMAutoUpdateModePolicyHandlerTest()
44       : local_state_(TestingBrowserProcess::GetGlobal()),
45         user_manager_(new chromeos::FakeChromeUserManager()),
46         user_manager_enabler_(base::WrapUnique(user_manager_)) {
47     chromeos::SessionManagerClient::InitializeFakeInMemory();
48   }
49 
~TPMAutoUpdateModePolicyHandlerTest()50   ~TPMAutoUpdateModePolicyHandlerTest() override {
51     chromeos::SessionManagerClient::Shutdown();
52   }
53 
SetAutoUpdateMode(AutoUpdateMode auto_update_mode)54   void SetAutoUpdateMode(AutoUpdateMode auto_update_mode) {
55     base::DictionaryValue dict;
56     dict.SetKey(chromeos::tpm_firmware_update::kSettingsKeyAutoUpdateMode,
57                 base::Value(static_cast<int>(auto_update_mode)));
58     scoped_testing_cros_settings_.device_settings()->Set(
59         chromeos::kTPMFirmwareUpdateSettings, dict);
60     base::RunLoop().RunUntilIdle();
61   }
62 
CheckForUpdate(base::OnceCallback<void (bool)> callback)63   void CheckForUpdate(base::OnceCallback<void(bool)> callback) {
64     std::move(callback).Run(update_available_);
65   }
66 
ShowNotification(chromeos::TpmAutoUpdateUserNotification notification_type)67   void ShowNotification(
68       chromeos::TpmAutoUpdateUserNotification notification_type) {
69     last_shown_notification_ = notification_type;
70   }
71 
72  protected:
73   bool update_available_ = false;
74   chromeos::TpmAutoUpdateUserNotification last_shown_notification_ =
75       chromeos::TpmAutoUpdateUserNotification::kNone;
76 
77   content::BrowserTaskEnvironment task_environment_;
78   ScopedTestingLocalState local_state_;
79   chromeos::FakeChromeUserManager* user_manager_;
80   user_manager::ScopedUserManager user_manager_enabler_;
81 
82   // Set up fake install attributes to pretend the machine is enrolled.
83   chromeos::ScopedStubInstallAttributes test_install_attributes_{
84       chromeos::StubInstallAttributes::CreateCloudManaged("example.com",
85                                                           "fake-id")};
86   chromeos::ScopedTestingCrosSettings scoped_testing_cros_settings_;
87 
88   base::WeakPtrFactory<TPMAutoUpdateModePolicyHandlerTest> weak_factory_{this};
89 };
90 
91 // Verify if the TPM updates are triggered (or not) according to the device
92 // policy option TPMFirmwareUpdateSettings.AutoUpdateMode.
TEST_F(TPMAutoUpdateModePolicyHandlerTest,PolicyUpdatesTriggered)93 TEST_F(TPMAutoUpdateModePolicyHandlerTest, PolicyUpdatesTriggered) {
94   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
95       chromeos::CrosSettings::Get(), local_state_.Get());
96   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
97       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
98                           weak_factory_.GetWeakPtr()));
99 
100   update_available_ = true;
101 
102   auto* fake_session_manager_client = chromeos::FakeSessionManagerClient::Get();
103 
104   base::RunLoop().RunUntilIdle();
105   EXPECT_EQ(
106       0, fake_session_manager_client->start_tpm_firmware_update_call_count());
107 
108   SetAutoUpdateMode(AutoUpdateMode::kWithoutAcknowledgment);
109   base::RunLoop().RunUntilIdle();
110   EXPECT_EQ(
111       1, fake_session_manager_client->start_tpm_firmware_update_call_count());
112 
113   SetAutoUpdateMode(AutoUpdateMode::kNever);
114   base::RunLoop().RunUntilIdle();
115   EXPECT_EQ(
116       1, fake_session_manager_client->start_tpm_firmware_update_call_count());
117 
118   SetAutoUpdateMode(AutoUpdateMode::kWithoutAcknowledgment);
119   base::RunLoop().RunUntilIdle();
120   EXPECT_EQ(
121       2, fake_session_manager_client->start_tpm_firmware_update_call_count());
122 
123   SetAutoUpdateMode(AutoUpdateMode::kEnrollment);
124   base::RunLoop().RunUntilIdle();
125   EXPECT_EQ(
126       2, fake_session_manager_client->start_tpm_firmware_update_call_count());
127 }
128 
129 // Verify that the DBus call to start TPM firmware update is not triggered if
130 // state preserving update is not available.
TEST_F(TPMAutoUpdateModePolicyHandlerTest,NoUpdatesAvailable)131 TEST_F(TPMAutoUpdateModePolicyHandlerTest, NoUpdatesAvailable) {
132   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
133       chromeos::CrosSettings::Get(), local_state_.Get());
134   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
135       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
136                           weak_factory_.GetWeakPtr()));
137 
138   update_available_ = false;
139 
140   SetAutoUpdateMode(AutoUpdateMode::kWithoutAcknowledgment);
141   base::RunLoop().RunUntilIdle();
142   EXPECT_EQ(0, chromeos::FakeSessionManagerClient::Get()
143                    ->start_tpm_firmware_update_call_count());
144 }
145 
146 // Verify that the notification informing the user that an update is planned
147 // after 24 hours is shown.
TEST_F(TPMAutoUpdateModePolicyHandlerTest,ShowPlannedUpdateNotification)148 TEST_F(TPMAutoUpdateModePolicyHandlerTest, ShowPlannedUpdateNotification) {
149   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
150       chromeos::CrosSettings::Get(), local_state_.Get());
151   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
152       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
153                           weak_factory_.GetWeakPtr()));
154   tpm_update_policy_handler.SetShowNotificationCallbackForTesting(
155       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::ShowNotification,
156                           base::Unretained(this)));
157 
158   const AccountId account_id(
159       AccountId::FromUserEmailGaiaId(kFakeUserName, kFakeGaiaId));
160   user_manager_->AddUser(account_id);
161   user_manager_->LoginUser(account_id);
162 
163   update_available_ = true;
164 
165   EXPECT_EQ(last_shown_notification_,
166             chromeos::TpmAutoUpdateUserNotification::kNone);
167 
168   SetAutoUpdateMode(AutoUpdateMode::kUserAcknowledgment);
169   base::RunLoop().RunUntilIdle();
170 
171   // TPM update is not triggered.
172   EXPECT_EQ(0, chromeos::FakeSessionManagerClient::Get()
173                    ->start_tpm_firmware_update_call_count());
174 
175   EXPECT_EQ(last_shown_notification_,
176             chromeos::TpmAutoUpdateUserNotification::kPlanned);
177 }
178 
179 // Verify that the notification informing the user that an update will happen at
180 // the next reboot is shown.
TEST_F(TPMAutoUpdateModePolicyHandlerTest,ShowUpdateOnRebootNotificationNoTimer)181 TEST_F(TPMAutoUpdateModePolicyHandlerTest,
182        ShowUpdateOnRebootNotificationNoTimer) {
183   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
184       chromeos::CrosSettings::Get(), local_state_.Get());
185   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
186       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
187                           weak_factory_.GetWeakPtr()));
188   tpm_update_policy_handler.SetShowNotificationCallbackForTesting(
189       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::ShowNotification,
190                           base::Unretained(this)));
191 
192   const AccountId account_id(
193       AccountId::FromUserEmailGaiaId(kFakeUserName, kFakeGaiaId));
194   user_manager_->AddUser(account_id);
195   user_manager_->LoginUser(account_id);
196 
197   update_available_ = true;
198 
199   // First notification was shwed more than 24 hours ago.
200   base::Time yesterday = base::Time::Now() - base::TimeDelta::FromHours(25);
201   local_state_.Get()->SetInt64(
202       prefs::kTPMUpdatePlannedNotificationShownTime,
203       yesterday.ToDeltaSinceWindowsEpoch().InSeconds());
204 
205   SetAutoUpdateMode(AutoUpdateMode::kUserAcknowledgment);
206   base::RunLoop().RunUntilIdle();
207 
208   // TPM update is not triggered.
209   EXPECT_EQ(0, chromeos::FakeSessionManagerClient::Get()
210                    ->start_tpm_firmware_update_call_count());
211 
212   // Show planned update notification.
213   EXPECT_EQ(last_shown_notification_,
214             chromeos::TpmAutoUpdateUserNotification::kOnNextReboot);
215 }
216 
217 // Verify that the notification informing the user that an update will happen at
218 // the next reboot is triggered by the timer.
TEST_F(TPMAutoUpdateModePolicyHandlerTest,ShowUpdateOnRebootNotificationTimer)219 TEST_F(TPMAutoUpdateModePolicyHandlerTest,
220        ShowUpdateOnRebootNotificationTimer) {
221   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
222       chromeos::CrosSettings::Get(), local_state_.Get());
223   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
224       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
225                           weak_factory_.GetWeakPtr()));
226   tpm_update_policy_handler.SetShowNotificationCallbackForTesting(
227       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::ShowNotification,
228                           base::Unretained(this)));
229 
230   auto mock_timer = std::make_unique<base::MockOneShotTimer>();
231   auto* mock_timer_ptr = mock_timer.get();
232 
233   tpm_update_policy_handler.SetNotificationTimerForTesting(
234       std::move(mock_timer));
235 
236   const AccountId account_id(
237       AccountId::FromUserEmailGaiaId(kFakeUserName, kFakeGaiaId));
238   user_manager_->AddUser(account_id);
239   user_manager_->LoginUser(account_id);
240 
241   update_available_ = true;
242 
243   SetAutoUpdateMode(AutoUpdateMode::kUserAcknowledgment);
244   base::RunLoop().RunUntilIdle();
245   EXPECT_EQ(0, chromeos::FakeSessionManagerClient::Get()
246                    ->start_tpm_firmware_update_call_count());
247 
248   // Show planned update notification.
249   EXPECT_EQ(last_shown_notification_,
250             chromeos::TpmAutoUpdateUserNotification::kPlanned);
251 
252   mock_timer_ptr->Fire();
253 
254   // Show update at reboot notification.
255   EXPECT_EQ(last_shown_notification_,
256             chromeos::TpmAutoUpdateUserNotification::kOnNextReboot);
257 }
258 
259 // TPM update with user acknowlegment triggered.
TEST_F(TPMAutoUpdateModePolicyHandlerTest,UpdateWithUserAcknowlegment)260 TEST_F(TPMAutoUpdateModePolicyHandlerTest, UpdateWithUserAcknowlegment) {
261   TPMAutoUpdateModePolicyHandler tpm_update_policy_handler(
262       chromeos::CrosSettings::Get(), local_state_.Get());
263   tpm_update_policy_handler.SetUpdateCheckerCallbackForTesting(
264       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::CheckForUpdate,
265                           weak_factory_.GetWeakPtr()));
266   tpm_update_policy_handler.SetShowNotificationCallbackForTesting(
267       base::BindRepeating(&TPMAutoUpdateModePolicyHandlerTest::ShowNotification,
268                           base::Unretained(this)));
269 
270   update_available_ = true;
271 
272   // Update at next reboot notification already shown.
273   local_state_.Get()->SetBoolean(prefs::kTPMUpdateOnNextRebootNotificationShown,
274                                  true);
275   SetAutoUpdateMode(AutoUpdateMode::kUserAcknowledgment);
276   base::RunLoop().RunUntilIdle();
277 
278   // Update is triggered.
279   EXPECT_EQ(1, chromeos::FakeSessionManagerClient::Get()
280                    ->start_tpm_firmware_update_call_count());
281 }
282 
283 }  // namespace policy
284