1f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// found in the LICENSE file.
4f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
5f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/schema_map.h"
6f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h"
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "base/values.h"
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_bundle.h"
10f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "components/policy/core/common/policy_map.h"
11f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
12f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)namespace policy {
13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SchemaMap::SchemaMap() {}
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SchemaMap::SchemaMap(DomainMap& map) {
17f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  map_.swap(map);
18f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
19f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)SchemaMap::~SchemaMap() {}
21f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
22f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const DomainMap& SchemaMap::GetDomains() const {
23f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return map_;
24f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
25f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
26f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const ComponentMap* SchemaMap::GetComponents(PolicyDomain domain) const {
27f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  DomainMap::const_iterator it = map_.find(domain);
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return it == map_.end() ? NULL : &it->second;
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
30f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
31f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)const Schema* SchemaMap::GetSchema(const PolicyNamespace& ns) const {
32f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  const ComponentMap* map = GetComponents(ns.domain);
33f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!map)
34f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return NULL;
35f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ComponentMap::const_iterator it = map->find(ns.component_id);
36f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return it == map->end() ? NULL : &it->second;
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
38f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
39f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void SchemaMap::FilterBundle(PolicyBundle* bundle) const {
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (PolicyBundle::iterator it = bundle->begin(); it != bundle->end(); ++it) {
41f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Chrome policies are not filtered, so that typos appear in about:policy.
42f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Everything else gets filtered, so that components only see valid policy.
43f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (it->first.domain == POLICY_DOMAIN_CHROME)
44f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      continue;
45f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const Schema* schema = GetSchema(it->first);
47f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
48f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!schema) {
49f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      it->second->Clear();
50f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      continue;
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
53f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // TODO(joaodasilva): if a component is registered but doesn't have a schema
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // then its policies aren't filtered. This behavior is enabled to allow a
55f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // graceful update of the Legacy Browser Support extension; it'll be removed
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // in a future release. http://crbug.com/240704
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    static const char kLegacyBrowserSupportExtensionId[] =
58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        "heildphpnddilhkemkielfhnkaagiabh";
59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (it->first.domain == POLICY_DOMAIN_EXTENSIONS &&
60116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        it->first.component_id == kLegacyBrowserSupportExtensionId) {
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      continue;
62116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
63116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!schema->valid()) {
65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      // Don't serve unknown policies.
66116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      it->second->Clear();
67116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      continue;
68116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
69f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
70f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PolicyMap* map = it->second;
71f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for (PolicyMap::const_iterator it_map = map->begin();
72f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         it_map != map->end();) {
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const std::string& policy_name = it_map->first;
74f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      const base::Value* policy_value = it_map->second.value;
75f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      Schema policy_schema = schema->GetProperty(policy_name);
76f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      ++it_map;
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::string error_path;
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      std::string error;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!policy_value ||
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          !policy_schema.Validate(*policy_value,
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  SCHEMA_STRICT,
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  &error_path,
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  &error)) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        LOG(ERROR) << "Dropping policy " << policy_name << " for "
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   << it->first.component_id
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   << " because it's not valid: " << error
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                   << " at " << error_path;
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        map->Erase(policy_name);
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)bool SchemaMap::HasComponents() const {
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (DomainMap::const_iterator domain = map_.begin();
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       domain != map_.end(); ++domain) {
97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (domain->first == POLICY_DOMAIN_CHROME)
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      continue;
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if (!domain->second.empty())
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      return true;
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return false;
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void SchemaMap::GetChanges(const scoped_refptr<SchemaMap>& older,
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           PolicyNamespaceList* removed,
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                           PolicyNamespaceList* added) const {
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  GetNamespacesNotInOther(older.get(), added);
109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  older->GetNamespacesNotInOther(this, removed);
110f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
111f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)void SchemaMap::GetNamespacesNotInOther(const SchemaMap* other,
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                        PolicyNamespaceList* list) const {
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  list->clear();
115f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  for (DomainMap::const_iterator domain = map_.begin();
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)       domain != map_.end(); ++domain) {
117f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    const ComponentMap& components = domain->second;
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for (ComponentMap::const_iterator comp = components.begin();
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         comp != components.end(); ++comp) {
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      PolicyNamespace ns(domain->first, comp->first);
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if (!other->GetSchema(ns))
122f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        list->push_back(ns);
123f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  }
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)}  // namespace policy
128