- add sources.
[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/device_local_account.h"
23 #include "chrome/browser/chromeos/settings/cros_settings.h"
24 #include "chrome/browser/chromeos/settings/owner_key_util.h"
25 #include "chrome/browser/policy/browser_policy_connector.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::EnableConsumerModeKiosk(
116     const KioskAppManager::EnableKioskModeCallback& callback) {
117   g_browser_process->browser_policy_connector()->GetInstallAttributes()->
118       LockDevice(std::string(),  // user
119                  policy::DEVICE_MODE_CONSUMER_KIOSK,
120                  std::string(),  // device_id
121                  base::Bind(&KioskAppManager::OnLockDevice,
122                             base::Unretained(this),
123                             callback));
124 }
125
126 void KioskAppManager::GetConsumerKioskModeStatus(
127     const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
128   g_browser_process->browser_policy_connector()->GetInstallAttributes()->
129       ReadImmutableAttributes(
130           base::Bind(&KioskAppManager::OnReadImmutableAttributes,
131                      base::Unretained(this),
132                      callback));
133 }
134
135 void KioskAppManager::OnLockDevice(
136     const KioskAppManager::EnableKioskModeCallback& callback,
137     policy::EnterpriseInstallAttributes::LockResult result) {
138   if (callback.is_null())
139     return;
140
141   callback.Run(result == policy::EnterpriseInstallAttributes::LOCK_SUCCESS);
142 }
143
144 void KioskAppManager::OnOwnerFileChecked(
145     const KioskAppManager::GetConsumerKioskModeStatusCallback& callback,
146     bool* owner_present) {
147   ownership_established_ = *owner_present;
148
149   if (callback.is_null())
150     return;
151
152   // If we have owner already established on the machine, don't let
153   // consumer kiosk to be enabled.
154   if (ownership_established_)
155     callback.Run(CONSUMER_KIOSK_MODE_DISABLED);
156   else
157     callback.Run(CONSUMER_KIOSK_MODE_CONFIGURABLE);
158 }
159
160 void KioskAppManager::OnReadImmutableAttributes(
161     const KioskAppManager::GetConsumerKioskModeStatusCallback& callback) {
162   if (callback.is_null())
163     return;
164
165   ConsumerKioskModeStatus status = CONSUMER_KIOSK_MODE_DISABLED;
166   policy::EnterpriseInstallAttributes* attributes =
167       g_browser_process->browser_policy_connector()->GetInstallAttributes();
168   switch (attributes->GetMode()) {
169     case policy::DEVICE_MODE_NOT_SET: {
170       if (!base::SysInfo::IsRunningOnChromeOS()) {
171         status = CONSUMER_KIOSK_MODE_CONFIGURABLE;
172       } else if (!ownership_established_) {
173         bool* owner_present = new bool(false);
174         content::BrowserThread::PostBlockingPoolTaskAndReply(
175             FROM_HERE,
176             base::Bind(&CheckOwnerFilePresence,
177                        owner_present),
178             base::Bind(&KioskAppManager::OnOwnerFileChecked,
179                        base::Unretained(this),
180                        callback,
181                        base::Owned(owner_present)));
182         return;
183       }
184       break;
185     }
186     case policy::DEVICE_MODE_CONSUMER_KIOSK:
187       status = CONSUMER_KIOSK_MODE_ENABLED;
188       break;
189     default:
190       break;
191   }
192
193   callback.Run(status);
194 }
195
196 void KioskAppManager::SetEnableAutoLaunch(bool value) {
197   SetAutoLoginState(value ? AUTOLOGIN_APPROVED : AUTOLOGIN_REJECTED);
198 }
199
200 bool KioskAppManager::IsAutoLaunchRequested() const {
201   if (GetAutoLaunchApp().empty())
202     return false;
203
204   // Apps that were installed by the policy don't require machine owner
205   // consent through UI.
206   if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged())
207     return false;
208
209   return GetAutoLoginState() == AUTOLOGIN_REQUESTED;
210 }
211
212 bool KioskAppManager::IsAutoLaunchEnabled() const {
213   if (GetAutoLaunchApp().empty())
214     return false;
215
216   // Apps that were installed by the policy don't require machine owner
217   // consent through UI.
218   if (g_browser_process->browser_policy_connector()->IsEnterpriseManaged())
219     return true;
220
221   return GetAutoLoginState() == AUTOLOGIN_APPROVED;
222 }
223
224 void KioskAppManager::AddApp(const std::string& app_id) {
225   std::vector<policy::DeviceLocalAccount> device_local_accounts =
226       policy::GetDeviceLocalAccounts(CrosSettings::Get());
227
228   // Don't insert the app if it's already in the list.
229   for (std::vector<policy::DeviceLocalAccount>::const_iterator
230            it = device_local_accounts.begin();
231        it != device_local_accounts.end(); ++it) {
232     if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
233         it->kiosk_app_id == app_id) {
234       return;
235     }
236   }
237
238   // Add the new account.
239   device_local_accounts.push_back(policy::DeviceLocalAccount(
240       policy::DeviceLocalAccount::TYPE_KIOSK_APP,
241       GenerateKioskAppAccountId(app_id),
242       app_id));
243
244   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
245 }
246
247 void KioskAppManager::RemoveApp(const std::string& app_id) {
248   // Resets auto launch app if it is the removed app.
249   if (auto_launch_app_id_ == app_id)
250     SetAutoLaunchApp(std::string());
251
252   std::vector<policy::DeviceLocalAccount> device_local_accounts =
253       policy::GetDeviceLocalAccounts(CrosSettings::Get());
254   if (device_local_accounts.empty())
255     return;
256
257   // Remove entries that match |app_id|.
258   for (std::vector<policy::DeviceLocalAccount>::iterator
259            it = device_local_accounts.begin();
260        it != device_local_accounts.end(); ++it) {
261     if (it->type == policy::DeviceLocalAccount::TYPE_KIOSK_APP &&
262         it->kiosk_app_id == app_id) {
263       device_local_accounts.erase(it);
264       break;
265     }
266   }
267
268   policy::SetDeviceLocalAccounts(CrosSettings::Get(), device_local_accounts);
269 }
270
271 void KioskAppManager::GetApps(Apps* apps) const {
272   apps->reserve(apps_.size());
273   for (size_t i = 0; i < apps_.size(); ++i)
274     apps->push_back(App(*apps_[i]));
275 }
276
277 bool KioskAppManager::GetApp(const std::string& app_id, App* app) const {
278   const KioskAppData* data = GetAppData(app_id);
279   if (!data)
280     return false;
281
282   *app = App(*data);
283   return true;
284 }
285
286 const base::RefCountedString* KioskAppManager::GetAppRawIcon(
287     const std::string& app_id) const {
288   const KioskAppData* data = GetAppData(app_id);
289   if (!data)
290     return NULL;
291
292   return data->raw_icon();
293 }
294
295 bool KioskAppManager::GetDisableBailoutShortcut() const {
296   bool enable;
297   if (CrosSettings::Get()->GetBoolean(
298           kAccountsPrefDeviceLocalAccountAutoLoginBailoutEnabled, &enable)) {
299     return !enable;
300   }
301
302   return false;
303 }
304
305 void KioskAppManager::AddObserver(KioskAppManagerObserver* observer) {
306   observers_.AddObserver(observer);
307 }
308
309 void KioskAppManager::RemoveObserver(KioskAppManagerObserver* observer) {
310   observers_.RemoveObserver(observer);
311 }
312
313 KioskAppManager::KioskAppManager() : ownership_established_(false) {
314   UpdateAppData();
315   local_accounts_subscription_ =
316       CrosSettings::Get()->AddSettingsObserver(
317           kAccountsPrefDeviceLocalAccounts,
318           base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
319   local_account_auto_login_id_subscription_ =
320       CrosSettings::Get()->AddSettingsObserver(
321           kAccountsPrefDeviceLocalAccountAutoLoginId,
322           base::Bind(&KioskAppManager::UpdateAppData, base::Unretained(this)));
323 }
324
325 KioskAppManager::~KioskAppManager() {}
326
327 void KioskAppManager::CleanUp() {
328   local_accounts_subscription_.reset();
329   local_account_auto_login_id_subscription_.reset();
330   apps_.clear();
331 }
332
333 const KioskAppData* KioskAppManager::GetAppData(
334     const std::string& app_id) const {
335   for (size_t i = 0; i < apps_.size(); ++i) {
336     const KioskAppData* data = apps_[i];
337     if (data->app_id() == app_id)
338       return data;
339   }
340
341   return NULL;
342 }
343
344 void KioskAppManager::UpdateAppData() {
345   // Gets app id to data mapping for existing apps.
346   std::map<std::string, KioskAppData*> old_apps;
347   for (size_t i = 0; i < apps_.size(); ++i)
348     old_apps[apps_[i]->app_id()] = apps_[i];
349   apps_.weak_clear();  // |old_apps| takes ownership
350
351   auto_launch_app_id_.clear();
352   std::string auto_login_account_id;
353   CrosSettings::Get()->GetString(kAccountsPrefDeviceLocalAccountAutoLoginId,
354                                  &auto_login_account_id);
355
356   // Re-populates |apps_| and reuses existing KioskAppData when possible.
357   const std::vector<policy::DeviceLocalAccount> device_local_accounts =
358       policy::GetDeviceLocalAccounts(CrosSettings::Get());
359   for (std::vector<policy::DeviceLocalAccount>::const_iterator
360            it = device_local_accounts.begin();
361        it != device_local_accounts.end(); ++it) {
362     if (it->type != policy::DeviceLocalAccount::TYPE_KIOSK_APP)
363       continue;
364
365     if (it->account_id == auto_login_account_id)
366       auto_launch_app_id_ = it->kiosk_app_id;
367
368     // TODO(mnissler): Support non-CWS update URLs.
369
370     std::map<std::string, KioskAppData*>::iterator old_it =
371         old_apps.find(it->kiosk_app_id);
372     if (old_it != old_apps.end()) {
373       apps_.push_back(old_it->second);
374       old_apps.erase(old_it);
375     } else {
376       KioskAppData* new_app =
377           new KioskAppData(this, it->kiosk_app_id, it->user_id);
378       apps_.push_back(new_app);  // Takes ownership of |new_app|.
379       new_app->Load();
380     }
381   }
382
383   // Clears cache and deletes the remaining old data.
384   for (std::map<std::string, KioskAppData*>::iterator it = old_apps.begin();
385        it != old_apps.end(); ++it) {
386     it->second->ClearCache();
387     cryptohome::AsyncMethodCaller::GetInstance()->AsyncRemove(
388         it->second->user_id(),
389         base::Bind(&OnRemoveAppCryptohomeComplete, it->first));
390   }
391   STLDeleteValues(&old_apps);
392
393   FOR_EACH_OBSERVER(KioskAppManagerObserver, observers_,
394                     OnKioskAppsSettingsChanged());
395 }
396
397 void KioskAppManager::GetKioskAppIconCacheDir(base::FilePath* cache_dir) {
398   base::FilePath user_data_dir;
399   CHECK(PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
400   *cache_dir = user_data_dir.AppendASCII(kIconCacheDir);
401 }
402
403 void KioskAppManager::OnKioskAppDataChanged(const std::string& app_id) {
404   FOR_EACH_OBSERVER(KioskAppManagerObserver,
405                     observers_,
406                     OnKioskAppDataChanged(app_id));
407 }
408
409 void KioskAppManager::OnKioskAppDataLoadFailure(const std::string& app_id) {
410   FOR_EACH_OBSERVER(KioskAppManagerObserver,
411                     observers_,
412                     OnKioskAppDataLoadFailure(app_id));
413   RemoveApp(app_id);
414 }
415
416 KioskAppManager::AutoLoginState KioskAppManager::GetAutoLoginState() const {
417   PrefService* prefs = g_browser_process->local_state();
418   const base::DictionaryValue* dict =
419       prefs->GetDictionary(KioskAppManager::kKioskDictionaryName);
420   int value;
421   if (!dict->GetInteger(kKeyAutoLoginState, &value))
422     return AUTOLOGIN_NONE;
423
424   return static_cast<AutoLoginState>(value);
425 }
426
427 void KioskAppManager::SetAutoLoginState(AutoLoginState state) {
428   PrefService* prefs = g_browser_process->local_state();
429   DictionaryPrefUpdate dict_update(prefs,
430                                    KioskAppManager::kKioskDictionaryName);
431   dict_update->SetInteger(kKeyAutoLoginState, state);
432   prefs->CommitPendingWrite();
433 }
434
435 }  // namespace chromeos