blob: fc1fcbf558dfe5e375a272a604cbf079351dc2f2 [file] [log] [blame]
// Copyright 2016 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/chromeos/policy/active_directory_policy_manager.h"
#include <string>
#include <utility>
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "chromeos/dbus/auth_policy_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "components/policy/core/common/policy_bundle.h"
#include "components/policy/core/common/policy_types.h"
#include "components/policy/policy_constants.h"
namespace {
// Fetch policy every 90 minutes which matches the Windows default:
// https://technet.microsoft.com/en-us/library/cc940895.aspx
constexpr base::TimeDelta kFetchInterval = base::TimeDelta::FromMinutes(90);
} // namespace
namespace policy {
ActiveDirectoryPolicyManager::~ActiveDirectoryPolicyManager() {}
// static
std::unique_ptr<ActiveDirectoryPolicyManager>
ActiveDirectoryPolicyManager::CreateForDevicePolicy(
std::unique_ptr<CloudPolicyStore> store) {
// Can't use MakeUnique<> because the constructor is private.
return base::WrapUnique(
new ActiveDirectoryPolicyManager(EmptyAccountId(), base::TimeDelta(),
base::OnceClosure(), std::move(store)));
}
// static
std::unique_ptr<ActiveDirectoryPolicyManager>
ActiveDirectoryPolicyManager::CreateForUserPolicy(
const AccountId& account_id,
base::TimeDelta initial_policy_fetch_timeout,
base::OnceClosure exit_session,
std::unique_ptr<CloudPolicyStore> store) {
// Can't use MakeUnique<> because the constructor is private.
return base::WrapUnique(new ActiveDirectoryPolicyManager(
account_id, initial_policy_fetch_timeout, std::move(exit_session),
std::move(store)));
}
void ActiveDirectoryPolicyManager::Init(SchemaRegistry* registry) {
ConfigurationPolicyProvider::Init(registry);
store_->AddObserver(this);
if (!store_->is_initialized()) {
store_->Load();
}
// Does nothing if |store_| hasn't yet initialized.
PublishPolicy();
scheduler_ = base::MakeUnique<PolicyScheduler>(
base::BindRepeating(&ActiveDirectoryPolicyManager::DoPolicyFetch,
weak_ptr_factory_.GetWeakPtr()),
base::BindRepeating(&ActiveDirectoryPolicyManager::OnPolicyFetched,
weak_ptr_factory_.GetWeakPtr()),
kFetchInterval);
}
void ActiveDirectoryPolicyManager::Shutdown() {
store_->RemoveObserver(this);
ConfigurationPolicyProvider::Shutdown();
}
bool ActiveDirectoryPolicyManager::IsInitializationComplete(
PolicyDomain domain) const {
if (waiting_for_initial_policy_fetch_) {
return false;
}
if (domain == POLICY_DOMAIN_CHROME) {
return store_->is_initialized();
}
return true;
}
void ActiveDirectoryPolicyManager::RefreshPolicies() {
scheduler_->ScheduleTaskNow();
}
void ActiveDirectoryPolicyManager::OnStoreLoaded(
CloudPolicyStore* cloud_policy_store) {
DCHECK_EQ(store_.get(), cloud_policy_store);
PublishPolicy();
if (fetch_ever_completed_) {
// Policy is guaranteed to be up to date with the previous fetch result
// because OnPolicyFetched() cancels any potentially running Load()
// operations.
CancelWaitForInitialPolicy(fetch_ever_succeeded_ /* success */);
}
}
void ActiveDirectoryPolicyManager::OnStoreError(
CloudPolicyStore* cloud_policy_store) {
DCHECK_EQ(store_.get(), cloud_policy_store);
// Publish policy (even though it hasn't changed) in order to signal load
// complete on the ConfigurationPolicyProvider interface. Technically, this is
// only required on the first load, but doesn't hurt in any case.
PublishPolicy();
if (fetch_ever_completed_) {
CancelWaitForInitialPolicy(false /* success */);
}
}
void ActiveDirectoryPolicyManager::ForceTimeoutForTest() {
DCHECK(initial_policy_timeout_.IsRunning());
// Stop the timer to mimic what happens when a real timer fires, then invoke
// the timer callback directly.
initial_policy_timeout_.Stop();
OnBlockingFetchTimeout();
}
ActiveDirectoryPolicyManager::ActiveDirectoryPolicyManager(
const AccountId& account_id,
base::TimeDelta initial_policy_fetch_timeout,
base::OnceClosure exit_session,
std::unique_ptr<CloudPolicyStore> store)
: account_id_(account_id),
waiting_for_initial_policy_fetch_(
!initial_policy_fetch_timeout.is_zero()),
initial_policy_fetch_may_fail_(!initial_policy_fetch_timeout.is_max()),
exit_session_(std::move(exit_session)),
store_(std::move(store)) {
// Delaying initialization complete is intended for user policy only.
DCHECK(account_id != EmptyAccountId() || !waiting_for_initial_policy_fetch_);
if (waiting_for_initial_policy_fetch_ && initial_policy_fetch_may_fail_) {
initial_policy_timeout_.Start(
FROM_HERE, initial_policy_fetch_timeout,
base::Bind(&ActiveDirectoryPolicyManager::OnBlockingFetchTimeout,
weak_ptr_factory_.GetWeakPtr()));
}
}
void ActiveDirectoryPolicyManager::PublishPolicy() {
if (!store_->is_initialized()) {
return;
}
std::unique_ptr<PolicyBundle> bundle = base::MakeUnique<PolicyBundle>();
PolicyMap& policy_map =
bundle->Get(PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
policy_map.CopyFrom(store_->policy_map());
// Overwrite the source which is POLICY_SOURCE_CLOUD by default.
// TODO(tnagel): Rename CloudPolicyStore to PolicyStore and make the source
// configurable, then drop PolicyMap::SetSourceForAll().
policy_map.SetSourceForAll(POLICY_SOURCE_ACTIVE_DIRECTORY);
SetEnterpriseUsersDefaults(&policy_map);
UpdatePolicy(std::move(bundle));
}
void ActiveDirectoryPolicyManager::DoPolicyFetch(
base::OnceCallback<void(bool success)> callback) {
chromeos::DBusThreadManager* thread_manager =
chromeos::DBusThreadManager::Get();
DCHECK(thread_manager);
chromeos::AuthPolicyClient* auth_policy_client =
thread_manager->GetAuthPolicyClient();
DCHECK(auth_policy_client);
if (account_id_ == EmptyAccountId()) {
auth_policy_client->RefreshDevicePolicy(std::move(callback));
} else {
auth_policy_client->RefreshUserPolicy(account_id_, std::move(callback));
}
}
void ActiveDirectoryPolicyManager::OnPolicyFetched(bool success) {
fetch_ever_completed_ = true;
if (success) {
fetch_ever_succeeded_ = true;
} else {
LOG(ERROR) << "Active Directory policy fetch failed.";
if (store_->is_initialized()) {
CancelWaitForInitialPolicy(false /* success */);
}
}
// Load independently of success or failure to keep in sync with the state in
// session manager. This cancels any potentially running Load() operations
// thus it is guaranteed that at the next OnStoreLoaded() invocation the
// policy is up-to-date with what was fetched.
store_->Load();
}
void ActiveDirectoryPolicyManager::OnBlockingFetchTimeout() {
DCHECK(waiting_for_initial_policy_fetch_);
LOG(WARNING) << "Timed out while waiting for the policy fetch. "
<< "The session will start with the cached policy.";
CancelWaitForInitialPolicy(false);
}
void ActiveDirectoryPolicyManager::CancelWaitForInitialPolicy(bool success) {
if (!waiting_for_initial_policy_fetch_)
return;
initial_policy_timeout_.Stop();
// If the conditions to continue profile initialization are not met, the user
// session is exited and initialization is not set as completed.
// TODO(tnagel): Maybe add code to retry policy fetch?
if (!store_->has_policy()) {
// If there's no policy at all (not even cached) the user session must not
// continue.
LOG(ERROR) << "Policy could not be obtained. "
<< "Aborting profile initialization";
// Prevent duplicate exit session calls.
if (exit_session_) {
std::move(exit_session_).Run();
}
return;
}
if (!success && !initial_policy_fetch_may_fail_) {
LOG(ERROR) << "Policy fetch failed for the user. "
<< "Aborting profile initialization";
// Prevent duplicate exit session calls.
if (exit_session_) {
std::move(exit_session_).Run();
}
return;
}
// Set initialization complete.
waiting_for_initial_policy_fetch_ = false;
// Publish policy (even though it hasn't changed) in order to signal load
// complete on the ConfigurationPolicyProvider interface.
PublishPolicy();
}
} // namespace policy