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