1// Copyright 2014 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/policy/device_local_account_extension_tracker.h"
6
7#include "base/logging.h"
8#include "base/prefs/pref_value_map.h"
9#include "base/values.h"
10#include "chrome/browser/chromeos/policy/device_local_account.h"
11#include "chrome/browser/extensions/policy_handlers.h"
12#include "components/policy/core/common/policy_map.h"
13#include "components/policy/core/common/policy_namespace.h"
14#include "components/policy/core/common/schema.h"
15#include "components/policy/core/common/schema_registry.h"
16#include "extensions/browser/pref_names.h"
17
18namespace policy {
19
20DeviceLocalAccountExtensionTracker::DeviceLocalAccountExtensionTracker(
21    const DeviceLocalAccount& account,
22    CloudPolicyStore* store,
23    SchemaRegistry* schema_registry)
24    : store_(store),
25      schema_registry_(schema_registry) {
26  if (account.type == DeviceLocalAccount::TYPE_KIOSK_APP) {
27    // This is easy: Just add a component for the app id.
28    PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, account.kiosk_app_id);
29    schema_registry_->RegisterComponent(ns, Schema());
30  } else if (account.type == DeviceLocalAccount::TYPE_PUBLIC_SESSION) {
31    // For public sessions, track the value of the ExtensionInstallForcelist
32    // policy.
33    store_->AddObserver(this);
34    UpdateFromStore();
35  } else {
36    NOTREACHED();
37  }
38
39  schema_registry_->SetReady(POLICY_DOMAIN_EXTENSIONS);
40}
41
42DeviceLocalAccountExtensionTracker::~DeviceLocalAccountExtensionTracker() {
43  store_->RemoveObserver(this);
44}
45
46void DeviceLocalAccountExtensionTracker::OnStoreLoaded(
47    CloudPolicyStore* store) {
48  UpdateFromStore();
49}
50
51void DeviceLocalAccountExtensionTracker::OnStoreError(CloudPolicyStore* store) {
52  UpdateFromStore();
53}
54
55void DeviceLocalAccountExtensionTracker::UpdateFromStore() {
56  const policy::PolicyMap& policy_map = store_->policy_map();
57
58  // TODO(binjin): Use two policy handlers here after
59  // ExtensionManagementPolicyHandler is introduced.
60  extensions::ExtensionInstallForcelistPolicyHandler policy_handler;
61  if (!policy_handler.CheckPolicySettings(policy_map, NULL))
62    return;
63
64  PrefValueMap pref_value_map;
65  policy_handler.ApplyPolicySettings(policy_map, &pref_value_map);
66
67  const base::Value* value = NULL;
68  const base::DictionaryValue* dict = NULL;
69  if (!pref_value_map.GetValue(extensions::pref_names::kInstallForceList,
70                               &value) ||
71      !value->GetAsDictionary(&dict)) {
72    return;
73  }
74
75  for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd(); it.Advance()) {
76    PolicyNamespace ns(POLICY_DOMAIN_EXTENSIONS, it.key());
77    schema_registry_->RegisterComponent(ns, Schema());
78  }
79
80  // Removing an extension from a public session at runtime can happen but is
81  // a rare event. In that case we leave the extension ID in the SchemaRegistry,
82  // and it will be purged on the next restart.
83}
84
85}  // namespace policy
86