Upstream version 6.35.121.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/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"
30
31 namespace chromeos {
32
33 namespace {
34
35 // Domain that is used for kiosk-app account IDs.
36 const char kKioskAppAccountDomain[] = "kiosk-apps";
37
38 std::string GenerateKioskAppAccountId(const std::string& app_id) {
39   return app_id + '@' + kKioskAppAccountDomain;
40 }
41
42 void OnRemoveAppCryptohomeComplete(const std::string& app,
43                                    bool success,
44                                    cryptohome::MountError return_code) {
45   if (!success) {
46     LOG(ERROR) << "Remove cryptohome for " << app
47         << " failed, return code: " << return_code;
48   }
49 }
50
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();
55 }
56
57 }  // namespace
58
59 // static
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";
64
65 // static
66 static base::LazyInstance<KioskAppManager> instance = LAZY_INSTANCE_INITIALIZER;
67 KioskAppManager* KioskAppManager::Get() {
68   return instance.Pointer();
69 }
70
71 // static
72 void KioskAppManager::Shutdown() {
73   if (instance == NULL)
74     return;
75
76   instance.Pointer()->CleanUp();
77 }
78
79 // static
80 void KioskAppManager::RegisterPrefs(PrefRegistrySimple* registry) {
81   registry->RegisterDictionaryPref(kKioskDictionaryName);
82 }
83
84 KioskAppManager::App::App(const KioskAppData& data)
85     : app_id(data.app_id()),
86       user_id(data.user_id()),
87       name(data.name()),
88       icon(data.icon()),
89       is_loading(data.IsLoading()) {
90 }
91
92 KioskAppManager::App::App() : is_loading(false) {}
93 KioskAppManager::App::~App() {}
94
95 std::string KioskAppManager::GetAutoLaunchApp() const {
96   return auto_launch_app_id_;
97 }
98
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,
105                                    std::string());
106   }
107
108   CrosSettings::Get()->SetString(
109       kAccountsPrefDeviceLocalAccountAutoLoginId,
110       app_id.empty() ? std::string() : GenerateKioskAppAccountId(app_id));
111   CrosSettings::Get()->SetInteger(
112       kAccountsPrefDeviceLocalAccountAutoLoginDelay, 0);
113 }
114
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
123       base::Bind(
124           &KioskAppManager::OnLockDevice, base::Unretained(this), callback));
125 }
126
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),
134                  callback));
135 }
136
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();
143 }
144
145 void KioskAppManager::OnLockDevice(
146     const KioskAppManager::EnableKioskAutoLaunchCallback& callback,
147     policy::EnterpriseInstallAttributes::LockResult result) {
148   if (callback.is_null())
149     return;
150
151   callback.Run(result == policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
152 }
153
154 void KioskAppManager::OnOwnerFileChecked(
155     const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback& callback,
156     bool* owner_present) {
157   ownership_established_ = *owner_present;
158
159   if (callback.is_null())
160     return;
161
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);
166   else
167     callback.Run(CONSUMER_KIOSK_AUTO_LAUNCH_CONFIGURABLE);
168 }
169
170 void KioskAppManager::OnReadImmutableAttributes(
171     const KioskAppManager::GetConsumerKioskAutoLaunchStatusCallback&
172         callback) {
173   if (callback.is_null())
174     return;
175
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(
189             FROM_HERE,
190             base::Bind(&CheckOwnerFilePresence,
191                        owner_present),
192             base::Bind(&KioskAppManager::OnOwnerFileChecked,
193                        base::Unretained(this),
194                        callback,
195                        base::Owned(owner_present)));
196         return;
197       }
198       break;
199     }
200     case policy::DEVICE_MODE_CONSUMER_KIOSK_AUTOLAUNCH:
201       status = CONSUMER_KIOSK_AUTO_LAUNCH_ENABLED;
202       break;
203     default:
204       break;
205   }
206
207   callback.Run(status);
208 }
209
210 void KioskAppManager::SetEnableAutoLaunch(bool value) {
211   SetAutoLoginState(value ? AUTOLOGIN_APPROVED : AUTOLOGIN_REJECTED);
212 }
213
214 bool KioskAppManager::IsAutoLaunchRequested() const {
215   if (GetAutoLaunchApp().empty())
216     return false;
217
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())
223     return false;
224
225   return GetAutoLoginState() == AUTOLOGIN_REQUESTED;
226 }
227
228 bool KioskAppManager::IsAutoLaunchEnabled() const {
229   if (GetAutoLaunchApp().empty())
230     return false;
231
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())
237     return true;
238
239   return GetAutoLoginState() == AUTOLOGIN_APPROVED;
240 }
241
242 void KioskAppManager::AddApp(const std::string& app_id) {
243   std::vector<policy::DeviceLocalAccount> device_local_accounts =
244       policy::GetDeviceLocalAccounts(CrosSettings::Get());
245
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) {
252       return;
253     }
254   }
255
256   // Add the new account.
257   device_local_accounts.push_back(policy::DeviceLocalAccount(
258       policy::DeviceLocalAccount::TYPE_KIOSK_APP,
259       GenerateKioskAppAccountId(app_id),
260       app_id));
261
262   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
263 }
264
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());
269
270   std::vector<policy::DeviceLocalAccount> device_local_accounts =
271       policy::GetDeviceLocalAccounts(CrosSettings::Get());
272   if (device_local_accounts.empty())
273     return;
274
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);
282       break;
283     }
284   }
285
286   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
287 }
288
289 void KioskAppManager::GetApps(Apps* apps) const {
290   apps->clear();
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));
296   }
297 }
298
299 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const {
300   const KioskAppData* data = GetAppData(app_id);
301   if (!data)
302     return false;
303
304   *app = App(*data);
305   return true;
306 }
307
308 const base::RefCountedString* KioskAppManager::GetAppRawIcon(
309     const std::string& app_id) const {
310   const KioskAppData* data = GetAppData(app_id);
311   if (!data)
312     return NULL;
313
314   return data->raw_icon();
315 }
316
317 bool KioskAppManager::GetDisableBailoutShortcut() const {
318   bool enable;
319   if (CrosSettings::Get()->GetBoolean(
320           kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) {
321     return !enable;
322   }
323
324   return false;
325 }
326
327 void KioskAppManager::ClearAppData(const std::string& app_id) {
328   KioskAppData* app_data = GetAppDataMutable(app_id);
329   if (!app_data)
330     return;
331
332   app_data->ClearCache();
333 }
334
335 void KioskAppManager::UpdateAppDataFromProfile(
336     const std::string& app_id,
337     Profile* profile,
338     const extensions::Extension* app) {
339   KioskAppData* app_data = GetAppDataMutable(app_id);
340   if (!app_data)
341     return;
342
343   app_data->LoadFromInstalledApp(profile, app);
344 }
345
346 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) {
347   observers_.AddObserver(observer);
348 }
349
350 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) {
351   observers_.RemoveObserver(observer);
352 }
353
354 KioskAppManager::KioskAppManager() : ownership_established_(false) {
355   UpdateAppData();
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)));
364 }
365
366 KioskAppManager::~KioskAppManager() {}
367
368 void KioskAppManager::CleanUp() {
369   local_accounts_subscription_.reset();
370   local_account_auto_login_id_subscription_.reset();
371   apps_.clear();
372 }
373
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)
379       return data;
380   }
381
382   return NULL;
383 }
384
385 KioskAppData* KioskAppManager::GetAppDataMutable(const std::string& app_id) {
386   return const_cast<KioskAppData*>(GetAppData(app_id));
387 }
388
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
395
396   auto_launch_app_id_.clear();
397   std::string auto_login_account_id;
398   CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
399                                  &auto_login_account_id);
400
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)
408       continue;
409
410     if (it->account_id == auto_login_account_id)
411       auto_launch_app_id_ = it->kiosk_app_id;
412
413     // TODO(mnissler): Support non-CWS update URLs.
414
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);
420     } else {
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|.
424       new_app->Load();
425     }
426   }
427
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));
435   }
436   STLDeleteValues(&old_apps);
437
438   FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_,
439                     OnKioskAppsSettingsChanged());
440 }
441
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);
446 }
447
448 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) {
449   FOR_EACH_OBSERVER(KioskAppManagerObserver,
450                     observers_,
451                     OnKioskAppDataChanged(app_id));
452 }
453
454 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) {
455   FOR_EACH_OBSERVER(KioskAppManagerObserver,
456                     observers_,
457                     OnKioskAppDataLoadFailure(app_id));
458 }
459
460 KioskAppManager::AutoLoginState KioskAppManager::GetAutoLoginState() const {
461   PrefService* prefs = g_browser_process->local_state();
462   const base::DictionaryValue* dict =
463       prefs->GetDictionary(KioskAppManager::kKioskDictionaryName);
464   int value;
465   if (!dict->GetInteger(kKeyAutoLoginState, &value))
466     return AUTOLOGIN_NONE;
467
468   return static_cast<AutoLoginState>(value);
469 }
470
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();
477 }
478
479 }  // namespace chromeos