1// Copyright 2014 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/chromeos/policy/consumer_management_service.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/callback.h"
10#include "base/prefs/pref_registry_simple.h"
11#include "base/prefs/pref_service.h"
12#include "base/prefs/testing_pref_service.h"
13#include "base/run_loop.h"
14#include "chrome/browser/browser_process.h"
15#include "chrome/browser/browser_process_platform_part.h"
16#include "chrome/browser/chrome_notification_types.h"
17#include "chrome/browser/chromeos/login/users/mock_user_manager.h"
18#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h"
19#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
20#include "chrome/browser/chromeos/policy/device_cloud_policy_initializer.h"
21#include "chrome/browser/chromeos/policy/device_policy_builder.h"
22#include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
23#include "chrome/browser/chromeos/policy/fake_device_cloud_policy_initializer.h"
24#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
25#include "chrome/browser/notifications/notification_ui_manager.h"
26#include "chrome/browser/profiles/profile.h"
27#include "chrome/browser/signin/fake_profile_oauth2_token_service.h"
28#include "chrome/browser/signin/fake_profile_oauth2_token_service_builder.h"
29#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
30#include "chrome/browser/signin/signin_manager_factory.h"
31#include "chrome/common/pref_names.h"
32#include "chrome/test/base/browser_with_test_window_test.h"
33#include "chrome/test/base/scoped_testing_local_state.h"
34#include "chrome/test/base/testing_browser_process.h"
35#include "chrome/test/base/testing_profile.h"
36#include "chrome/test/base/testing_profile_manager.h"
37#include "chromeos/dbus/cryptohome/rpc.pb.h"
38#include "chromeos/dbus/cryptohome_client.h"
39#include "chromeos/dbus/mock_cryptohome_client.h"
40#include "components/signin/core/browser/profile_oauth2_token_service.h"
41#include "components/signin/core/browser/signin_manager_base.h"
42#include "content/public/browser/notification_details.h"
43#include "content/public/browser/notification_source.h"
44#include "google_apis/gaia/google_service_auth_error.h"
45#include "policy/proto/device_management_backend.pb.h"
46#include "testing/gmock/include/gmock/gmock.h"
47#include "testing/gtest/include/gtest/gtest.h"
48
49using testing::Invoke;
50using testing::NiceMock;
51using testing::Return;
52using testing::_;
53
54namespace em = enterprise_management;
55
56namespace {
57const char* kAttributeOwnerId = "consumer_management.owner_id";
58const char* kTestOwner = "test@chromium.org.test";
59}
60
61namespace policy {
62
63class ConsumerManagementServiceTest : public BrowserWithTestWindowTest {
64 public:
65  ConsumerManagementServiceTest()
66      : cryptohome_result_(false),
67        set_owner_status_(false) {
68    ON_CALL(mock_cryptohome_client_, GetBootAttribute(_, _))
69        .WillByDefault(
70            Invoke(this, &ConsumerManagementServiceTest::MockGetBootAttribute));
71    ON_CALL(mock_cryptohome_client_, SetBootAttribute(_, _))
72        .WillByDefault(
73            Invoke(this, &ConsumerManagementServiceTest::MockSetBootAttribute));
74    ON_CALL(mock_cryptohome_client_, FlushAndSignBootAttributes(_, _))
75        .WillByDefault(
76            Invoke(this,
77                   &ConsumerManagementServiceTest::
78                       MockFlushAndSignBootAttributes));
79  }
80
81  virtual void SetUp() OVERRIDE {
82    BrowserWithTestWindowTest::SetUp();
83
84    testing_profile_manager_.reset(new TestingProfileManager(
85        TestingBrowserProcess::GetGlobal()));
86    ASSERT_TRUE(testing_profile_manager_->SetUp());
87
88    service_.reset(new ConsumerManagementService(&mock_cryptohome_client_,
89                                                 NULL));
90  }
91
92  virtual void TearDown() OVERRIDE {
93    testing_profile_manager_.reset();
94
95    service_.reset();
96
97    BrowserWithTestWindowTest::TearDown();
98  }
99
100  ConsumerManagementService::EnrollmentStage GetEnrollmentStage() {
101    return static_cast<ConsumerManagementService::EnrollmentStage>(
102        g_browser_process->local_state()->GetInteger(
103            prefs::kConsumerManagementEnrollmentStage));
104  }
105
106  void SetEnrollmentStage(ConsumerManagementService::EnrollmentStage stage) {
107    g_browser_process->local_state()->SetInteger(
108        prefs::kConsumerManagementEnrollmentStage, stage);
109  }
110
111  void MockGetBootAttribute(
112      const cryptohome::GetBootAttributeRequest& request,
113      const chromeos::CryptohomeClient::ProtobufMethodCallback& callback) {
114    get_boot_attribute_request_ = request;
115    callback.Run(cryptohome_status_, cryptohome_result_, cryptohome_reply_);
116  }
117
118  void MockSetBootAttribute(
119      const cryptohome::SetBootAttributeRequest& request,
120      const chromeos::CryptohomeClient::ProtobufMethodCallback& callback) {
121    set_boot_attribute_request_ = request;
122    callback.Run(cryptohome_status_, cryptohome_result_, cryptohome_reply_);
123  }
124
125  void MockFlushAndSignBootAttributes(
126      const cryptohome::FlushAndSignBootAttributesRequest& request,
127      const chromeos::CryptohomeClient::ProtobufMethodCallback& callback) {
128    callback.Run(cryptohome_status_, cryptohome_result_, cryptohome_reply_);
129  }
130
131  void OnGetOwnerDone(const std::string& owner) {
132    owner_ = owner;
133  }
134
135  void OnSetOwnerDone(bool status) {
136    set_owner_status_ = status;
137  }
138
139  // Variables for building the service.
140  NiceMock<chromeos::MockCryptohomeClient> mock_cryptohome_client_;
141  scoped_ptr<ConsumerManagementService> service_;
142
143  scoped_ptr<TestingProfileManager> testing_profile_manager_;
144
145  // Variables for setting the return value or catching the arguments of mock
146  // functions.
147  chromeos::DBusMethodCallStatus cryptohome_status_;
148  bool cryptohome_result_;
149  cryptohome::BaseReply cryptohome_reply_;
150  cryptohome::GetBootAttributeRequest get_boot_attribute_request_;
151  cryptohome::SetBootAttributeRequest set_boot_attribute_request_;
152  std::string owner_;
153  bool set_owner_status_;
154};
155
156TEST_F(ConsumerManagementServiceTest, CanGetEnrollmentStage) {
157  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_NONE,
158            service_->GetEnrollmentStage());
159
160  SetEnrollmentStage(ConsumerManagementService::ENROLLMENT_STAGE_REQUESTED);
161
162  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_REQUESTED,
163            service_->GetEnrollmentStage());
164}
165
166TEST_F(ConsumerManagementServiceTest, CanSetEnrollmentStage) {
167  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_NONE,
168            GetEnrollmentStage());
169
170  service_->SetEnrollmentStage(
171      ConsumerManagementService::ENROLLMENT_STAGE_REQUESTED);
172
173  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_REQUESTED,
174            GetEnrollmentStage());
175}
176
177TEST_F(ConsumerManagementServiceTest, CanGetOwner) {
178  cryptohome_status_ = chromeos::DBUS_METHOD_CALL_SUCCESS;
179  cryptohome_result_ = true;
180  cryptohome_reply_.MutableExtension(cryptohome::GetBootAttributeReply::reply)->
181      set_value(kTestOwner);
182
183  service_->GetOwner(base::Bind(&ConsumerManagementServiceTest::OnGetOwnerDone,
184                                base::Unretained(this)));
185
186  EXPECT_EQ(kAttributeOwnerId, get_boot_attribute_request_.name());
187  EXPECT_EQ(kTestOwner, owner_);
188}
189
190TEST_F(ConsumerManagementServiceTest, GetOwnerReturnsAnEmptyStringWhenItFails) {
191  cryptohome_status_ = chromeos::DBUS_METHOD_CALL_FAILURE;
192  cryptohome_result_ = false;
193  cryptohome_reply_.MutableExtension(cryptohome::GetBootAttributeReply::reply)->
194      set_value(kTestOwner);
195
196  service_->GetOwner(base::Bind(&ConsumerManagementServiceTest::OnGetOwnerDone,
197                                base::Unretained(this)));
198
199  EXPECT_EQ("", owner_);
200}
201
202TEST_F(ConsumerManagementServiceTest, CanSetOwner) {
203  cryptohome_status_ = chromeos::DBUS_METHOD_CALL_SUCCESS;
204  cryptohome_result_ = true;
205
206  service_->SetOwner(kTestOwner,
207                     base::Bind(&ConsumerManagementServiceTest::OnSetOwnerDone,
208                                base::Unretained(this)));
209
210  EXPECT_EQ(kAttributeOwnerId, set_boot_attribute_request_.name());
211  EXPECT_EQ(kTestOwner, set_boot_attribute_request_.value());
212  EXPECT_TRUE(set_owner_status_);
213}
214
215TEST_F(ConsumerManagementServiceTest, SetOwnerReturnsFalseWhenItFails) {
216  cryptohome_status_ = chromeos::DBUS_METHOD_CALL_FAILURE;
217  cryptohome_result_ = false;
218
219  service_->SetOwner(kTestOwner,
220                     base::Bind(&ConsumerManagementServiceTest::OnSetOwnerDone,
221                                base::Unretained(this)));
222
223  EXPECT_FALSE(set_owner_status_);
224}
225
226class ConsumerManagementServiceEnrollmentTest
227    : public ConsumerManagementServiceTest {
228 public:
229  ConsumerManagementServiceEnrollmentTest()
230      : mock_user_manager_(new NiceMock<chromeos::MockUserManager>()),
231        scoped_user_manager_enabler_(mock_user_manager_),
232        fake_initializer_(new FakeDeviceCloudPolicyInitializer()),
233        enrollment_status_(EnrollmentStatus::ForStatus(
234            EnrollmentStatus::STATUS_SUCCESS)) {
235    // Set up MockUserManager. The first user will be the owner.
236    mock_user_manager_->AddUser(kTestOwner);
237
238    // Return false for IsCurrentUserOwner() so that the enrollment stage is not
239    // reset.
240    ON_CALL(*mock_user_manager_, IsCurrentUserOwner())
241        .WillByDefault(Return(false));
242
243    // Inject FakeDeviceCloudPolicyInitializer.
244    BrowserPolicyConnectorChromeOS* connector =
245        g_browser_process->platform_part()->browser_policy_connector_chromeos();
246    connector->SetDeviceCloudPolicyInitializerForTesting(
247        scoped_ptr<DeviceCloudPolicyInitializer>(fake_initializer_));
248  }
249
250  virtual void SetUp() OVERRIDE {
251    ConsumerManagementServiceTest::SetUp();
252
253    // Set up the testing profile.
254    profile()->set_profile_name(kTestOwner);
255
256    // Set up FakeProfileOAuth2TokenService and issue a fake refresh token.
257    ProfileOAuth2TokenServiceFactory::GetInstance()->SetTestingFactory(
258        profile(), &BuildAutoIssuingFakeProfileOAuth2TokenService);
259    GetFakeProfileOAuth2TokenService()->
260        IssueRefreshTokenForUser(kTestOwner, "fake_token");
261
262    // Set up the authenticated user name and ID.
263    SigninManagerFactory::GetForProfile(profile())->
264        SetAuthenticatedUsername(kTestOwner);
265
266    // The service should continue the enrollment process if the stage is
267    // ENROLLMENT_STAGE_OWNER_STORED.
268    SetEnrollmentStage(
269        ConsumerManagementService::ENROLLMENT_STAGE_OWNER_STORED);
270  }
271
272  virtual void TearDown() OVERRIDE {
273    g_browser_process->notification_ui_manager()->CancelAll();
274
275    ConsumerManagementServiceTest::TearDown();
276  }
277
278  FakeProfileOAuth2TokenService* GetFakeProfileOAuth2TokenService() {
279    return static_cast<FakeProfileOAuth2TokenService*>(
280        ProfileOAuth2TokenServiceFactory::GetForProfile(profile()));
281  }
282
283  bool HasEnrollmentNotification() {
284    return g_browser_process->notification_ui_manager()->
285        FindById("consumer_management.enroll");
286  }
287
288  void RunEnrollmentTest() {
289    // Send the profile prepared notification to continue the enrollment.
290    service_->Observe(chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
291                      content::Source<void>(NULL),  // Not used.
292                      content::Details<Profile>(profile()));
293    base::RunLoop().RunUntilIdle();
294  }
295
296  NiceMock<chromeos::MockUserManager>* mock_user_manager_;
297  chromeos::ScopedUserManagerEnabler scoped_user_manager_enabler_;
298  FakeDeviceCloudPolicyInitializer* fake_initializer_;
299  EnrollmentStatus enrollment_status_;
300};
301
302TEST_F(ConsumerManagementServiceEnrollmentTest, EnrollsSuccessfully) {
303  EXPECT_FALSE(fake_initializer_->was_start_enrollment_called());
304
305  RunEnrollmentTest();
306
307  EXPECT_TRUE(fake_initializer_->was_start_enrollment_called());
308  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_SUCCESS,
309            GetEnrollmentStage());
310  EXPECT_FALSE(HasEnrollmentNotification());
311}
312
313TEST_F(ConsumerManagementServiceEnrollmentTest,
314       ShowsDesktopNotificationAndResetsEnrollmentStageIfCurrentUserIsOwner) {
315  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_OWNER_STORED,
316            GetEnrollmentStage());
317  EXPECT_FALSE(HasEnrollmentNotification());
318  EXPECT_CALL(*mock_user_manager_, IsCurrentUserOwner())
319      .WillOnce(Return(true));
320
321  RunEnrollmentTest();
322
323  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_NONE,
324            GetEnrollmentStage());
325  EXPECT_TRUE(HasEnrollmentNotification());
326}
327
328TEST_F(ConsumerManagementServiceEnrollmentTest, FailsToGetAccessToken) {
329  // Disable auto-posting so that RunEnrollmentTest() should stop and wait for
330  // the access token to be available.
331  GetFakeProfileOAuth2TokenService()->
332      set_auto_post_fetch_response_on_message_loop(false);
333
334  RunEnrollmentTest();
335
336  // The service should have a pending token request.
337  OAuth2TokenService::Request* token_request =
338      service_->GetTokenRequestForTesting();
339  EXPECT_TRUE(token_request);
340
341  // Tell the service that the access token is not available because of some
342  // backend issue.
343  service_->OnGetTokenFailure(
344      token_request,
345      GoogleServiceAuthError(GoogleServiceAuthError::SERVICE_ERROR));
346
347  EXPECT_FALSE(fake_initializer_->was_start_enrollment_called());
348  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_GET_TOKEN_FAILED,
349            GetEnrollmentStage());
350}
351
352TEST_F(ConsumerManagementServiceEnrollmentTest, FailsToRegister) {
353  EXPECT_FALSE(fake_initializer_->was_start_enrollment_called());
354  fake_initializer_->set_enrollment_status(EnrollmentStatus::ForStatus(
355      EnrollmentStatus::STATUS_REGISTRATION_FAILED));
356
357  RunEnrollmentTest();
358
359  EXPECT_TRUE(fake_initializer_->was_start_enrollment_called());
360  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_DM_SERVER_FAILED,
361            GetEnrollmentStage());
362}
363
364TEST_F(ConsumerManagementServiceEnrollmentTest,
365       ShowsDesktopNotificationOnlyIfEnrollmentIsAlreadyCompleted) {
366  SetEnrollmentStage(ConsumerManagementService::ENROLLMENT_STAGE_CANCELED);
367  EXPECT_FALSE(HasEnrollmentNotification());
368
369  RunEnrollmentTest();
370
371  EXPECT_FALSE(fake_initializer_->was_start_enrollment_called());
372  EXPECT_EQ(ConsumerManagementService::ENROLLMENT_STAGE_NONE,
373            GetEnrollmentStage());
374  EXPECT_TRUE(HasEnrollmentNotification());
375}
376
377class ConsumerManagementServiceStatusTest
378    : public chromeos::DeviceSettingsTestBase {
379 public:
380  ConsumerManagementServiceStatusTest()
381      : testing_local_state_(TestingBrowserProcess::GetGlobal()),
382        service_(NULL, &device_settings_service_) {
383  }
384
385  void SetEnrollmentStage(ConsumerManagementService::EnrollmentStage stage) {
386    testing_local_state_.Get()->SetInteger(
387        prefs::kConsumerManagementEnrollmentStage, stage);
388  }
389
390  void SetManagementMode(em::PolicyData::ManagementMode mode) {
391    device_policy_.policy_data().set_management_mode(mode);
392    device_policy_.Build();
393    device_settings_test_helper_.set_policy_blob(device_policy_.GetBlob());
394    ReloadDeviceSettings();
395  }
396
397  ScopedTestingLocalState testing_local_state_;
398  ConsumerManagementService service_;
399};
400
401TEST_F(ConsumerManagementServiceStatusTest, GetStatusAndGetStatusStringWork) {
402  EXPECT_EQ(ConsumerManagementService::STATUS_UNKNOWN, service_.GetStatus());
403  EXPECT_EQ("StatusUnknown", service_.GetStatusString());
404
405  SetManagementMode(em::PolicyData::NOT_MANAGED);
406  SetEnrollmentStage(ConsumerManagementService::ENROLLMENT_STAGE_NONE);
407
408  EXPECT_EQ(ConsumerManagementService::STATUS_UNENROLLED, service_.GetStatus());
409  EXPECT_EQ("StatusUnenrolled", service_.GetStatusString());
410
411  SetEnrollmentStage(ConsumerManagementService::ENROLLMENT_STAGE_REQUESTED);
412
413  EXPECT_EQ(ConsumerManagementService::STATUS_ENROLLING, service_.GetStatus());
414  EXPECT_EQ("StatusEnrolling", service_.GetStatusString());
415
416  SetManagementMode(em::PolicyData::CONSUMER_MANAGED);
417  SetEnrollmentStage(ConsumerManagementService::ENROLLMENT_STAGE_SUCCESS);
418
419  EXPECT_EQ(ConsumerManagementService::STATUS_ENROLLED, service_.GetStatus());
420  EXPECT_EQ("StatusEnrolled", service_.GetStatusString());
421
422  // TODO(davidyu): Test for STATUS_UNENROLLING when it is implemented.
423  // http://crbug.com/353050.
424}
425
426}  // namespace policy
427