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/login/test/device_state_mixin.h"
6 
7 #include <utility>
8 #include <vector>
9 
10 #include "base/callback.h"
11 #include "base/files/file_util.h"
12 #include "base/json/json_writer.h"
13 #include "base/numerics/safe_conversions.h"
14 #include "base/path_service.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chromeos/policy/device_policy_builder.h"
17 #include "chrome/common/chrome_paths.h"
18 #include "chrome/common/pref_names.h"
19 #include "chromeos/constants/chromeos_paths.h"
20 #include "chromeos/dbus/session_manager/fake_session_manager_client.h"
21 #include "chromeos/dbus/session_manager/session_manager_client.h"
22 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
23 #include "components/policy/core/common/cloud/policy_builder.h"
24 #include "components/policy/proto/install_attributes.pb.h"
25 #include "components/prefs/pref_service.h"
26 
27 namespace chromeos {
28 
29 namespace {
30 
31 constexpr char kFakeDomain[] = "example.com";
32 constexpr char kFakeDeviceId[] = "device_id";
33 
34 bool g_instance_created = false;
35 
BuildInstallAttributes(const std::string & mode,const std::string & domain,const std::string & realm,const std::string & device_id)36 cryptohome::SerializedInstallAttributes BuildInstallAttributes(
37     const std::string& mode,
38     const std::string& domain,
39     const std::string& realm,
40     const std::string& device_id) {
41   std::map<std::string, std::string> install_attrs_;
42   install_attrs_["enterprise.mode"] = mode;
43   install_attrs_["enterprise.domain"] = domain;
44   install_attrs_["enterprise.realm"] = realm;
45   install_attrs_["enterprise.device_id"] = device_id;
46   if (!mode.empty())
47     install_attrs_["enterprise.owned"] = "true";
48 
49   cryptohome::SerializedInstallAttributes install_attrs;
50   install_attrs.set_version(1);
51 
52   for (const auto& it : install_attrs_) {
53     if (it.second.empty())
54       continue;
55     cryptohome::SerializedInstallAttributes::Attribute* attr_entry =
56         install_attrs.add_attributes();
57     const std::string& name = it.first;
58     const std::string& value = it.second;
59     attr_entry->set_name(name);
60     attr_entry->mutable_value()->assign(value.data(),
61                                         value.data() + value.size());
62   }
63   return install_attrs;
64 }
65 
WriteFile(const base::FilePath & path,const std::string & blob)66 void WriteFile(const base::FilePath& path, const std::string& blob) {
67   CHECK_EQ(base::checked_cast<int>(blob.length()),
68            base::WriteFile(path, blob.data(), blob.length()));
69 }
70 
71 }  // namespace
72 
DeviceStateMixin(InProcessBrowserTestMixinHost * host,State initial_state)73 DeviceStateMixin::DeviceStateMixin(InProcessBrowserTestMixinHost* host,
74                                    State initial_state)
75     : InProcessBrowserTestMixin(host),
76       state_(initial_state),
77       local_state_mixin_(host, this) {
78   DCHECK(!g_instance_created);
79   g_instance_created = true;
80 }
81 
SetUpUserDataDirectory()82 bool DeviceStateMixin::SetUpUserDataDirectory() {
83   SetDeviceState();
84   return true;
85 }
86 
SetUpInProcessBrowserTestFixture()87 void DeviceStateMixin::SetUpInProcessBrowserTestFixture() {
88   // Make sure session manager client has been initialized as in-memory. This is
89   // requirement for setting policy blobs.
90   if (!chromeos::SessionManagerClient::Get())
91     chromeos::SessionManagerClient::InitializeFakeInMemory();
92 
93   session_manager_initialized_ = true;
94 
95   std::vector<std::string> state_keys;
96   state_keys.push_back("1");
97   FakeSessionManagerClient::Get()->set_server_backed_state_keys(state_keys);
98 
99   if (IsEnrolledState() && !skip_initial_policy_setup_) {
100     SetCachedDevicePolicy();
101 
102     for (const auto& device_local_account : device_local_account_policies_)
103       SetCachedDeviceLocalAccountPolicy(device_local_account.first);
104   }
105 }
106 
SetUpLocalState()107 void DeviceStateMixin::SetUpLocalState() {
108   PrefService* local_state = g_browser_process->local_state();
109   switch (state_) {
110     case DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED:
111     case DeviceStateMixin::State::OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED:
112     case DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED:
113     case DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE:
114       local_state->SetBoolean(prefs::kOobeComplete, true);
115       local_state->SetInteger(prefs::kDeviceRegistered, 1);
116       local_state->SetBoolean(prefs::kEnrollmentRecoveryRequired, false);
117       break;
118     case DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED:
119       local_state->SetBoolean(prefs::kOobeComplete, true);
120       local_state->SetInteger(prefs::kDeviceRegistered, 0);
121       local_state->SetBoolean(prefs::kEnrollmentRecoveryRequired, false);
122       break;
123     case DeviceStateMixin::State::BEFORE_OOBE:
124       local_state->SetInteger(prefs::kDeviceRegistered, 0);
125       break;
126   }
127 }
128 
129 std::unique_ptr<ScopedDevicePolicyUpdate>
RequestDevicePolicyUpdate()130 DeviceStateMixin::RequestDevicePolicyUpdate() {
131   if (!IsEnrolledState())
132     return nullptr;
133 
134   return std::make_unique<ScopedDevicePolicyUpdate>(
135       &device_policy_, base::BindOnce(&DeviceStateMixin::SetCachedDevicePolicy,
136                                       weak_factory_.GetWeakPtr()));
137 }
138 
139 std::unique_ptr<ScopedUserPolicyUpdate>
RequestDeviceLocalAccountPolicyUpdate(const std::string & account_id)140 DeviceStateMixin::RequestDeviceLocalAccountPolicyUpdate(
141     const std::string& account_id) {
142   if (!IsEnrolledState())
143     return nullptr;
144 
145   policy::UserPolicyBuilder& builder =
146       device_local_account_policies_[account_id];
147   return std::make_unique<ScopedUserPolicyUpdate>(
148       &builder,
149       base::BindRepeating(&DeviceStateMixin::SetCachedDeviceLocalAccountPolicy,
150                           weak_factory_.GetWeakPtr(), account_id));
151 }
152 
SetState(State state)153 void DeviceStateMixin::SetState(State state) {
154   DCHECK(!is_setup_) << "SetState called after device was set up";
155   state_ = state;
156 }
157 
SetDeviceState()158 void DeviceStateMixin::SetDeviceState() {
159   DCHECK(!is_setup_);
160   DCHECK(domain_.empty() || state_ == State::OOBE_COMPLETED_CLOUD_ENROLLED);
161   is_setup_ = true;
162 
163   WriteInstallAttrFile();
164   WriteOwnerKey();
165 }
166 
WriteInstallAttrFile()167 void DeviceStateMixin::WriteInstallAttrFile() {
168   base::FilePath user_data_dir;
169   CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
170   base::FilePath install_attrs_file =
171       user_data_dir.Append("stub_install_attributes.pb");
172   if (base::PathExists(install_attrs_file)) {
173     return;
174   }
175 
176   std::string device_mode, domain, realm, device_id;
177   switch (state_) {
178     case DeviceStateMixin::State::BEFORE_OOBE:
179     case DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED:
180       // No file at all.
181       return;
182     case DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED:
183       // File with version only.
184       break;
185     case DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED:
186       device_mode = "enterprise";
187       domain = !domain_.empty() ? domain_ : kFakeDomain;
188       device_id = kFakeDeviceId;
189       break;
190     case DeviceStateMixin::State::OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED:
191       device_mode = "enterprise_ad";
192       realm = kFakeDomain;
193       device_id = kFakeDeviceId;
194       break;
195     case DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE:
196       device_mode = "demo_mode";
197       domain = "cros-demo-mode.com";
198       device_id = kFakeDeviceId;
199       break;
200   }
201 
202   std::string install_attrs_bits;
203   CHECK(BuildInstallAttributes(device_mode, domain, realm, device_id)
204             .SerializeToString(&install_attrs_bits));
205   WriteFile(install_attrs_file, install_attrs_bits);
206 }
207 
WriteOwnerKey()208 void DeviceStateMixin::WriteOwnerKey() {
209   switch (state_) {
210     case DeviceStateMixin::State::BEFORE_OOBE:
211     case DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED:
212     case DeviceStateMixin::State::OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED:
213       return;
214     case DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED:
215     case DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED:
216     case DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE:
217       break;
218   }
219 
220   base::FilePath user_data_dir;
221   CHECK(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
222   base::FilePath owner_key_file = user_data_dir.Append("stub_owner.key");
223   const std::string owner_key_bits =
224       policy::PolicyBuilder::GetPublicTestKeyAsString();
225   CHECK(!owner_key_bits.empty());
226   WriteFile(owner_key_file, owner_key_bits);
227 }
228 
IsEnrolledState() const229 bool DeviceStateMixin::IsEnrolledState() const {
230   switch (state_) {
231     case DeviceStateMixin::State::BEFORE_OOBE:
232     case DeviceStateMixin::State::OOBE_COMPLETED_UNOWNED:
233     case DeviceStateMixin::State::OOBE_COMPLETED_CONSUMER_OWNED:
234       return false;
235     case DeviceStateMixin::State::OOBE_COMPLETED_ACTIVE_DIRECTORY_ENROLLED:
236     case DeviceStateMixin::State::OOBE_COMPLETED_CLOUD_ENROLLED:
237     case DeviceStateMixin::State::OOBE_COMPLETED_DEMO_MODE:
238       return true;
239   }
240   return false;
241 }
242 
SetCachedDevicePolicy()243 void DeviceStateMixin::SetCachedDevicePolicy() {
244   if (!session_manager_initialized_)
245     return;
246 
247   DCHECK(IsEnrolledState());
248 
249   device_policy_.SetDefaultSigningKey();
250   device_policy_.Build();
251   FakeSessionManagerClient::Get()->set_device_policy(device_policy_.GetBlob());
252   FakeSessionManagerClient::Get()->OnPropertyChangeComplete(true);
253 }
254 
SetCachedDeviceLocalAccountPolicy(const std::string & account_id)255 void DeviceStateMixin::SetCachedDeviceLocalAccountPolicy(
256     const std::string& account_id) {
257   if (!session_manager_initialized_ ||
258       !device_local_account_policies_.count(account_id))
259     return;
260 
261   DCHECK(IsEnrolledState());
262 
263   policy::UserPolicyBuilder& builder =
264       device_local_account_policies_[account_id];
265   builder.policy_data().set_username(account_id);
266   builder.policy_data().set_settings_entity_id(account_id);
267   builder.policy_data().set_policy_type(
268       policy::dm_protocol::kChromePublicAccountPolicyType);
269   builder.SetDefaultSigningKey();
270   builder.Build();
271 
272   FakeSessionManagerClient::Get()->set_device_local_account_policy(
273       account_id, builder.GetBlob());
274 }
275 
276 DeviceStateMixin::~DeviceStateMixin() = default;
277 
278 }  // namespace chromeos
279