1// Copyright 2013 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_base.h"
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
11#include "chrome/browser/profiles/profile.h"
12#include "chrome/browser/signin/signin_manager_factory.h"
13#include "chrome/common/chrome_content_client.h"
14#include "components/policy/core/browser/browser_policy_connector.h"
15#include "components/policy/core/common/cloud/device_management_service.h"
16#include "components/policy/core/common/cloud/system_policy_request_context.h"
17#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
18#include "components/policy/core/common/cloud/user_policy_request_context.h"
19#include "components/signin/core/browser/signin_manager.h"
20#include "content/public/browser/notification_source.h"
21#include "net/url_request/url_request_context_getter.h"
22
23namespace policy {
24
25UserPolicySigninServiceBase::UserPolicySigninServiceBase(
26    Profile* profile,
27    PrefService* local_state,
28    DeviceManagementService* device_management_service,
29    UserCloudPolicyManager* policy_manager,
30    SigninManager* signin_manager,
31    scoped_refptr<net::URLRequestContextGetter> system_request_context)
32    : policy_manager_(policy_manager),
33      signin_manager_(signin_manager),
34      local_state_(local_state),
35      device_management_service_(device_management_service),
36      system_request_context_(system_request_context),
37      weak_factory_(this) {
38  // Register a listener to be called back once the current profile has finished
39  // initializing, so we can startup/shutdown the UserCloudPolicyManager.
40  registrar_.Add(this,
41                 chrome::NOTIFICATION_PROFILE_ADDED,
42                 content::Source<Profile>(profile));
43}
44
45UserPolicySigninServiceBase::~UserPolicySigninServiceBase() {}
46
47void UserPolicySigninServiceBase::FetchPolicyForSignedInUser(
48    const std::string& username,
49    const std::string& dm_token,
50    const std::string& client_id,
51    scoped_refptr<net::URLRequestContextGetter> profile_request_context,
52    const PolicyFetchCallback& callback) {
53  scoped_ptr<CloudPolicyClient> client(
54      UserCloudPolicyManager::CreateCloudPolicyClient(
55          device_management_service_,
56          CreateUserRequestContext(profile_request_context)).Pass());
57  client->SetupRegistration(dm_token, client_id);
58  DCHECK(client->is_registered());
59  // The user has just signed in, so the UserCloudPolicyManager should not yet
60  // be initialized. This routine will initialize the UserCloudPolicyManager
61  // with the passed client and will proactively ask the client to fetch
62  // policy without waiting for the CloudPolicyService to finish initialization.
63  UserCloudPolicyManager* manager = policy_manager();
64  DCHECK(manager);
65  DCHECK(!manager->core()->client());
66  InitializeUserCloudPolicyManager(username, client.Pass());
67  DCHECK(manager->IsClientRegistered());
68
69  // Now initiate a policy fetch.
70  manager->core()->service()->RefreshPolicy(callback);
71}
72
73void UserPolicySigninServiceBase::GoogleSignedOut(const std::string& account_id,
74                                                  const std::string& username) {
75  ShutdownUserCloudPolicyManager();
76}
77
78void UserPolicySigninServiceBase::Observe(
79    int type,
80    const content::NotificationSource& source,
81    const content::NotificationDetails& details) {
82  switch (type) {
83    case chrome::NOTIFICATION_PROFILE_ADDED:
84      // A new profile has been loaded - if it's signed in, then initialize the
85      // UCPM, otherwise shut down the UCPM (which deletes any cached policy
86      // data). This must be done here instead of at constructor time because
87      // the Profile is not fully initialized when this object is constructed
88      // (DoFinalInit() has not yet been called, so ProfileIOData and
89      // SSLConfigServiceManager have not been created yet).
90      // TODO(atwilson): Switch to using a timer instead, to avoid contention
91      // with other services at startup (http://crbug.com/165468).
92      InitializeOnProfileReady(content::Source<Profile>(source).ptr());
93      break;
94    default:
95      NOTREACHED();
96  }
97}
98
99void UserPolicySigninServiceBase::OnInitializationCompleted(
100    CloudPolicyService* service) {
101  // This is meant to be overridden by subclasses. Starting and stopping to
102  // observe the CloudPolicyService from this base class avoids the need for
103  // more virtuals.
104}
105
106void UserPolicySigninServiceBase::OnPolicyFetched(CloudPolicyClient* client) {}
107
108void UserPolicySigninServiceBase::OnRegistrationStateChanged(
109    CloudPolicyClient* client) {}
110
111void UserPolicySigninServiceBase::OnClientError(CloudPolicyClient* client) {
112  if (client->is_registered()) {
113    // If the client is already registered, it means this error must have
114    // come from a policy fetch.
115    if (client->status() == DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED) {
116      // OK, policy fetch failed with MANAGEMENT_NOT_SUPPORTED - this is our
117      // trigger to revert to "unmanaged" mode (we will check for management
118      // being re-enabled on the next restart and/or login).
119      DVLOG(1) << "DMServer returned NOT_SUPPORTED error - removing policy";
120
121      // Can't shutdown now because we're in the middle of a callback from
122      // the CloudPolicyClient, so queue up a task to do the shutdown.
123      base::MessageLoop::current()->PostTask(
124          FROM_HERE,
125          base::Bind(
126              &UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager,
127              weak_factory_.GetWeakPtr()));
128    } else {
129      DVLOG(1) << "Error fetching policy: " << client->status();
130    }
131  }
132}
133
134void UserPolicySigninServiceBase::Shutdown() {
135  if (signin_manager())
136    signin_manager()->RemoveObserver(this);
137  PrepareForUserCloudPolicyManagerShutdown();
138}
139
140void UserPolicySigninServiceBase::PrepareForUserCloudPolicyManagerShutdown() {
141  UserCloudPolicyManager* manager = policy_manager();
142  if (manager && manager->core()->client())
143    manager->core()->client()->RemoveObserver(this);
144  if (manager && manager->core()->service())
145    manager->core()->service()->RemoveObserver(this);
146}
147
148scoped_ptr<CloudPolicyClient>
149UserPolicySigninServiceBase::CreateClientForRegistrationOnly(
150    const std::string& username) {
151  DCHECK(!username.empty());
152  // We should not be called with a client already initialized.
153#if !defined(OS_IOS)
154  // On iOS we check if an account has policy while the profile is signed in
155  // to another account.
156  DCHECK(!policy_manager() || !policy_manager()->core()->client());
157#endif
158
159  // If the user should not get policy, just bail out.
160  if (!policy_manager() || !ShouldLoadPolicyForUser(username)) {
161    DVLOG(1) << "Signed in user is not in the whitelist";
162    return scoped_ptr<CloudPolicyClient>();
163  }
164
165  // If the DeviceManagementService is not yet initialized, start it up now.
166  device_management_service_->ScheduleInitialization(0);
167
168  // Create a new CloudPolicyClient for fetching the DMToken.
169  return UserCloudPolicyManager::CreateCloudPolicyClient(
170      device_management_service_, CreateSystemRequestContext());
171}
172
173bool UserPolicySigninServiceBase::ShouldLoadPolicyForUser(
174    const std::string& username) {
175  if (username.empty())
176    return false;  // Not signed in.
177
178  return !BrowserPolicyConnector::IsNonEnterpriseUser(username);
179}
180
181void UserPolicySigninServiceBase::InitializeOnProfileReady(Profile* profile) {
182  // If using a TestingProfile with no SigninManager or UserCloudPolicyManager,
183  // skip initialization.
184  if (!policy_manager() || !signin_manager()) {
185    DVLOG(1) << "Skipping initialization for tests due to missing components.";
186    return;
187  }
188
189  // Shutdown the UserCloudPolicyManager when the user signs out. We start
190  // observing the SigninManager here because we don't want to get signout
191  // notifications until after the profile has started initializing
192  // (http://crbug.com/316229).
193  signin_manager()->AddObserver(this);
194
195  std::string username = signin_manager()->GetAuthenticatedUsername();
196  if (username.empty())
197    ShutdownUserCloudPolicyManager();
198  else
199    InitializeForSignedInUser(username, profile->GetRequestContext());
200}
201
202void UserPolicySigninServiceBase::InitializeForSignedInUser(
203    const std::string& username,
204    scoped_refptr<net::URLRequestContextGetter> profile_request_context) {
205  DCHECK(!username.empty());
206  if (!ShouldLoadPolicyForUser(username)) {
207    DVLOG(1) << "Policy load not enabled for user: " << username;
208    return;
209  }
210
211  UserCloudPolicyManager* manager = policy_manager();
212  // Initialize the UCPM if it is not already initialized.
213  if (!manager->core()->service()) {
214    // If there is no cached DMToken then we can detect this when the
215    // OnInitializationCompleted() callback is invoked and this will
216    // initiate a policy fetch.
217    InitializeUserCloudPolicyManager(
218        username,
219        UserCloudPolicyManager::CreateCloudPolicyClient(
220            device_management_service_,
221            CreateUserRequestContext(profile_request_context)).Pass());
222  } else {
223    manager->SetSigninUsername(username);
224  }
225
226  // If the CloudPolicyService is initialized, kick off registration.
227  // Otherwise OnInitializationCompleted is invoked as soon as the service
228  // finishes its initialization.
229  if (manager->core()->service()->IsInitializationComplete())
230    OnInitializationCompleted(manager->core()->service());
231}
232
233void UserPolicySigninServiceBase::InitializeUserCloudPolicyManager(
234    const std::string& username,
235    scoped_ptr<CloudPolicyClient> client) {
236  DCHECK(client);
237  UserCloudPolicyManager* manager = policy_manager();
238  manager->SetSigninUsername(username);
239  DCHECK(!manager->core()->client());
240  scoped_refptr<net::URLRequestContextGetter> context =
241      client->GetRequestContext();
242  manager->Connect(local_state_, context, client.Pass());
243  DCHECK(manager->core()->service());
244
245  // Observe the client to detect errors fetching policy.
246  manager->core()->client()->AddObserver(this);
247  // Observe the service to determine when it's initialized.
248  manager->core()->service()->AddObserver(this);
249}
250
251void UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager() {
252  PrepareForUserCloudPolicyManagerShutdown();
253  UserCloudPolicyManager* manager = policy_manager();
254  if (manager)
255    manager->DisconnectAndRemovePolicy();
256}
257
258scoped_refptr<net::URLRequestContextGetter>
259UserPolicySigninServiceBase::CreateSystemRequestContext() {
260  return new SystemPolicyRequestContext(
261      system_request_context(), GetUserAgent());
262}
263
264scoped_refptr<net::URLRequestContextGetter>
265UserPolicySigninServiceBase::CreateUserRequestContext(
266    scoped_refptr<net::URLRequestContextGetter> profile_request_context) {
267  return new UserPolicyRequestContext(
268      profile_request_context, system_request_context(), GetUserAgent());
269}
270
271}  // namespace policy
272