blob: e34a9d2342bcb3b22bc60ab59e1559eb061aec6b [file] [log] [blame]
// Copyright (c) 2012 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 "chrome/browser/policy/configuration_policy_provider.h"
#include <string>
#include "chrome/browser/policy/policy_map.h"
#include "policy/policy_constants.h"
namespace policy {
namespace {
const char* kProxyPolicies[] = {
key::kProxyMode,
key::kProxyServerMode,
key::kProxyServer,
key::kProxyPacUrl,
key::kProxyBypassList,
};
// Helper that converts deprecated chrome policies into their corresponding
// actual policies.
void FixDeprecatedPolicies(PolicyMap* policies) {
// Proxy settings have been configured by 5 policies that didn't mix well
// together, and maps of policies had to take this into account when merging
// policy sources. The proxy settings will eventually be configured by a
// single Dictionary policy when all providers have support for that. For
// now, the individual policies are mapped here to a single Dictionary policy
// that the rest of the policy machinery uses.
// The highest (level, scope) pair for an existing proxy policy is determined
// first, and then only policies with those exact attributes are merged.
PolicyMap::Entry current_priority; // Defaults to the lowest priority.
scoped_ptr<DictionaryValue> proxy_settings(new DictionaryValue);
for (size_t i = 0; i < arraysize(kProxyPolicies); ++i) {
const PolicyMap::Entry* entry = policies->Get(kProxyPolicies[i]);
if (entry) {
if (entry->has_higher_priority_than(current_priority)) {
proxy_settings->Clear();
current_priority = *entry;
}
if (!entry->has_higher_priority_than(current_priority) &&
!current_priority.has_higher_priority_than(*entry)) {
proxy_settings->Set(kProxyPolicies[i], entry->value->DeepCopy());
}
policies->Erase(kProxyPolicies[i]);
}
}
// Sets the new |proxy_settings| if kProxySettings isn't set yet, or if the
// new priority is higher.
const PolicyMap::Entry* existing = policies->Get(key::kProxySettings);
if (!proxy_settings->empty() &&
(!existing || current_priority.has_higher_priority_than(*existing))) {
policies->Set(key::kProxySettings,
current_priority.level,
current_priority.scope,
proxy_settings.release());
}
}
} // namespace
ConfigurationPolicyProvider::Observer::~Observer() {}
void ConfigurationPolicyProvider::Observer::OnProviderGoingAway(
ConfigurationPolicyProvider* provider) {}
ConfigurationPolicyProvider::ConfigurationPolicyProvider() {}
ConfigurationPolicyProvider::~ConfigurationPolicyProvider() {
FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
observer_list_,
OnProviderGoingAway(this));
}
bool ConfigurationPolicyProvider::IsInitializationComplete() const {
return true;
}
void ConfigurationPolicyProvider::UpdatePolicy(
scoped_ptr<PolicyBundle> bundle) {
if (bundle.get())
policy_bundle_.Swap(bundle.get());
else
policy_bundle_.Clear();
FixDeprecatedPolicies(
&policy_bundle_.Get(POLICY_DOMAIN_CHROME, std::string()));
FOR_EACH_OBSERVER(ConfigurationPolicyProvider::Observer,
observer_list_,
OnUpdatePolicy(this));
}
void ConfigurationPolicyProvider::AddObserver(Observer* observer) {
observer_list_.AddObserver(observer);
}
void ConfigurationPolicyProvider::RemoveObserver(Observer* observer) {
observer_list_.RemoveObserver(observer);
}
ConfigurationPolicyObserverRegistrar::ConfigurationPolicyObserverRegistrar()
: provider_(NULL),
observer_(NULL) {}
ConfigurationPolicyObserverRegistrar::~ConfigurationPolicyObserverRegistrar() {
// Subtle: see the comment in OnProviderGoingAway().
if (observer_)
provider_->RemoveObserver(this);
}
void ConfigurationPolicyObserverRegistrar::Init(
ConfigurationPolicyProvider* provider,
ConfigurationPolicyProvider::Observer* observer) {
// Must be either both NULL or both not NULL.
DCHECK(provider);
DCHECK(observer);
provider_ = provider;
observer_ = observer;
provider_->AddObserver(this);
}
void ConfigurationPolicyObserverRegistrar::OnUpdatePolicy(
ConfigurationPolicyProvider* provider) {
DCHECK_EQ(provider_, provider);
observer_->OnUpdatePolicy(provider_);
}
void ConfigurationPolicyObserverRegistrar::OnProviderGoingAway(
ConfigurationPolicyProvider* provider) {
DCHECK_EQ(provider_, provider);
// The |observer_| might delete |this| during this callback: don't touch any
// of |this| field's after it returns.
// It might also invoke provider() during this callback, so |provider_| can't
// be set to NULL. So we set |observer_| to NULL instead to signal that
// we're not observing the provider anymore.
ConfigurationPolicyProvider::Observer* observer = observer_;
observer_ = NULL;
provider_->RemoveObserver(this);
observer->OnProviderGoingAway(provider);
}
} // namespace policy