Home | History | Annotate | Download | only in managed
      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/login/managed/managed_user_test_base.h"
      6 
      7 #include <string>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/run_loop.h"
     11 #include "base/strings/string_number_conversions.h"
     12 #include "base/strings/stringprintf.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "base/threading/sequenced_worker_pool.h"
     15 #include "chrome/browser/chrome_notification_types.h"
     16 #include "chrome/browser/chromeos/login/auth/key.h"
     17 #include "chrome/browser/chromeos/login/auth/user_context.h"
     18 #include "chrome/browser/chromeos/login/login_manager_test.h"
     19 #include "chrome/browser/chromeos/login/managed/supervised_user_authentication.h"
     20 #include "chrome/browser/chromeos/login/startup_utils.h"
     21 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
     22 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
     23 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
     24 #include "chrome/browser/chromeos/net/network_portal_detector_test_impl.h"
     25 #include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h"
     26 #include "chrome/browser/profiles/profile_impl.h"
     27 #include "chrome/browser/supervised_user/supervised_user_constants.h"
     28 #include "chrome/browser/supervised_user/supervised_user_registration_utility.h"
     29 #include "chrome/browser/supervised_user/supervised_user_registration_utility_stub.h"
     30 #include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
     31 #include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h"
     32 #include "chrome/browser/supervised_user/supervised_user_sync_service.h"
     33 #include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
     34 #include "chromeos/cryptohome/mock_async_method_caller.h"
     35 #include "chromeos/cryptohome/mock_homedir_methods.h"
     36 #include "content/public/browser/notification_service.h"
     37 #include "content/public/test/browser_test_utils.h"
     38 #include "content/public/test/test_utils.h"
     39 #include "sync/api/attachments/attachment_service_proxy_for_test.h"
     40 #include "sync/api/fake_sync_change_processor.h"
     41 #include "sync/api/sync_change.h"
     42 #include "sync/api/sync_error_factory_mock.h"
     43 #include "sync/protocol/sync.pb.h"
     44 
     45 using testing::_;
     46 using base::StringPrintf;
     47 
     48 namespace chromeos {
     49 
     50 namespace {
     51 
     52 const char kCurrentPage[] = "$('managed-user-creation').currentPage_";
     53 }
     54 
     55 ManagedUsersSyncTestAdapter::ManagedUsersSyncTestAdapter(Profile* profile)
     56     : processor_(), next_sync_data_id_(0) {
     57   service_ = SupervisedUserSyncServiceFactory::GetForProfile(profile);
     58   processor_ = new syncer::FakeSyncChangeProcessor();
     59   service_->MergeDataAndStartSyncing(
     60       syncer::SUPERVISED_USERS,
     61       syncer::SyncDataList(),
     62       scoped_ptr<syncer::SyncChangeProcessor>(processor_),
     63       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock));
     64 }
     65 
     66 scoped_ptr< ::sync_pb::ManagedUserSpecifics>
     67 ManagedUsersSyncTestAdapter::GetFirstChange() {
     68   scoped_ptr< ::sync_pb::ManagedUserSpecifics> result(
     69       new ::sync_pb::ManagedUserSpecifics);
     70   CHECK(HasChanges())
     71       << "GetFirstChange() should only be callled if HasChanges() is true";
     72   const syncer::SyncData& data = processor_->changes().front().sync_data();
     73   EXPECT_EQ(syncer::SUPERVISED_USERS, data.GetDataType());
     74   result->CopyFrom(data.GetSpecifics().managed_user());
     75   return result.Pass();
     76 }
     77 
     78 void ManagedUsersSyncTestAdapter::AddChange(
     79     const ::sync_pb::ManagedUserSpecifics& proto,
     80     bool update) {
     81   sync_pb::EntitySpecifics specifics;
     82 
     83   specifics.mutable_managed_user()->CopyFrom(proto);
     84 
     85   syncer::SyncData change_data = syncer::SyncData::CreateRemoteData(
     86       ++next_sync_data_id_,
     87       specifics,
     88       base::Time(),
     89       syncer::AttachmentIdList(),
     90       syncer::AttachmentServiceProxyForTest::Create());
     91   syncer::SyncChange change(FROM_HERE,
     92                             update ? syncer::SyncChange::ACTION_UPDATE
     93                                    : syncer::SyncChange::ACTION_ADD,
     94                             change_data);
     95 
     96   syncer::SyncChangeList change_list;
     97   change_list.push_back(change);
     98 
     99   service_->ProcessSyncChanges(FROM_HERE, change_list);
    100 }
    101 
    102 ManagedUsersSharedSettingsSyncTestAdapter::
    103     ManagedUsersSharedSettingsSyncTestAdapter(Profile* profile)
    104     : processor_(), next_sync_data_id_(0) {
    105   service_ =
    106       SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(profile);
    107   processor_ = new syncer::FakeSyncChangeProcessor();
    108   service_->MergeDataAndStartSyncing(
    109       syncer::SUPERVISED_USER_SHARED_SETTINGS,
    110       syncer::SyncDataList(),
    111       scoped_ptr<syncer::SyncChangeProcessor>(processor_),
    112       scoped_ptr<syncer::SyncErrorFactory>(new syncer::SyncErrorFactoryMock));
    113 }
    114 
    115 scoped_ptr< ::sync_pb::ManagedUserSharedSettingSpecifics>
    116 ManagedUsersSharedSettingsSyncTestAdapter::GetFirstChange() {
    117   scoped_ptr< ::sync_pb::ManagedUserSharedSettingSpecifics> result(
    118       new ::sync_pb::ManagedUserSharedSettingSpecifics);
    119   CHECK(HasChanges())
    120       << "GetFirstChange() should only be callled if HasChanges() is true";
    121   const syncer::SyncData& data = processor_->changes().front().sync_data();
    122   EXPECT_EQ(syncer::SUPERVISED_USER_SHARED_SETTINGS, data.GetDataType());
    123   result->CopyFrom(data.GetSpecifics().managed_user_shared_setting());
    124   return result.Pass();
    125 }
    126 
    127 void ManagedUsersSharedSettingsSyncTestAdapter::AddChange(
    128     const ::sync_pb::ManagedUserSharedSettingSpecifics& proto,
    129     bool update) {
    130   sync_pb::EntitySpecifics specifics;
    131 
    132   specifics.mutable_managed_user_shared_setting()->CopyFrom(proto);
    133 
    134   syncer::SyncData change_data = syncer::SyncData::CreateRemoteData(
    135       ++next_sync_data_id_,
    136       specifics,
    137       base::Time(),
    138       syncer::AttachmentIdList(),
    139       syncer::AttachmentServiceProxyForTest::Create());
    140   syncer::SyncChange change(FROM_HERE,
    141                             update ? syncer::SyncChange::ACTION_UPDATE
    142                                    : syncer::SyncChange::ACTION_ADD,
    143                             change_data);
    144 
    145   syncer::SyncChangeList change_list;
    146   change_list.push_back(change);
    147 
    148   service_->ProcessSyncChanges(FROM_HERE, change_list);
    149 }
    150 
    151 void ManagedUsersSharedSettingsSyncTestAdapter::AddChange(
    152     const std::string& mu_id,
    153     const std::string& key,
    154     const base::Value& value,
    155     bool acknowledged,
    156     bool update) {
    157   syncer::SyncData data =
    158       SupervisedUserSharedSettingsService::CreateSyncDataForSetting(
    159           mu_id, key, value, acknowledged);
    160   AddChange(data.GetSpecifics().managed_user_shared_setting(), update);
    161 }
    162 
    163 ManagedUserTestBase::ManagedUserTestBase()
    164     : LoginManagerTest(true),
    165       mock_async_method_caller_(NULL),
    166       mock_homedir_methods_(NULL),
    167       network_portal_detector_(NULL),
    168       registration_utility_stub_(NULL) {
    169 }
    170 
    171 ManagedUserTestBase::~ManagedUserTestBase() {
    172 }
    173 
    174 void ManagedUserTestBase::SetUpInProcessBrowserTestFixture() {
    175   LoginManagerTest::SetUpInProcessBrowserTestFixture();
    176   mock_async_method_caller_ = new cryptohome::MockAsyncMethodCaller;
    177   mock_async_method_caller_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    178   cryptohome::AsyncMethodCaller::InitializeForTesting(
    179       mock_async_method_caller_);
    180 
    181   mock_homedir_methods_ = new cryptohome::MockHomedirMethods;
    182   mock_homedir_methods_->SetUp(true, cryptohome::MOUNT_ERROR_NONE);
    183   cryptohome::HomedirMethods::InitializeForTesting(mock_homedir_methods_);
    184 
    185   registration_utility_stub_ = new SupervisedUserRegistrationUtilityStub();
    186   scoped_utility_.reset(new ScopedTestingSupervisedUserRegistrationUtility(
    187       registration_utility_stub_));
    188 
    189   // Setup network portal detector to return online state for both
    190   // ethernet and wifi networks. Ethernet is an active network by
    191   // default.
    192   network_portal_detector_ = new NetworkPortalDetectorTestImpl();
    193   NetworkPortalDetector::InitializeForTesting(network_portal_detector_);
    194   NetworkPortalDetector::CaptivePortalState online_state;
    195   online_state.status = NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE;
    196   online_state.response_code = 204;
    197   network_portal_detector_->SetDefaultNetworkPathForTesting(
    198       kStubEthernetServicePath,
    199       kStubEthernetServicePath /* guid */);
    200   network_portal_detector_->SetDetectionResultsForTesting(
    201       kStubEthernetServicePath, online_state);
    202 }
    203 
    204 void ManagedUserTestBase::CleanUpOnMainThread() {
    205   LoginManagerTest::CleanUpOnMainThread();
    206 }
    207 
    208 void ManagedUserTestBase::TearDown() {
    209   cryptohome::AsyncMethodCaller::Shutdown();
    210   cryptohome::HomedirMethods::Shutdown();
    211   mock_homedir_methods_ = NULL;
    212   mock_async_method_caller_ = NULL;
    213   LoginManagerTest::TearDown();
    214 }
    215 
    216 void ManagedUserTestBase::TearDownInProcessBrowserTestFixture() {
    217   NetworkPortalDetector::Shutdown();
    218 }
    219 
    220 void ManagedUserTestBase::JSEval(const std::string& script) {
    221   EXPECT_TRUE(content::ExecuteScript(web_contents(), script)) << script;
    222 }
    223 
    224 void ManagedUserTestBase::JSExpectAsync(const std::string& function) {
    225   bool result;
    226   EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
    227       web_contents(),
    228       StringPrintf(
    229           "(%s)(function() { window.domAutomationController.send(true); });",
    230           function.c_str()),
    231       &result)) << function;
    232   EXPECT_TRUE(result);
    233 }
    234 
    235 void ManagedUserTestBase::JSSetTextField(const std::string& element_selector,
    236                                          const std::string& value) {
    237   std::string function =
    238       StringPrintf("document.querySelector('%s').value = '%s'",
    239                    element_selector.c_str(),
    240                    value.c_str());
    241   JSEval(function);
    242 }
    243 
    244 void ManagedUserTestBase::PrepareUsers() {
    245   RegisterUser(kTestManager);
    246   RegisterUser(kTestOtherUser);
    247   chromeos::StartupUtils::MarkOobeCompleted();
    248 }
    249 
    250 void ManagedUserTestBase::StartFlowLoginAsManager() {
    251   // Navigate to supervised user creation screen.
    252   JSEval("chrome.send('showLocallyManagedUserCreationScreen')");
    253 
    254   // Read intro and proceed.
    255   JSExpect(StringPrintf("%s == 'intro'", kCurrentPage));
    256 
    257   JSEval("$('managed-user-creation-start-button').click()");
    258 
    259   // Check that both users appear as managers, and test-manager (at) gmail.com is
    260   // the first one.
    261   JSExpect(StringPrintf("%s == 'manager'", kCurrentPage));
    262 
    263   std::string manager_pods =
    264       "document.querySelectorAll('#managed-user-creation-managers-pane "
    265       ".manager-pod')";
    266   std::string selected_manager_pods =
    267       "document.querySelectorAll('#managed-user-creation-managers-pane "
    268       ".manager-pod.focused')";
    269 
    270   int managers_on_device = 2;
    271 
    272   JSExpect(StringPrintf("%s.length == 1", selected_manager_pods.c_str()));
    273 
    274   JSExpect(
    275       StringPrintf("$('managed-user-creation').managerList_.pods.length == %d",
    276                    managers_on_device));
    277   JSExpect(StringPrintf(
    278       "%s.length == %d", manager_pods.c_str(), managers_on_device));
    279   JSExpect(StringPrintf("%s[%d].user.emailAddress == '%s'",
    280                         manager_pods.c_str(),
    281                         0,
    282                         kTestManager));
    283 
    284   // Select the first user as manager, and enter password.
    285   JSExpect("$('managed-user-creation-next-button').disabled");
    286   JSSetTextField("#managed-user-creation .manager-pod.focused input",
    287                  kTestManagerPassword);
    288 
    289   JSEval("$('managed-user-creation').updateNextButtonForManager_()");
    290 
    291   // Next button is now enabled.
    292   JSExpect("!$('managed-user-creation-next-button').disabled");
    293   UserContext user_context(kTestManager);
    294   user_context.SetKey(Key(kTestManagerPassword));
    295   SetExpectedCredentials(user_context);
    296   content::WindowedNotificationObserver login_observer(
    297       chrome::NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
    298       content::NotificationService::AllSources());
    299 
    300   // Log in as manager.
    301   JSEval("$('managed-user-creation-next-button').click()");
    302   login_observer.Wait();
    303 
    304   // OAuth token is valid.
    305   UserManager::Get()->SaveUserOAuthStatus(kTestManager,
    306                                           User::OAUTH2_TOKEN_STATUS_VALID);
    307   base::RunLoop().RunUntilIdle();
    308 
    309   // Check the page have changed.
    310   JSExpect(StringPrintf("%s == 'username'", kCurrentPage));
    311 }
    312 
    313 void ManagedUserTestBase::FillNewUserData(const std::string& display_name) {
    314   JSExpect("$('managed-user-creation-next-button').disabled");
    315   JSSetTextField("#managed-user-creation-name", display_name);
    316   JSEval("$('managed-user-creation').checkUserName_()");
    317 
    318   base::RunLoop().RunUntilIdle();
    319 
    320   JSSetTextField("#managed-user-creation-password",
    321                  kTestSupervisedUserPassword);
    322   JSSetTextField("#managed-user-creation-password-confirm",
    323                  kTestSupervisedUserPassword);
    324 
    325   JSEval("$('managed-user-creation').updateNextButtonForUser_()");
    326   JSExpect("!$('managed-user-creation-next-button').disabled");
    327 }
    328 
    329 void ManagedUserTestBase::StartUserCreation(
    330     const std::string& button_id,
    331     const std::string& expected_display_name) {
    332   EXPECT_CALL(*mock_homedir_methods_, MountEx(_, _, _, _)).Times(1);
    333   EXPECT_CALL(*mock_homedir_methods_, AddKeyEx(_, _, _, _, _)).Times(1);
    334 
    335   JSEval(std::string("$('").append(button_id).append("').click()"));
    336 
    337   ::testing::Mock::VerifyAndClearExpectations(mock_homedir_methods_);
    338 
    339   EXPECT_TRUE(registration_utility_stub_->register_was_called());
    340   EXPECT_EQ(registration_utility_stub_->display_name(),
    341             base::UTF8ToUTF16(expected_display_name));
    342 
    343   registration_utility_stub_->RunSuccessCallback("token");
    344 
    345   // Token writing moves control to BlockingPool and back.
    346   base::RunLoop().RunUntilIdle();
    347   content::BrowserThread::GetBlockingPool()->FlushForTesting();
    348   base::RunLoop().RunUntilIdle();
    349 
    350   JSExpect(StringPrintf("%s == 'created'", kCurrentPage));
    351   JSEval("$('managed-user-creation-gotit-button').click()");
    352 }
    353 
    354 void ManagedUserTestBase::SigninAsSupervisedUser(
    355     bool check_homedir_calls,
    356     int user_index,
    357     const std::string& expected_display_name) {
    358   if (check_homedir_calls)
    359     EXPECT_CALL(*mock_homedir_methods_, MountEx(_, _, _, _)).Times(1);
    360 
    361   // Log in as supervised user, make sure that everything works.
    362   ASSERT_EQ(3UL, UserManager::Get()->GetUsers().size());
    363 
    364   // Created supervised user have to be first in a list.
    365   const User* user = UserManager::Get()->GetUsers().at(user_index);
    366   ASSERT_EQ(base::UTF8ToUTF16(expected_display_name), user->display_name());
    367   LoginUser(user->email());
    368   if (check_homedir_calls)
    369     ::testing::Mock::VerifyAndClearExpectations(mock_homedir_methods_);
    370   Profile* profile = UserManager::Get()->GetProfileByUser(user);
    371   shared_settings_adapter_.reset(
    372       new ManagedUsersSharedSettingsSyncTestAdapter(profile));
    373 
    374   // Check ChromeOS preference is initialized.
    375   EXPECT_TRUE(
    376       static_cast<ProfileImpl*>(profile)->chromeos_preferences_);
    377 }
    378 
    379 void ManagedUserTestBase::SigninAsManager(int user_index) {
    380   // Log in as supervised user, make sure that everything works.
    381   ASSERT_EQ(3UL, UserManager::Get()->GetUsers().size());
    382 
    383   // Created supervised user have to be first in a list.
    384   const User* user = UserManager::Get()->GetUsers().at(user_index);
    385   LoginUser(user->email());
    386   Profile* profile = UserManager::Get()->GetProfileByUser(user);
    387   shared_settings_adapter_.reset(
    388       new ManagedUsersSharedSettingsSyncTestAdapter(profile));
    389   managed_users_adapter_.reset(new ManagedUsersSyncTestAdapter(profile));
    390 }
    391 
    392 void ManagedUserTestBase::RemoveSupervisedUser(
    393     unsigned long original_user_count,
    394     int user_index,
    395     const std::string& expected_display_name) {
    396   // Remove supervised user.
    397   ASSERT_EQ(original_user_count, UserManager::Get()->GetUsers().size());
    398 
    399   // Created supervised user have to be first in a list.
    400   const User* user = UserManager::Get()->GetUsers().at(user_index);
    401   ASSERT_EQ(base::UTF8ToUTF16(expected_display_name), user->display_name());
    402 
    403   // Open pod menu.
    404   JSExpect(
    405       StringPrintf("!$('pod-row').pods[%d].isActionBoxMenuActive", user_index));
    406   JSEval(StringPrintf(
    407       "$('pod-row').pods[%d].querySelector('.action-box-button').click()",
    408       user_index));
    409   JSExpect(
    410       StringPrintf("$('pod-row').pods[%d].isActionBoxMenuActive", user_index));
    411 
    412   // Select "Remove user" element.
    413   JSExpect(StringPrintf(
    414       "$('pod-row').pods[%d].actionBoxRemoveUserWarningElement.hidden",
    415       user_index));
    416   JSEval(StringPrintf(
    417       "$('pod-row').pods[%d].querySelector('.action-box-menu-remove').click()",
    418       user_index));
    419   JSExpect(StringPrintf(
    420       "!$('pod-row').pods[%d].actionBoxRemoveUserWarningElement.hidden",
    421       user_index));
    422 
    423   EXPECT_CALL(*mock_async_method_caller_, AsyncRemove(_, _)).Times(1);
    424 
    425   // Confirm deletion.
    426   JSEval(StringPrintf(
    427       "$('pod-row').pods[%d].querySelector('.remove-warning-button').click()",
    428       user_index));
    429 
    430   // Make sure there is no supervised user in list.
    431   ASSERT_EQ(original_user_count - 1, UserManager::Get()->GetUsers().size());
    432 }
    433 
    434 }  // namespace chromeos
    435