user_policy_signin_service.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/policy/cloud/user_policy_signin_service.h" 6 7#include <vector> 8 9#include "base/command_line.h" 10#include "base/prefs/pref_service.h" 11#include "base/values.h" 12#include "chrome/browser/browser_process.h" 13#include "chrome/browser/policy/browser_policy_connector.h" 14#include "chrome/browser/policy/cloud/cloud_policy_client.h" 15#include "chrome/browser/policy/cloud/cloud_policy_service.h" 16#include "chrome/browser/policy/cloud/user_cloud_policy_manager.h" 17#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h" 18#include "chrome/browser/policy/cloud/user_info_fetcher.h" 19#include "chrome/browser/profiles/profile.h" 20#include "chrome/browser/profiles/profile_manager.h" 21#include "chrome/browser/signin/signin_manager.h" 22#include "chrome/browser/signin/signin_manager_factory.h" 23#include "chrome/browser/signin/token_service.h" 24#include "chrome/browser/signin/token_service_factory.h" 25#include "chrome/common/chrome_notification_types.h" 26#include "chrome/common/chrome_switches.h" 27#include "chrome/common/pref_names.h" 28#include "content/public/browser/notification_details.h" 29#include "content/public/browser/notification_source.h" 30#include "google_apis/gaia/gaia_constants.h" 31#include "google_apis/gaia/gaia_urls.h" 32#include "google_apis/gaia/oauth2_access_token_consumer.h" 33#include "google_apis/gaia/oauth2_access_token_fetcher.h" 34 35namespace em = enterprise_management; 36 37namespace { 38 39const char kServiceScopeGetUserInfo[] = 40 "https://www.googleapis.com/auth/userinfo.email"; 41 42// The key under which the hosted-domain value is stored in the UserInfo 43// response. 44const char kGetHostedDomainKey[] = "hd"; 45 46bool ShouldForceLoadPolicy() { 47 return CommandLine::ForCurrentProcess()->HasSwitch( 48 switches::kForceLoadCloudPolicy); 49} 50 51} // namespace 52 53namespace policy { 54 55// Helper class that registers a CloudPolicyClient and returns the associated 56// DMToken to the caller. 57class CloudPolicyClientRegistrationHelper 58 : public policy::CloudPolicyClient::Observer, 59 public OAuth2AccessTokenConsumer, 60 public policy::UserInfoFetcher::Delegate { 61 public: 62 explicit CloudPolicyClientRegistrationHelper( 63 net::URLRequestContextGetter* context); 64 65 virtual ~CloudPolicyClientRegistrationHelper(); 66 67 // Starts the client registration process. Callback is invoked when the 68 // registration is complete. 69 void StartRegistration(policy::CloudPolicyClient* client, 70 const std::string& oauth2_login_token, 71 base::Closure callback); 72 73 // OAuth2AccessTokenConsumer implementation. 74 virtual void OnGetTokenSuccess(const std::string& access_token, 75 const base::Time& expiration_time) OVERRIDE; 76 virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE; 77 78 // UserInfoFetcher::Delegate implementation: 79 virtual void OnGetUserInfoSuccess(const DictionaryValue* response) OVERRIDE; 80 virtual void OnGetUserInfoFailure( 81 const GoogleServiceAuthError& error) OVERRIDE; 82 83 // CloudPolicyClient::Observer implementation. 84 virtual void OnPolicyFetched(policy::CloudPolicyClient* client) OVERRIDE {} 85 virtual void OnRegistrationStateChanged( 86 policy::CloudPolicyClient* client) OVERRIDE; 87 virtual void OnClientError(policy::CloudPolicyClient* client) OVERRIDE; 88 89 private: 90 // Invoked when the registration request has been completed. 91 void RequestCompleted(); 92 93 // Fetcher used while obtaining an OAuth token for client registration. 94 scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_; 95 96 // Helper class for fetching information from GAIA about the currently 97 // signed-in user. 98 scoped_ptr<policy::UserInfoFetcher> user_info_fetcher_; 99 100 // Access token used to register the CloudPolicyClient and also access 101 // GAIA to get information about the signed in user. 102 std::string oauth_access_token_; 103 104 net::URLRequestContextGetter* context_; 105 policy::CloudPolicyClient* client_; 106 base::Closure callback_; 107}; 108 109CloudPolicyClientRegistrationHelper::CloudPolicyClientRegistrationHelper( 110 net::URLRequestContextGetter* context) : context_(context) { 111 DCHECK(context_); 112} 113 114CloudPolicyClientRegistrationHelper::~CloudPolicyClientRegistrationHelper() { 115 // Clean up any pending observers in case the browser is shutdown while 116 // trying to register for policy. 117 if (client_) 118 client_->RemoveObserver(this); 119} 120 121void CloudPolicyClientRegistrationHelper::RequestCompleted() { 122 if (client_) { 123 client_->RemoveObserver(this); 124 // |client_| may be freed by the callback so clear it now. 125 client_ = NULL; 126 callback_.Run(); 127 } 128} 129 130void CloudPolicyClientRegistrationHelper::StartRegistration( 131 policy::CloudPolicyClient* client, 132 const std::string& login_token, 133 base::Closure callback) { 134 DVLOG(1) << "Starting registration process"; 135 DCHECK(client); 136 DCHECK(!client->is_registered()); 137 client_ = client; 138 callback_ = callback; 139 client_->AddObserver(this); 140 141 // Start fetching an OAuth2 access token for the device management and 142 // userinfo services. 143 oauth2_access_token_fetcher_.reset( 144 new OAuth2AccessTokenFetcher(this, context_)); 145 std::vector<std::string> scopes; 146 scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth); 147 scopes.push_back(kServiceScopeGetUserInfo); 148 GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); 149 oauth2_access_token_fetcher_->Start( 150 gaia_urls->oauth2_chrome_client_id(), 151 gaia_urls->oauth2_chrome_client_secret(), 152 login_token, 153 scopes); 154} 155 156void CloudPolicyClientRegistrationHelper::OnGetTokenFailure( 157 const GoogleServiceAuthError& error) { 158 DLOG(WARNING) << "Could not fetch access token for " 159 << GaiaConstants::kDeviceManagementServiceOAuth; 160 oauth2_access_token_fetcher_.reset(); 161 162 // Invoke the callback to let them know the fetch failed. 163 RequestCompleted(); 164} 165 166void CloudPolicyClientRegistrationHelper::OnGetTokenSuccess( 167 const std::string& access_token, 168 const base::Time& expiration_time) { 169 // Cache the access token to be used after the GetUserInfo call. 170 oauth_access_token_ = access_token; 171 DVLOG(1) << "Fetched new scoped OAuth token:" << oauth_access_token_; 172 oauth2_access_token_fetcher_.reset(); 173 // Now we've gotten our access token - contact GAIA to see if this is a 174 // hosted domain. 175 user_info_fetcher_.reset(new policy::UserInfoFetcher(this, context_)); 176 user_info_fetcher_->Start(oauth_access_token_); 177} 178 179void CloudPolicyClientRegistrationHelper::OnGetUserInfoFailure( 180 const GoogleServiceAuthError& error) { 181 DVLOG(1) << "Failed to fetch user info from GAIA: " << error.state(); 182 user_info_fetcher_.reset(); 183 RequestCompleted(); 184} 185 186void CloudPolicyClientRegistrationHelper::OnGetUserInfoSuccess( 187 const DictionaryValue* data) { 188 user_info_fetcher_.reset(); 189 if (!data->HasKey(kGetHostedDomainKey) && !ShouldForceLoadPolicy()) { 190 DVLOG(1) << "User not from a hosted domain - skipping registration"; 191 RequestCompleted(); 192 return; 193 } 194 DVLOG(1) << "Registering CloudPolicyClient for user from hosted domain"; 195 // The user is from a hosted domain, so it's OK to register the 196 // CloudPolicyClient and make requests to DMServer. 197 if (client_->is_registered()) { 198 // Client should not be registered yet. 199 NOTREACHED(); 200 RequestCompleted(); 201 return; 202 } 203 204 // Kick off registration of the CloudPolicyClient with our newly minted 205 // oauth_access_token_. 206 client_->Register(em::DeviceRegisterRequest::BROWSER, oauth_access_token_, 207 std::string(), false, std::string()); 208} 209 210void CloudPolicyClientRegistrationHelper::OnRegistrationStateChanged( 211 policy::CloudPolicyClient* client) { 212 DVLOG(1) << "Client registration succeeded"; 213 DCHECK_EQ(client, client_); 214 DCHECK(client->is_registered()); 215 RequestCompleted(); 216} 217 218void CloudPolicyClientRegistrationHelper::OnClientError( 219 policy::CloudPolicyClient* client) { 220 DVLOG(1) << "Client registration failed"; 221 DCHECK_EQ(client, client_); 222 RequestCompleted(); 223} 224 225UserPolicySigninService::UserPolicySigninService( 226 Profile* profile) 227 : profile_(profile), 228 weak_factory_(this) { 229 if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin)) 230 return; 231 232 // Initialize/shutdown the UserCloudPolicyManager when the user signs out. 233 registrar_.Add(this, 234 chrome::NOTIFICATION_GOOGLE_SIGNED_OUT, 235 content::Source<Profile>(profile)); 236 237 // Listen for an OAuth token to become available so we can register a client 238 // if for some reason the client is not already registered (for example, if 239 // the policy load failed during initial signin). 240 registrar_.Add(this, 241 chrome::NOTIFICATION_TOKEN_AVAILABLE, 242 content::Source<TokenService>( 243 TokenServiceFactory::GetForProfile(profile))); 244 245 // TokenService should not yet have loaded its tokens since this happens in 246 // the background after PKS initialization - so this service should always be 247 // created before the oauth token is available. 248 DCHECK(!TokenServiceFactory::GetForProfile(profile_)->HasOAuthLoginToken()); 249 250 // Register a listener to be called back once the current profile has finished 251 // initializing, so we can startup the UserCloudPolicyManager. 252 registrar_.Add(this, 253 chrome::NOTIFICATION_PROFILE_ADDED, 254 content::Source<Profile>(profile)); 255 256 // Register a listener for the import finished notification in a first run 257 // scenario, which indicates the profile is ready to be further initialized. 258 registrar_.Add(this, 259 chrome::NOTIFICATION_IMPORT_FINISHED, 260 content::Source<Profile>(profile)); 261} 262 263UserPolicySigninService::~UserPolicySigninService() {} 264 265void UserPolicySigninService::RegisterPolicyClient( 266 const std::string& username, 267 const std::string& oauth2_refresh_token, 268 const PolicyRegistrationCallback& callback) { 269 DCHECK(!username.empty()); 270 DCHECK(!oauth2_refresh_token.empty()); 271 // We should not be called with a client already initialized. 272 DCHECK(!GetManager() || !GetManager()->core()->client()); 273 274 // If the user should not get policy, just bail out. 275 if (!GetManager() || !ShouldLoadPolicyForUser(username)) { 276 DVLOG(1) << "Signed in user is not in the whitelist"; 277 callback.Run(scoped_ptr<CloudPolicyClient>().Pass()); 278 return; 279 } 280 281 // If the DeviceManagementService is not yet initialized, start it up now. 282 g_browser_process->browser_policy_connector()-> 283 ScheduleServiceInitialization(0); 284 285 // Create a new CloudPolicyClient for fetching the DMToken. 286 scoped_ptr<CloudPolicyClient> policy_client( 287 UserCloudPolicyManager::CreateCloudPolicyClient( 288 g_browser_process->browser_policy_connector()-> 289 device_management_service())); 290 291 registration_helper_.reset( 292 new CloudPolicyClientRegistrationHelper(profile_->GetRequestContext())); 293 294 // Fire off the registration process. Callback keeps the CloudPolicyClient 295 // alive for the length of the registration process. 296 // Grab a pointer to the client before base::Bind() clears the reference in 297 // |policy_client|. 298 CloudPolicyClient* client = policy_client.get(); 299 base::Closure registration_callback = 300 base::Bind(&UserPolicySigninService::CallPolicyRegistrationCallback, 301 base::Unretained(this), base::Passed(&policy_client), 302 callback); 303 registration_helper_->StartRegistration( 304 client, oauth2_refresh_token, registration_callback); 305} 306 307void UserPolicySigninService::CallPolicyRegistrationCallback( 308 scoped_ptr<CloudPolicyClient> client, 309 PolicyRegistrationCallback callback) { 310 registration_helper_.reset(); 311 if (!client->is_registered()) { 312 // Registration failed, so free the client and pass NULL to the callback. 313 client.reset(); 314 } 315 callback.Run(client.Pass()); 316} 317 318void UserPolicySigninService::FetchPolicyForSignedInUser( 319 scoped_ptr<CloudPolicyClient> client, 320 const PolicyFetchCallback& callback) { 321 DCHECK(client); 322 DCHECK(client->is_registered()); 323 // The user has just signed in, so the UserCloudPolicyManager should not yet 324 // be initialized. This routine will initialize the UserCloudPolicyManager 325 // with the passed client and will proactively ask the client to fetch 326 // policy without waiting for the CloudPolicyService to finish initialization. 327 UserCloudPolicyManager* manager = GetManager(); 328 DCHECK(manager); 329 DCHECK(!manager->core()->client()); 330 InitializeUserCloudPolicyManager(client.Pass()); 331 DCHECK(manager->IsClientRegistered()); 332 333 // Now initiate a policy fetch. 334 manager->core()->service()->RefreshPolicy(callback); 335} 336 337void UserPolicySigninService::StopObserving() { 338 UserCloudPolicyManager* manager = GetManager(); 339 if (manager && manager->core()->service()) 340 manager->core()->service()->RemoveObserver(this); 341 if (manager && manager->core()->client()) 342 manager->core()->client()->RemoveObserver(this); 343} 344 345void UserPolicySigninService::StartObserving() { 346 UserCloudPolicyManager* manager = GetManager(); 347 // Manager should be fully initialized by now. 348 DCHECK(manager); 349 DCHECK(manager->core()->service()); 350 manager->core()->service()->AddObserver(this); 351 manager->core()->client()->AddObserver(this); 352} 353 354void UserPolicySigninService::Observe( 355 int type, 356 const content::NotificationSource& source, 357 const content::NotificationDetails& details) { 358 // If an import process is running, wait for NOTIFICATION_IMPORT_FINISHED 359 // before potentially creating the SigninManager. Its dependencies can access 360 // databases that the import process is also accessing, causing conflicts. 361 // Note that the profile manager is NULL in unit tests. 362 if (g_browser_process->profile_manager() && 363 g_browser_process->profile_manager()->will_import()) { 364 return; 365 } 366 367 // If using a TestingProfile with no SigninManager or UserCloudPolicyManager, 368 // skip initialization. 369 if (!GetManager() || !SigninManagerFactory::GetForProfile(profile_)) { 370 DVLOG(1) << "Skipping initialization for tests due to missing components."; 371 return; 372 } 373 374 switch (type) { 375 case chrome::NOTIFICATION_GOOGLE_SIGNED_OUT: 376 ShutdownUserCloudPolicyManager(); 377 break; 378 case chrome::NOTIFICATION_IMPORT_FINISHED: 379 case chrome::NOTIFICATION_PROFILE_ADDED: { 380 // A new profile has been loaded - if it's signed in, then initialize the 381 // UCPM, otherwise shut down the UCPM (which deletes any cached policy 382 // data). This must be done here instead of at constructor time because 383 // the Profile is not fully initialized when this object is constructed 384 // (DoFinalInit() has not yet been called, so ProfileIOData and 385 // SSLConfigServiceManager have not been created yet). 386 // TODO(atwilson): Switch to using a timer instead, to avoid contention 387 // with other services at startup (http://crbug.com/165468). 388 SigninManager* signin_manager = 389 SigninManagerFactory::GetForProfile(profile_); 390 std::string username = signin_manager->GetAuthenticatedUsername(); 391 if (username.empty()) 392 ShutdownUserCloudPolicyManager(); 393 else 394 InitializeForSignedInUser(); 395 break; 396 } 397 case chrome::NOTIFICATION_TOKEN_AVAILABLE: { 398 const TokenService::TokenAvailableDetails& token_details = 399 *(content::Details<const TokenService::TokenAvailableDetails>( 400 details).ptr()); 401 if (token_details.service() == 402 GaiaConstants::kGaiaOAuth2LoginRefreshToken) { 403 SigninManager* signin_manager = 404 SigninManagerFactory::GetForProfile(profile_); 405 std::string username = signin_manager->GetAuthenticatedUsername(); 406 // Should not have GAIA tokens if the user isn't signed in. 407 DCHECK(!username.empty()); 408 // TokenService now has a refresh token (implying that the user is 409 // signed in) so initialize the UserCloudPolicyManager. 410 InitializeForSignedInUser(); 411 } 412 break; 413 } 414 default: 415 NOTREACHED(); 416 } 417} 418 419bool UserPolicySigninService::ShouldLoadPolicyForUser( 420 const std::string& username) { 421 if (profile_->GetPrefs()->GetBoolean(prefs::kDisableCloudPolicyOnSignin)) 422 return false; // Cloud policy is disabled. 423 424 if (username.empty()) 425 return false; // Not signed in. 426 427 if (ShouldForceLoadPolicy()) 428 return true; 429 430 return !BrowserPolicyConnector::IsNonEnterpriseUser(username); 431} 432 433void UserPolicySigninService::InitializeUserCloudPolicyManager( 434 scoped_ptr<CloudPolicyClient> client) { 435 UserCloudPolicyManager* manager = GetManager(); 436 DCHECK(!manager->core()->client()); 437 // If there is no cached DMToken then we can detect this below (or when 438 // the OnInitializationCompleted() callback is invoked). 439 manager->Connect(g_browser_process->local_state(), client.Pass()); 440 DCHECK(manager->core()->service()); 441 StartObserving(); 442 ProhibitSignoutIfNeeded(); 443} 444 445void UserPolicySigninService::InitializeForSignedInUser() { 446 SigninManager* signin_manager = 447 SigninManagerFactory::GetForProfile(profile_); 448 std::string username = signin_manager->GetAuthenticatedUsername(); 449 450 if (!ShouldLoadPolicyForUser(username)) { 451 DVLOG(1) << "Policy load not enabled for user: " << username; 452 return; 453 } 454 DCHECK(!username.empty()); 455 456 UserCloudPolicyManager* manager = GetManager(); 457 // Initialize the UCPM if it is not already initialized. 458 if (!manager->core()->service()) { 459 // If there is no cached DMToken then we can detect this when the 460 // OnInitializationCompleted() callback is invoked and this will 461 // initiate a policy fetch. 462 BrowserPolicyConnector* connector = 463 g_browser_process->browser_policy_connector(); 464 InitializeUserCloudPolicyManager( 465 UserCloudPolicyManager::CreateCloudPolicyClient( 466 connector->device_management_service()).Pass()); 467 } 468 469 // If the CloudPolicyService is initialized, kick off registration. If the 470 // TokenService doesn't have an OAuth token yet (e.g. this is during initial 471 // signin, or when dynamically loading a signed-in policy) this does nothing 472 // until the OAuth token is loaded. 473 if (manager->core()->service()->IsInitializationComplete()) 474 OnInitializationCompleted(manager->core()->service()); 475} 476 477void UserPolicySigninService::ShutdownUserCloudPolicyManager() { 478 // Stop any in-progress token fetch. 479 registration_helper_.reset(); 480 481 StopObserving(); 482 483 UserCloudPolicyManager* manager = GetManager(); 484 if (manager) { // Can be null in unit tests. 485 manager->DisconnectAndRemovePolicy(); 486 // Allow the user to signout again. 487 SigninManagerFactory::GetForProfile(profile_)->ProhibitSignout(false); 488 } 489} 490 491void UserPolicySigninService::OnInitializationCompleted( 492 CloudPolicyService* service) { 493 UserCloudPolicyManager* manager = GetManager(); 494 DCHECK_EQ(service, manager->core()->service()); 495 DCHECK(service->IsInitializationComplete()); 496 // The service is now initialized - if the client is not yet registered, then 497 // it means that there is no cached policy and so we need to initiate a new 498 // client registration. 499 DVLOG_IF(1, manager->IsClientRegistered()) 500 << "Client already registered - not fetching DMToken"; 501 if (!manager->IsClientRegistered()) { 502 std::string token = TokenServiceFactory::GetForProfile(profile_)-> 503 GetOAuth2LoginRefreshToken(); 504 if (token.empty()) { 505 // No token yet - this class listens for NOTIFICATION_TOKEN_AVAILABLE 506 // and will re-attempt registration once the token is available. 507 DLOG(WARNING) << "No OAuth Refresh Token - delaying policy download"; 508 return; 509 } 510 RegisterCloudPolicyService(token); 511 } 512 // If client is registered now, prohibit signout. 513 ProhibitSignoutIfNeeded(); 514} 515 516void UserPolicySigninService::OnPolicyFetched(CloudPolicyClient* client) { 517} 518 519void UserPolicySigninService::OnRegistrationStateChanged( 520 CloudPolicyClient* client) { 521} 522 523void UserPolicySigninService::OnClientError(CloudPolicyClient* client) { 524 if (client->is_registered()) { 525 // If the client is already registered, it means this error must have 526 // come from a policy fetch. 527 if (client->status() == 528 policy::DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED) { 529 // OK, policy fetch failed with MANAGEMENT_NOT_SUPPORTED - this is our 530 // trigger to revert to "unmanaged" mode (we will check for management 531 // being re-enabled on the next restart and/or login). 532 DVLOG(1) << "DMServer returned NOT_SUPPORTED error - removing policy"; 533 534 // Can't shutdown now because we're in the middle of a callback from 535 // the CloudPolicyClient, so queue up a task to do the shutdown. 536 base::MessageLoop::current()->PostTask( 537 FROM_HERE, 538 base::Bind(&UserPolicySigninService::ShutdownUserCloudPolicyManager, 539 weak_factory_.GetWeakPtr())); 540 } else { 541 DVLOG(1) << "Error fetching policy: " << client->status(); 542 } 543 } 544} 545 546void UserPolicySigninService::RegisterCloudPolicyService( 547 std::string login_token) { 548 DCHECK(!GetManager()->IsClientRegistered()); 549 DVLOG(1) << "Fetching new DM Token"; 550 // Do nothing if already starting the registration process. 551 if (registration_helper_) 552 return; 553 554 // Start the process of registering the CloudPolicyClient. Once it completes, 555 // policy fetch will automatically happen. 556 registration_helper_.reset( 557 new CloudPolicyClientRegistrationHelper(profile_->GetRequestContext())); 558 registration_helper_->StartRegistration( 559 GetManager()->core()->client(), 560 login_token, 561 base::Bind(&UserPolicySigninService::OnRegistrationComplete, 562 base::Unretained(this))); 563} 564 565void UserPolicySigninService::OnRegistrationComplete() { 566 ProhibitSignoutIfNeeded(); 567 registration_helper_.reset(); 568} 569 570void UserPolicySigninService::ProhibitSignoutIfNeeded() { 571 if (GetManager()->IsClientRegistered()) { 572 DVLOG(1) << "User is registered for policy - prohibiting signout"; 573 SigninManager* signin_manager = 574 SigninManagerFactory::GetForProfile(profile_); 575 signin_manager->ProhibitSignout(true); 576 } 577} 578 579void UserPolicySigninService::Shutdown() { 580 // Stop any pending registration helper activity. We do this here instead of 581 // in the destructor because we want to shutdown the registration helper 582 // before UserCloudPolicyManager shuts down the CloudPolicyClient. 583 registration_helper_.reset(); 584 StopObserving(); 585} 586 587UserCloudPolicyManager* UserPolicySigninService::GetManager() { 588 return UserCloudPolicyManagerFactory::GetForProfile(profile_); 589} 590 591} // namespace policy 592