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