1 // Copyright 2013 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.
5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/prefs/pref_registry_simple.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/prefs/scoped_user_pref_update.h"
16 #include "base/stl_util.h"
17 #include "base/sys_info.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
20 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
21 #include "chrome/browser/chromeos/login/user_manager.h"
22 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
23 #include "chrome/browser/chromeos/policy/device_local_account.h"
24 #include "chrome/browser/chromeos/settings/cros_settings.h"
25 #include "chrome/browser/chromeos/settings/owner_key_util.h"
26 #include "chrome/common/chrome_paths.h"
27 #include "chromeos/cryptohome/async_method_caller.h"
28 #include "chromeos/settings/cros_settings_names.h"
29 #include "content/public/browser/browser_thread.h"
35 // Domain that is used for kiosk-app account IDs.
36 const char kKioskAppAccountDomain[] = "kiosk-apps";
38 std::string GenerateKioskAppAccountId(const std::string& app_id) {
39 return app_id + '@' + kKioskAppAccountDomain;
42 void OnRemoveAppCryptohomeComplete(const std::string& app,
44 cryptohome::MountError return_code) {
46 LOG(ERROR) << "Remove cryptohome for " << app
47 << " failed, return code: " << return_code;
51 // Check for presence of machine owner public key file.
52 void CheckOwnerFilePresence(bool *present) {
53 scoped_refptr<OwnerKeyUtil> util = OwnerKeyUtil::Create();
54 *present = util->IsPublicKeyPresent();
60 const char KioskAppManager::kKioskDictionaryName[] = "kiosk";
61 const char KioskAppManager::kKeyApps[] = "apps";
62 const char KioskAppManager::kKeyAutoLoginState[] = "auto_login_state";
63 const char KioskAppManager::kIconCacheDir[] = "kiosk";
66 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER;
67 KioskAppManager* KioskAppManager::Get() {
68 return instance.Pointer();
72 void KioskAppManager::Shutdown() {
76 instance.Pointer()->CleanUp();
80 void KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) {
81 registry->RegisterDictionaryPref(kKioskDictionaryName);
84 KioskAppManager::App::App(const KioskAppData& data)
85 : app_id(data.app_id()),
86 user_id(data.user_id()),
89 is_loading(data.IsLoading()) {
92 KioskAppManager::App::App() : is_loading(false) {}
93 KioskAppManager::App::~App() {}
95 std::string KioskAppManager::GetAutoLaunchApp() const {
96 return auto_launch_app_id_;
99 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) {
100 SetAutoLoginState(AUTOLOGIN_REQUESTED);
101 // Clean first, so the proper change callbacks are triggered even
102 // if we are only changing AutoLoginState here.
103 if (!auto_launch_app_id_.empty()) {
104 CrosSettings::Get()->SetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
108 CrosSettings::Get()->SetString(
109 kAccountsPrefDeviceLocalAccountAutoLoginId,
110 app_id.empty() ? std::string() : GenerateKioskAppAccountId(app_id));
111 CrosSettings::Get()->SetInteger(
112 kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0);
115 void KioskAppManager::EnableConsumerKioskAutoLaunch(
116 const KioskAppManager::EnableKioskAutoLaunchCallback& callback) {
117 policy::BrowserPolicyConnectorChromeOS* connector =
118 g_browser_process->platform_part()->browser_policy_connector_chromeos();
119 connector->GetInstallAttributes()->LockDevice(
120 std::string(), // user
121 policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH,
122 std::string(), // device_id
124 &KioskAppManager::OnLockDevice, base::Unretained(this), callback));
127 void KioskAppManager::GetConsumerKioskAutoLaunchStatus(
128 const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback& callback) {
129 policy::BrowserPolicyConnectorChromeOS* connector =
130 g_browser_process->platform_part()->browser_policy_connector_chromeos();
131 connector->GetInstallAttributes()->ReadImmutableAttributes(
132 base::Bind(&KioskAppManager::OnReadImmutableAttributes,
133 base::Unretained(this),
137 bool KioskAppManager::IsConsumerKioskDeviceWithAutoLaunch() {
138 policy::BrowserPolicyConnectorChromeOS* connector =
139 g_browser_process->platform_part()->browser_policy_connector_chromeos();
140 return connector->GetInstallAttributes() &&
141 connector->GetInstallAttributes()
142 ->IsConsumerKioskDeviceWithAutoLaunch();
145 void KioskAppManager::OnLockDevice(
146 const KioskAppManager::EnableKioskAutoLaunchCallback& callback,
147 policy::EnterpriseInstallAttributes::LockResult result) {
148 if (callback.is_null())
151 callback.Run(result == policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
154 void KioskAppManager::OnOwnerFileChecked(
155 const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback& callback,
156 bool* owner_present) {
157 ownership_established_ = *owner_present;
159 if (callback.is_null())
162 // If we have owner already established on the machine, don't let
163 // consumer kiosk to be enabled.
164 if (ownership_established_)
165 callback.Run(CONSUMER_KIOSK_AUTO_LAUNCH_DISABLED);
167 callback.Run(CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE);
170 void KioskAppManager::OnReadImmutableAttributes(
171 const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback&
173 if (callback.is_null())
176 ConsumerKioskAutoLaunchStatus status =
177 CONSUMER_KIOSK_AUTO_LAUNCH_DISABLED;
178 policy::BrowserPolicyConnectorChromeOS* connector =
179 g_browser_process->platform_part()->browser_policy_connector_chromeos();
180 policy::EnterpriseInstallAttributes* attributes =
181 connector->GetInstallAttributes();
182 switch (attributes->GetMode()) {
183 case policy::DEVICE_MODE_NOT_SET: {
184 if (!base::SysInfo::IsRunningOnChromeOS()) {
185 status = CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE;
186 } else if (!ownership_established_) {
187 bool* owner_present = new bool(false);
188 content::BrowserThread::PostBlockingPoolTaskAndReply(
190 base::Bind(&CheckOwnerFilePresence,
192 base::Bind(&KioskAppManager::OnOwnerFileChecked,
193 base::Unretained(this),
195 base::Owned(owner_present)));
200 case policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
201 status = CONSUMER_KIOSK_AUTO_LAUNCH_ENABLED;
207 callback.Run(status);
210 void KioskAppManager::SetEnableAutoLaunch(bool value) {
211 SetAutoLoginState(value ? AUTOLOGIN_APPROVED : AUTOLOGIN_REJECTED);
214 bool KioskAppManager::IsAutoLaunchRequested() const {
215 if (GetAutoLaunchApp().empty())
218 // Apps that were installed by the policy don't require machine owner
219 // consent through UI.
220 policy::BrowserPolicyConnectorChromeOS* connector =
221 g_browser_process->platform_part()->browser_policy_connector_chromeos();
222 if (connector->IsEnterpriseManaged())
225 return GetAutoLoginState() == AUTOLOGIN_REQUESTED;
228 bool KioskAppManager::IsAutoLaunchEnabled() const {
229 if (GetAutoLaunchApp().empty())
232 // Apps that were installed by the policy don't require machine owner
233 // consent through UI.
234 policy::BrowserPolicyConnectorChromeOS* connector =
235 g_browser_process->platform_part()->browser_policy_connector_chromeos();
236 if (connector->IsEnterpriseManaged())
239 return GetAutoLoginState() == AUTOLOGIN_APPROVED;
242 void KioskAppManager::AddApp(const std::string& app_id) {
243 std::vector<policy::DeviceLocalAccount> device_local_accounts =
244 policy::GetDeviceLocalAccounts(CrosSettings::Get());
246 // Don't insert the app if it's already in the list.
247 for (std::vector<policy::DeviceLocalAccount>::const_iterator
248 it = device_local_accounts.begin();
249 it != device_local_accounts.end(); ++it) {
250 if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
251 it->kiosk_app_id == app_id) {
256 // Add the new account.
257 device_local_accounts.push_back(policy::DeviceLocalAccount(
258 policy::DeviceLocalAccount::TYPE_KIOSK_APP,
259 GenerateKioskAppAccountId(app_id),
262 policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
265 void KioskAppManager::RemoveApp(const std::string& app_id) {
266 // Resets auto launch app if it is the removed app.
267 if (auto_launch_app_id_ == app_id)
268 SetAutoLaunchApp(std::string());
270 std::vector<policy::DeviceLocalAccount> device_local_accounts =
271 policy::GetDeviceLocalAccounts(CrosSettings::Get());
272 if (device_local_accounts.empty())
275 // Remove entries that match |app_id|.
276 for (std::vector<policy::DeviceLocalAccount>::iterator
277 it = device_local_accounts.begin();
278 it != device_local_accounts.end(); ++it) {
279 if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
280 it->kiosk_app_id == app_id) {
281 device_local_accounts.erase(it);
286 policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
289 void KioskAppManager::GetApps(Apps* apps) const {
291 apps->reserve(apps_.size());
292 for (size_t i = 0; i < apps_.size(); ++i) {
293 const KioskAppData& app_data = *apps_[i];
294 if (app_data.status() != KioskAppData::STATUS_ERROR)
295 apps->push_back(App(app_data));
299 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const {
300 const KioskAppData* data = GetAppData(app_id);
308 const base::RefCountedString* KioskAppManager::GetAppRawIcon(
309 const std::string& app_id) const {
310 const KioskAppData* data = GetAppData(app_id);
314 return data->raw_icon();
317 bool KioskAppManager::GetDisableBailoutShortcut() const {
319 if (CrosSettings::Get()->GetBoolean(
320 kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) {
327 void KioskAppManager::ClearAppData(const std::string& app_id) {
328 KioskAppData* app_data = GetAppDataMutable(app_id);
332 app_data->ClearCache();
335 void KioskAppManager::UpdateAppDataFromProfile(
336 const std::string& app_id,
338 const extensions::Extension* app) {
339 KioskAppData* app_data = GetAppDataMutable(app_id);
343 app_data->LoadFromInstalledApp(profile, app);
346 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) {
347 observers_.AddObserver(observer);
350 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) {
351 observers_.RemoveObserver(observer);
354 KioskAppManager::KioskAppManager() : ownership_established_(false) {
356 local_accounts_subscription_ =
357 CrosSettings::Get()->AddSettingsObserver(
358 kAccountsPrefDeviceLocalAccounts,
359 base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
360 local_account_auto_login_id_subscription_ =
361 CrosSettings::Get()->AddSettingsObserver(
362 kAccountsPrefDeviceLocalAccountAutoLoginId,
363 base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
366 KioskAppManager::~KioskAppManager() {}
368 void KioskAppManager::CleanUp() {
369 local_accounts_subscription_.reset();
370 local_account_auto_login_id_subscription_.reset();
374 const KioskAppData* KioskAppManager::GetAppData(
375 const std::string& app_id) const {
376 for (size_t i = 0; i < apps_.size(); ++i) {
377 const KioskAppData* data = apps_[i];
378 if (data->app_id() == app_id)
385 KioskAppData* KioskAppManager::GetAppDataMutable(const std::string& app_id) {
386 return const_cast<KioskAppData*>(GetAppData(app_id));
389 void KioskAppManager::UpdateAppData() {
390 // Gets app id to data mapping for existing apps.
391 std::map<std::string, KioskAppData*> old_apps;
392 for (size_t i = 0; i < apps_.size(); ++i)
393 old_apps[apps_[i]->app_id()] = apps_[i];
394 apps_.weak_clear(); // |old_apps| takes ownership
396 auto_launch_app_id_.clear();
397 std::string auto_login_account_id;
398 CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
399 &auto_login_account_id);
401 // Re-populates |apps_| and reuses existing KioskAppData when possible.
402 const std::vector<policy::DeviceLocalAccount> device_local_accounts =
403 policy::GetDeviceLocalAccounts(CrosSettings::Get());
404 for (std::vector<policy::DeviceLocalAccount>::const_iterator
405 it = device_local_accounts.begin();
406 it != device_local_accounts.end(); ++it) {
407 if (it->type != policy::DeviceLocalAccount::TYPE_KIOSK_APP)
410 if (it->account_id == auto_login_account_id)
411 auto_launch_app_id_ = it->kiosk_app_id;
413 // TODO(mnissler): Support non-CWS update URLs.
415 std::map<std::string, KioskAppData*>::iterator old_it =
416 old_apps.find(it->kiosk_app_id);
417 if (old_it != old_apps.end()) {
418 apps_.push_back(old_it->second);
419 old_apps.erase(old_it);
421 KioskAppData* new_app =
422 new KioskAppData(this, it->kiosk_app_id, it->user_id);
423 apps_.push_back(new_app); // Takes ownership of |new_app|.
428 // Clears cache and deletes the remaining old data.
429 for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin();
430 it != old_apps.end(); ++it) {
431 it->second->ClearCache();
432 cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
433 it->second->user_id(),
434 base::Bind(&OnRemoveAppCryptohomeComplete, it->first));
436 STLDeleteValues(&old_apps);
438 FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_,
439 OnKioskAppsSettingsChanged());
442 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) {
443 base::FilePath user_data_dir;
444 CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
445 *cache_dir = user_data_dir.AppendASCII(kIconCacheDir);
448 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) {
449 FOR_EACH_OBSERVER(KioskAppManagerObserver,
451 OnKioskAppDataChanged(app_id));
454 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) {
455 FOR_EACH_OBSERVER(KioskAppManagerObserver,
457 OnKioskAppDataLoadFailure(app_id));
460 KioskAppManager::AutoLoginState KioskAppManager::GetAutoLoginState() const {
461 PrefService* prefs = g_browser_process->local_state();
462 const base::DictionaryValue* dict =
463 prefs->GetDictionary(KioskAppManager::kKioskDictionaryName);
465 if (!dict->GetInteger(kKeyAutoLoginState, &value))
466 return AUTOLOGIN_NONE;
468 return static_cast<AutoLoginState>(value);
471 void KioskAppManager::SetAutoLoginState(AutoLoginState state) {
472 PrefService* prefs = g_browser_process->local_state();
473 DictionaryPrefUpdate dict_update(prefs,
474 KioskAppManager::kKioskDictionaryName);
475 dict_update->SetInteger(kKeyAutoLoginState, state);
476 prefs->CommitPendingWrite();
479 } // namespace chromeos