blob: 1c3aaac363243ec3b474fef5c631af9796e9bc8e [file] [log] [blame]
// 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 "chrome/browser/policy/cloud/user_policy_signin_service_base.h"
#include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/common/chrome_content_client.h"
#include "components/account_id/account_id.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/storage_partition.h"
#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace policy {
UserPolicySigninServiceBase::UserPolicySigninServiceBase(
Profile* profile,
PrefService* local_state,
DeviceManagementService* device_management_service,
UserCloudPolicyManager* policy_manager,
SigninManager* signin_manager,
scoped_refptr<net::URLRequestContextGetter> system_request_context,
scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory)
: policy_manager_(policy_manager),
signin_manager_(signin_manager),
local_state_(local_state),
device_management_service_(device_management_service),
system_request_context_(system_request_context),
system_url_loader_factory_(system_url_loader_factory),
weak_factory_(this) {
// Register a listener to be called back once the current profile has finished
// initializing, so we can startup/shutdown the UserCloudPolicyManager.
registrar_.Add(this,
chrome::NOTIFICATION_PROFILE_ADDED,
content::Source<Profile>(profile));
}
UserPolicySigninServiceBase::~UserPolicySigninServiceBase() {}
void UserPolicySigninServiceBase::FetchPolicyForSignedInUser(
const AccountId& account_id,
const std::string& dm_token,
const std::string& client_id,
scoped_refptr<net::URLRequestContextGetter> profile_request_context,
scoped_refptr<network::SharedURLLoaderFactory> profile_url_loader_factory,
const PolicyFetchCallback& callback) {
std::unique_ptr<CloudPolicyClient> client =
UserCloudPolicyManager::CreateCloudPolicyClient(
device_management_service_, profile_request_context,
profile_url_loader_factory);
client->SetupRegistration(
dm_token, client_id,
std::vector<std::string>() /* user_affiliation_ids */);
DCHECK(client->is_registered());
// The user has just signed in, so the UserCloudPolicyManager should not yet
// be initialized. This routine will initialize the UserCloudPolicyManager
// with the passed client and will proactively ask the client to fetch
// policy without waiting for the CloudPolicyService to finish initialization.
UserCloudPolicyManager* manager = policy_manager();
DCHECK(manager);
DCHECK(!manager->core()->client());
InitializeUserCloudPolicyManager(account_id, std::move(client));
DCHECK(manager->IsClientRegistered());
// Now initiate a policy fetch.
manager->core()->service()->RefreshPolicy(callback);
}
void UserPolicySigninServiceBase::GoogleSignedOut(const std::string& account_id,
const std::string& username) {
ShutdownUserCloudPolicyManager();
}
void UserPolicySigninServiceBase::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(chrome::NOTIFICATION_PROFILE_ADDED, type);
// A new profile has been loaded - if it's signed in, then initialize the
// UCPM, otherwise shut down the UCPM (which deletes any cached policy
// data). This must be done here instead of at constructor time because
// the Profile is not fully initialized when this object is constructed
// (DoFinalInit() has not yet been called, so ProfileIOData and
// SSLConfigServiceManager have not been created yet).
// TODO(atwilson): Switch to using a timer instead, to avoid contention
// with other services at startup (http://crbug.com/165468).
InitializeOnProfileReady(content::Source<Profile>(source).ptr());
}
void UserPolicySigninServiceBase::OnInitializationCompleted(
CloudPolicyService* service) {
// This is meant to be overridden by subclasses. Starting and stopping to
// observe the CloudPolicyService from this base class avoids the need for
// more virtuals.
}
void UserPolicySigninServiceBase::OnPolicyFetched(CloudPolicyClient* client) {}
void UserPolicySigninServiceBase::OnRegistrationStateChanged(
CloudPolicyClient* client) {}
void UserPolicySigninServiceBase::OnClientError(CloudPolicyClient* client) {
if (client->is_registered()) {
// If the client is already registered, it means this error must have
// come from a policy fetch.
if (client->status() == DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED) {
// OK, policy fetch failed with MANAGEMENT_NOT_SUPPORTED - this is our
// trigger to revert to "unmanaged" mode (we will check for management
// being re-enabled on the next restart and/or login).
DVLOG(1) << "DMServer returned NOT_SUPPORTED error - removing policy";
// Can't shutdown now because we're in the middle of a callback from
// the CloudPolicyClient, so queue up a task to do the shutdown.
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(
&UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager,
weak_factory_.GetWeakPtr()));
} else {
DVLOG(1) << "Error fetching policy: " << client->status();
}
}
}
void UserPolicySigninServiceBase::Shutdown() {
if (signin_manager())
signin_manager()->RemoveObserver(this);
PrepareForUserCloudPolicyManagerShutdown();
}
void UserPolicySigninServiceBase::PrepareForUserCloudPolicyManagerShutdown() {
UserCloudPolicyManager* manager = policy_manager();
if (manager && manager->core()->client())
manager->core()->client()->RemoveObserver(this);
if (manager && manager->core()->service())
manager->core()->service()->RemoveObserver(this);
}
std::unique_ptr<CloudPolicyClient>
UserPolicySigninServiceBase::CreateClientForRegistrationOnly(
const std::string& username) {
DCHECK(!username.empty());
// We should not be called with a client already initialized.
DCHECK(!policy_manager() || !policy_manager()->core()->client());
// If the user should not get policy, just bail out.
if (!policy_manager() || !ShouldLoadPolicyForUser(username)) {
DVLOG(1) << "Signed in user is not in the whitelist";
return std::unique_ptr<CloudPolicyClient>();
}
// If the DeviceManagementService is not yet initialized, start it up now.
device_management_service_->ScheduleInitialization(0);
// Create a new CloudPolicyClient for fetching the DMToken.
return UserCloudPolicyManager::CreateCloudPolicyClient(
device_management_service_, system_request_context_,
system_url_loader_factory_);
}
bool UserPolicySigninServiceBase::ShouldLoadPolicyForUser(
const std::string& username) {
if (username.empty())
return false; // Not signed in.
return !BrowserPolicyConnector::IsNonEnterpriseUser(username);
}
void UserPolicySigninServiceBase::InitializeOnProfileReady(Profile* profile) {
// If using a TestingProfile with no SigninManager or UserCloudPolicyManager,
// skip initialization.
if (!policy_manager() || !signin_manager()) {
DVLOG(1) << "Skipping initialization for tests due to missing components.";
return;
}
// Shutdown the UserCloudPolicyManager when the user signs out. We start
// observing the SigninManager here because we don't want to get signout
// notifications until after the profile has started initializing
// (http://crbug.com/316229).
signin_manager()->AddObserver(this);
AccountId account_id =
signin_manager()->GetAuthenticatedAccountInfo().GetAccountId();
if (!account_id.is_valid())
ShutdownUserCloudPolicyManager();
else
InitializeForSignedInUser(
account_id, profile->GetRequestContext(),
content::BrowserContext::GetDefaultStoragePartition(profile)
->GetURLLoaderFactoryForBrowserProcess());
}
void UserPolicySigninServiceBase::InitializeForSignedInUser(
const AccountId& account_id,
scoped_refptr<net::URLRequestContextGetter> profile_request_context,
scoped_refptr<network::SharedURLLoaderFactory> profile_url_loader_factory) {
DCHECK(account_id.is_valid());
if (!ShouldLoadPolicyForUser(account_id.GetUserEmail())) {
DVLOG(1) << "Policy load not enabled for user: "
<< account_id.GetUserEmail();
return;
}
UserCloudPolicyManager* manager = policy_manager();
// Initialize the UCPM if it is not already initialized.
if (!manager->core()->service()) {
// If there is no cached DMToken then we can detect this when the
// OnInitializationCompleted() callback is invoked and this will
// initiate a policy fetch.
InitializeUserCloudPolicyManager(
account_id, UserCloudPolicyManager::CreateCloudPolicyClient(
device_management_service_, profile_request_context,
profile_url_loader_factory));
} else {
manager->SetSigninAccountId(account_id);
}
// If the CloudPolicyService is initialized, kick off registration.
// Otherwise OnInitializationCompleted is invoked as soon as the service
// finishes its initialization.
if (manager->core()->service()->IsInitializationComplete())
OnInitializationCompleted(manager->core()->service());
}
void UserPolicySigninServiceBase::InitializeUserCloudPolicyManager(
const AccountId& account_id,
std::unique_ptr<CloudPolicyClient> client) {
DCHECK(client);
UserCloudPolicyManager* manager = policy_manager();
manager->SetSigninAccountId(account_id);
DCHECK(!manager->core()->client());
scoped_refptr<net::URLRequestContextGetter> context =
client->GetRequestContext();
manager->Connect(local_state_, context, std::move(client));
DCHECK(manager->core()->service());
// Observe the client to detect errors fetching policy.
manager->core()->client()->AddObserver(this);
// Observe the service to determine when it's initialized.
manager->core()->service()->AddObserver(this);
}
void UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager() {
PrepareForUserCloudPolicyManagerShutdown();
UserCloudPolicyManager* manager = policy_manager();
if (manager)
manager->DisconnectAndRemovePolicy();
}
} // namespace policy