OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011 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/login_utils.h" |
| 6 |
| 7 #include "base/basictypes.h" |
| 8 #include "base/command_line.h" |
| 9 #include "base/message_loop.h" |
| 10 #include "base/path_service.h" |
| 11 #include "base/scoped_temp_dir.h" |
| 12 #include "base/string_util.h" |
| 13 #include "chrome/browser/chromeos/cros/cros_library.h" |
| 14 #include "chrome/browser/chromeos/cros/mock_cryptohome_library.h" |
| 15 #include "chrome/browser/chromeos/cros/mock_library_loader.h" |
| 16 #include "chrome/browser/chromeos/dbus/mock_dbus_thread_manager.h" |
| 17 #include "chrome/browser/chromeos/dbus/mock_session_manager_client.h" |
| 18 #include "chrome/browser/chromeos/login/authenticator.h" |
| 19 #include "chrome/browser/chromeos/login/login_status_consumer.h" |
| 20 #include "chrome/browser/chromeos/login/user_manager.h" |
| 21 #include "chrome/browser/io_thread.h" |
| 22 #include "chrome/browser/net/predictor.h" |
| 23 #include "chrome/browser/policy/browser_policy_connector.h" |
| 24 #include "chrome/browser/policy/proto/device_management_backend.pb.h" |
| 25 #include "chrome/browser/profiles/profile_manager.h" |
| 26 #include "chrome/common/chrome_paths.h" |
| 27 #include "chrome/common/chrome_switches.h" |
| 28 #include "chrome/common/net/gaia/gaia_urls.h" |
| 29 #include "chrome/common/pref_names.h" |
| 30 #include "chrome/common/net/gaia/gaia_auth_consumer.h" |
| 31 #include "chrome/test/base/testing_browser_process.h" |
| 32 #include "chrome/test/base/testing_pref_service.h" |
| 33 #include "content/test/test_browser_thread.h" |
| 34 #include "content/test/test_url_fetcher_factory.h" |
| 35 #include "net/url_request/url_request.h" |
| 36 #include "net/url_request/url_request_status.h" |
| 37 #include "testing/gmock/include/gmock/gmock.h" |
| 38 #include "testing/gtest/include/gtest/gtest.h" |
| 39 |
| 40 namespace chromeos { |
| 41 |
| 42 namespace { |
| 43 |
| 44 namespace em = enterprise_management; |
| 45 |
| 46 using ::testing::DoAll; |
| 47 using ::testing::Return; |
| 48 using ::testing::SetArgPointee; |
| 49 using ::testing::_; |
| 50 |
| 51 const char kTrue[] = "true"; |
| 52 const char kDomain[] = "domain.com"; |
| 53 const char kUsername[] = "user@domain.com"; |
| 54 const char kUsernameOtherDomain[] = "user@other.com"; |
| 55 const char kAttributeOwned[] = "enterprise.owned"; |
| 56 const char kAttributeOwner[] = "enterprise.user"; |
| 57 |
| 58 const char kOAuthTokenCookie[] = "oauth_token=1234"; |
| 59 const char kOAuthGetAccessTokenData[] = |
| 60 "oauth_token=1234&oauth_token_secret=1234"; |
| 61 const char kOAuthServiceTokenData[] = |
| 62 "wrap_access_token=1234&wrap_access_token_expires_in=123456789"; |
| 63 |
| 64 const char kDMServer[] = "http://server/device_management"; |
| 65 const char kDMRegisterRequest[] = |
| 66 "http://server/device_management?request=register"; |
| 67 const char kDMPolicyRequest[] = |
| 68 "http://server/device_management?request=policy"; |
| 69 |
| 70 const char kDMToken[] = "1234"; |
| 71 |
| 72 ACTION_P(MockSessionManagerClientPolicyCallback, policy) { |
| 73 arg0.Run(policy); |
| 74 } |
| 75 |
| 76 // Subclass IOThread to expose set_message_loop. |
| 77 class TestIOThread : public IOThread { |
| 78 public: |
| 79 explicit TestIOThread(PrefService* local_state) |
| 80 : IOThread(local_state, NULL, NULL) {} |
| 81 |
| 82 using IOThread::set_message_loop; |
| 83 }; |
| 84 |
| 85 template<typename TESTBASE> |
| 86 class LoginUtilsTestBase : public TESTBASE, |
| 87 public LoginUtils::Delegate, |
| 88 public LoginStatusConsumer { |
| 89 public: |
| 90 LoginUtilsTestBase() |
| 91 : loop_(MessageLoop::TYPE_IO), |
| 92 browser_process_( |
| 93 static_cast<TestingBrowserProcess*>(g_browser_process)), |
| 94 local_state_(browser_process_), |
| 95 ui_thread_(content::BrowserThread::UI, &loop_), |
| 96 file_thread_(content::BrowserThread::FILE, &loop_), |
| 97 io_thread_(local_state_.Get()), |
| 98 prepared_profile_(NULL) {} |
| 99 |
| 100 virtual void SetUp() OVERRIDE { |
| 101 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); |
| 102 // BrowserPolicyConnector makes the UserPolicyCache read relative to this |
| 103 // path. Make sure it's in a clean state. |
| 104 PathService::Override(chrome::DIR_USER_DATA, scoped_temp_dir_.path()); |
| 105 |
| 106 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
| 107 command_line->AppendSwitch(switches::kEnableDevicePolicy); |
| 108 command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, kDMServer); |
| 109 command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); |
| 110 |
| 111 local_state_.Get()->RegisterStringPref(prefs::kApplicationLocale, ""); |
| 112 |
| 113 browser_process_->SetIOThread(&io_thread_); |
| 114 |
| 115 DBusThreadManager::InitializeForTesting(&dbus_thread_manager_); |
| 116 |
| 117 MockSessionManagerClient* session_managed_client = |
| 118 dbus_thread_manager_.mock_session_manager_client(); |
| 119 EXPECT_CALL(*session_managed_client, RetrievePolicy(_)) |
| 120 .WillRepeatedly(MockSessionManagerClientPolicyCallback("")); |
| 121 |
| 122 CrosLibrary::TestApi* test_api = CrosLibrary::Get()->GetTestApi(); |
| 123 ASSERT_TRUE(test_api); |
| 124 |
| 125 MockLibraryLoader* loader = new MockLibraryLoader(); |
| 126 ON_CALL(*loader, Load(_)).WillByDefault(Return(true)); |
| 127 test_api->SetLibraryLoader(loader, true); |
| 128 |
| 129 cryptohome_ = new MockCryptohomeLibrary(); |
| 130 EXPECT_CALL(*cryptohome_, InstallAttributesIsReady()) |
| 131 .WillRepeatedly(Return(true)); |
| 132 EXPECT_CALL(*cryptohome_, InstallAttributesIsInvalid()) |
| 133 .WillRepeatedly(Return(false)); |
| 134 EXPECT_CALL(*cryptohome_, InstallAttributesIsFirstInstall()) |
| 135 .WillRepeatedly(Return(true)); |
| 136 EXPECT_CALL(*cryptohome_, TpmIsEnabled()) |
| 137 .WillRepeatedly(Return(false)); |
| 138 EXPECT_CALL(*cryptohome_, IsMounted()) |
| 139 .WillRepeatedly(Return(true)); |
| 140 EXPECT_CALL(*cryptohome_, InstallAttributesSet(kAttributeOwned, kTrue)) |
| 141 .WillRepeatedly(Return(true)); |
| 142 EXPECT_CALL(*cryptohome_, InstallAttributesSet(kAttributeOwner, |
| 143 kUsername)) |
| 144 .WillRepeatedly(Return(true)); |
| 145 EXPECT_CALL(*cryptohome_, InstallAttributesFinalize()) |
| 146 .WillRepeatedly(Return(true)); |
| 147 EXPECT_CALL(*cryptohome_, InstallAttributesGet(kAttributeOwned, _)) |
| 148 .WillRepeatedly(DoAll(SetArgPointee<1>(kTrue), |
| 149 Return(true))); |
| 150 EXPECT_CALL(*cryptohome_, InstallAttributesGet(kAttributeOwner, _)) |
| 151 .WillRepeatedly(DoAll(SetArgPointee<1>(kUsername), |
| 152 Return(true))); |
| 153 test_api->SetCryptohomeLibrary(cryptohome_, true); |
| 154 |
| 155 browser_process_->SetProfileManager( |
| 156 new ProfileManagerWithoutInit(scoped_temp_dir_.path())); |
| 157 connector_ = policy::BrowserPolicyConnector::Create(); |
| 158 browser_process_->SetBrowserPolicyConnector(connector_); |
| 159 |
| 160 loop_.RunAllPending(); |
| 161 } |
| 162 |
| 163 virtual void TearDown() OVERRIDE { |
| 164 loop_.RunAllPending(); |
| 165 { |
| 166 // chrome_browser_net::Predictor usually skips its shutdown routines on |
| 167 // unit_tests, but does the full thing when |
| 168 // g_browser_process->profile_manager() is valid during initialization. |
| 169 // Run a task on a temporary BrowserThread::IO that allows skipping |
| 170 // these routines. |
| 171 io_thread_.set_message_loop(&loop_); |
| 172 loop_.PostTask(FROM_HERE, |
| 173 base::Bind(&LoginUtilsTestBase::TearDownOnIO, |
| 174 base::Unretained(this))); |
| 175 loop_.RunAllPending(); |
| 176 io_thread_.set_message_loop(NULL); |
| 177 } |
| 178 |
| 179 // These trigger some tasks that have to run while BrowserThread::UI |
| 180 // exists. |
| 181 connector_ = NULL; |
| 182 browser_process_->SetBrowserPolicyConnector(NULL); |
| 183 browser_process_->SetProfileManager(NULL); |
| 184 loop_.RunAllPending(); |
| 185 } |
| 186 |
| 187 void TearDownOnIO() { |
| 188 std::vector<Profile*> profiles = |
| 189 browser_process_->profile_manager()->GetLoadedProfiles(); |
| 190 for (size_t i = 0; i < profiles.size(); ++i) { |
| 191 chrome_browser_net::Predictor* predictor = |
| 192 profiles[i]->GetNetworkPredictor(); |
| 193 if (predictor) { |
| 194 predictor->EnablePredictorOnIOThread(false); |
| 195 predictor->Shutdown(); |
| 196 } |
| 197 } |
| 198 } |
| 199 |
| 200 virtual void OnProfilePrepared(Profile* profile) OVERRIDE { |
| 201 EXPECT_FALSE(prepared_profile_); |
| 202 prepared_profile_ = profile; |
| 203 } |
| 204 |
| 205 virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE { |
| 206 FAIL() << "OnLoginFailure not expected"; |
| 207 } |
| 208 |
| 209 virtual void OnLoginSuccess(const std::string& username, |
| 210 const std::string& password, |
| 211 const GaiaAuthConsumer::ClientLoginResult& creds, |
| 212 bool pending_requests, |
| 213 bool using_oauth) OVERRIDE { |
| 214 FAIL() << "OnLoginSuccess not expected"; |
| 215 } |
| 216 |
| 217 void LockDevice(const std::string& username) { |
| 218 EXPECT_CALL(*cryptohome_, InstallAttributesIsFirstInstall()) |
| 219 .WillOnce(Return(true)) |
| 220 .WillRepeatedly(Return(false)); |
| 221 EXPECT_EQ(policy::EnterpriseInstallAttributes::LOCK_SUCCESS, |
| 222 connector_->LockDevice(username)); |
| 223 loop_.RunAllPending(); |
| 224 } |
| 225 |
| 226 void PrepareProfile(const std::string& username) { |
| 227 MockSessionManagerClient* session_managed_client = |
| 228 dbus_thread_manager_.mock_session_manager_client(); |
| 229 EXPECT_CALL(*session_managed_client, StartSession(_)); |
| 230 |
| 231 // crypto::Encryptor::SetCounter wants exactly 128 bits, and |
| 232 // ParallelAuthenticator CHECKs on that. |
| 233 CryptohomeBlob blob; |
| 234 for (size_t i = 0; i < 16; ++i) |
| 235 blob.push_back(i); |
| 236 EXPECT_CALL(*cryptohome_, GetSystemSalt()) |
| 237 .WillRepeatedly(Return(blob)); |
| 238 EXPECT_CALL(*cryptohome_, AsyncMount(_, _, _, _)) |
| 239 .WillRepeatedly(Return(true)); |
| 240 |
| 241 scoped_refptr<Authenticator> authenticator = |
| 242 LoginUtils::Get()->CreateAuthenticator(this); |
| 243 authenticator->CompleteLogin(ProfileManager::GetDefaultProfile(), |
| 244 username, |
| 245 "password"); |
| 246 |
| 247 GaiaAuthConsumer::ClientLoginResult credentials; |
| 248 LoginUtils::Get()->PrepareProfile( |
| 249 username, "password", credentials, false, true, false, this); |
| 250 loop_.RunAllPending(); |
| 251 } |
| 252 |
| 253 TestURLFetcher* PrepareOAuthFetcher(const std::string& expected_url) { |
| 254 TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0); |
| 255 EXPECT_TRUE(fetcher); |
| 256 EXPECT_TRUE(fetcher->delegate()); |
| 257 EXPECT_TRUE(StartsWithASCII(fetcher->GetOriginalURL().spec(), |
| 258 expected_url, |
| 259 true)); |
| 260 fetcher->set_url(fetcher->GetOriginalURL()); |
| 261 fetcher->set_response_code(200); |
| 262 fetcher->set_status(net::URLRequestStatus()); |
| 263 return fetcher; |
| 264 } |
| 265 |
| 266 TestURLFetcher* PrepareDMServiceFetcher( |
| 267 const std::string& expected_url, |
| 268 const em::DeviceManagementResponse& response) { |
| 269 TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0); |
| 270 EXPECT_TRUE(fetcher); |
| 271 EXPECT_TRUE(fetcher->delegate()); |
| 272 EXPECT_TRUE(StartsWithASCII(fetcher->GetOriginalURL().spec(), |
| 273 expected_url, |
| 274 true)); |
| 275 fetcher->set_url(fetcher->GetOriginalURL()); |
| 276 fetcher->set_response_code(200); |
| 277 fetcher->set_status(net::URLRequestStatus()); |
| 278 std::string data; |
| 279 EXPECT_TRUE(response.SerializeToString(&data)); |
| 280 fetcher->SetResponseString(data); |
| 281 return fetcher; |
| 282 } |
| 283 |
| 284 TestURLFetcher* PrepareDMRegisterFetcher() { |
| 285 em::DeviceManagementResponse response; |
| 286 em::DeviceRegisterResponse* register_response = |
| 287 response.mutable_register_response(); |
| 288 register_response->set_device_management_token(kDMToken); |
| 289 return PrepareDMServiceFetcher(kDMRegisterRequest, response); |
| 290 } |
| 291 |
| 292 TestURLFetcher* PrepareDMPolicyFetcher() { |
| 293 em::DeviceManagementResponse response; |
| 294 response.mutable_policy_response()->add_response(); |
| 295 return PrepareDMServiceFetcher(kDMPolicyRequest, response); |
| 296 } |
| 297 |
| 298 protected: |
| 299 ScopedStubCrosEnabler stub_cros_enabler_; |
| 300 |
| 301 MessageLoop loop_; |
| 302 TestingBrowserProcess* browser_process_; |
| 303 ScopedTestingLocalState local_state_; |
| 304 |
| 305 content::TestBrowserThread ui_thread_; |
| 306 content::TestBrowserThread file_thread_; |
| 307 TestIOThread io_thread_; |
| 308 |
| 309 MockDBusThreadManager dbus_thread_manager_; |
| 310 TestURLFetcherFactory test_url_fetcher_factory_; |
| 311 |
| 312 policy::BrowserPolicyConnector* connector_; |
| 313 MockCryptohomeLibrary* cryptohome_; |
| 314 Profile* prepared_profile_; |
| 315 |
| 316 private: |
| 317 ScopedTempDir scoped_temp_dir_; |
| 318 |
| 319 DISALLOW_COPY_AND_ASSIGN(LoginUtilsTestBase); |
| 320 }; |
| 321 |
| 322 class LoginUtilsTest : public LoginUtilsTestBase<testing::Test> { |
| 323 }; |
| 324 |
| 325 class LoginUtilsBlockingLoginTest |
| 326 : public LoginUtilsTestBase<testing::TestWithParam<int> > { |
| 327 }; |
| 328 |
| 329 TEST_F(LoginUtilsTest, NormalLoginDoesntBlock) { |
| 330 UserManager* user_manager = UserManager::Get(); |
| 331 EXPECT_FALSE(user_manager->user_is_logged_in()); |
| 332 EXPECT_FALSE(connector_->IsEnterpriseManaged()); |
| 333 EXPECT_FALSE(prepared_profile_); |
| 334 |
| 335 // The profile will be created without waiting for a policy response. |
| 336 PrepareProfile(kUsername); |
| 337 |
| 338 EXPECT_TRUE(prepared_profile_); |
| 339 EXPECT_TRUE(user_manager->user_is_logged_in()); |
| 340 EXPECT_EQ(kUsername, user_manager->logged_in_user().email()); |
| 341 } |
| 342 |
| 343 TEST_F(LoginUtilsTest, EnterpriseLoginDoesntBlockForNormalUser) { |
| 344 UserManager* user_manager = UserManager::Get(); |
| 345 EXPECT_FALSE(user_manager->user_is_logged_in()); |
| 346 EXPECT_FALSE(connector_->IsEnterpriseManaged()); |
| 347 EXPECT_FALSE(prepared_profile_); |
| 348 |
| 349 // Enroll the device. |
| 350 LockDevice(kUsername); |
| 351 |
| 352 EXPECT_FALSE(user_manager->user_is_logged_in()); |
| 353 EXPECT_TRUE(connector_->IsEnterpriseManaged()); |
| 354 EXPECT_EQ(kDomain, connector_->GetEnterpriseDomain()); |
| 355 EXPECT_FALSE(prepared_profile_); |
| 356 |
| 357 // Login with a non-enterprise user shouldn't block. |
| 358 PrepareProfile(kUsernameOtherDomain); |
| 359 |
| 360 EXPECT_TRUE(prepared_profile_); |
| 361 EXPECT_TRUE(user_manager->user_is_logged_in()); |
| 362 EXPECT_EQ(kUsernameOtherDomain, user_manager->logged_in_user().email()); |
| 363 } |
| 364 |
| 365 TEST_P(LoginUtilsBlockingLoginTest, EnterpriseLoginBlocksForEnterpriseUser) { |
| 366 UserManager* user_manager = UserManager::Get(); |
| 367 EXPECT_FALSE(user_manager->user_is_logged_in()); |
| 368 EXPECT_FALSE(connector_->IsEnterpriseManaged()); |
| 369 EXPECT_FALSE(prepared_profile_); |
| 370 |
| 371 // Enroll the device. |
| 372 LockDevice(kUsername); |
| 373 |
| 374 EXPECT_FALSE(user_manager->user_is_logged_in()); |
| 375 EXPECT_TRUE(connector_->IsEnterpriseManaged()); |
| 376 EXPECT_EQ(kDomain, connector_->GetEnterpriseDomain()); |
| 377 EXPECT_FALSE(prepared_profile_); |
| 378 |
| 379 // Login with a user of the enterprise domain waits for policy. |
| 380 PrepareProfile(kUsername); |
| 381 |
| 382 EXPECT_FALSE(prepared_profile_); |
| 383 EXPECT_TRUE(user_manager->user_is_logged_in()); |
| 384 |
| 385 GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); |
| 386 TestURLFetcher* fetcher; |
| 387 |
| 388 // |steps| is the test parameter, and is the number of successful fetches. |
| 389 // The first incomplete fetch will fail. In any case, the profile creation |
| 390 // should resume. |
| 391 int steps = GetParam(); |
| 392 |
| 393 do { |
| 394 if (steps < 1) break; |
| 395 |
| 396 // Fake OAuth token retrieval: |
| 397 fetcher = PrepareOAuthFetcher(gaia_urls->get_oauth_token_url()); |
| 398 net::ResponseCookies cookies; |
| 399 cookies.push_back(kOAuthTokenCookie); |
| 400 fetcher->set_cookies(cookies); |
| 401 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 402 if (steps < 2) break; |
| 403 |
| 404 // Fake OAuth access token retrieval: |
| 405 fetcher = PrepareOAuthFetcher(gaia_urls->oauth_get_access_token_url()); |
| 406 fetcher->SetResponseString(kOAuthGetAccessTokenData); |
| 407 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 408 if (steps < 3) break; |
| 409 |
| 410 // Fake OAuth service token retrieval: |
| 411 fetcher = PrepareOAuthFetcher(gaia_urls->oauth_wrap_bridge_url()); |
| 412 fetcher->SetResponseString(kOAuthServiceTokenData); |
| 413 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 414 |
| 415 // The cloud policy subsystem is now ready to fetch the dmtoken and the user |
| 416 // policy. |
| 417 loop_.RunAllPending(); |
| 418 if (steps < 4) break; |
| 419 |
| 420 fetcher = PrepareDMRegisterFetcher(); |
| 421 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 422 // The policy fetch job has now been scheduled, run it: |
| 423 loop_.RunAllPending(); |
| 424 if (steps < 5) break; |
| 425 |
| 426 // Verify that there is no profile prepared just before the policy fetch. |
| 427 EXPECT_FALSE(prepared_profile_); |
| 428 |
| 429 fetcher = PrepareDMPolicyFetcher(); |
| 430 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 431 } while (0); |
| 432 |
| 433 if (steps < 5) { |
| 434 // Verify that the profile hasn't been created yet. |
| 435 EXPECT_FALSE(prepared_profile_); |
| 436 |
| 437 // Make the current fetcher fail. |
| 438 TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0); |
| 439 EXPECT_TRUE(fetcher); |
| 440 EXPECT_TRUE(fetcher->delegate()); |
| 441 fetcher->set_url(fetcher->GetOriginalURL()); |
| 442 fetcher->set_response_code(500); |
| 443 fetcher->delegate()->OnURLFetchComplete(fetcher); |
| 444 } |
| 445 |
| 446 // The profile is finally ready: |
| 447 EXPECT_TRUE(prepared_profile_); |
| 448 } |
| 449 |
| 450 INSTANTIATE_TEST_CASE_P( |
| 451 LoginUtilsBlockingLoginTestInstance, |
| 452 LoginUtilsBlockingLoginTest, |
| 453 testing::Values(0, 1, 2, 3, 4, 5)); |
| 454 |
| 455 } // namespace |
| 456 |
| 457 } |
OLD | NEW |