// 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 "base/bind.h" #include "base/message_loop/message_loop.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/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/cloud/system_policy_request_context.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" #include "components/policy/core/common/cloud/user_policy_request_context.h" #include "components/signin/core/browser/signin_manager.h" #include "content/public/browser/notification_source.h" #include "net/url_request/url_request_context_getter.h" namespace policy { UserPolicySigninServiceBase::UserPolicySigninServiceBase( Profile* profile, PrefService* local_state, DeviceManagementService* device_management_service, UserCloudPolicyManager* policy_manager, SigninManager* signin_manager, scoped_refptr system_request_context) : policy_manager_(policy_manager), signin_manager_(signin_manager), local_state_(local_state), device_management_service_(device_management_service), system_request_context_(system_request_context), 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)); } UserPolicySigninServiceBase::~UserPolicySigninServiceBase() {} void UserPolicySigninServiceBase::FetchPolicyForSignedInUser( const std::string& username, const std::string& dm_token, const std::string& client_id, scoped_refptr profile_request_context, const PolicyFetchCallback& callback) { scoped_ptr client( UserCloudPolicyManager::CreateCloudPolicyClient( device_management_service_, CreateUserRequestContext(profile_request_context)).Pass()); client->SetupRegistration(dm_token, client_id); 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(username, client.Pass()); DCHECK(manager->IsClientRegistered()); // Now initiate a policy fetch. manager->core()->service()->RefreshPolicy(callback); } void UserPolicySigninServiceBase::GoogleSignedOut(const std::string& username) { ShutdownUserCloudPolicyManager(); } void UserPolicySigninServiceBase::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_PROFILE_ADDED: // 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(source).ptr()); break; default: NOTREACHED(); } } 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::MessageLoop::current()->PostTask( FROM_HERE, base::Bind( &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); } scoped_ptr UserPolicySigninServiceBase::CreateClientForRegistrationOnly( const std::string& username) { DCHECK(!username.empty()); // We should not be called with a client already initialized. #if !defined(OS_IOS) // On iOS we check if an account has policy while the profile is signed in // to another account. DCHECK(!policy_manager() || !policy_manager()->core()->client()); #endif // 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 scoped_ptr(); } // 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_, CreateSystemRequestContext()); } 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); std::string username = signin_manager()->GetAuthenticatedUsername(); if (username.empty()) ShutdownUserCloudPolicyManager(); else InitializeForSignedInUser(username, profile->GetRequestContext()); } void UserPolicySigninServiceBase::InitializeForSignedInUser( const std::string& username, scoped_refptr profile_request_context) { DCHECK(!username.empty()); if (!ShouldLoadPolicyForUser(username)) { DVLOG(1) << "Policy load not enabled for user: " << username; 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( username, UserCloudPolicyManager::CreateCloudPolicyClient( device_management_service_, CreateUserRequestContext(profile_request_context)).Pass()); } else { manager->SetSigninUsername(username); } // 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 std::string& username, scoped_ptr client) { DCHECK(client); UserCloudPolicyManager* manager = policy_manager(); manager->SetSigninUsername(username); DCHECK(!manager->core()->client()); scoped_refptr context = client->GetRequestContext(); manager->Connect(local_state_, context, client.Pass()); 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(); } scoped_refptr UserPolicySigninServiceBase::CreateSystemRequestContext() { return new SystemPolicyRequestContext( system_request_context(), GetUserAgent()); } scoped_refptr UserPolicySigninServiceBase::CreateUserRequestContext( scoped_refptr profile_request_context) { return new UserPolicyRequestContext( profile_request_context, system_request_context(), GetUserAgent()); } } // namespace policy