summaryrefslogtreecommitdiff
path: root/chromium/components/policy/core/browser/cloud/user_policy_signin_service_base.cc
blob: 219f5b61aaf0889ab84383ae617a5e22fe7ba23f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
// Copyright 2022 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 "components/policy/core/browser/cloud/user_policy_signin_service_base.h"

#include <utility>

#include "base/bind.h"
#include "base/dcheck_is_on.h"
#include "base/location.h"
#include "base/task/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/cloud/cloud_policy_client_registration_helper.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/account_info.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"

namespace em = enterprise_management;

namespace {

#if BUILDFLAG(IS_ANDROID)
const em::DeviceRegisterRequest::Type kCloudPolicyRegistrationType =
    em::DeviceRegisterRequest::ANDROID_BROWSER;
#elif BUILDFLAG(IS_IOS)
// TODO(crbug.com/1312263): Use em::DeviceRegisterRequest::IOS_BROWSER when
// supported in the dmserver. The type for Desktop is temporarily used on iOS
// to allow early testing of the feature before the DMServer can support iOS
// User Policy.
const em::DeviceRegisterRequest::Type kCloudPolicyRegistrationType =
    em::DeviceRegisterRequest::BROWSER;
#else
const em::DeviceRegisterRequest::Type kCloudPolicyRegistrationType =
    em::DeviceRegisterRequest::BROWSER;
#endif

}  // namespace

