diff options
52 files changed, 1444 insertions, 234 deletions
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index f09c755..769f07b 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc @@ -441,8 +441,7 @@ policy::BrowserPolicyConnector* BrowserProcessImpl::browser_policy_connector() { policy::PolicyService* BrowserProcessImpl::policy_service() { if (!policy_service_.get()) { #if defined(ENABLE_CONFIGURATION_POLICY) - policy_service_.reset( - browser_policy_connector()->CreatePolicyService(NULL)); + policy_service_ = browser_policy_connector()->CreatePolicyService(NULL); #else policy_service_.reset(new policy::PolicyServiceStub()); #endif diff --git a/chrome/browser/chromeos/login/login_utils.cc b/chrome/browser/chromeos/login/login_utils.cc index abd594d..67a4242 100644 --- a/chrome/browser/chromeos/login/login_utils.cc +++ b/chrome/browser/chromeos/login/login_utils.cc @@ -49,6 +49,9 @@ #include "chrome/browser/net/chrome_url_request_context.h" #include "chrome/browser/net/preconnect.h" #include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/policy/cloud_policy_client.h" +#include "chrome/browser/policy/cloud_policy_service.h" +#include "chrome/browser/policy/user_cloud_policy_manager.h" #include "chrome/browser/prefs/pref_member.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" @@ -487,6 +490,23 @@ void LoginUtilsImpl::PrepareProfile( // initialization code sees the cached policy settings. connector->InitializeUserPolicy(username, wait_for_policy_fetch); + // The default profile will have been changed because the ProfileManager + // will process the notification that the UserManager sends out. + ProfileManager::CreateDefaultProfileAsync( + base::Bind(&LoginUtilsImpl::OnProfileCreated, AsWeakPtr())); + + // The default profile is only partially initialized at this point. + // Setup the UserCloudPolicyManager so profile initialization can complete. + Profile* user_profile = ProfileManager::GetDefaultProfile(); + + // Initialize the new cloud policy framework, if enabled. + if (user_profile->GetUserCloudPolicyManager()) { + user_profile->GetUserCloudPolicyManager()->Initialize( + g_browser_process->local_state(), + connector->device_management_service(), + connector->GetUserAffiliation(username)); + } + if (wait_for_policy_fetch) { // Profile creation will block until user policy is fetched, which // requires the DeviceManagement token. Try to fetch it now. @@ -495,11 +515,6 @@ void LoginUtilsImpl::PrepareProfile( new PolicyOAuthFetcher(authenticator_->authentication_profile())); policy_oauth_fetcher_->Start(); } - - // The default profile will have been changed because the ProfileManager - // will process the notification that the UserManager sends out. - ProfileManager::CreateDefaultProfileAsync( - base::Bind(&LoginUtilsImpl::OnProfileCreated, AsWeakPtr())); } void LoginUtilsImpl::DelegateDeleted(LoginUtils::Delegate* delegate) { diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc index 4546141..89eda71 100644 --- a/chrome/browser/chromeos/login/login_utils_browsertest.cc +++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc @@ -203,7 +203,6 @@ class LoginUtilsTest : public testing::Test, browser_process_->SetProfileManager( new ProfileManagerWithoutInit(scoped_temp_dir_.path())); connector_ = browser_process_->browser_policy_connector(); - connector_->Init(); RunAllPending(); } diff --git a/chrome/browser/chromeos/login/policy_oauth_fetcher.cc b/chrome/browser/chromeos/login/policy_oauth_fetcher.cc index deb93db..add6120b 100644 --- a/chrome/browser/chromeos/login/policy_oauth_fetcher.cc +++ b/chrome/browser/chromeos/login/policy_oauth_fetcher.cc @@ -7,7 +7,9 @@ #include "base/logging.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/policy/user_cloud_policy_manager.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/net/gaia/google_service_auth_error.h" @@ -94,6 +96,18 @@ void PolicyOAuthFetcher::OnOAuthWrapBridgeFailure( void PolicyOAuthFetcher::SetPolicyToken(const std::string& token) { policy_token_ = token; g_browser_process->browser_policy_connector()->RegisterForUserPolicy(token); + + // The Profile object passed in to the constructor is destroyed after the + // login process is complete. Get the UserCloudPolicyManager from the user's + // default profile instead. + policy::UserCloudPolicyManager* cloud_policy_manager = + ProfileManager::GetDefaultProfile()->GetUserCloudPolicyManager(); + if (cloud_policy_manager) { + if (token.empty()) + cloud_policy_manager->CancelWaitForPolicyFetch(); + else + cloud_policy_manager->RegisterClient(token); + } } } // namespace chromeos diff --git a/chrome/browser/policy/auto_enrollment_client.cc b/chrome/browser/policy/auto_enrollment_client.cc index eabe10e..c6ca989 100644 --- a/chrome/browser/policy/auto_enrollment_client.cc +++ b/chrome/browser/policy/auto_enrollment_client.cc @@ -111,15 +111,12 @@ bool AutoEnrollmentClient::IsDisabled() { // static AutoEnrollmentClient* AutoEnrollmentClient::Create( const base::Closure& completion_callback) { - CommandLine* command_line = CommandLine::ForCurrentProcess(); - // The client won't do anything if |service| is NULL. DeviceManagementService* service = NULL; if (IsDisabled()) { VLOG(1) << "Auto-enrollment is disabled"; } else { - std::string url = - command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl); + std::string url = BrowserPolicyConnector::GetDeviceManagementUrl(); if (!url.empty()) { service = new DeviceManagementService(url); service->ScheduleInitialization(0); diff --git a/chrome/browser/policy/browser_policy_connector.cc b/chrome/browser/policy/browser_policy_connector.cc index 2874a91..552de44 100644 --- a/chrome/browser/policy/browser_policy_connector.cc +++ b/chrome/browser/policy/browser_policy_connector.cc @@ -23,10 +23,12 @@ #include "chrome/browser/policy/user_cloud_policy_manager.h" #include "chrome/browser/policy/user_policy_cache.h" #include "chrome/browser/policy/user_policy_token_cache.h" +#include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/token_service.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/net/gaia/gaia_auth_util.h" #include "chrome/common/net/gaia/gaia_constants.h" #include "chrome/common/pref_names.h" #include "content/public/browser/notification_details.h" @@ -45,6 +47,8 @@ #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/login/authenticator.h" +#include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/system/statistics_provider.h" #include "chrome/browser/policy/app_pack_updater.h" #include "chrome/browser/policy/cros_user_policy_cache.h" @@ -70,6 +74,10 @@ const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy"); // Delay in milliseconds from startup. const int64 kServiceInitializationStartupDelay = 5000; +// The URL for the device management server. +const char kDefaultDeviceManagementServerUrl[] = + "https://m.google.com/devicemanagement/data/api"; + #if defined(OS_CHROMEOS) // MachineInfo key names. const char kMachineInfoSystemHwqual[] = "hardware_class"; @@ -114,40 +122,37 @@ BrowserPolicyConnector::~BrowserPolicyConnector() { user_policy_token_cache_.reset(); user_data_store_.reset(); - if (user_cloud_policy_manager_.get()) - user_cloud_policy_manager_->Shutdown(); - user_cloud_policy_manager_.reset(); - device_management_service_.reset(); } void BrowserPolicyConnector::Init() { - platform_provider_.reset(CreatePlatformProvider()); + DCHECK(!device_management_service_.get()) << + "BrowserPolicyConnector::Init() called twice."; + // Don't create platform providers if running in a unit test, since + // AsyncPlatformLoader requires deletion on the FILE thread. + if (MessageLoop::current()) + platform_provider_.reset(CreatePlatformProvider()); + + device_management_service_.reset( + new DeviceManagementService(GetDeviceManagementUrl())); #if defined(OS_CHROMEOS) - // The CloudPolicyProvider blocks asynchronous Profile creation until a login - // is performed. This is used to ensure that the Profile's PrefService sees - // managed preferences on managed Chrome OS devices. However, this also - // prevents creation of new Profiles in Desktop Chrome. The implementation of - // cloud policy on the Desktop requires a refactoring of the cloud provider, - // but for now it just isn't created. CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kDeviceManagementUrl)) { - device_management_service_.reset( - new DeviceManagementService( - command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl))); - if (!command_line->HasSwitch(switches::kEnableCloudPolicyService)) { - managed_cloud_provider_.reset(new CloudPolicyProvider( - this, - POLICY_LEVEL_MANDATORY)); - recommended_cloud_provider_.reset(new CloudPolicyProvider( - this, - POLICY_LEVEL_RECOMMENDED)); - } + if (!command_line->HasSwitch(switches::kEnableCloudPolicyService)) { + managed_cloud_provider_.reset(new CloudPolicyProvider( + this, + POLICY_LEVEL_MANDATORY)); + recommended_cloud_provider_.reset(new CloudPolicyProvider( + this, + POLICY_LEVEL_RECOMMENDED)); } InitializeDevicePolicy(); + // Don't bother updating the cache if this is a unit test. + if (!MessageLoop::current()) + return; + // Create the AppPackUpdater to start updating the cache. It requires the // system request context, which isn't available yet; therefore it is // created only once the loops are running. @@ -158,7 +163,36 @@ void BrowserPolicyConnector::Init() { #endif } -PolicyService* BrowserPolicyConnector::CreatePolicyService( +scoped_ptr<UserCloudPolicyManager> + BrowserPolicyConnector::CreateCloudPolicyManager(Profile* profile) { + scoped_ptr<UserCloudPolicyManager> manager; + const CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kEnableCloudPolicyService)) { + bool wait_for_policy_fetch = false; +#if defined(OS_CHROMEOS) + // TODO(mnissler): Revisit once Chrome OS gains multi-profiles support. + // Don't wait for a policy fetch if there's no logged in user. + if (chromeos::UserManager::Get()->IsUserLoggedIn()) { + wait_for_policy_fetch = + g_browser_process->browser_policy_connector()->GetUserAffiliation( + chromeos::UserManager::Get()->GetLoggedInUser().email()) == + policy::USER_AFFILIATION_MANAGED; + } +#else + // On desktop, there's no way to figure out if a user is logged in yet + // because prefs are not yet initialized. So we do not block waiting for + // the policy fetch to happen (because that would inhibit startup for + // non-signed-in users) and instead rely on the fact that a signed-in + // profile will already have policy downloaded. If no policy is available + // (due to a previous fetch failing), the normal policy refresh mechanism + // will cause it to get downloaded eventually. +#endif + manager = UserCloudPolicyManager::Create(profile, wait_for_policy_fetch); + } + return manager.Pass(); +} + +scoped_ptr<PolicyService> BrowserPolicyConnector::CreatePolicyService( Profile* profile) { // |providers| in decreasing order of priority. PolicyServiceImpl::Providers providers; @@ -176,8 +210,9 @@ PolicyService* BrowserPolicyConnector::CreatePolicyService( // directly as their provider, which may also block initialization on a policy // fetch at login time. if (profile) { - if (user_cloud_policy_manager_.get()) - providers.push_back(user_cloud_policy_manager_.get()); + UserCloudPolicyManager* manager = profile->GetUserCloudPolicyManager(); + if (manager) + providers.push_back(manager); providers.push_back( ManagedModePolicyProviderFactory::GetForProfile(profile)); @@ -185,7 +220,7 @@ PolicyService* BrowserPolicyConnector::CreatePolicyService( providers.push_back(&user_cloud_policy_provider_); } - return new PolicyServiceImpl(providers); + return scoped_ptr<PolicyService>(new PolicyServiceImpl(providers)).Pass(); } void BrowserPolicyConnector::RegisterForDevicePolicy( @@ -302,12 +337,11 @@ void BrowserPolicyConnector::ScheduleServiceInitialization( } #endif } + void BrowserPolicyConnector::InitializeUserPolicy( const std::string& user_name, bool wait_for_policy_fetch) { // Throw away the old backend. - user_cloud_policy_manager_.reset(); - user_cloud_policy_subsystem_.reset(); user_policy_token_cache_.reset(); user_data_store_.reset(); @@ -316,66 +350,54 @@ void BrowserPolicyConnector::InitializeUserPolicy( CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kDeviceManagementUrl)) { - int64 startup_delay = - wait_for_policy_fetch ? 0 : kServiceInitializationStartupDelay; + int64 startup_delay = + wait_for_policy_fetch ? 0 : kServiceInitializationStartupDelay; - if (command_line->HasSwitch(switches::kEnableCloudPolicyService)) { -#if defined(OS_CHROMEOS) - user_cloud_policy_manager_ = - UserCloudPolicyManager::Create(wait_for_policy_fetch); - user_cloud_policy_manager_->Initialize(g_browser_process->local_state(), - device_management_service_.get(), - GetUserAffiliation(user_name)); - user_cloud_policy_provider_.SetDelegate(user_cloud_policy_manager_.get()); - - device_management_service_->ScheduleInitialization(startup_delay); -#endif - } else { - FilePath profile_dir; - PathService::Get(chrome::DIR_USER_DATA, &profile_dir); + if (!command_line->HasSwitch(switches::kEnableCloudPolicyService)) { + FilePath profile_dir; + PathService::Get(chrome::DIR_USER_DATA, &profile_dir); #if defined(OS_CHROMEOS) - profile_dir = profile_dir.Append( - command_line->GetSwitchValuePath(switches::kLoginProfile)); + profile_dir = profile_dir.Append( + command_line->GetSwitchValuePath(switches::kLoginProfile)); #endif - const FilePath policy_dir = profile_dir.Append(kPolicyDir); - const FilePath policy_cache_file = policy_dir.Append(kPolicyCacheFile); - const FilePath token_cache_file = policy_dir.Append(kTokenCacheFile); - CloudPolicyCacheBase* user_policy_cache = NULL; + const FilePath policy_dir = profile_dir.Append(kPolicyDir); + const FilePath policy_cache_file = policy_dir.Append(kPolicyCacheFile); + const FilePath token_cache_file = policy_dir.Append(kTokenCacheFile); + CloudPolicyCacheBase* user_policy_cache = NULL; - user_data_store_.reset(CloudPolicyDataStore::CreateForUserPolicies()); + user_data_store_.reset(CloudPolicyDataStore::CreateForUserPolicies()); #if defined(OS_CHROMEOS) - user_policy_cache = - new CrosUserPolicyCache( - chromeos::DBusThreadManager::Get()->GetSessionManagerClient(), - user_data_store_.get(), - wait_for_policy_fetch, - token_cache_file, - policy_cache_file); + user_policy_cache = + new CrosUserPolicyCache( + chromeos::DBusThreadManager::Get()->GetSessionManagerClient(), + user_data_store_.get(), + wait_for_policy_fetch, + token_cache_file, + policy_cache_file); #else - user_policy_cache = new UserPolicyCache(policy_cache_file, - wait_for_policy_fetch); - user_policy_token_cache_.reset( - new UserPolicyTokenCache(user_data_store_.get(), token_cache_file)); + user_policy_cache = new UserPolicyCache(policy_cache_file, + wait_for_policy_fetch); + user_policy_token_cache_.reset( + new UserPolicyTokenCache(user_data_store_.get(), token_cache_file)); - // Initiate the DM-Token load. - user_policy_token_cache_->Load(); + // Initiate the DM-Token load. + user_policy_token_cache_->Load(); #endif - user_cloud_policy_subsystem_.reset(new CloudPolicySubsystem( - user_data_store_.get(), - user_policy_cache)); + user_cloud_policy_subsystem_.reset(new CloudPolicySubsystem( + user_data_store_.get(), + user_policy_cache, + GetDeviceManagementUrl())); - user_data_store_->set_user_name(user_name); - user_data_store_->set_user_affiliation(GetUserAffiliation(user_name)); + user_data_store_->set_user_name(user_name); + user_data_store_->set_user_affiliation(GetUserAffiliation(user_name)); - user_cloud_policy_subsystem_->CompleteInitialization( - prefs::kUserPolicyRefreshRate, - startup_delay); + user_cloud_policy_subsystem_->CompleteInitialization( + prefs::kUserPolicyRefreshRate, + startup_delay); - managed_cloud_provider_->SetUserPolicyCache(user_policy_cache); - recommended_cloud_provider_->SetUserPolicyCache(user_policy_cache); - } + managed_cloud_provider_->SetUserPolicyCache(user_policy_cache); + recommended_cloud_provider_->SetUserPolicyCache(user_policy_cache); } } @@ -407,17 +429,6 @@ void BrowserPolicyConnector::RegisterForUserPolicy( if (user_data_store_.get()) user_data_store_->SetOAuthToken(oauth_token); } - if (user_cloud_policy_manager_.get()) { - CloudPolicyService* service = - user_cloud_policy_manager_->cloud_policy_service(); - if (service->client() && - !service->client()->is_registered() && - !oauth_token.empty()) { - service->client()->Register(oauth_token); - } else { - user_cloud_policy_manager_->CancelWaitForPolicyFetch(); - } - } } CloudPolicyDataStore* BrowserPolicyConnector::GetDeviceCloudPolicyDataStore() { @@ -441,9 +452,11 @@ UserAffiliation BrowserPolicyConnector::GetUserAffiliation( const std::string& user_name) { #if defined(OS_CHROMEOS) if (install_attributes_.get()) { - size_t pos = user_name.find('@'); + std::string canonicalized_user_name(gaia::CanonicalizeEmail(user_name)); + size_t pos = canonicalized_user_name.find('@'); if (pos != std::string::npos && - user_name.substr(pos + 1) == install_attributes_->GetDomain()) { + canonicalized_user_name.substr(pos + 1) == + install_attributes_->GetDomain()) { return USER_AFFILIATION_MANAGED; } } @@ -474,6 +487,15 @@ void BrowserPolicyConnector::SetPolicyProviderForTesting( g_testing_provider = provider; } +// static +std::string BrowserPolicyConnector::GetDeviceManagementUrl() { + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(switches::kDeviceManagementUrl)) + return command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl); + else + return kDefaultDeviceManagementServerUrl; +} + void BrowserPolicyConnector::Observe( int type, const content::NotificationSource& source, @@ -521,7 +543,12 @@ void BrowserPolicyConnector::InitializeDevicePolicy() { device_cloud_policy_subsystem_.reset(new CloudPolicySubsystem( device_data_store_.get(), - device_policy_cache)); + device_policy_cache, + GetDeviceManagementUrl())); + + // Skip the final initialization if this is a unit test. + if (!MessageLoop::current()) + return; // Initialize the subsystem once the message loops are spinning. MessageLoop::current()->PostTask( diff --git a/chrome/browser/policy/browser_policy_connector.h b/chrome/browser/policy/browser_policy_connector.h index 818c2bf..8218f36 100644 --- a/chrome/browser/policy/browser_policy_connector.h +++ b/chrome/browser/policy/browser_policy_connector.h @@ -48,9 +48,14 @@ class BrowserPolicyConnector : public content::NotificationObserver { // policy system running. void Init(); + // Creates a UserCloudPolicyManager for the given profile, or returns NULL if + // it is not supported on this platform. Ownership is transferred to the + // caller. + scoped_ptr<UserCloudPolicyManager> CreateCloudPolicyManager(Profile* profile); + // Creates a new policy service for the given profile, or a global one if // it is NULL. Ownership is transferred to the caller. - PolicyService* CreatePolicyService(Profile* profile); + scoped_ptr<PolicyService> CreatePolicyService(Profile* profile); // Returns a weak pointer to the CloudPolicySubsystem corresponding to the // device policy managed by this policy connector, or NULL if no such @@ -140,6 +145,10 @@ class BrowserPolicyConnector : public content::NotificationObserver { AppPackUpdater* GetAppPackUpdater(); + DeviceManagementService* device_management_service() { + return device_management_service_.get(); + } + // Sets a |provider| that will be included in PolicyServices returned by // CreatePolicyService. This is a static method because local state is // created immediately after the connector, and tests don't have a chance to @@ -148,6 +157,10 @@ class BrowserPolicyConnector : public content::NotificationObserver { static void SetPolicyProviderForTesting( ConfigurationPolicyProvider* provider); + // Gets the URL of the DM server (either the default or a URL provided via the + // command line). + static std::string GetDeviceManagementUrl(); + private: // content::NotificationObserver method overrides: virtual void Observe(int type, @@ -190,7 +203,6 @@ class BrowserPolicyConnector : public content::NotificationObserver { scoped_ptr<DeviceManagementService> device_management_service_; ProxyPolicyProvider user_cloud_policy_provider_; - scoped_ptr<UserCloudPolicyManager> user_cloud_policy_manager_; // Used to initialize the device policy subsystem once the message loops // are spinning. diff --git a/chrome/browser/policy/cloud_policy_client.cc b/chrome/browser/policy/cloud_policy_client.cc index c34adac..6a27d06 100644 --- a/chrome/browser/policy/cloud_policy_client.cc +++ b/chrome/browser/policy/cloud_policy_client.cc @@ -31,9 +31,10 @@ CloudPolicyClient::CloudPolicyClient(const std::string& machine_id, submit_machine_id_(false), public_key_version_(-1), public_key_version_valid_(false), - service_(service), - status_provider_(status_provider), - status_(DM_STATUS_SUCCESS) {} + service_(service), // Can be NULL for unit tests. + status_provider_(status_provider), // Can be NULL for unit tests. + status_(DM_STATUS_SUCCESS) { +} CloudPolicyClient::~CloudPolicyClient() {} @@ -52,6 +53,7 @@ void CloudPolicyClient::SetupRegistration(const std::string& dm_token, } void CloudPolicyClient::Register(const std::string& auth_token) { + DCHECK(service_); DCHECK(!auth_token.empty()); DCHECK(!is_registered()); @@ -120,6 +122,7 @@ void CloudPolicyClient::FetchPolicy() { } void CloudPolicyClient::Unregister() { + DCHECK(service_); request_job_.reset( service_->CreateJob(DeviceManagementRequestJob::TYPE_UNREGISTRATION)); request_job_->SetDMToken(dm_token_); diff --git a/chrome/browser/policy/cloud_policy_provider.cc b/chrome/browser/policy/cloud_policy_provider.cc index f921b8a..e4af5ce 100644 --- a/chrome/browser/policy/cloud_policy_provider.cc +++ b/chrome/browser/policy/cloud_policy_provider.cc @@ -4,10 +4,12 @@ #include "chrome/browser/policy/cloud_policy_provider.h" +#include "base/command_line.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/policy/browser_policy_connector.h" #include "chrome/browser/policy/policy_bundle.h" #include "chrome/browser/policy/policy_map.h" +#include "chrome/common/chrome_switches.h" namespace policy { @@ -83,6 +85,14 @@ void CloudPolicyProvider::Merge() { if (!initialization_complete_) { initialization_complete_ = true; for (size_t i = 0; i < CACHE_SIZE; ++i) { +#if defined(OS_CHROMEOS) + // Ignore the device policy cache if device policy is not enabled. + if (i == CACHE_DEVICE && + !CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableDevicePolicy)) { + continue; + } +#endif if (caches_[i] == NULL || !caches_[i]->IsReady()) { initialization_complete_ = false; break; diff --git a/chrome/browser/policy/cloud_policy_store.h b/chrome/browser/policy/cloud_policy_store.h index 224fcea..080e50e 100644 --- a/chrome/browser/policy/cloud_policy_store.h +++ b/chrome/browser/policy/cloud_policy_store.h @@ -12,6 +12,8 @@ #include "chrome/browser/policy/policy_map.h" #include "chrome/browser/policy/proto/device_management_backend.pb.h" +class Profile; + namespace policy { // Defines the low-level interface used by the cloud policy code to: @@ -91,6 +93,12 @@ class CloudPolicyStore { // Removes the specified observer. void RemoveObserver(Observer* observer); + // Factory method to create a CloudPolicyStore appropriate for the current + // platform, for storing user policy for the user associated with the passed + // |profile|. Implementation is defined in the individual platform store + // files. + static scoped_ptr<CloudPolicyStore> CreateUserPolicyStore(Profile* profile); + protected: // Invokes the corresponding callback on all registered observers. void NotifyStoreLoaded(); diff --git a/chrome/browser/policy/cloud_policy_subsystem.cc b/chrome/browser/policy/cloud_policy_subsystem.cc index c48f61e..bc51d67 100644 --- a/chrome/browser/policy/cloud_policy_subsystem.cc +++ b/chrome/browser/policy/cloud_policy_subsystem.cc @@ -50,13 +50,8 @@ CloudPolicySubsystem::ObserverRegistrar::~ObserverRegistrar() { CloudPolicySubsystem::CloudPolicySubsystem( CloudPolicyDataStore* data_store, - CloudPolicyCacheBase* policy_cache) { - std::string device_management_url; - CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (command_line->HasSwitch(switches::kDeviceManagementUrl)) { - device_management_url = - command_line->GetSwitchValueASCII(switches::kDeviceManagementUrl); - } + CloudPolicyCacheBase* policy_cache, + const std::string& device_management_url) { Initialize(data_store, policy_cache, device_management_url); } diff --git a/chrome/browser/policy/cloud_policy_subsystem.h b/chrome/browser/policy/cloud_policy_subsystem.h index bb95c15..12effca 100644 --- a/chrome/browser/policy/cloud_policy_subsystem.h +++ b/chrome/browser/policy/cloud_policy_subsystem.h @@ -71,7 +71,8 @@ class CloudPolicySubsystem }; CloudPolicySubsystem(CloudPolicyDataStore* data_store, - CloudPolicyCacheBase* policy_cache); + CloudPolicyCacheBase* policy_cache, + const std::string& device_management_url); virtual ~CloudPolicySubsystem(); // Initializes the subsystem. The first network request will only be made diff --git a/chrome/browser/policy/config_dir_policy_loader.cc b/chrome/browser/policy/config_dir_policy_loader.cc index 4e83229..82495a4b 100644 --- a/chrome/browser/policy/config_dir_policy_loader.cc +++ b/chrome/browser/policy/config_dir_policy_loader.cc @@ -13,9 +13,11 @@ #include "base/file_util.h" #include "base/json/json_file_value_serializer.h" #include "base/logging.h" +#include "base/message_loop.h" #include "base/platform_file.h" #include "base/stl_util.h" #include "chrome/browser/policy/policy_bundle.h" +#include "content/public/browser/browser_thread.h" namespace policy { @@ -36,6 +38,13 @@ ConfigDirPolicyLoader::ConfigDirPolicyLoader(const FilePath& config_dir, ConfigDirPolicyLoader::~ConfigDirPolicyLoader() {} void ConfigDirPolicyLoader::InitOnFile() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); + // Some unit tests create a File thread that shares a MessageLoop with the + // UI thread, and this causes DCHECKs because IO operations aren't allowed on + // that thread. So if this is running in the context of one of those tests, + // just exit. + if (!MessageLoop::current()->IsType(MessageLoop::TYPE_IO)) + return; base::files::FilePathWatcher::Callback callback = base::Bind(&ConfigDirPolicyLoader::OnFileUpdated, base::Unretained(this)); mandatory_watcher_.Watch(config_dir_.Append(kMandatoryConfigDir), callback); diff --git a/chrome/browser/policy/user_cloud_policy_manager.cc b/chrome/browser/policy/user_cloud_policy_manager.cc index ccbc55d..84f4c67 100644 --- a/chrome/browser/policy/user_cloud_policy_manager.cc +++ b/chrome/browser/policy/user_cloud_policy_manager.cc @@ -56,32 +56,21 @@ UserCloudPolicyManager::~UserCloudPolicyManager() { store_->RemoveObserver(this); } -#if defined(OS_CHROMEOS) // static scoped_ptr<UserCloudPolicyManager> UserCloudPolicyManager::Create( + Profile* profile, bool wait_for_policy_fetch) { - FilePath profile_dir; - CHECK(PathService::Get(chrome::DIR_USER_DATA, &profile_dir)); - CommandLine* command_line = CommandLine::ForCurrentProcess(); - const FilePath policy_dir = - profile_dir - .Append(command_line->GetSwitchValuePath(switches::kLoginProfile)) - .Append(kPolicyDir); - const FilePath policy_cache_file = policy_dir.Append(kPolicyCacheFile); - const FilePath token_cache_file = policy_dir.Append(kTokenCacheFile); - - scoped_ptr<CloudPolicyStore> store( - new UserCloudPolicyStoreChromeOS( - chromeos::DBusThreadManager::Get()->GetSessionManagerClient(), - token_cache_file, policy_cache_file)); + scoped_ptr<CloudPolicyStore> store = + CloudPolicyStore::CreateUserPolicyStore(profile); return scoped_ptr<UserCloudPolicyManager>( new UserCloudPolicyManager(store.Pass(), wait_for_policy_fetch)); } -#endif void UserCloudPolicyManager::Initialize(PrefService* prefs, DeviceManagementService* service, UserAffiliation user_affiliation) { + DCHECK(service); + DCHECK(prefs); DCHECK(!service_.get()); prefs_ = prefs; scoped_ptr<CloudPolicyClient> client( @@ -129,6 +118,18 @@ void UserCloudPolicyManager::CancelWaitForPolicyFetch() { } } +bool UserCloudPolicyManager::IsClientRegistered() const { + if (!service_.get()) + return false; + return service_->client()->is_registered(); +} + +void UserCloudPolicyManager::RegisterClient(const std::string& access_token) { + DCHECK(cloud_policy_service()) << "Callers must invoke Initialize() first"; + if (!cloud_policy_service()->client()->is_registered()) + cloud_policy_service()->client()->Register(access_token); +} + bool UserCloudPolicyManager::IsInitializationComplete() const { return store_->is_initialized() && !wait_for_policy_fetch_; } diff --git a/chrome/browser/policy/user_cloud_policy_manager.h b/chrome/browser/policy/user_cloud_policy_manager.h index 8db19d0..98c59e2 100644 --- a/chrome/browser/policy/user_cloud_policy_manager.h +++ b/chrome/browser/policy/user_cloud_policy_manager.h @@ -13,6 +13,7 @@ #include "chrome/browser/policy/configuration_policy_provider.h" class PrefService; +class Profile; namespace policy { @@ -33,23 +34,32 @@ class UserCloudPolicyManager : public ConfigurationPolicyProvider, bool wait_for_policy_fetch); virtual ~UserCloudPolicyManager(); -#if defined(OS_CHROMEOS) - // Creates a UserCloudPolicyService instance for the Chrome OS platform. - static scoped_ptr<UserCloudPolicyManager> Create(bool wait_for_policy_fetch); -#endif + // Creates a UserCloudPolicyService instance associated with the passed + // |profile|. + static scoped_ptr<UserCloudPolicyManager> Create(Profile* profile, + bool wait_for_policy_fetch); - // Initializes the cloud connection. |prefs| and |service| must stay valid - // until Shutdown() gets called. - void Initialize(PrefService* prefs, - DeviceManagementService* service, - UserAffiliation user_affiliation); - void Shutdown(); + // Initializes the cloud connection. |local_prefs| and |service| must stay + // valid until Shutdown() gets called. Virtual for mocking. + virtual void Initialize(PrefService* local_prefs, + DeviceManagementService* service, + UserAffiliation user_affiliation); + + // Virtual for mocks. + virtual void Shutdown(); // Cancels waiting for the policy fetch and flags the // ConfigurationPolicyProvider ready (assuming all other initialization tasks // have completed). void CancelWaitForPolicyFetch(); + // Returns true if the underlying CloudPolicyClient is already registered. + // Virtual for mocking. + virtual bool IsClientRegistered() const; + + // Register the CloudPolicyClient using the passed OAuth token. + void RegisterClient(const std::string& access_token); + CloudPolicyService* cloud_policy_service() { return service_.get(); } // ConfigurationPolicyProvider: diff --git a/chrome/browser/policy/user_cloud_policy_store.cc b/chrome/browser/policy/user_cloud_policy_store.cc new file mode 100644 index 0000000..9817828 --- /dev/null +++ b/chrome/browser/policy/user_cloud_policy_store.cc @@ -0,0 +1,79 @@ +// 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/user_cloud_policy_store.h" + +#include "base/bind.h" +#include "chrome/browser/policy/proto/cloud_policy.pb.h" +#include "chrome/browser/signin/signin_manager.h" +#include "chrome/browser/signin/signin_manager_factory.h" + +using enterprise_management::PolicyData; + +namespace policy { + +UserCloudPolicyStore::UserCloudPolicyStore(Profile* profile) + : ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), + profile_(profile) { +} + +UserCloudPolicyStore::~UserCloudPolicyStore() { +} + +void UserCloudPolicyStore::Load() { + // TODO(atwilson): Read policy from file. + policy_.reset(); + policy_map_.Clear(); + NotifyStoreLoaded(); +} + +void UserCloudPolicyStore::Store( + const enterprise_management::PolicyFetchResponse& policy) { + // Stop any pending requests to store policy, then validate the new policy + // before storing it. + weak_factory_.InvalidateWeakPtrs(); + scoped_ptr<enterprise_management::PolicyFetchResponse> policy_copy( + new enterprise_management::PolicyFetchResponse(policy)); + Validate(policy_copy.Pass(), + base::Bind(&UserCloudPolicyStore::StorePolicyAfterValidation, + weak_factory_.GetWeakPtr())); +} + +void UserCloudPolicyStore::Validate( + scoped_ptr<enterprise_management::PolicyFetchResponse> policy, + const UserCloudPolicyValidator::CompletionCallback& callback) { + // Configure the validator. + scoped_ptr<UserCloudPolicyValidator> validator = + CreateValidator(policy.Pass(), callback); + SigninManager* signin = SigninManagerFactory::GetForProfile(profile_); + std::string username = signin->GetAuthenticatedUsername(); + DCHECK(!username.empty()); + validator->ValidateUsername(username); + + // Start validation. The Validator will free itself once validation is + // complete. + validator.release()->StartValidation(); +} + +void UserCloudPolicyStore::StorePolicyAfterValidation( + UserCloudPolicyValidator* validator) { + validation_status_ = validator->status(); + if (!validator->success()) { + status_ = STATUS_VALIDATION_ERROR; + NotifyStoreError(); + return; + } + // TODO(atwilson): Write policy to file. + InstallPolicy(validator->policy_data().Pass(), validator->payload().Pass()); + status_ = STATUS_OK; + NotifyStoreLoaded(); +} + +// static +scoped_ptr<CloudPolicyStore> CloudPolicyStore::CreateUserPolicyStore( + Profile* profile) { + return scoped_ptr<CloudPolicyStore>(new UserCloudPolicyStore(profile)); +} + +} // namespace policy diff --git a/chrome/browser/policy/user_cloud_policy_store.h b/chrome/browser/policy/user_cloud_policy_store.h new file mode 100644 index 0000000..85141dd --- /dev/null +++ b/chrome/browser/policy/user_cloud_policy_store.h @@ -0,0 +1,52 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_USER_CLOUD_POLICY_STORE_H_ +#define CHROME_BROWSER_POLICY_USER_CLOUD_POLICY_STORE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/policy/user_cloud_policy_store_base.h" + +namespace policy { + +// Implements a cloud policy store that is stored in a simple file in the user's +// profile directory. This is used on (non-chromeos) platforms that do not have +// a secure storage implementation. +class UserCloudPolicyStore : public UserCloudPolicyStoreBase { + public: + // Creates a policy store associated with the user signed in to this + // |profile|. + explicit UserCloudPolicyStore(Profile* profile); + virtual ~UserCloudPolicyStore(); + + // CloudPolicyStore implementation. + virtual void Load() OVERRIDE; + virtual void Store( + const enterprise_management::PolicyFetchResponse& policy) OVERRIDE; + + private: + // Starts policy blob validation. |callback| is invoked once validation is + // complete. + void Validate( + scoped_ptr<enterprise_management::PolicyFetchResponse> policy, + const UserCloudPolicyValidator::CompletionCallback& callback); + + // Callback invoked to store the policy after validation has finished. + void StorePolicyAfterValidation(UserCloudPolicyValidator* validator); + + base::WeakPtrFactory<UserCloudPolicyStore> weak_factory_; + + // Weak pointer to the profile associated with this store. + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStore); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_USER_CLOUD_POLICY_STORE_H_ diff --git a/chrome/browser/policy/user_cloud_policy_store_base.cc b/chrome/browser/policy/user_cloud_policy_store_base.cc new file mode 100644 index 0000000..4658ab9 --- /dev/null +++ b/chrome/browser/policy/user_cloud_policy_store_base.cc @@ -0,0 +1,44 @@ +// 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/user_cloud_policy_store_base.h" + +#include "chrome/browser/policy/cloud_policy_constants.h" +#include "chrome/browser/policy/proto/cloud_policy.pb.h" + +namespace policy { + +// Decodes a CloudPolicySettings object into a policy map. The implementation is +// generated code in policy/cloud_policy_generated.cc. +void DecodePolicy(const enterprise_management::CloudPolicySettings& policy, + PolicyMap* policies); + +UserCloudPolicyStoreBase::UserCloudPolicyStoreBase() { +} + +UserCloudPolicyStoreBase::~UserCloudPolicyStoreBase() { +} + +scoped_ptr<UserCloudPolicyValidator> UserCloudPolicyStoreBase::CreateValidator( + scoped_ptr<enterprise_management::PolicyFetchResponse> policy, + const UserCloudPolicyValidator::CompletionCallback& callback) { + // Configure the validator. + UserCloudPolicyValidator* validator = + UserCloudPolicyValidator::Create(policy.Pass(), callback); + validator->ValidatePolicyType(dm_protocol::kChromeUserPolicyType); + validator->ValidateAgainstCurrentPolicy(policy_.get()); + validator->ValidatePayload(); + return scoped_ptr<UserCloudPolicyValidator>(validator); +} + +void UserCloudPolicyStoreBase::InstallPolicy( + scoped_ptr<enterprise_management::PolicyData> policy_data, + scoped_ptr<enterprise_management::CloudPolicySettings> payload) { + // Decode the payload. + policy_map_.Clear(); + DecodePolicy(*payload, &policy_map_); + policy_ = policy_data.Pass(); +} + +} // namespace policy diff --git a/chrome/browser/policy/user_cloud_policy_store_base.h b/chrome/browser/policy/user_cloud_policy_store_base.h new file mode 100644 index 0000000..5fda2f8 --- /dev/null +++ b/chrome/browser/policy/user_cloud_policy_store_base.h @@ -0,0 +1,42 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_USER_CLOUD_POLICY_STORE_BASE_H_ +#define CHROME_BROWSER_POLICY_USER_CLOUD_POLICY_STORE_BASE_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/policy/cloud_policy_store.h" + +namespace policy { + +// Base class that implements common cross-platform UserCloudPolicyStore +// functionality. +class UserCloudPolicyStoreBase : public CloudPolicyStore { + public: + UserCloudPolicyStoreBase(); + virtual ~UserCloudPolicyStoreBase(); + + protected: + // Creates a validator configured to validate a user policy. The caller owns + // the resulting object until StartValidation() is invoked. + scoped_ptr<UserCloudPolicyValidator> CreateValidator( + scoped_ptr<enterprise_management::PolicyFetchResponse> policy, + const UserCloudPolicyValidator::CompletionCallback& callback); + + // Sets |policy_data| and |payload| as the active policy. + void InstallPolicy( + scoped_ptr<enterprise_management::PolicyData> policy_data, + scoped_ptr<enterprise_management::CloudPolicySettings> payload); + + private: + DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreBase); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_USER_CLOUD_POLICY_STORE_BASE_H_ diff --git a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc index 4a0a38f..f44b10c 100644 --- a/chrome/browser/policy/user_cloud_policy_store_chromeos.cc +++ b/chrome/browser/policy/user_cloud_policy_store_chromeos.cc @@ -9,14 +9,19 @@ #include "base/bind.h" #include "base/bind_helpers.h" #include "base/callback.h" +#include "base/command_line.h" #include "base/file_util.h" #include "base/memory/ref_counted.h" +#include "base/path_service.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/policy/proto/cloud_policy.pb.h" #include "chrome/browser/policy/proto/device_management_local.pb.h" #include "chrome/browser/policy/user_policy_disk_cache.h" #include "chrome/browser/policy/user_policy_token_cache.h" #include "chrome/common/net/gaia/gaia_auth_util.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/session_manager_client.h" #include "content/public/browser/browser_thread.h" @@ -24,10 +29,15 @@ namespace em = enterprise_management; namespace policy { -// Decodes a CloudPolicySettings object into a policy map. The implementation is -// generated code in policy/cloud_policy_generated.cc. -void DecodePolicy(const em::CloudPolicySettings& policy, - PolicyMap* policies); +namespace { +// Subdirectory in the user's profile for storing user policies. +const FilePath::CharType kPolicyDir[] = FILE_PATH_LITERAL("Device Management"); +// File in the above directory for stroing user policy dmtokens. +const FilePath::CharType kTokenCacheFile[] = FILE_PATH_LITERAL("Token"); +// File in the above directory for storing user policy data. +const FilePath::CharType kPolicyCacheFile[] = FILE_PATH_LITERAL("Policy"); +} // namespace + // Helper class for loading legacy policy caches. class LegacyPolicyCacheLoader : public UserPolicyTokenCache::Delegate, @@ -158,10 +168,10 @@ void UserCloudPolicyStoreChromeOS::Store( const em::PolicyFetchResponse& policy) { // Cancel all pending requests. weak_factory_.InvalidateWeakPtrs(); - Validate(scoped_ptr<em::PolicyFetchResponse>( - new em::PolicyFetchResponse(policy)), - base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated, - weak_factory_.GetWeakPtr())); + Validate( + scoped_ptr<em::PolicyFetchResponse>(new em::PolicyFetchResponse(policy)), + base::Bind(&UserCloudPolicyStoreChromeOS::OnPolicyToStoreValidated, + weak_factory_.GetWeakPtr())); } void UserCloudPolicyStoreChromeOS::Load() { @@ -262,33 +272,22 @@ void UserCloudPolicyStoreChromeOS::OnPolicyStored(bool success) { } } -void UserCloudPolicyStoreChromeOS::InstallPolicy( - scoped_ptr<em::PolicyData> policy_data, - scoped_ptr<em::CloudPolicySettings> payload) { - // Decode the payload. - policy_map_.Clear(); - DecodePolicy(*payload, &policy_map_); - policy_ = policy_data.Pass(); -} - void UserCloudPolicyStoreChromeOS::Validate( scoped_ptr<em::PolicyFetchResponse> policy, const UserCloudPolicyValidator::CompletionCallback& callback) { // Configure the validator. - UserCloudPolicyValidator* validator = - UserCloudPolicyValidator::Create(policy.Pass(), callback); + scoped_ptr<UserCloudPolicyValidator> validator = + CreateValidator(policy.Pass(), callback); validator->ValidateUsername( chromeos::UserManager::Get()->GetLoggedInUser().email()); - validator->ValidatePolicyType(dm_protocol::kChromeUserPolicyType); - validator->ValidateAgainstCurrentPolicy(policy_.get()); - validator->ValidatePayload(); // TODO(mnissler): Do a signature check here as well. The key is stored by // session_manager in the root-owned cryptohome area, which is currently // inaccessible to Chrome though. - // Start validation. - validator->StartValidation(); + // Start validation. The Validator will free itself once validation is + // complete. + validator.release()->StartValidation(); } void UserCloudPolicyStoreChromeOS::OnLegacyLoadFinished( @@ -352,4 +351,22 @@ void UserCloudPolicyStoreChromeOS::RemoveLegacyCacheDir(const FilePath& dir) { LOG(ERROR) << "Failed to remove cache dir " << dir.value(); } +// static +scoped_ptr<CloudPolicyStore> CloudPolicyStore::CreateUserPolicyStore( + Profile* profile) { + FilePath profile_dir; + CHECK(PathService::Get(chrome::DIR_USER_DATA, &profile_dir)); + CommandLine* command_line = CommandLine::ForCurrentProcess(); + const FilePath policy_dir = + profile_dir + .Append(command_line->GetSwitchValuePath(switches::kLoginProfile)) + .Append(kPolicyDir); + const FilePath policy_cache_file = policy_dir.Append(kPolicyCacheFile); + const FilePath token_cache_file = policy_dir.Append(kTokenCacheFile); + + return scoped_ptr<CloudPolicyStore>(new UserCloudPolicyStoreChromeOS( + chromeos::DBusThreadManager::Get()->GetSessionManagerClient(), + token_cache_file, policy_cache_file)); +} + } // namespace policy diff --git a/chrome/browser/policy/user_cloud_policy_store_chromeos.h b/chrome/browser/policy/user_cloud_policy_store_chromeos.h index 41ea0d1..3fba4b0 100644 --- a/chrome/browser/policy/user_cloud_policy_store_chromeos.h +++ b/chrome/browser/policy/user_cloud_policy_store_chromeos.h @@ -12,8 +12,8 @@ #include "base/file_path.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" -#include "chrome/browser/policy/cloud_policy_store.h" #include "chrome/browser/policy/cloud_policy_validator.h" +#include "chrome/browser/policy/user_cloud_policy_store_base.h" namespace chromeos { class SessionManagerClient; @@ -34,7 +34,7 @@ class LegacyPolicyCacheLoader; // Additionally, this class drives legacy UserPolicyTokenCache and // UserPolicyDiskCache instances, migrating policy from these to session_manager // storage on the fly. -class UserCloudPolicyStoreChromeOS : public CloudPolicyStore { +class UserCloudPolicyStoreChromeOS : public UserCloudPolicyStoreBase { public: UserCloudPolicyStoreChromeOS( chromeos::SessionManagerClient* session_manager_client, @@ -62,11 +62,6 @@ class UserCloudPolicyStoreChromeOS : public CloudPolicyStore { // Called back from SessionManagerClient for policy store operations. void OnPolicyStored(bool); - // Installs |policy_data| and |payload|. - void InstallPolicy( - scoped_ptr<enterprise_management::PolicyData> policy_data, - scoped_ptr<enterprise_management::CloudPolicySettings> payload); - // Starts policy blob validation. void Validate( scoped_ptr<enterprise_management::PolicyFetchResponse> policy, diff --git a/chrome/browser/policy/user_cloud_policy_store_unittest.cc b/chrome/browser/policy/user_cloud_policy_store_unittest.cc new file mode 100644 index 0000000..5f0ff80 --- /dev/null +++ b/chrome/browser/policy/user_cloud_policy_store_unittest.cc @@ -0,0 +1,133 @@ +// 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/user_cloud_policy_store.h" + +#include "base/message_loop.h" +#include "base/run_loop.h" +#include "chrome/browser/policy/policy_builder.h" +#include "chrome/browser/signin/signin_manager.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/signin/signin_manager_fake.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/test/test_browser_thread.h" +#include "policy/policy_constants.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::AllOf; +using testing::Eq; +using testing::Property; + +namespace policy { + +namespace { + +class MockCloudPolicyStoreObserver : public CloudPolicyStore::Observer { + public: + MockCloudPolicyStoreObserver() {} + virtual ~MockCloudPolicyStoreObserver() {} + + MOCK_METHOD1(OnStoreLoaded, void(CloudPolicyStore* store)); + MOCK_METHOD1(OnStoreError, void(CloudPolicyStore* store)); + + private: + DISALLOW_COPY_AND_ASSIGN(MockCloudPolicyStoreObserver); +}; + +class UserCloudPolicyStoreTest : public testing::Test { + public: + UserCloudPolicyStoreTest() + : loop_(MessageLoop::TYPE_UI), + ui_thread_(content::BrowserThread::UI, &loop_), + file_thread_(content::BrowserThread::FILE, &loop_), + profile_(new TestingProfile()) {} + + virtual void SetUp() OVERRIDE { + SigninManager* signin = static_cast<SigninManager*>( + SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse( + profile_.get(), FakeSigninManager::Build)); + signin->SetAuthenticatedUsername(PolicyBuilder::kFakeUsername); + store_.reset(new UserCloudPolicyStore(profile_.get())); + store_->AddObserver(&observer_); + + policy_.payload().mutable_showhomebutton()->set_showhomebutton(true); + policy_.Build(); + } + + virtual void TearDown() OVERRIDE { + store_->RemoveObserver(&observer_); + store_.reset(); + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + } + + // Verifies that store_->policy_map() has the ShowHomeButton entry. + void VerifyPolicyMap() { + EXPECT_EQ(1U, store_->policy_map().size()); + const PolicyMap::Entry* entry = + store_->policy_map().Get(key::kShowHomeButton); + ASSERT_TRUE(entry); + EXPECT_TRUE(base::FundamentalValue(true).Equals(entry->value)); + } + + // Install an expectation on |observer_| for an error code. + void ExpectError(CloudPolicyStore::Status error) { + EXPECT_CALL(observer_, + OnStoreError(AllOf(Eq(store_.get()), + Property(&CloudPolicyStore::status, + Eq(error))))); + } + + UserPolicyBuilder policy_; + MockCloudPolicyStoreObserver observer_; + scoped_ptr<UserCloudPolicyStore> store_; + + // CloudPolicyValidator() requires a FILE thread so declare one here. Both + // |ui_thread_| and |file_thread_| share the same MessageLoop |loop_| so + // callers can use RunLoop to manage both virtual threads. + MessageLoop loop_; + content::TestBrowserThread ui_thread_; + content::TestBrowserThread file_thread_; + + scoped_ptr<TestingProfile> profile_; + + DISALLOW_COPY_AND_ASSIGN(UserCloudPolicyStoreTest); +}; + +TEST_F(UserCloudPolicyStoreTest, Store) { + EXPECT_FALSE(store_->policy()); + EXPECT_TRUE(store_->policy_map().empty()); + + // Store a simple policy and make sure it ends up as the currently active + // policy. + store_->Store(policy_.policy()); + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + + // Policy should be decoded and stored. + ASSERT_TRUE(store_->policy()); + EXPECT_EQ(policy_.policy_data().SerializeAsString(), + store_->policy()->SerializeAsString()); + VerifyPolicyMap(); + EXPECT_EQ(CloudPolicyStore::STATUS_OK, store_->status()); +} + +TEST_F(UserCloudPolicyStoreTest, StoreValidationError) { + // Create an invalid policy (no policy type). + policy_.policy_data().clear_policy_type(); + policy_.Build(); + + // Store policy. + ExpectError(CloudPolicyStore::STATUS_VALIDATION_ERROR); + store_->Store(policy_.policy()); + base::RunLoop run_loop; + run_loop.RunUntilIdle(); + ASSERT_FALSE(store_->policy()); +} + +} // namespace + +} // namespace policy + diff --git a/chrome/browser/policy/user_policy_signin_service.cc b/chrome/browser/policy/user_policy_signin_service.cc new file mode 100644 index 0000000..32137be --- /dev/null +++ b/chrome/browser/policy/user_policy_signin_service.cc @@ -0,0 +1,177 @@ +// 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/user_policy_signin_service.h" + +#include "chrome/browser/browser_process.h" +#include "chrome/browser/policy/browser_policy_connector.h" +#include "chrome/browser/policy/cloud_policy_service.h" +#include "chrome/browser/policy/user_cloud_policy_manager.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/signin_manager.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/signin/token_service.h" +#include "chrome/browser/signin/token_service_factory.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/net/gaia/gaia_constants.h" +#include "chrome/common/net/gaia/gaia_urls.h" +#include "chrome/common/net/gaia/oauth2_access_token_fetcher.h" +#include "chrome/common/pref_names.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_source.h" + +namespace { +// TODO(atwilson): Move this once we add OAuth token support to TokenService. +const char kServiceScopeChromeOSDeviceManagement[] = + "https://www.googleapis.com/auth/chromeosdevicemanagement"; + +// How long to delay before starting device policy network requests. Set to a +// few seconds to alleviate contention during initial startup. +const int64 kPolicyServiceInitializationDelayMilliseconds = 2000; +} // namespace + +namespace policy { + +UserPolicySigninService::UserPolicySigninService( + Profile* profile, + UserCloudPolicyManager* manager) + : profile_(profile), + manager_(manager) { + + // Initialize/shutdown the UserCloudPolicyManager when the user signs in or + // out. + registrar_.Add(this, + chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, + content::Source<Profile>(profile)); + registrar_.Add(this, + chrome::NOTIFICATION_TOKEN_AVAILABLE, + content::Source<TokenService>( + TokenServiceFactory::GetForProfile(profile))); + + // The Profile is not yet fully initialized when this object is created, + // so wait until the initialization has finished to initialize the + // UserCloudPolicyManager as otherwise various crashes ensue from services + // trying to access the partially-initialized Profile. + // TODO(atwilson): Remove this once ProfileImpl::DoFinalInit() goes away and + // the profile is fully initialized before ProfileKeyedServices are created. + registrar_.Add(this, + chrome::NOTIFICATION_PROFILE_ADDED, + content::Source<Profile>(profile)); +} + +UserPolicySigninService::~UserPolicySigninService() { +} + +void UserPolicySigninService::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + switch (type) { + case chrome::NOTIFICATION_PROFILE_ADDED: + // Profile is initialized so it's safe to initialize the + // UserCloudPolicyManager now. + ConfigureUserCloudPolicyManager(); + break; + case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: + ConfigureUserCloudPolicyManager(); + break; + case chrome::NOTIFICATION_TOKEN_AVAILABLE: { + const TokenService::TokenAvailableDetails& token_details = + *(content::Details<const TokenService::TokenAvailableDetails>( + details).ptr()); + if (token_details.service() == + GaiaConstants::kGaiaOAuth2LoginRefreshToken) { + // TokenService now has a refresh token, so reconfigure the + // UserCloudPolicyManager to initiate a DMToken fetch if needed. + ConfigureUserCloudPolicyManager(); + } + break; + } + default: + NOTREACHED(); + } +} + + +void UserPolicySigninService::ConfigureUserCloudPolicyManager() { + // Don't do anything unless cloud policy is enabled. + if (!profile_->GetPrefs()->GetBoolean(prefs::kLoadCloudPolicyOnSignin)) + return; + + // Either startup or shutdown the UserCloudPolicyManager depending on whether + // the user is signed in or not. + if (!manager_) + return; // Can be null in unit tests. + + SigninManager* signin_manager = SigninManagerFactory::GetForProfile(profile_); + if (signin_manager->GetAuthenticatedUsername().empty()) { + manager_->Shutdown(); + } else { + if (!manager_->cloud_policy_service()) { + // Make sure we've initialized the DeviceManagementService. It's OK to + // call this multiple times so we do it every time we initialize the + // UserCloudPolicyManager. + g_browser_process->browser_policy_connector()-> + ScheduleServiceInitialization( + kPolicyServiceInitializationDelayMilliseconds); + // Initialize the UserCloudPolicyManager if it isn't already initialized. + policy::DeviceManagementService* service = g_browser_process-> + browser_policy_connector()->device_management_service(); + manager_->Initialize(g_browser_process->local_state(), + service, + policy::USER_AFFILIATION_NONE); + DCHECK(manager_->cloud_policy_service()); + } + + // Register the CloudPolicyService if needed. + if (!manager_->IsClientRegistered()) + RegisterCloudPolicyService(); + } +} + +void UserPolicySigninService::RegisterCloudPolicyService() { + // TODO(atwilson): Move the code to mint the devicemanagement token into + // TokenService. + std::string token = TokenServiceFactory::GetForProfile(profile_)-> + GetOAuth2LoginRefreshToken(); + if (token.empty()) { + DLOG(WARNING) << "No OAuth Refresh Token - delaying policy download"; + return; + } + + // Do nothing if already fetching an access token. + if (oauth2_access_token_fetcher_.get()) + return; + + // Start fetching an OAuth2 access token for the device management service and + // hand it off to the CloudPolicyClient when done. + oauth2_access_token_fetcher_.reset( + new OAuth2AccessTokenFetcher(this, profile_->GetRequestContext())); + std::vector<std::string> scopes(1, kServiceScopeChromeOSDeviceManagement); + GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); + oauth2_access_token_fetcher_->Start( + gaia_urls->oauth2_chrome_client_id(), + gaia_urls->oauth2_chrome_client_secret(), + token, + scopes); +} + +void UserPolicySigninService::OnGetTokenFailure( + const GoogleServiceAuthError& error) { + DLOG(WARNING) << "Could not fetch access token for " + << kServiceScopeChromeOSDeviceManagement; + oauth2_access_token_fetcher_.reset(); + manager_->CancelWaitForPolicyFetch(); +} + +void UserPolicySigninService::OnGetTokenSuccess( + const std::string& access_token, + const base::Time& expiration_time) { + // Pass along the new access token to the CloudPolicyClient. + manager_->RegisterClient(access_token); + oauth2_access_token_fetcher_.reset(); +} + +} // namespace policy diff --git a/chrome/browser/policy/user_policy_signin_service.h b/chrome/browser/policy/user_policy_signin_service.h new file mode 100644 index 0000000..99a6381 --- /dev/null +++ b/chrome/browser/policy/user_policy_signin_service.h @@ -0,0 +1,73 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_USER_POLICY_SIGNIN_SERVICE_H_ +#define CHROME_BROWSER_POLICY_USER_POLICY_SIGNIN_SERVICE_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/profiles/profile_keyed_service.h" +#include "chrome/common/net/gaia/oauth2_access_token_consumer.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" + +class OAuth2AccessTokenFetcher; +class Profile; + +namespace base { +class Time; +} + +namespace policy { + +class UserCloudPolicyManager; + +// The UserPolicySigninService tracks when user signin/signout actions occur and +// initializes/shuts down the UserCloudPolicyManager as required. This class is +// not used on ChromeOS because UserCloudPolicyManager initialization is handled +// via LoginUtils, since it must happen before profile creation. +class UserPolicySigninService + : public ProfileKeyedService, + public OAuth2AccessTokenConsumer, + public content::NotificationObserver { + public: + // Creates a UserPolicySigninService associated with the passed |profile|. + UserPolicySigninService(Profile* profile, UserCloudPolicyManager* manager); + virtual ~UserPolicySigninService(); + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + // OAuth2AccessTokenConsumer implementation. + virtual void OnGetTokenSuccess(const std::string& access_token, + const base::Time& expiration_time) OVERRIDE; + virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; + + private: + // Initializes the UserCloudPolicyManager to reflect the currently-signed-in + // user. + void ConfigureUserCloudPolicyManager(); + + // Fetches an OAuth token to allow the cloud policy service to register with + // the cloud policy server. + void RegisterCloudPolicyService(); + + // Weak pointer to the profile this service is associated with. + Profile* profile_; + + content::NotificationRegistrar registrar_; + scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_; + + // Weak pointer to the UserCloudPolicyManager (allows dependency injection + // for tests). + UserCloudPolicyManager* manager_; + + DISALLOW_COPY_AND_ASSIGN(UserPolicySigninService); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_USER_POLICY_SIGNIN_SERVICE_H_ diff --git a/chrome/browser/policy/user_policy_signin_service_factory.cc b/chrome/browser/policy/user_policy_signin_service_factory.cc new file mode 100644 index 0000000..34cb028 --- /dev/null +++ b/chrome/browser/policy/user_policy_signin_service_factory.cc @@ -0,0 +1,56 @@ +// 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/user_policy_signin_service_factory.h" + +#include "chrome/browser/policy/user_policy_signin_service.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_dependency_manager.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/signin/token_service_factory.h" +#include "chrome/common/pref_names.h" + +namespace policy { + +UserPolicySigninServiceFactory::UserPolicySigninServiceFactory() + : ProfileKeyedServiceFactory("UserPolicySigninService", + ProfileDependencyManager::GetInstance()) { + DependsOn(TokenServiceFactory::GetInstance()); + DependsOn(SigninManagerFactory::GetInstance()); +} + +UserPolicySigninServiceFactory::~UserPolicySigninServiceFactory() {} + +// static +UserPolicySigninService* UserPolicySigninServiceFactory::GetForProfile( + Profile* profile) { + return static_cast<UserPolicySigninService*>( + GetInstance()->GetServiceForProfile(profile, true)); +} + +// static +UserPolicySigninServiceFactory* UserPolicySigninServiceFactory::GetInstance() { + return Singleton<UserPolicySigninServiceFactory>::get(); +} + +ProfileKeyedService* UserPolicySigninServiceFactory::BuildServiceInstanceFor( + Profile* profile) const { + return new UserPolicySigninService(profile, + profile->GetUserCloudPolicyManager()); +} + +bool UserPolicySigninServiceFactory::ServiceIsCreatedWithProfile() { + // Create this object when the profile is created so it can track any + // user signin activity. + return true; +} + +void UserPolicySigninServiceFactory::RegisterUserPrefs( + PrefService* user_prefs) { + user_prefs->RegisterBooleanPref(prefs::kLoadCloudPolicyOnSignin, + false, PrefService::UNSYNCABLE_PREF); +} + +} // namespace policy diff --git a/chrome/browser/policy/user_policy_signin_service_factory.h b/chrome/browser/policy/user_policy_signin_service_factory.h new file mode 100644 index 0000000..5b60b32 --- /dev/null +++ b/chrome/browser/policy/user_policy_signin_service_factory.h @@ -0,0 +1,48 @@ +// 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. + +#ifndef CHROME_BROWSER_POLICY_USER_POLICY_SIGNIN_SERVICE_FACTORY_H_ +#define CHROME_BROWSER_POLICY_USER_POLICY_SIGNIN_SERVICE_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "chrome/browser/profiles/profile_keyed_service_factory.h" + +namespace policy { + +class UserPolicySigninService; + +// Singleton that owns all UserPolicySigninServices and creates/deletes them as +// new Profiles are created/shutdown. +class UserPolicySigninServiceFactory : public ProfileKeyedServiceFactory { + public: + // Returns an instance of the UserPolicySigninServiceFactory singleton. + static UserPolicySigninServiceFactory* GetInstance(); + + // Returns the instance of UserPolicySigninService for the passed |profile|. + // Used primarily for testing. + static UserPolicySigninService* GetForProfile(Profile* profile); + + protected: + // ProfileKeyedServiceFactory implementation. + virtual ProfileKeyedService* BuildServiceInstanceFor( + Profile* profile) const OVERRIDE; + + // Overridden to cause this object to be created when the profile is created. + virtual bool ServiceIsCreatedWithProfile() OVERRIDE; + + // Register the preferences related to cloud-based user policy. + virtual void RegisterUserPrefs(PrefService* user_prefs) OVERRIDE; + + private: + friend struct DefaultSingletonTraits<UserPolicySigninServiceFactory>; + + UserPolicySigninServiceFactory(); + virtual ~UserPolicySigninServiceFactory(); + + DISALLOW_COPY_AND_ASSIGN(UserPolicySigninServiceFactory); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_POLICY_USER_POLICY_SIGNIN_SERVICE_FACTORY_H_ diff --git a/chrome/browser/policy/user_policy_signin_service_unittest.cc b/chrome/browser/policy/user_policy_signin_service_unittest.cc new file mode 100644 index 0000000..fc3d3fa --- /dev/null +++ b/chrome/browser/policy/user_policy_signin_service_unittest.cc @@ -0,0 +1,161 @@ +// 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 "base/message_loop.h" +#include "chrome/browser/policy/mock_cloud_policy_store.h" +#include "chrome/browser/policy/user_cloud_policy_manager.h" +#include "chrome/browser/policy/user_policy_signin_service.h" +#include "chrome/browser/policy/user_policy_signin_service_factory.h" +#include "chrome/browser/prefs/browser_prefs.h" +#include "chrome/browser/prefs/pref_service.h" +#include "chrome/browser/signin/signin_manager.h" +#include "chrome/browser/signin/signin_manager_factory.h" +#include "chrome/browser/signin/signin_manager_fake.h" +#include "chrome/common/chrome_notification_types.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_pref_service.h" +#include "chrome/test/base/testing_profile.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "content/public/test/test_browser_thread.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::Return; + +namespace policy { + +namespace { + +class UserPolicySigninServiceTest : public testing::Test { + public: + UserPolicySigninServiceTest() + : loop_(MessageLoop::TYPE_UI), + ui_thread_(content::BrowserThread::UI, &loop_) { + } + + virtual void SetUp() OVERRIDE { + local_state_.reset(new TestingPrefService); + chrome::RegisterLocalState(local_state_.get()); + static_cast<TestingBrowserProcess*>(g_browser_process)->SetLocalState( + local_state_.get()); + + // Create a UserCloudPolicyManager with a MockCloudPolicyStore, and build a + // TestingProfile that uses it. + mock_store_ = new MockCloudPolicyStore(); + mock_store_->NotifyStoreLoaded(); + EXPECT_CALL(*mock_store_, Load()); + scoped_ptr<UserCloudPolicyManager> manager(new UserCloudPolicyManager( + scoped_ptr<CloudPolicyStore>(mock_store_), false)); + TestingProfile::Builder builder; + builder.SetUserCloudPolicyManager(manager.Pass()); + profile_ = builder.Build().Pass(); + profile_->GetPrefs()->SetBoolean(prefs::kLoadCloudPolicyOnSignin, true); + SigninManagerFactory::GetInstance()->SetTestingFactory( + profile_.get(), FakeSigninManager::Build); + + // Make sure the UserPolicySigninService is created. + UserPolicySigninServiceFactory::GetForProfile(profile_.get()); + } + + virtual void TearDown() OVERRIDE { + // Free the profile before we clear out the browser prefs. + profile_.reset(); + static_cast<TestingBrowserProcess*>(g_browser_process)->SetLocalState(NULL); + local_state_.reset(); + } + + + scoped_ptr<TestingProfile> profile_; + // Weak pointer to a MockCloudPolicyStore - lifetime is managed by the + // UserCloudPolicyManager. + MockCloudPolicyStore* mock_store_; + + // BrowserPolicyConnector wants to initialize various components + // asynchronously via tasks, so create a fake thread here. + MessageLoop loop_; + content::TestBrowserThread ui_thread_; + + scoped_ptr<TestingPrefService> local_state_; +}; + +TEST_F(UserPolicySigninServiceTest, InitWhileSignedOut) { + // Make sure user is not signed in. + ASSERT_TRUE(SigninManagerFactory::GetForProfile(profile_.get())-> + GetAuthenticatedUsername().empty()); + + // Let the SigninService know that the profile has been created. + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROFILE_ADDED, + content::Source<Profile>(profile_.get()), + content::NotificationService::NoDetails()); + + // UserCloudPolicyManager should not be initialized. + ASSERT_FALSE(profile_->GetUserCloudPolicyManager()->cloud_policy_service()); +} + +TEST_F(UserPolicySigninServiceTest, InitWhileSignedIn) { + // Set the user as signed in. + SigninManagerFactory::GetForProfile(profile_.get())->SetAuthenticatedUsername( + "testuser@test.com"); + + // Let the SigninService know that the profile has been created. + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROFILE_ADDED, + content::Source<Profile>(profile_.get()), + content::NotificationService::NoDetails()); + + // UserCloudPolicyManager should be initialized. + ASSERT_TRUE(profile_->GetUserCloudPolicyManager()->cloud_policy_service()); +} + +// TODO(atwilson): Enable test for signing in once it is possible to use a +// mock TokenService (http://crbug.com/138618). +TEST_F(UserPolicySigninServiceTest, DISABLED_SignInAfterInit) { + // Let the SigninService know that the profile has been created. + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROFILE_ADDED, + content::Source<Profile>(profile_.get()), + content::NotificationService::NoDetails()); + + // UserCloudPolicyManager should not be initialized. + ASSERT_FALSE(profile_->GetUserCloudPolicyManager()->cloud_policy_service()); + + // Now sign in the user. + SigninManagerFactory::GetForProfile(profile_.get())->SetAuthenticatedUsername( + "testuser@test.com"); + + // Make oauth token available (needs MockTokenService - see TODO above). + + // UserCloudPolicyManager should be initialized. + ASSERT_TRUE(profile_->GetUserCloudPolicyManager()->cloud_policy_service()); +} + +TEST_F(UserPolicySigninServiceTest, SignOutAfterInit) { + // Set the user as signed in. + SigninManagerFactory::GetForProfile(profile_.get())->SetAuthenticatedUsername( + "testuser@test.com"); + + // Let the SigninService know that the profile has been created. + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_PROFILE_ADDED, + content::Source<Profile>(profile_.get()), + content::NotificationService::NoDetails()); + + // UserCloudPolicyManager should be initialized. + ASSERT_TRUE(profile_->GetUserCloudPolicyManager()->cloud_policy_service()); + + // Now sign out. + SigninManagerFactory::GetForProfile(profile_.get())->SignOut(); + + // UserCloudPolicyManager should be shut down. + ASSERT_FALSE(profile_->GetUserCloudPolicyManager()->cloud_policy_service()); +} + +} // namespace + +} // namespace policy diff --git a/chrome/browser/prefs/command_line_pref_store.cc b/chrome/browser/prefs/command_line_pref_store.cc index 70d8056..a3ce691 100644 --- a/chrome/browser/prefs/command_line_pref_store.cc +++ b/chrome/browser/prefs/command_line_pref_store.cc @@ -64,6 +64,8 @@ const CommandLinePrefStore::BooleanSwitchToPreferenceMapEntry { switches::kEnableTouchpadThreeFingerClick, prefs::kEnableTouchpadThreeFingerClick, true }, #endif + { switches::kLoadCloudPolicyOnSignin, prefs::kLoadCloudPolicyOnSignin, + true }, }; const CommandLinePrefStore::IntegerSwitchToPreferenceMapEntry diff --git a/chrome/browser/prefs/pref_member.cc b/chrome/browser/prefs/pref_member.cc index 025138e..902224e 100644 --- a/chrome/browser/prefs/pref_member.cc +++ b/chrome/browser/prefs/pref_member.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// 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. @@ -35,7 +35,8 @@ void PrefMemberBase::Init(const char* pref_name, prefs_ = prefs; pref_name_ = pref_name; // Check that the preference is registered. - DCHECK(prefs_->FindPreference(pref_name_.c_str())); + DCHECK(prefs_->FindPreference(pref_name_.c_str())) + << pref_name << " not registered."; // Add ourselves as a pref observer so we can keep our local value in sync. prefs_->AddPrefObserver(pref_name, this); diff --git a/chrome/browser/profiles/off_the_record_profile_impl.cc b/chrome/browser/profiles/off_the_record_profile_impl.cc index 94f3bab..ef78264 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.cc +++ b/chrome/browser/profiles/off_the_record_profile_impl.cc @@ -241,6 +241,11 @@ FaviconService* OffTheRecordProfileImpl::GetFaviconService( return NULL; } +policy::UserCloudPolicyManager* + OffTheRecordProfileImpl::GetUserCloudPolicyManager() { + return profile_->GetUserCloudPolicyManager(); +} + policy::PolicyService* OffTheRecordProfileImpl::GetPolicyService() { return profile_->GetPolicyService(); } diff --git a/chrome/browser/profiles/off_the_record_profile_impl.h b/chrome/browser/profiles/off_the_record_profile_impl.h index 6b09bd4..2ebc061 100644 --- a/chrome/browser/profiles/off_the_record_profile_impl.h +++ b/chrome/browser/profiles/off_the_record_profile_impl.h @@ -49,6 +49,7 @@ class OffTheRecordProfileImpl : public Profile, virtual HistoryService* GetHistoryService(ServiceAccessType sat) OVERRIDE; virtual HistoryService* GetHistoryServiceWithoutCreating() OVERRIDE; virtual FaviconService* GetFaviconService(ServiceAccessType sat) OVERRIDE; + virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager() OVERRIDE; virtual policy::PolicyService* GetPolicyService() OVERRIDE; virtual PrefService* GetPrefs() OVERRIDE; virtual PrefService* GetOffTheRecordPrefs() OVERRIDE; diff --git a/chrome/browser/profiles/profile.h b/chrome/browser/profiles/profile.h index 37dd180..3912eda 100644 --- a/chrome/browser/profiles/profile.h +++ b/chrome/browser/profiles/profile.h @@ -65,8 +65,8 @@ class FileSystemContext; } namespace history { -class TopSites; class ShortcutsBackend; +class TopSites; } namespace net { @@ -75,6 +75,7 @@ class SSLConfigService; namespace policy { class PolicyService; +class UserCloudPolicyManager; } class Profile : public content::BrowserContext { @@ -249,6 +250,10 @@ class Profile : public content::BrowserContext { // doesn't already exist. virtual HistoryService* GetHistoryServiceWithoutCreating() = 0; + // Returns the UserCloudPolicyManager (if any) that handles this profile's + // connection to the cloud-based management service. + virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager() = 0; + // Returns the PolicyService that provides policies for this profile. virtual policy::PolicyService* GetPolicyService() = 0; diff --git a/chrome/browser/profiles/profile_dependency_manager.cc b/chrome/browser/profiles/profile_dependency_manager.cc index c070b97..0a30db0 100644 --- a/chrome/browser/profiles/profile_dependency_manager.cc +++ b/chrome/browser/profiles/profile_dependency_manager.cc @@ -60,6 +60,7 @@ #if defined(ENABLE_CONFIGURATION_POLICY) #include "chrome/browser/policy/managed_mode_policy_provider_factory.h" +#include "chrome/browser/policy/user_policy_signin_service_factory.h" #endif #if defined(USE_AURA) @@ -233,6 +234,10 @@ void ProfileDependencyManager::AssertFactoriesBuilt() { PinnedTabServiceFactory::GetInstance(); #endif PluginPrefsFactory::GetInstance(); +#if defined(ENABLE_CONFIGURATION_POLICY) && !defined(OS_CHROMEOS) + // Not used on chromeos because signin happens before the profile is loaded. + policy::UserPolicySigninServiceFactory::GetInstance(); +#endif predictors::AutocompleteActionPredictorFactory::GetInstance(); predictors::PredictorDatabaseFactory::GetInstance(); predictors::ResourcePrefetchPredictorFactory::GetInstance(); diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index 34b30d9..bb1f44e 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc @@ -56,6 +56,7 @@ #include "chrome/browser/net/url_fixer_upper.h" #include "chrome/browser/plugin_prefs.h" #include "chrome/browser/policy/policy_service.h" +#include "chrome/browser/policy/user_cloud_policy_manager.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/prefs/scoped_user_pref_update.h" #include "chrome/browser/prerender/prerender_manager_factory.h" @@ -286,10 +287,17 @@ ProfileImpl::ProfileImpl(const FilePath& path, session_restore_enabled_ = !command_line->HasSwitch(switches::kDisableRestoreSessionState); #if defined(ENABLE_CONFIGURATION_POLICY) - policy_service_.reset( - g_browser_process->browser_policy_connector()->CreatePolicyService(this)); + // TODO(atwilson): Change these to ProfileKeyedServices once PrefService is + // a ProfileKeyedService (policy must be initialized before PrefService + // because PrefService depends on policy loading to get overridden pref + // values). + cloud_policy_manager_ = + g_browser_process->browser_policy_connector()->CreateCloudPolicyManager( + this); + policy_service_ = + g_browser_process->browser_policy_connector()->CreatePolicyService(this); #else - policy_service_.reset(new policy::PolicyServiceStub()); + policy_service_.reset(new policy::PolicyServiceStub()); #endif if (create_mode == CREATE_MODE_ASYNCHRONOUS) { prefs_.reset(PrefService::CreatePrefService( @@ -649,6 +657,10 @@ bool ProfileImpl::WasCreatedByVersionOrLater(const std::string& version) { return (profile_version.CompareTo(arg_version) >= 0); } +policy::UserCloudPolicyManager* ProfileImpl::GetUserCloudPolicyManager() { + return cloud_policy_manager_.get(); +} + policy::PolicyService* ProfileImpl::GetPolicyService() { DCHECK(policy_service_.get()); // Should explicitly be initialized. return policy_service_.get(); diff --git a/chrome/browser/profiles/profile_impl.h b/chrome/browser/profiles/profile_impl.h index be96345..cebc882 100644 --- a/chrome/browser/profiles/profile_impl.h +++ b/chrome/browser/profiles/profile_impl.h @@ -87,6 +87,7 @@ class ProfileImpl : public Profile, virtual GAIAInfoUpdateService* GetGAIAInfoUpdateService() OVERRIDE; virtual HistoryService* GetHistoryService(ServiceAccessType sat) OVERRIDE; virtual HistoryService* GetHistoryServiceWithoutCreating() OVERRIDE; + virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager() OVERRIDE; virtual policy::PolicyService* GetPolicyService() OVERRIDE; virtual PrefService* GetPrefs() OVERRIDE; virtual PrefService* GetOffTheRecordPrefs() OVERRIDE; @@ -186,9 +187,12 @@ class ProfileImpl : public Profile, // that the declaration occurs AFTER things it depends on as destruction // happens in reverse order of declaration. - // |prefs_| depends on |policy_service_|. - // TODO(bauerb): Once |prefs_| is a ProfileKeyedService, |policy_service_| - // should become one as well. + // |prefs_| depends on |policy_service_|, which depends on + // |user_cloud_policy_manager_|. + // TODO(bauerb, mnissler): Once |prefs_| is a ProfileKeyedService, + // |policy_service_| and |user_cloud_policy_manager_| should become + // ProfiledKeyedServices as well. + scoped_ptr<policy::UserCloudPolicyManager> cloud_policy_manager_; scoped_ptr<policy::PolicyService> policy_service_; // Keep |prefs_| on top for destruction order because |extension_prefs_|, diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index 2c8c08d..d9904ab 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc @@ -360,6 +360,7 @@ ProfileIOData::GetIsolatedAppRequestContext( } ExtensionInfoMap* ProfileIOData::GetExtensionInfoMap() const { + DCHECK(extension_info_map_) << "ExtensionSystem not initialized"; return extension_info_map_; } diff --git a/chrome/browser/signin/signin_manager.h b/chrome/browser/signin/signin_manager.h index 1baecf7..49879c7 100644 --- a/chrome/browser/signin/signin_manager.h +++ b/chrome/browser/signin/signin_manager.h @@ -140,6 +140,11 @@ class SigninManager : public GaiaAuthConsumer, const content::NotificationSource& source, const content::NotificationDetails& details) OVERRIDE; + protected: + // Weak pointer to parent profile (protected so FakeSigninManager can access + // it). + Profile* profile_; + private: enum SigninType { SIGNIN_TYPE_NONE, @@ -173,8 +178,6 @@ class SigninManager : public GaiaAuthConsumer, void HandleAuthError(const GoogleServiceAuthError& error, bool clear_transient_data); - Profile* profile_; - // ClientLogin identity. std::string possibly_invalid_username_; std::string password_; // This is kept empty whenever possible. diff --git a/chrome/browser/signin/signin_manager_fake.cc b/chrome/browser/signin/signin_manager_fake.cc index 4cd8ecc..b3068ea 100644 --- a/chrome/browser/signin/signin_manager_fake.cc +++ b/chrome/browser/signin/signin_manager_fake.cc @@ -4,7 +4,12 @@ #include "chrome/browser/signin/signin_manager_fake.h" -FakeSigninManager::FakeSigninManager() {} +#include "chrome/common/chrome_notification_types.h" +#include "content/public/browser/notification_service.h" + +FakeSigninManager::FakeSigninManager(Profile* profile) { + profile_ = profile; +} FakeSigninManager::~FakeSigninManager() {} @@ -29,9 +34,13 @@ void FakeSigninManager::StartSignInWithOAuth(const std::string& username, void FakeSigninManager::SignOut() { authenticated_username_.clear(); + content::NotificationService::current()->Notify( + chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, + content::Source<Profile>(profile_), + content::NotificationService::NoDetails()); } // static ProfileKeyedService* FakeSigninManager::Build(Profile* profile) { - return new FakeSigninManager(); + return new FakeSigninManager(profile); } diff --git a/chrome/browser/signin/signin_manager_fake.h b/chrome/browser/signin/signin_manager_fake.h index a108b0a..2cd46d7 100644 --- a/chrome/browser/signin/signin_manager_fake.h +++ b/chrome/browser/signin/signin_manager_fake.h @@ -17,7 +17,7 @@ class ProfileKeyedService; // and accepts the credentials provided to StartSignIn. class FakeSigninManager : public SigninManager { public: - FakeSigninManager(); + explicit FakeSigninManager(Profile* profile); virtual ~FakeSigninManager(); virtual void StartSignIn(const std::string& username, diff --git a/chrome/browser/sync/profile_sync_service_mock.cc b/chrome/browser/sync/profile_sync_service_mock.cc index 694753a..e62e8f1 100644 --- a/chrome/browser/sync/profile_sync_service_mock.cc +++ b/chrome/browser/sync/profile_sync_service_mock.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/prefs/pref_service_mock_builder.h" +#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/testing_pref_store.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/sync/profile_sync_service_mock.h" @@ -31,14 +31,7 @@ ProfileSyncServiceMock::~ProfileSyncServiceMock() { // static TestingProfile* ProfileSyncServiceMock::MakeSignedInTestingProfile() { TestingProfile* profile = new TestingProfile(); - TestingPrefStore* user_prefs = new TestingPrefStore(); - PrefService* prefs = PrefServiceMockBuilder() - .WithUserPrefs(user_prefs) - .Create(); - profile->SetPrefService(prefs); - // We just blew away our prefs, so reregister them. - SigninManagerFactory::GetInstance()->RegisterUserPrefs(prefs); - user_prefs->SetString(prefs::kGoogleServicesUsername, "foo"); + profile->GetPrefs()->SetString(prefs::kGoogleServicesUsername, "foo"); return profile; } diff --git a/chrome/browser/sync/sync_ui_util_unittest.cc b/chrome/browser/sync/sync_ui_util_unittest.cc index 0448118..d15be1d 100644 --- a/chrome/browser/sync/sync_ui_util_unittest.cc +++ b/chrome/browser/sync/sync_ui_util_unittest.cc @@ -78,7 +78,7 @@ TEST(SyncUIUtilTest, PassphraseGlobalError) { scoped_ptr<Profile> profile( ProfileSyncServiceMock::MakeSignedInTestingProfile()); NiceMock<ProfileSyncServiceMock> service(profile.get()); - FakeSigninManager signin; + FakeSigninManager signin(profile.get()); browser_sync::SyncBackendHost::Status status; EXPECT_CALL(service, QueryDetailedSyncStatus(_)) .WillRepeatedly(Return(false)); @@ -99,7 +99,7 @@ TEST(SyncUIUtilTest, AuthAndPassphraseGlobalError) { scoped_ptr<Profile> profile( ProfileSyncServiceMock::MakeSignedInTestingProfile()); NiceMock<ProfileSyncServiceMock> service(profile.get()); - FakeSigninManager signin; + FakeSigninManager signin(profile.get()); browser_sync::SyncBackendHost::Status status; EXPECT_CALL(service, QueryDetailedSyncStatus(_)) .WillRepeatedly(Return(false)); @@ -153,7 +153,7 @@ TEST(SyncUIUtilTest, AuthStateGlobalError) { { GoogleServiceAuthError::HOSTED_NOT_ALLOWED, true }, }; - FakeSigninManager signin; + FakeSigninManager signin(profile.get()); for (size_t i = 0; i < sizeof(table)/sizeof(*table); ++i) { VerifySyncGlobalErrorResult( &service, signin, table[i].error_state, true, table[i].is_error); diff --git a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc index 826f188..1330c8c 100644 --- a/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc +++ b/chrome/browser/ui/sync/one_click_signin_helper_unittest.cc @@ -35,7 +35,8 @@ namespace { class SigninManagerMock : public FakeSigninManager { public: - SigninManagerMock() {} + explicit SigninManagerMock(Profile* profile) + : FakeSigninManager(profile) {} MOCK_CONST_METHOD1(IsAllowedUsername, bool(const std::string& username)); }; @@ -78,7 +79,7 @@ void OneClickSigninHelperTest::SetUp() { } static ProfileKeyedService* BuildSigninManagerMock(Profile* profile) { - return new SigninManagerMock(); + return new SigninManagerMock(profile); } content::WebContents* OneClickSigninHelperTest::CreateMockWebContents( diff --git a/chrome/browser/ui/webui/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/sync_setup_handler_unittest.cc index ae1b4be..662614c 100644 --- a/chrome/browser/ui/webui/sync_setup_handler_unittest.cc +++ b/chrome/browser/ui/webui/sync_setup_handler_unittest.cc @@ -341,12 +341,12 @@ class TestingSyncSetupHandler : public SyncSetupHandler { class SigninManagerMock : public FakeSigninManager { public: - SigninManagerMock() {} + explicit SigninManagerMock(Profile* profile) : FakeSigninManager(profile) {} MOCK_CONST_METHOD1(IsAllowedUsername, bool(const std::string& username)); }; static ProfileKeyedService* BuildSigninManagerMock(Profile* profile) { - return new SigninManagerMock(); + return new SigninManagerMock(profile); } // The boolean parameter indicates whether the test is run with ClientOAuth @@ -367,7 +367,6 @@ class SyncSetupHandlerTest : public testing::TestWithParam<bool> { error_ = GoogleServiceAuthError::None(); profile_.reset(ProfileSyncServiceMock::MakeSignedInTestingProfile()); - SyncPromoUI::RegisterUserPrefs(profile_->GetPrefs()); mock_pss_ = static_cast<ProfileSyncServiceMock*>( ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile_.get(), diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index d74c016..12cca45 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1764,12 +1764,20 @@ 'browser/policy/url_blacklist_manager.h', 'browser/policy/user_cloud_policy_manager.cc', 'browser/policy/user_cloud_policy_manager.h', + 'browser/policy/user_cloud_policy_store.cc', + 'browser/policy/user_cloud_policy_store.h', + 'browser/policy/user_cloud_policy_store_base.cc', + 'browser/policy/user_cloud_policy_store_base.h', 'browser/policy/user_cloud_policy_store_chromeos.cc', 'browser/policy/user_cloud_policy_store_chromeos.h', 'browser/policy/user_policy_cache.cc', 'browser/policy/user_policy_cache.h', 'browser/policy/user_policy_disk_cache.cc', 'browser/policy/user_policy_disk_cache.h', + 'browser/policy/user_policy_signin_service.cc', + 'browser/policy/user_policy_signin_service.h', + 'browser/policy/user_policy_signin_service_factory.cc', + 'browser/policy/user_policy_signin_service_factory.h', 'browser/policy/user_policy_token_cache.cc', 'browser/policy/user_policy_token_cache.h', 'browser/predictors/autocomplete_action_predictor.cc', @@ -4615,6 +4623,12 @@ ['exclude', 'browser/password_manager/native_backend_gnome_x.h'], ['exclude', 'browser/password_manager/native_backend_kwallet_x.cc'], ['exclude', 'browser/password_manager/native_backend_kwallet_x.h'], + ['exclude', 'browser/policy/user_cloud_policy_store.cc'], + ['exclude', 'browser/policy/user_cloud_policy_store.h'], + ['exclude', 'browser/policy/user_policy_signin_service.cc'], + ['exclude', 'browser/policy/user_policy_signin_service.h'], + ['exclude', 'browser/policy/user_policy_signin_service_factory.cc'], + ['exclude', 'browser/policy/user_policy_signin_service_factory.h'], ['exclude', 'browser/platform_util_linux.cc'], ['exclude', 'browser/speech/extension_api/tts_extension_api_linux.cc'], ['exclude', 'browser/ui/webui/help/version_updater_basic.cc'], diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index d7e6e915..a97ad5c 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1452,8 +1452,10 @@ 'browser/policy/testing_policy_url_fetcher_factory.h', 'browser/policy/url_blacklist_manager_unittest.cc', 'browser/policy/user_cloud_policy_manager_unittest.cc', + 'browser/policy/user_cloud_policy_store_unittest.cc', 'browser/policy/user_cloud_policy_store_chromeos_unittest.cc', 'browser/policy/user_policy_cache_unittest.cc', + 'browser/policy/user_policy_signin_service_unittest.cc', 'browser/predictors/autocomplete_action_predictor_table_unittest.cc', 'browser/predictors/autocomplete_action_predictor_unittest.cc', 'browser/predictors/resource_prefetch_predictor_unittest.cc', @@ -2186,6 +2188,9 @@ ['exclude', '^browser/media_gallery/media_device_notifications_linux_unittest.cc'], ['exclude', '^browser/password_manager/native_backend_gnome_x_unittest.cc'], ['exclude', '^browser/password_manager/native_backend_kwallet_x_unittest.cc'], + ['exclude', '^browser/policy/user_cloud_policy_store_unittest.cc'], + ['exclude', '^browser/policy/user_policy_signin_service_unittest.cc'], + ['exclude', '^browser/safe_browsing/download_protection_service_unittest.cc' ], ], 'sources': [ diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc index a406daf..4e24a2d 100644 --- a/chrome/common/chrome_switches.cc +++ b/chrome/common/chrome_switches.cc @@ -821,6 +821,10 @@ const char kKioskModePrinting[] = "kiosk-printing"; // Comma-separated list of directories with component extensions to load. const char kLoadComponentExtension[] = "load-component-extension"; +// If present, cloud policy will be loaded and applied once the user is signed +// in to the browser. +const char kLoadCloudPolicyOnSignin[] = "load-cloud-policy-on-signin"; + // Loads an extension from the specified directory. const char kLoadExtension[] = "load-extension"; diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h index 0774788..ffac570 100644 --- a/chrome/common/chrome_switches.h +++ b/chrome/common/chrome_switches.h @@ -221,6 +221,7 @@ extern const char kKeepAliveForTest[]; extern const char kKioskMode[]; extern const char kKioskModePrinting[]; extern const char kLoadComponentExtension[]; +extern const char kLoadCloudPolicyOnSignin[]; extern const char kLoadExtension[]; extern const char kLoadOpencryptoki[]; extern const char kUninstallExtension[]; diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc index 023067f..ec389ed 100644 --- a/chrome/common/pref_names.cc +++ b/chrome/common/pref_names.cc @@ -1845,6 +1845,9 @@ const char kChromeOsReleaseChannel[] = "cros.system.releaseChannel"; // Value of the enums in TabStrip::LayoutType as an int. const char kTabStripLayoutType[] = "tab_strip_layout_type"; +// If true, cloud policy for the user is loaded once the user signs in. +const char kLoadCloudPolicyOnSignin[] = "policy.load_cloud_policy_on_signin"; + // *************** SERVICE PREFS *************** // These are attached to the service process. diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h index 2e823de3..54cbc6c 100644 --- a/chrome/common/pref_names.h +++ b/chrome/common/pref_names.h @@ -708,6 +708,7 @@ extern const char kBackgroundModeEnabled[]; extern const char kDevicePolicyRefreshRate[]; extern const char kUserPolicyRefreshRate[]; +extern const char kLoadCloudPolicyOnSignin[]; extern const char kRecoveryComponentVersion[]; extern const char kComponentUpdaterState[]; diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc index 5251c93..da4fa89 100644 --- a/chrome/test/base/testing_browser_process.cc +++ b/chrome/test/base/testing_browser_process.cc @@ -16,8 +16,8 @@ #include "chrome/browser/safe_browsing/safe_browsing_service.h" #include "content/public/browser/notification_service.h" #include "net/url_request/url_request_context_getter.h" -#include "ui/base/clipboard/clipboard.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/clipboard/clipboard.h" #if !defined(ENABLE_CONFIGURATION_POLICY) #include "chrome/browser/policy/policy_service_stub.h" @@ -73,8 +73,10 @@ chrome_variations::VariationsService* policy::BrowserPolicyConnector* TestingBrowserProcess::browser_policy_connector() { #if defined(ENABLE_CONFIGURATION_POLICY) - if (!browser_policy_connector_.get()) + if (!browser_policy_connector_.get()) { browser_policy_connector_.reset(new policy::BrowserPolicyConnector()); + browser_policy_connector_->Init(); + } #endif return browser_policy_connector_.get(); } @@ -82,8 +84,7 @@ policy::BrowserPolicyConnector* policy::PolicyService* TestingBrowserProcess::policy_service() { if (!policy_service_.get()) { #if defined(ENABLE_CONFIGURATION_POLICY) - policy_service_.reset( - browser_policy_connector()->CreatePolicyService(NULL)); + policy_service_ = browser_policy_connector()->CreatePolicyService(NULL); #else policy_service_.reset(new policy::PolicyServiceStub()); #endif @@ -249,8 +250,19 @@ CRLSetFetcher* TestingBrowserProcess::crl_set_fetcher() { } void TestingBrowserProcess::SetLocalState(PrefService* local_state) { - if (!local_state && notification_ui_manager_.get()) - notification_ui_manager_.reset(); // Used local_state_. + if (!local_state) { + // The local_state_ PrefService is owned outside of TestingBrowserProcess, + // but some of the members of TestingBrowserProcess hold references to it + // (for example, via PrefNotifier members). But given our test + // infrastructure which tears down individual tests before freeing the + // TestingBrowserProcess, there's not a good way to make local_state outlive + // these dependencies. As a workaround, whenever local_state_ is cleared + // (assumedly as part of exiting the test and freeing TestingBrowserProcess) + // any components owned by TestingBrowserProcess that depend on local_state + // are also freed. + notification_ui_manager_.reset(); + browser_policy_connector_.reset(); + } local_state_ = local_state; } diff --git a/chrome/test/base/testing_profile.cc b/chrome/test/base/testing_profile.cc index 388b452..c173ef3 100644 --- a/chrome/test/base/testing_profile.cc +++ b/chrome/test/base/testing_profile.cc @@ -34,6 +34,7 @@ #include "chrome/browser/net/proxy_service_factory.h" #include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/notifications/desktop_notification_service_factory.h" +#include "chrome/browser/policy/user_cloud_policy_manager.h" #include "chrome/browser/prefs/browser_prefs.h" #include "chrome/browser/prefs/testing_pref_store.h" #include "chrome/browser/prerender/prerender_manager.h" @@ -159,30 +160,7 @@ TestingProfile::TestingProfile() last_session_exited_cleanly_(true), profile_dependency_manager_(ProfileDependencyManager::GetInstance()), delegate_(NULL) { - if (!temp_dir_.CreateUniqueTempDir()) { - LOG(ERROR) << "Failed to create unique temporary directory."; - - // Fallback logic in case we fail to create unique temporary directory. - FilePath system_tmp_dir; - bool success = PathService::Get(base::DIR_TEMP, &system_tmp_dir); - - // We're severly screwed if we can't get the system temporary - // directory. Die now to avoid writing to the filesystem root - // or other bad places. - CHECK(success); - - FilePath fallback_dir(system_tmp_dir.AppendASCII("TestingProfilePath")); - file_util::Delete(fallback_dir, true); - file_util::CreateDirectory(fallback_dir); - if (!temp_dir_.Set(fallback_dir)) { - // That shouldn't happen, but if it does, try to recover. - LOG(ERROR) << "Failed to use a fallback temporary directory."; - - // We're screwed if this fails, see CHECK above. - CHECK(temp_dir_.Set(system_tmp_dir)); - } - } - + CreateTempProfileDir(); profile_path_ = temp_dir_.path(); Init(); @@ -220,6 +198,69 @@ TestingProfile::TestingProfile(const FilePath& path, } } +TestingProfile::TestingProfile( + const FilePath& path, + Delegate* delegate, + scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy, + scoped_ptr<PrefService> prefs, + scoped_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager) + : start_time_(Time::Now()), + prefs_(prefs.release()), + testing_prefs_(NULL), + incognito_(false), + last_session_exited_cleanly_(true), + extension_special_storage_policy_(extension_policy), + user_cloud_policy_manager_(user_cloud_policy_manager.release()), + profile_path_(path), + profile_dependency_manager_(ProfileDependencyManager::GetInstance()), + delegate_(delegate) { + + // If no profile path was supplied, create one. + if (profile_path_.empty()) { + CreateTempProfileDir(); + profile_path_ = temp_dir_.path(); + } + + Init(); + // If caller supplied a delegate, delay the FinishInit invocation until other + // tasks have run. + // TODO(atwilson): See if this is still required once we convert the current + // users of the constructor that takes a Delegate* param. + if (delegate_) { + MessageLoop::current()->PostTask(FROM_HERE, + base::Bind(&TestingProfile::FinishInit, + base::Unretained(this))); + } else { + FinishInit(); + } +} + +void TestingProfile::CreateTempProfileDir() { + if (!temp_dir_.CreateUniqueTempDir()) { + LOG(ERROR) << "Failed to create unique temporary directory."; + + // Fallback logic in case we fail to create unique temporary directory. + FilePath system_tmp_dir; + bool success = PathService::Get(base::DIR_TEMP, &system_tmp_dir); + + // We're severly screwed if we can't get the system temporary + // directory. Die now to avoid writing to the filesystem root + // or other bad places. + CHECK(success); + + FilePath fallback_dir(system_tmp_dir.AppendASCII("TestingProfilePath")); + file_util::Delete(fallback_dir, true); + file_util::CreateDirectory(fallback_dir); + if (!temp_dir_.Set(fallback_dir)) { + // That shouldn't happen, but if it does, try to recover. + LOG(ERROR) << "Failed to use a fallback temporary directory."; + + // We're screwed if this fails, see CHECK above. + CHECK(temp_dir_.Set(system_tmp_dir)); + } + } +} + void TestingProfile::Init() { if (!file_util::PathExists(profile_path_)) file_util::CreateDirectory(profile_path_); @@ -494,6 +535,10 @@ net::CookieMonster* TestingProfile::GetCookieMonster() { GetCookieMonster(); } +policy::UserCloudPolicyManager* TestingProfile::GetUserCloudPolicyManager() { + return user_cloud_policy_manager_.get(); +} + policy::PolicyService* TestingProfile::GetPolicyService() { if (!policy_service_.get()) { #if defined(ENABLE_CONFIGURATION_POLICY) @@ -732,3 +777,46 @@ base::Callback<ChromeURLDataManagerBackend*(void)> TestingProfile::GetChromeURLDataManagerBackendGetter() const { return base::Callback<ChromeURLDataManagerBackend*(void)>(); } + +TestingProfile::Builder::Builder() + : build_called_(false), + delegate_(NULL) { +} + +TestingProfile::Builder::~Builder() { +} + +void TestingProfile::Builder::SetPath(const FilePath& path) { + path_ = path; +} + +void TestingProfile::Builder::SetDelegate(Delegate* delegate) { + delegate_ = delegate; +} + +void TestingProfile::Builder::SetExtensionSpecialStoragePolicy( + scoped_refptr<ExtensionSpecialStoragePolicy> policy) { + extension_policy_ = policy; +} + +void TestingProfile::Builder::SetPrefService(scoped_ptr<PrefService> prefs) { + pref_service_ = prefs.Pass(); +} + +void TestingProfile::Builder::SetUserCloudPolicyManager( + scoped_ptr<policy::UserCloudPolicyManager> manager) { + user_cloud_policy_manager_ = manager.Pass(); +} + +scoped_ptr<TestingProfile> TestingProfile::Builder::Build() { + DCHECK(!build_called_); + build_called_ = true; + return scoped_ptr<TestingProfile>(new TestingProfile( + path_, + delegate_, + extension_policy_, + pref_service_.Pass(), + user_cloud_policy_manager_.Pass())); +} + + diff --git a/chrome/test/base/testing_profile.h b/chrome/test/base/testing_profile.h index 0e34cdd..493f903 100644 --- a/chrome/test/base/testing_profile.h +++ b/chrome/test/base/testing_profile.h @@ -58,6 +58,54 @@ class TestingProfile : public Profile { // Default constructor that cannot be used with multi-profiles. TestingProfile(); + // Helper class for building an instance of TestingProfile (allows injecting + // mocks for various services prior to profile initialization). + // TODO(atwilson): Remove non-default constructors and various setters in + // favor of using the Builder API. + class Builder { + public: + Builder(); + ~Builder(); + + // Sets a Delegate to be called back when the Profile is fully initialized. + // This causes the final initialization to be performed via a task so the + // caller must run a MessageLoop. Caller maintains ownership of the Delegate + // and must manage its lifetime so it continues to exist until profile + // initialization is complete. + void SetDelegate(Delegate* delegate); + + // Sets the ExtensionSpecialStoragePolicy to be returned by + // GetExtensionSpecialStoragePolicy(). + void SetExtensionSpecialStoragePolicy( + scoped_refptr<ExtensionSpecialStoragePolicy> policy); + + // Sets the path to the directory to be used to hold profile data. + void SetPath(const FilePath& path); + + // Sets the PrefService to be used by this profile. + void SetPrefService(scoped_ptr<PrefService> prefs); + + // Sets the UserCloudPolicyManager to be used by this profile. + void SetUserCloudPolicyManager( + scoped_ptr<policy::UserCloudPolicyManager> manager); + + // Creates the TestingProfile using previously-set settings. + scoped_ptr<TestingProfile> Build(); + + private: + // If true, Build() has already been called. + bool build_called_; + + // Various staging variables where values are held until Build() is invoked. + scoped_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager_; + scoped_ptr<PrefService> pref_service_; + scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy_; + FilePath path_; + Delegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(Builder); + }; + // Multi-profile aware constructor that takes the path to a directory managed // for this profile. This constructor is meant to be used by // TestingProfileManager::CreateTestingProfile. If you need to create multi- @@ -71,6 +119,14 @@ class TestingProfile : public Profile { // for unittesting the ProfileManager. TestingProfile(const FilePath& path, Delegate* delegate); + // Full constructor allowing the setting of all possible instance data. + // Callers should use Builder::Build() instead of invoking this constructor. + TestingProfile(const FilePath& path, + Delegate* delegate, + scoped_refptr<ExtensionSpecialStoragePolicy> extension_policy, + scoped_ptr<PrefService> prefs, + scoped_ptr<policy::UserCloudPolicyManager> manager); + virtual ~TestingProfile(); // Creates the favicon service. Consequent calls would recreate the service. @@ -167,6 +223,8 @@ class TestingProfile : public Profile { // this by calling CreateRequestContext(). See the note at GetRequestContext // for more information. net::CookieMonster* GetCookieMonster(); + + virtual policy::UserCloudPolicyManager* GetUserCloudPolicyManager() OVERRIDE; virtual policy::PolicyService* GetPolicyService() OVERRIDE; // Sets the profile's PrefService. If a pref service hasn't been explicitly // set GetPrefs creates one, so normally you need not invoke this. If you need @@ -242,6 +300,9 @@ class TestingProfile : public Profile { TestingPrefService* testing_prefs_; private: + // Creates a temporary directory for use by this profile. + void CreateTempProfileDir(); + // Common initialization between the two constructors. void Init(); @@ -289,6 +350,9 @@ class TestingProfile : public Profile { // The proxy prefs tracker. scoped_ptr<PrefProxyConfigTracker> pref_proxy_config_tracker_; + // UserCloudPolicyManager returned by GetUserCloudPolicyManager(). + scoped_ptr<policy::UserCloudPolicyManager> user_cloud_policy_manager_; + // We use a temporary directory to store testing profile data. In a multi- // profile environment, this is invalid and the directory is managed by the // TestingProfileManager. |