summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authordconnelly@chromium.org <dconnelly@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-22 11:48:57 +0000
committerdconnelly@chromium.org <dconnelly@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-22 11:48:57 +0000
commit3af8f808950710f6a054646f749e51526624eab5 (patch)
tree40a3295ecc045b9176bdc5ed98ccf51cd9c6dcdb /components
parent449c07370159f5e0899eb857de459656b3dfb3f2 (diff)
downloadchromium_src-3af8f808950710f6a054646f749e51526624eab5.zip
chromium_src-3af8f808950710f6a054646f749e51526624eab5.tar.gz
chromium_src-3af8f808950710f6a054646f749e51526624eab5.tar.bz2
Move PolicyBundle into components/policy/.
This facilitates the refactoring of chrome/browser/policy into a layered component. Depends on https://codereview.chromium.org/78763002/ BUG=271392 Review URL: https://codereview.chromium.org/78823004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236747 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components')
-rw-r--r--components/components_tests.gyp1
-rw-r--r--components/policy.gypi2
-rw-r--r--components/policy/core/common/external_data_manager.h3
-rw-r--r--components/policy/core/common/policy_bundle.cc110
-rw-r--r--components/policy/core/common/policy_bundle.h73
-rw-r--r--components/policy/core/common/policy_bundle_unittest.cc260
6 files changed, 448 insertions, 1 deletions
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index e8c9b89..96d1cd3 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -171,6 +171,7 @@
}],
['configuration_policy==1', {
'sources': [
+ 'policy/core/common/policy_bundle_unittest.cc',
'policy/core/common/policy_map_unittest.cc',
'policy/core/common/schema_unittest.cc',
],
diff --git a/components/policy.gypi b/components/policy.gypi
index 2ac51d8..9c2c34c 100644
--- a/components/policy.gypi
+++ b/components/policy.gypi
@@ -20,6 +20,8 @@
'conditions': [
['configuration_policy==1', {
'sources': [
+ 'policy/core/common/policy_bundle.cc',
+ 'policy/core/common/policy_bundle.h',
'policy/core/common/external_data_fetcher.cc',
'policy/core/common/external_data_fetcher.h',
'policy/core/common/external_data_manager.h',
diff --git a/components/policy/core/common/external_data_manager.h b/components/policy/core/common/external_data_manager.h
index fa69953..406cf59 100644
--- a/components/policy/core/common/external_data_manager.h
+++ b/components/policy/core/common/external_data_manager.h
@@ -8,6 +8,7 @@
#include <string>
#include "components/policy/core/common/external_data_fetcher.h"
+#include "components/policy/policy_export.h"
namespace policy {
@@ -16,7 +17,7 @@ namespace policy {
// An implementation of this abstract interface should be provided for each
// policy source (cloud policy, platform policy) that supports external data
// references.
-class ExternalDataManager {
+class POLICY_EXPORT ExternalDataManager {
public:
// Retrieves the external data referenced by |policy| and invokes |callback|
// with the result. If |policy| does not reference any external data, the
diff --git a/components/policy/core/common/policy_bundle.cc b/components/policy/core/common/policy_bundle.cc
new file mode 100644
index 0000000..96d7e82
--- /dev/null
+++ b/components/policy/core/common/policy_bundle.cc
@@ -0,0 +1,110 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/policy_bundle.h"
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+
+namespace policy {
+
+PolicyBundle::PolicyBundle() {}
+
+PolicyBundle::~PolicyBundle() {
+ Clear();
+}
+
+PolicyMap& PolicyBundle::Get(const PolicyNamespace& ns) {
+ DCHECK(ns.domain != POLICY_DOMAIN_CHROME || ns.component_id.empty());
+ PolicyMap*& policy = policy_bundle_[ns];
+ if (!policy)
+ policy = new PolicyMap();
+ return *policy;
+}
+
+const PolicyMap& PolicyBundle::Get(const PolicyNamespace& ns) const {
+ DCHECK(ns.domain != POLICY_DOMAIN_CHROME || ns.component_id.empty());
+ const_iterator it = policy_bundle_.find(ns);
+ return it == end() ? kEmpty_ : *it->second;
+}
+
+void PolicyBundle::Swap(PolicyBundle* other) {
+ policy_bundle_.swap(other->policy_bundle_);
+}
+
+void PolicyBundle::CopyFrom(const PolicyBundle& other) {
+ Clear();
+ for (PolicyBundle::const_iterator it = other.begin();
+ it != other.end(); ++it) {
+ policy_bundle_[it->first] = it->second->DeepCopy().release();
+ }
+}
+
+void PolicyBundle::MergeFrom(const PolicyBundle& other) {
+ // Iterate over both |this| and |other| in order; skip what's extra in |this|,
+ // add what's missing, and merge the namespaces in common.
+ MapType::iterator it_this = policy_bundle_.begin();
+ MapType::iterator end_this = policy_bundle_.end();
+ const_iterator it_other = other.begin();
+ const_iterator end_other = other.end();
+
+ while (it_this != end_this && it_other != end_other) {
+ if (it_this->first == it_other->first) {
+ // Same namespace: merge existing PolicyMaps.
+ it_this->second->MergeFrom(*it_other->second);
+ ++it_this;
+ ++it_other;
+ } else if (it_this->first < it_other->first) {
+ // |this| has a PolicyMap that |other| doesn't; skip it.
+ ++it_this;
+ } else if (it_other->first < it_this->first) {
+ // |other| has a PolicyMap that |this| doesn't; copy it.
+ PolicyMap*& policy = policy_bundle_[it_other->first];
+ DCHECK(!policy);
+ policy = it_other->second->DeepCopy().release();
+ ++it_other;
+ } else {
+ NOTREACHED();
+ }
+ }
+
+ // Add extra PolicyMaps at the end.
+ while (it_other != end_other) {
+ PolicyMap*& policy = policy_bundle_[it_other->first];
+ DCHECK(!policy);
+ policy = it_other->second->DeepCopy().release();
+ ++it_other;
+ }
+}
+
+bool PolicyBundle::Equals(const PolicyBundle& other) const {
+ // Equals() has the peculiarity that an entry with an empty PolicyMap equals
+ // an non-existant entry. This handles usage of non-const Get() that doesn't
+ // insert any policies.
+ const_iterator it_this = begin();
+ const_iterator it_other = other.begin();
+
+ while (true) {
+ // Skip empty PolicyMaps.
+ while (it_this != end() && it_this->second->empty())
+ ++it_this;
+ while (it_other != other.end() && it_other->second->empty())
+ ++it_other;
+ if (it_this == end() || it_other == other.end())
+ break;
+ if (it_this->first != it_other->first ||
+ !it_this->second->Equals(*it_other->second)) {
+ return false;
+ }
+ ++it_this;
+ ++it_other;
+ }
+ return it_this == end() && it_other == other.end();
+}
+
+void PolicyBundle::Clear() {
+ STLDeleteValues(&policy_bundle_);
+}
+
+} // namespace policy
diff --git a/components/policy/core/common/policy_bundle.h b/components/policy/core/common/policy_bundle.h
new file mode 100644
index 0000000..0266672
--- /dev/null
+++ b/components/policy/core/common/policy_bundle.h
@@ -0,0 +1,73 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_POLICY_CORE_COMMON_POLICY_BUNDLE_H_
+#define COMPONENTS_POLICY_CORE_COMMON_POLICY_BUNDLE_H_
+
+#include <map>
+#include <string>
+
+#include "base/basictypes.h"
+#include "components/policy/core/common/policy_map.h"
+#include "components/policy/core/common/policy_namespace.h"
+#include "components/policy/policy_export.h"
+
+namespace policy {
+
+// Maps policy namespaces to PolicyMaps.
+class POLICY_EXPORT PolicyBundle {
+ public:
+ typedef std::map<PolicyNamespace, PolicyMap*> MapType;
+ typedef MapType::iterator iterator;
+ typedef MapType::const_iterator const_iterator;
+
+ PolicyBundle();
+ virtual ~PolicyBundle();
+
+ // Returns the PolicyMap for namespace |ns|.
+ PolicyMap& Get(const PolicyNamespace& ns);
+ const PolicyMap& Get(const PolicyNamespace& ns) const;
+
+ // Swaps the internal representation of |this| with |other|.
+ void Swap(PolicyBundle* other);
+
+ // |this| becomes a copy of |other|. Any existing PolicyMaps are dropped.
+ void CopyFrom(const PolicyBundle& other);
+
+ // Merges the PolicyMaps of |this| with those of |other| for each namespace
+ // in common. Also adds copies of the (namespace, PolicyMap) pairs in |other|
+ // that don't have an entry in |this|.
+ // Each policy in each PolicyMap is replaced only if the policy from |other|
+ // has a higher priority.
+ // See PolicyMap::MergeFrom for details on merging individual PolicyMaps.
+ void MergeFrom(const PolicyBundle& other);
+
+ // Returns true if |other| has the same keys and value as |this|.
+ bool Equals(const PolicyBundle& other) const;
+
+ // Returns iterators to the beginning and end of the underlying container.
+ iterator begin() { return policy_bundle_.begin(); }
+ iterator end() { return policy_bundle_.end(); }
+
+ // These can be used to iterate over and read the PolicyMaps, but not to
+ // modify them.
+ const_iterator begin() const { return policy_bundle_.begin(); }
+ const_iterator end() const { return policy_bundle_.end(); }
+
+ // Erases all the existing pairs.
+ void Clear();
+
+ private:
+ MapType policy_bundle_;
+
+ // An empty PolicyMap that is returned by const Get() for namespaces that
+ // do not exist in |policy_bundle_|.
+ const PolicyMap kEmpty_;
+
+ DISALLOW_COPY_AND_ASSIGN(PolicyBundle);
+};
+
+} // namespace policy
+
+#endif // COMPONENTS_POLICY_CORE_COMMON_POLICY_BUNDLE_H_
diff --git a/components/policy/core/common/policy_bundle_unittest.cc b/components/policy/core/common/policy_bundle_unittest.cc
new file mode 100644
index 0000000..bafa25e
--- /dev/null
+++ b/components/policy/core/common/policy_bundle_unittest.cc
@@ -0,0 +1,260 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/policy/core/common/policy_bundle.h"
+
+#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "components/policy/core/common/external_data_fetcher.h"
+#include "components/policy/core/common/policy_map.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace policy {
+
+namespace {
+
+const char kPolicyClashing0[] = "policy-clashing-0";
+const char kPolicyClashing1[] = "policy-clashing-1";
+const char kPolicy0[] = "policy-0";
+const char kPolicy1[] = "policy-1";
+const char kPolicy2[] = "policy-2";
+const char kExtension0[] = "extension-0";
+const char kExtension1[] = "extension-1";
+const char kExtension2[] = "extension-2";
+const char kExtension3[] = "extension-3";
+
+// Adds test policies to |policy|.
+void AddTestPolicies(PolicyMap* policy) {
+ policy->Set("mandatory-user", POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER, base::Value::CreateIntegerValue(123), NULL);
+ policy->Set("mandatory-machine", POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+ base::Value::CreateStringValue("omg"), NULL);
+ policy->Set("recommended-user", POLICY_LEVEL_RECOMMENDED,
+ POLICY_SCOPE_USER, base::Value::CreateBooleanValue(true), NULL);
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetBoolean("false", false);
+ dict->SetInteger("int", 456);
+ dict->SetString("str", "bbq");
+ policy->Set("recommended-machine", POLICY_LEVEL_RECOMMENDED,
+ POLICY_SCOPE_MACHINE, dict, NULL);
+}
+
+// Adds test policies to |policy| based on the parameters:
+// - kPolicyClashing0 mapped to |value|, user mandatory
+// - kPolicyClashing1 mapped to |value|, with |level| and |scope|
+// - |name| mapped to |value|, user mandatory
+void AddTestPoliciesWithParams(PolicyMap *policy,
+ const char* name,
+ int value,
+ PolicyLevel level,
+ PolicyScope scope) {
+ policy->Set(kPolicyClashing0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(value), NULL);
+ policy->Set(kPolicyClashing1, level, scope,
+ base::Value::CreateIntegerValue(value), NULL);
+ policy->Set(name, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(value), NULL);
+}
+
+// Returns true if |bundle| is empty.
+bool IsEmpty(const PolicyBundle& bundle) {
+ return bundle.begin() == bundle.end();
+}
+
+} // namespace
+
+TEST(PolicyBundleTest, Get) {
+ PolicyBundle bundle;
+ EXPECT_TRUE(IsEmpty(bundle));
+
+ AddTestPolicies(&bundle.Get(
+ PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
+ EXPECT_FALSE(IsEmpty(bundle));
+
+ PolicyMap policy;
+ AddTestPolicies(&policy);
+ EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
+ std::string())).Equals(policy));
+
+ PolicyBundle::const_iterator it = bundle.begin();
+ ASSERT_TRUE(it != bundle.end());
+ EXPECT_EQ(POLICY_DOMAIN_CHROME, it->first.domain);
+ EXPECT_EQ("", it->first.component_id);
+ ASSERT_TRUE(it->second);
+ EXPECT_TRUE(it->second->Equals(policy));
+ ++it;
+ EXPECT_TRUE(it == bundle.end());
+ EXPECT_TRUE(bundle.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension0)).empty());
+
+ EXPECT_FALSE(IsEmpty(bundle));
+ bundle.Clear();
+ EXPECT_TRUE(IsEmpty(bundle));
+}
+
+TEST(PolicyBundleTest, SwapAndCopy) {
+ PolicyBundle bundle0;
+ PolicyBundle bundle1;
+
+ AddTestPolicies(&bundle0.Get(
+ PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
+ AddTestPolicies(&bundle0.Get(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)));
+ EXPECT_FALSE(IsEmpty(bundle0));
+ EXPECT_TRUE(IsEmpty(bundle1));
+
+ PolicyMap policy;
+ AddTestPolicies(&policy);
+ EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
+ std::string())).Equals(policy));
+ EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension0)).Equals(policy));
+
+ bundle0.Swap(&bundle1);
+ EXPECT_TRUE(IsEmpty(bundle0));
+ EXPECT_FALSE(IsEmpty(bundle1));
+
+ EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
+ std::string())).Equals(policy));
+ EXPECT_TRUE(bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension0)).Equals(policy));
+
+ bundle0.CopyFrom(bundle1);
+ EXPECT_FALSE(IsEmpty(bundle0));
+ EXPECT_FALSE(IsEmpty(bundle1));
+ EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
+ std::string())).Equals(policy));
+ EXPECT_TRUE(bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension0)).Equals(policy));
+}
+
+TEST(PolicyBundleTest, MergeFrom) {
+ // Each bundleN has kExtensionN. Each bundle also has policy for
+ // chrome and kExtension3.
+ // |bundle0| has the highest priority, |bundle2| the lowest.
+ PolicyBundle bundle0;
+ PolicyBundle bundle1;
+ PolicyBundle bundle2;
+
+ PolicyMap policy0;
+ AddTestPoliciesWithParams(
+ &policy0, kPolicy0, 0u, POLICY_LEVEL_RECOMMENDED, POLICY_SCOPE_USER);
+ bundle0.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .CopyFrom(policy0);
+ bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0))
+ .CopyFrom(policy0);
+ bundle0.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
+ .CopyFrom(policy0);
+
+ PolicyMap policy1;
+ AddTestPoliciesWithParams(
+ &policy1, kPolicy1, 1u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE);
+ bundle1.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .CopyFrom(policy1);
+ bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1))
+ .CopyFrom(policy1);
+ bundle1.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
+ .CopyFrom(policy1);
+
+ PolicyMap policy2;
+ AddTestPoliciesWithParams(
+ &policy2, kPolicy2, 2u, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER);
+ bundle2.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .CopyFrom(policy2);
+ bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2))
+ .CopyFrom(policy2);
+ bundle2.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension3))
+ .CopyFrom(policy2);
+
+ // Merge in order of decreasing priority.
+ PolicyBundle merged;
+ merged.MergeFrom(bundle0);
+ merged.MergeFrom(bundle1);
+ merged.MergeFrom(bundle2);
+ PolicyBundle empty_bundle;
+ merged.MergeFrom(empty_bundle);
+
+ // chrome and kExtension3 policies are merged:
+ // - kPolicyClashing0 comes from bundle0, which has the highest priority;
+ // - kPolicyClashing1 comes from bundle1, which has the highest level/scope
+ // combination;
+ // - kPolicyN are merged from each bundle.
+ PolicyMap expected;
+ expected.Set(kPolicyClashing0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(0), NULL);
+ expected.Set(kPolicyClashing1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_MACHINE,
+ base::Value::CreateIntegerValue(1), NULL);
+ expected.Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(0), NULL);
+ expected.Set(kPolicy1, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(1), NULL);
+ expected.Set(kPolicy2, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(2), NULL);
+ EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_CHROME,
+ std::string())).Equals(expected));
+ EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension3)).Equals(expected));
+ // extension0 comes only from bundle0.
+ EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension0)).Equals(policy0));
+ // extension1 comes only from bundle1.
+ EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension1)).Equals(policy1));
+ // extension2 comes only from bundle2.
+ EXPECT_TRUE(merged.Get(PolicyNamespace(POLICY_DOMAIN_EXTENSIONS,
+ kExtension2)).Equals(policy2));
+}
+
+TEST(PolicyBundleTest, Equals) {
+ PolicyBundle bundle;
+ AddTestPolicies(&bundle.Get(
+ PolicyNamespace(POLICY_DOMAIN_CHROME, std::string())));
+ AddTestPolicies(&bundle.Get(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension0)));
+
+ PolicyBundle other;
+ EXPECT_FALSE(bundle.Equals(other));
+ other.CopyFrom(bundle);
+ EXPECT_TRUE(bundle.Equals(other));
+
+ AddTestPolicies(&bundle.Get(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension1)));
+ EXPECT_FALSE(bundle.Equals(other));
+ other.CopyFrom(bundle);
+ EXPECT_TRUE(bundle.Equals(other));
+ AddTestPolicies(&other.Get(
+ PolicyNamespace(POLICY_DOMAIN_EXTENSIONS, kExtension2)));
+ EXPECT_FALSE(bundle.Equals(other));
+
+ other.CopyFrom(bundle);
+ bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .Set(kPolicy0,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(123),
+ NULL);
+ EXPECT_FALSE(bundle.Equals(other));
+ other.CopyFrom(bundle);
+ EXPECT_TRUE(bundle.Equals(other));
+ bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()))
+ .Set(kPolicy0,
+ POLICY_LEVEL_MANDATORY,
+ POLICY_SCOPE_MACHINE,
+ base::Value::CreateIntegerValue(123),
+ NULL);
+ EXPECT_FALSE(bundle.Equals(other));
+
+ // Test non-const Get().
+ bundle.Clear();
+ other.Clear();
+ PolicyMap& policy_map =
+ bundle.Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
+ EXPECT_TRUE(bundle.Equals(other));
+ policy_map.Set(kPolicy0, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+ base::Value::CreateIntegerValue(123), NULL);
+ EXPECT_FALSE(bundle.Equals(other));
+}
+
+} // namespace policy