Upstream version 9.37.197.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / app_mode / kiosk_app_manager.cc
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.
4
5 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
6
7 #include <map>
8 #include <set>
9
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/logging.h"
13 #include "base/path_service.h"
14 #include "base/prefs/pref_registry_simple.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/prefs/scoped_user_pref_update.h"
17 #include "base/stl_util.h"
18 #include "base/sys_info.h"
19 #include "chrome/browser/browser_process.h"
20 #include "chrome/browser/chromeos/app_mode/kiosk_app_data.h"
21 #include "chrome/browser/chromeos/app_mode/kiosk_app_manager_observer.h"
22 #include "chrome/browser/chromeos/login/users/user_manager.h"
23 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
24 #include "chrome/browser/chromeos/policy/device_local_account.h"
25 #include "chrome/browser/chromeos/settings/cros_settings.h"
26 #include "chrome/browser/chromeos/settings/owner_key_util.h"
27 #include "chrome/browser/extensions/external_provider_impl.h"
28 #include "chrome/common/chrome_paths.h"
29 #include "chrome/common/extensions/extension_constants.h"
30 #include "chromeos/chromeos_paths.h"
31 #include "chromeos/cryptohome/async_method_caller.h"
32 #include "chromeos/settings/cros_settings_names.h"
33 #include "content/public/browser/browser_thread.h"
34
35 namespace chromeos {
36
37 namespace {
38
39 // Domain that is used for kiosk-app account IDs.
40 const char kKioskAppAccountDomain[] = "kiosk-apps";
41
42 std::string GenerateKioskAppAccountId(const std::string& app_id) {
43   return app_id + '@' + kKioskAppAccountDomain;
44 }
45
46 void OnRemoveAppCryptohomeComplete(const std::string& app,
47                                    bool success,
48                                    cryptohome::MountError return_code) {
49   if (!success) {
50     LOG(ERROR) << "Remove cryptohome for " << app
51         << " failed, return code: " << return_code;
52   }
53 }
54
55 // Check for presence of machine owner public key file.
56 void CheckOwnerFilePresence(bool *present) {
57   scoped_refptr<OwnerKeyUtil> util = OwnerKeyUtil::Create();
58   *present = util->IsPublicKeyPresent();
59 }
60
61 scoped_refptr<base::SequencedTaskRunner> GetBackgroundTaskRunner() {
62   base::SequencedWorkerPool* pool = content::BrowserThread::GetBlockingPool();
63   CHECK(pool);
64   return pool->GetSequencedTaskRunnerWithShutdownBehavior(
65       pool->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
66 }
67
68 }  // namespace
69
70 // static
71 const char KioskAppManager::kKioskDictionaryName[] = "kiosk";
72 const char KioskAppManager::kKeyApps[] = "apps";
73 const char KioskAppManager::kKeyAutoLoginState[] = "auto_login_state";
74 const char KioskAppManager::kIconCacheDir[] = "kiosk/icon";
75 const char KioskAppManager::kCrxCacheDir[] = "kiosk/crx";
76
77 // static
78 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER;
79 KioskAppManager* KioskAppManager::Get() {
80   return instance.Pointer();
81 }
82
83 // static
84 void KioskAppManager::Shutdown() {
85   if (instance == NULL)
86     return;
87
88   instance.Pointer()->CleanUp();
89 }
90
91 // static
92 void KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) {
93   registry->RegisterDictionaryPref(kKioskDictionaryName);
94 }
95
96 KioskAppManager::App::App(const KioskAppData& data, bool is_extension_pending)
97     : app_id(data.app_id()),
98       user_id(data.user_id()),
99       name(data.name()),
100       icon(data.icon()),
101       is_loading(data.IsLoading() || is_extension_pending) {
102 }
103
104 KioskAppManager::App::App() : is_loading(false) {}
105 KioskAppManager::App::~App() {}
106
107 std::string KioskAppManager::GetAutoLaunchApp() const {
108   return auto_launch_app_id_;
109 }
110
111 void KioskAppManager::SetAutoLaunchApp(const std::string& app_id) {
112   SetAutoLoginState(AUTOLOGIN_REQUESTED);
113   // Clean first, so the proper change callbacks are triggered even
114   // if we are only changing AutoLoginState here.
115   if (!auto_launch_app_id_.empty()) {
116     CrosSettings::Get()->SetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
117                                    std::string());
118   }
119
120   CrosSettings::Get()->SetString(
121       kAccountsPrefDeviceLocalAccountAutoLoginId,
122       app_id.empty() ? std::string() : GenerateKioskAppAccountId(app_id));
123   CrosSettings::Get()->SetInteger(
124       kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0);
125 }
126
127 void KioskAppManager::EnableConsumerKioskAutoLaunch(
128     const KioskAppManager::EnableKioskAutoLaunchCallback& callback) {
129   policy::BrowserPolicyConnectorChromeOS* connector =
130       g_browser_process->platform_part()->browser_policy_connector_chromeos();
131   connector->GetInstallAttributes()->LockDevice(
132       std::string(),  // user
133       policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH,
134       std::string(),  // device_id
135       base::Bind(
136           &KioskAppManager::OnLockDevice, base::Unretained(this), callback));
137 }
138
139 void KioskAppManager::GetConsumerKioskAutoLaunchStatus(
140     const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback& callback) {
141   policy::BrowserPolicyConnectorChromeOS* connector =
142       g_browser_process->platform_part()->browser_policy_connector_chromeos();
143   connector->GetInstallAttributes()->ReadImmutableAttributes(
144       base::Bind(&KioskAppManager::OnReadImmutableAttributes,
145                  base::Unretained(this),
146                  callback));
147 }
148
149 bool KioskAppManager::IsConsumerKioskDeviceWithAutoLaunch() {
150   policy::BrowserPolicyConnectorChromeOS* connector =
151       g_browser_process->platform_part()->browser_policy_connector_chromeos();
152   return connector->GetInstallAttributes() &&
153          connector->GetInstallAttributes()
154              ->IsConsumerKioskDeviceWithAutoLaunch();
155 }
156
157 void KioskAppManager::OnLockDevice(
158     const KioskAppManager::EnableKioskAutoLaunchCallback& callback,
159     policy::EnterpriseInstallAttributes::LockResult result) {
160   if (callback.is_null())
161     return;
162
163   callback.Run(result == policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
164 }
165
166 void KioskAppManager::OnOwnerFileChecked(
167     const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback& callback,
168     bool* owner_present) {
169   ownership_established_ = *owner_present;
170
171   if (callback.is_null())
172     return;
173
174   // If we have owner already established on the machine, don't let
175   // consumer kiosk to be enabled.
176   if (ownership_established_)
177     callback.Run(CONSUMER_KIOSK_AUTO_LAUNCH_DISABLED);
178   else
179     callback.Run(CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE);
180 }
181
182 void KioskAppManager::OnReadImmutableAttributes(
183     const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback&
184         callback) {
185   if (callback.is_null())
186     return;
187
188   ConsumerKioskAutoLaunchStatus status =
189       CONSUMER_KIOSK_AUTO_LAUNCH_DISABLED;
190   policy::BrowserPolicyConnectorChromeOS* connector =
191       g_browser_process->platform_part()->browser_policy_connector_chromeos();
192   policy::EnterpriseInstallAttributes* attributes =
193       connector->GetInstallAttributes();
194   switch (attributes->GetMode()) {
195     case policy::DEVICE_MODE_NOT_SET: {
196       if (!base::SysInfo::IsRunningOnChromeOS()) {
197         status = CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE;
198       } else if (!ownership_established_) {
199         bool* owner_present = new bool(false);
200         content::BrowserThread::PostBlockingPoolTaskAndReply(
201             FROM_HERE,
202             base::Bind(&CheckOwnerFilePresence,
203                        owner_present),
204             base::Bind(&KioskAppManager::OnOwnerFileChecked,
205                        base::Unretained(this),
206                        callback,
207                        base::Owned(owner_present)));
208         return;
209       }
210       break;
211     }
212     case policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
213       status = CONSUMER_KIOSK_AUTO_LAUNCH_ENABLED;
214       break;
215     default:
216       break;
217   }
218
219   callback.Run(status);
220 }
221
222 void KioskAppManager::SetEnableAutoLaunch(bool value) {
223   SetAutoLoginState(value ? AUTOLOGIN_APPROVED : AUTOLOGIN_REJECTED);
224 }
225
226 bool KioskAppManager::IsAutoLaunchRequested() const {
227   if (GetAutoLaunchApp().empty())
228     return false;
229
230   // Apps that were installed by the policy don't require machine owner
231   // consent through UI.
232   policy::BrowserPolicyConnectorChromeOS* connector =
233       g_browser_process->platform_part()->browser_policy_connector_chromeos();
234   if (connector->IsEnterpriseManaged())
235     return false;
236
237   return GetAutoLoginState() == AUTOLOGIN_REQUESTED;
238 }
239
240 bool KioskAppManager::IsAutoLaunchEnabled() const {
241   if (GetAutoLaunchApp().empty())
242     return false;
243
244   // Apps that were installed by the policy don't require machine owner
245   // consent through UI.
246   policy::BrowserPolicyConnectorChromeOS* connector =
247       g_browser_process->platform_part()->browser_policy_connector_chromeos();
248   if (connector->IsEnterpriseManaged())
249     return true;
250
251   return GetAutoLoginState() == AUTOLOGIN_APPROVED;
252 }
253
254 void KioskAppManager::AddApp(const std::string& app_id) {
255   std::vector<policy::DeviceLocalAccount> device_local_accounts =
256       policy::GetDeviceLocalAccounts(CrosSettings::Get());
257
258   // Don't insert the app if it's already in the list.
259   for (std::vector<policy::DeviceLocalAccount>::const_iterator
260            it = device_local_accounts.begin();
261        it != device_local_accounts.end(); ++it) {
262     if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
263         it->kiosk_app_id == app_id) {
264       return;
265     }
266   }
267
268   // Add the new account.
269   device_local_accounts.push_back(policy::DeviceLocalAccount(
270       policy::DeviceLocalAccount::TYPE_KIOSK_APP,
271       GenerateKioskAppAccountId(app_id),
272       app_id));
273
274   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
275 }
276
277 void KioskAppManager::RemoveApp(const std::string& app_id) {
278   // Resets auto launch app if it is the removed app.
279   if (auto_launch_app_id_ == app_id)
280     SetAutoLaunchApp(std::string());
281
282   std::vector<policy::DeviceLocalAccount> device_local_accounts =
283       policy::GetDeviceLocalAccounts(CrosSettings::Get());
284   if (device_local_accounts.empty())
285     return;
286
287   // Remove entries that match |app_id|.
288   for (std::vector<policy::DeviceLocalAccount>::iterator
289            it = device_local_accounts.begin();
290        it != device_local_accounts.end(); ++it) {
291     if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
292         it->kiosk_app_id == app_id) {
293       device_local_accounts.erase(it);
294       break;
295     }
296   }
297
298   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
299 }
300
301 void KioskAppManager::GetApps(Apps* apps) const {
302   apps->clear();
303   apps->reserve(apps_.size());
304   for (size_t i = 0; i < apps_.size(); ++i) {
305     const KioskAppData& app_data = *apps_[i];
306     if (app_data.status() != KioskAppData::STATUS_ERROR)
307       apps->push_back(App(
308           app_data, external_cache_->IsExtensionPending(app_data.app_id())));
309   }
310 }
311
312 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const {
313   const KioskAppData* data = GetAppData(app_id);
314   if (!data)
315     return false;
316
317   *app = App(*data, external_cache_->IsExtensionPending(app_id));
318   return true;
319 }
320
321 const base::RefCountedString* KioskAppManager::GetAppRawIcon(
322     const std::string& app_id) const {
323   const KioskAppData* data = GetAppData(app_id);
324   if (!data)
325     return NULL;
326
327   return data->raw_icon();
328 }
329
330 bool KioskAppManager::GetDisableBailoutShortcut() const {
331   bool enable;
332   if (CrosSettings::Get()->GetBoolean(
333           kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) {
334     return !enable;
335   }
336
337   return false;
338 }
339
340 void KioskAppManager::ClearAppData(const std::string& app_id) {
341   KioskAppData* app_data = GetAppDataMutable(app_id);
342   if (!app_data)
343     return;
344
345   app_data->ClearCache();
346 }
347
348 void KioskAppManager::UpdateAppDataFromProfile(
349     const std::string& app_id,
350     Profile* profile,
351     const extensions::Extension* app) {
352   KioskAppData* app_data = GetAppDataMutable(app_id);
353   if (!app_data)
354     return;
355
356   app_data->LoadFromInstalledApp(profile, app);
357 }
358
359 void KioskAppManager::RetryFailedAppDataFetch() {
360   for (size_t i = 0; i < apps_.size(); ++i) {
361     if (apps_[i]->status() == KioskAppData::STATUS_ERROR)
362       apps_[i]->Load();
363   }
364 }
365
366 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) {
367   observers_.AddObserver(observer);
368 }
369
370 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) {
371   observers_.RemoveObserver(observer);
372 }
373
374 KioskAppManager::KioskAppManager() : ownership_established_(false) {
375   base::FilePath cache_dir;
376   GetCrxCacheDir(&cache_dir);
377   external_cache_.reset(
378       new ExternalCache(cache_dir,
379                         g_browser_process->system_request_context(),
380                         GetBackgroundTaskRunner(),
381                         this,
382                         true /* always_check_updates */,
383                         false /* wait_for_cache_initialization */));
384
385   UpdateAppData();
386   local_accounts_subscription_ =
387       CrosSettings::Get()->AddSettingsObserver(
388           kAccountsPrefDeviceLocalAccounts,
389           base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
390   local_account_auto_login_id_subscription_ =
391       CrosSettings::Get()->AddSettingsObserver(
392           kAccountsPrefDeviceLocalAccountAutoLoginId,
393           base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
394 }
395
396 KioskAppManager::~KioskAppManager() {}
397
398 void KioskAppManager::CleanUp() {
399   local_accounts_subscription_.reset();
400   local_account_auto_login_id_subscription_.reset();
401   apps_.clear();
402   external_cache_.reset();
403 }
404
405 const KioskAppData* KioskAppManager::GetAppData(
406     const std::string& app_id) const {
407   for (size_t i = 0; i < apps_.size(); ++i) {
408     const KioskAppData* data = apps_[i];
409     if (data->app_id() == app_id)
410       return data;
411   }
412
413   return NULL;
414 }
415
416 KioskAppData* KioskAppManager::GetAppDataMutable(const std::string& app_id) {
417   return const_cast<KioskAppData*>(GetAppData(app_id));
418 }
419
420 void KioskAppManager::UpdateAppData() {
421   // Gets app id to data mapping for existing apps.
422   std::map<std::string, KioskAppData*> old_apps;
423   for (size_t i = 0; i < apps_.size(); ++i)
424     old_apps[apps_[i]->app_id()] = apps_[i];
425   apps_.weak_clear();  // |old_apps| takes ownership
426
427   auto_launch_app_id_.clear();
428   std::string auto_login_account_id;
429   CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
430                                  &auto_login_account_id);
431
432   // Re-populates |apps_| and reuses existing KioskAppData when possible.
433   const std::vector<policy::DeviceLocalAccount> device_local_accounts =
434       policy::GetDeviceLocalAccounts(CrosSettings::Get());
435   for (std::vector<policy::DeviceLocalAccount>::const_iterator
436            it = device_local_accounts.begin();
437        it != device_local_accounts.end(); ++it) {
438     if (it->type != policy::DeviceLocalAccount::TYPE_KIOSK_APP)
439       continue;
440
441     if (it->account_id == auto_login_account_id)
442       auto_launch_app_id_ = it->kiosk_app_id;
443
444     // TODO(mnissler): Support non-CWS update URLs.
445
446     std::map<std::string, KioskAppData*>::iterator old_it =
447         old_apps.find(it->kiosk_app_id);
448     if (old_it != old_apps.end()) {
449       apps_.push_back(old_it->second);
450       old_apps.erase(old_it);
451     } else {
452       KioskAppData* new_app =
453           new KioskAppData(this, it->kiosk_app_id, it->user_id);
454       apps_.push_back(new_app);  // Takes ownership of |new_app|.
455       new_app->Load();
456     }
457   }
458
459   // Clears cache and deletes the remaining old data.
460   std::vector<std::string> apps_to_remove;
461   for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin();
462        it != old_apps.end(); ++it) {
463     it->second->ClearCache();
464     cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
465         it->second->user_id(),
466         base::Bind(&OnRemoveAppCryptohomeComplete, it->first));
467     apps_to_remove.push_back(it->second->app_id());
468   }
469   STLDeleteValues(&old_apps);
470   external_cache_->RemoveExtensions(apps_to_remove);
471
472   // Request external_cache_ to download new apps and update the existing
473   // apps.
474   scoped_ptr<base::DictionaryValue> prefs(new base::DictionaryValue);
475   for (size_t i = 0; i < apps_.size(); ++i)
476     prefs->Set(apps_[i]->app_id(), new base::DictionaryValue);
477   external_cache_->UpdateExtensionsList(prefs.Pass());
478
479   RetryFailedAppDataFetch();
480
481   FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_,
482                     OnKioskAppsSettingsChanged());
483 }
484
485 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) {
486   base::FilePath user_data_dir;
487   CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
488   *cache_dir = user_data_dir.AppendASCII(kIconCacheDir);
489 }
490
491 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) {
492   FOR_EACH_OBSERVER(KioskAppManagerObserver,
493                     observers_,
494                     OnKioskAppDataChanged(app_id));
495 }
496
497 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) {
498   FOR_EACH_OBSERVER(KioskAppManagerObserver,
499                     observers_,
500                     OnKioskAppDataLoadFailure(app_id));
501 }
502
503 void KioskAppManager::OnExtensionListsUpdated(
504     const base::DictionaryValue* prefs) {
505 }
506
507 void KioskAppManager::OnExtensionLoadedInCache(const std::string& id) {
508   KioskAppData* app_data = GetAppDataMutable(id);
509   if (!app_data)
510     return;
511   OnKioskAppDataChanged(id);
512 }
513
514 void KioskAppManager::OnExtensionDownloadFailed(
515     const std::string& id,
516     extensions::ExtensionDownloaderDelegate::Error error) {
517   KioskAppData* app_data = GetAppDataMutable(id);
518   if (!app_data)
519     return;
520   OnKioskAppDataLoadFailure(id);
521 }
522
523 KioskAppManager::AutoLoginState KioskAppManager::GetAutoLoginState() const {
524   PrefService* prefs = g_browser_process->local_state();
525   const base::DictionaryValue* dict =
526       prefs->GetDictionary(KioskAppManager::kKioskDictionaryName);
527   int value;
528   if (!dict->GetInteger(kKeyAutoLoginState, &value))
529     return AUTOLOGIN_NONE;
530
531   return static_cast<AutoLoginState>(value);
532 }
533
534 void KioskAppManager::SetAutoLoginState(AutoLoginState state) {
535   PrefService* prefs = g_browser_process->local_state();
536   DictionaryPrefUpdate dict_update(prefs,
537                                    KioskAppManager::kKioskDictionaryName);
538   dict_update->SetInteger(kKeyAutoLoginState, state);
539   prefs->CommitPendingWrite();
540 }
541
542 void KioskAppManager::GetCrxCacheDir(base::FilePath* cache_dir) {
543   base::FilePath user_data_dir;
544   CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
545   *cache_dir = user_data_dir.AppendASCII(kCrxCacheDir);
546 }
547
548 bool KioskAppManager::GetCachedCrx(const std::string& app_id,
549                                    base::FilePath* file_path,
550                                    std::string* version) {
551   return external_cache_->GetExtension(app_id, file_path, version);
552 }
553
554 }  // namespace chromeos