namespace policy {

UserPolicySigninServiceBase::UserPolicySigninServiceBase(
    PrefService* local_state,
    DeviceManagementService* device_management_service,
    UserCloudPolicyManager* policy_manager,
    signin::IdentityManager* identity_manager,
    scoped_refptr<network::SharedURLLoaderFactory> system_url_loader_factory)
    : policy_manager_(policy_manager),
      identity_manager_(identity_manager),
      local_state_(local_state),
      device_management_service_(device_management_service),
      system_url_loader_factory_(system_url_loader_factory) {}

UserPolicySigninServiceBase::~UserPolicySigninServiceBase() {}

void UserPolicySigninServiceBase::FetchPolicyForSignedInUser(
    const AccountId& account_id,
    const std::string& dm_token,
    const std::string& client_id,
    scoped_refptr<network::SharedURLLoaderFactory> profile_url_loader_factory,
    PolicyFetchCallback callback) {
  UserCloudPolicyManager* manager = policy_manager();
  DCHECK(manager);

  // Initialize the cloud policy manager there was no prior initialization.
  if (!manager->core()->client()) {
    std::unique_ptr<CloudPolicyClient> client =
        UserCloudPolicyManager::CreateCloudPolicyClient(
            device_management_service_, profile_url_loader_factory);
    client->SetupRegistration(
        dm_token, client_id,
        std::vector<std::string>() /* user_affiliation_ids */);
    DCHECK(client->is_registered());
    DCHECK(!manager->core()->client());
    InitializeUserCloudPolicyManager(account_id, std::move(client));
  }

  DCHECK(manager->IsClientRegistered());

  // Now initiate a policy fetch.
  manager->core()->service()->RefreshPolicy(std::move(callback));
}

void UserPolicySigninServiceBase::OnPolicyFetched(CloudPolicyClient* client) {}

void UserPolicySigninServiceBase::OnRegistrationStateChanged(
    CloudPolicyClient* client) {}

void UserPolicySigninServiceBase::OnClientError(CloudPolicyClient* client) {
  if (client->is_registered()) {
    // If the client is already registered, it means this error must have
    // come from a policy fetch.
    if (client->status() == DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED) {
      // OK, policy fetch failed with MANAGEMENT_NOT_SUPPORTED - this is our
      // trigger to revert to "unmanaged" mode (we will check for management
      // being re-enabled on the next restart and/or login).
      DVLOG(1) << "DMServer returned NOT_SUPPORTED error - removing policy";

      // Can't shutdown now because we're in the middle of a callback from
      // the CloudPolicyClient, so queue up a task to do the shutdown.
      base::ThreadTaskRunnerHandle::Get()->PostTask(
          FROM_HERE,
          base::BindOnce(
              &UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager,
              weak_factory_.GetWeakPtr()));
    } else {
      DVLOG(1) << "Error fetching policy: " << client->status();
    }
  }
}

void UserPolicySigninServiceBase::Shutdown() {
  PrepareForUserCloudPolicyManagerShutdown();
}

void UserPolicySigninServiceBase::PrepareForUserCloudPolicyManagerShutdown() {
  registration_helper_.reset();
  UserCloudPolicyManager* manager = policy_manager();
  if (manager && manager->core()->client())
    manager->core()->client()->RemoveObserver(this);
  if (manager && manager->core()->service())
    manager->core()->service()->RemoveObserver(this);
}

std::unique_ptr<CloudPolicyClient>
UserPolicySigninServiceBase::CreateClientForRegistrationOnly(
    const std::string& username) {
  DCHECK(!username.empty());
  // We should not be called with a client already initialized.
  DCHECK(!policy_manager() || !policy_manager()->core()->client());

  // If the user should not get policy, just bail out.
  if (!policy_manager() || !ShouldLoadPolicyForUser(username)) {
    DVLOG(1) << "Signed in user is not in the allowlist";
    return nullptr;
  }

  // If the DeviceManagementService is not yet initialized, start it up now.
  device_management_service_->ScheduleInitialization(0);

  // Create a new CloudPolicyClient for fetching the DMToken.
  return UserCloudPolicyManager::CreateCloudPolicyClient(
      device_management_service_, system_url_loader_factory_);
}

bool UserPolicySigninServiceBase::ShouldLoadPolicyForUser(
    const std::string& username) {
  if (username.empty())
    return false;  // Not signed in.

  return !BrowserPolicyConnector::IsNonEnterpriseUser(username);
}

void UserPolicySigninServiceBase::InitializeForSignedInUser(
    const AccountId& account_id,
    scoped_refptr<network::SharedURLLoaderFactory> profile_url_loader_factory) {
  DCHECK(account_id.is_valid());
  UserCloudPolicyManager* manager = policy_manager();
  if (!ShouldLoadPolicyForUser(account_id.GetUserEmail())) {
    manager->SetPoliciesRequired(false);
    DVLOG(1) << "Policy load not enabled for user: "
             << account_id.GetUserEmail();
    return;
  }

  // Initialize the UCPM if it is not already initialized.
  if (!manager->core()->service()) {
    // If there is no cached DMToken then we can detect this when the
    // OnCloudPolicyServiceInitializationCompleted() callback is invoked and
    // this will initiate a policy fetch.
    InitializeUserCloudPolicyManager(
        account_id,
        UserCloudPolicyManager::CreateCloudPolicyClient(
            device_management_service_, profile_url_loader_factory));
  } else {
    manager->SetSigninAccountId(account_id);
  }

  // If the CloudPolicyService is initialized, kick off registration.
  // Otherwise OnCloudPolicyServiceInitializationCompleted is invoked as soon as
  // the service finishes its initialization.
  if (manager->core()->service()->IsInitializationComplete())
    OnCloudPolicyServiceInitializationCompleted();
}

void UserPolicySigninServiceBase::InitializeUserCloudPolicyManager(
    const AccountId& account_id,
    std::unique_ptr<CloudPolicyClient> client) {
  DCHECK(client);
  UserCloudPolicyManager* manager = policy_manager();
  manager->SetSigninAccountId(account_id);
  DCHECK(!manager->core()->client());
  manager->Connect(local_state_, std::move(client));
  DCHECK(manager->core()->service());

  // Observe the client to detect errors fetching policy.
  manager->core()->client()->AddObserver(this);
  // Observe the service to determine when it's initialized.
  manager->core()->service()->AddObserver(this);
}

void UserPolicySigninServiceBase::ShutdownUserCloudPolicyManager() {
  PrepareForUserCloudPolicyManagerShutdown();
  UserCloudPolicyManager* manager = policy_manager();
  if (manager)
    manager->DisconnectAndRemovePolicy();
}

void UserPolicySigninServiceBase::CancelPendingRegistration() {
  weak_factory_for_registration_.InvalidateWeakPtrs();
  registration_helper_.reset();
}

void UserPolicySigninServiceBase::CallPolicyRegistrationCallback(
    std::unique_ptr<CloudPolicyClient> client,
    PolicyRegistrationCallback callback) {
  registration_helper_.reset();
  std::move(callback).Run(client->dm_token(), client->client_id());
}

void UserPolicySigninServiceBase::RegisterForPolicyWithAccountId(
    const std::string& username,
    const CoreAccountId& account_id,
    PolicyRegistrationCallback callback) {
  DCHECK(!account_id.empty());

  if (policy_manager() && policy_manager()->IsClientRegistered()) {
    // Reuse the already fetched DM token if the client of the manager is
    // already registered.
    std::move(callback).Run(policy_manager()->core()->client()->dm_token(),
                            policy_manager()->core()->client()->client_id());
    return;
  }

  // Create a new CloudPolicyClient for fetching the DMToken. This is a
  // different client from the one used by the manager.
  std::unique_ptr<CloudPolicyClient> policy_client =
      CreateClientForRegistrationOnly(username);
  if (!policy_client) {
    std::move(callback).Run(std::string(), std::string());
    return;
  }

  CancelPendingRegistration();

  // Fire off the registration process. Callback owns and keeps the
  // CloudPolicyClient alive for the length of the registration process.
  registration_helper_ = std::make_unique<CloudPolicyClientRegistrationHelper>(
      policy_client.get(), kCloudPolicyRegistrationType);

  // Using a raw pointer to |this| is okay, because the service owns
  // |registration_helper_|.
  auto registration_callback = base::BindOnce(
      &UserPolicySigninServiceBase::CallPolicyRegistrationCallback,
      base::Unretained(this), std::move(policy_client), std::move(callback));
  registration_helper_->StartRegistration(identity_manager(), account_id,
                                          std::move(registration_callback));
}

void UserPolicySigninServiceBase::RegisterCloudPolicyService() {
  DCHECK(
      identity_manager()->HasPrimaryAccount(GetConsentLevelForRegistration()));
  DCHECK(policy_manager()->core()->client());
  DCHECK(!policy_manager()->IsClientRegistered());

  DVLOG(1) << "Fetching new DM Token";

  // Do nothing if already starting the registration process in which case there
  // will be an instance of |registration_helper_|.
  if (registration_helper_)
    return;

  UpdateLastPolicyCheckTime();

  // Start the process of registering the CloudPolicyClient. Once it completes,
  // policy fetch will automatically happen.
  registration_helper_ = std::make_unique<CloudPolicyClientRegistrationHelper>(
      policy_manager()->core()->client(), kCloudPolicyRegistrationType);
  registration_helper_->StartRegistration(
      identity_manager(),
      identity_manager()->GetPrimaryAccountId(GetConsentLevelForRegistration()),
      base::BindOnce(&UserPolicySigninServiceBase::OnRegistrationComplete,
                     base::Unretained(this)));
}

void UserPolicySigninServiceBase::OnRegistrationComplete() {
  ProhibitSignoutIfNeeded();
  registration_helper_.reset();
}

base::TimeDelta UserPolicySigninServiceBase::GetTryRegistrationDelay() {
  return base::TimeDelta();
}

void UserPolicySigninServiceBase::
    OnCloudPolicyServiceInitializationCompleted() {
  UserCloudPolicyManager* manager = policy_manager();
  DCHECK(manager->core()->service()->IsInitializationComplete());
  // The service is now initialized - if the client is not yet registered, then
  // it means that there is no cached policy and so we need to initiate a new
  // client registration.
  if (manager->IsClientRegistered()) {
    DVLOG(1) << "Client already registered - not fetching DMToken";
    ProhibitSignoutIfNeeded();
    return;
  }

  if (!CanApplyPolicies(/*check_for_refresh_token=*/true)) {
    // No token yet. This can only happen on Desktop platforms which should
    // listen to OnRefreshTokenUpdatedForAccount() and will re-attempt
    // registration once the token is available.
    DLOG(WARNING) << "No OAuth Refresh Token - delaying policy download";
    return;
  }

  base::TimeDelta try_registration_delay = GetTryRegistrationDelay();
  if (try_registration_delay.is_zero()) {
    // If the try registration delay is 0, register the cloud policy service
    // immediately without queueing a task. This is the case for Desktop.
    RegisterCloudPolicyService();
  } else {
    base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&UserPolicySigninServiceBase::RegisterCloudPolicyService,
                       weak_factory_for_registration_.GetWeakPtr()),
        try_registration_delay);
  }

  ProhibitSignoutIfNeeded();
}

void UserPolicySigninServiceBase::ProhibitSignoutIfNeeded() {}

bool UserPolicySigninServiceBase::CanApplyPolicies(
    bool check_for_refresh_token) {
  return false;
}

void UserPolicySigninServiceBase::UpdateLastPolicyCheckTime() {}

signin::ConsentLevel
UserPolicySigninServiceBase::GetConsentLevelForRegistration() {
  return signin::ConsentLevel::kSignin;
}

}  // namespace policy