Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Unified Diff: chrome/browser/chromeos/login/login_utils_browsertest.cc

Issue 8499021: UserPolicyCache only becomes ready after policy has been fetched. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/login/login_utils_browsertest.cc
diff --git a/chrome/browser/chromeos/login/login_utils_browsertest.cc b/chrome/browser/chromeos/login/login_utils_browsertest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..06673dc8adcef408bef4e02dd86f883a076c390a
--- /dev/null
+++ b/chrome/browser/chromeos/login/login_utils_browsertest.cc
@@ -0,0 +1,457 @@
+// Copyright (c) 2011 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 "chrome/browser/chromeos/login/login_utils.h"
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/scoped_temp_dir.h"
+#include "base/string_util.h"
+#include "chrome/browser/chromeos/cros/cros_library.h"
+#include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
+#include "chrome/browser/chromeos/cros/mock_library_loader.h"
+#include "chrome/browser/chromeos/dbus/mock_dbus_thread_manager.h"
+#include "chrome/browser/chromeos/dbus/mock_session_manager_client.h"
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/login/login_status_consumer.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/io_thread.h"
+#include "chrome/browser/net/predictor.h"
+#include "chrome/browser/policy/browser_policy_connector.h"
+#include "chrome/browser/policy/proto/device_management_backend.pb.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/chrome_switches.h"
+#include "chrome/common/net/gaia/gaia_urls.h"
+#include "chrome/common/pref_names.h"
+#include "chrome/common/net/gaia/gaia_auth_consumer.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "chrome/test/base/testing_pref_service.h"
+#include "content/test/test_browser_thread.h"
+#include "content/test/test_url_fetcher_factory.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_status.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chromeos {
+
+namespace {
+
+namespace em = enterprise_management;
+
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::_;
+
+const char kTrue[] = "true";
+const char kDomain[] = "domain.com";
+const char kUsername[] = "user@domain.com";
+const char kUsernameOtherDomain[] = "user@other.com";
+const char kAttributeOwned[] = "enterprise.owned";
+const char kAttributeOwner[] = "enterprise.user";
+
+const char kOAuthTokenCookie[] = "oauth_token=1234";
+const char kOAuthGetAccessTokenData[] =
+ "oauth_token=1234&oauth_token_secret=1234";
+const char kOAuthServiceTokenData[] =
+ "wrap_access_token=1234&wrap_access_token_expires_in=123456789";
+
+const char kDMServer[] = "http://server/device_management";
+const char kDMRegisterRequest[] =
+ "http://server/device_management?request=register";
+const char kDMPolicyRequest[] =
+ "http://server/device_management?request=policy";
+
+const char kDMToken[] = "1234";
+
+ACTION_P(MockSessionManagerClientPolicyCallback, policy) {
+ arg0.Run(policy);
+}
+
+// Subclass IOThread to expose set_message_loop.
+class TestIOThread : public IOThread {
+ public:
+ explicit TestIOThread(PrefService* local_state)
+ : IOThread(local_state, NULL, NULL) {}
+
+ using IOThread::set_message_loop;
+};
+
+template<typename TESTBASE>
+class LoginUtilsTestBase : public TESTBASE,
+ public LoginUtils::Delegate,
+ public LoginStatusConsumer {
+ public:
+ LoginUtilsTestBase()
+ : loop_(MessageLoop::TYPE_IO),
+ browser_process_(
+ static_cast<TestingBrowserProcess*>(g_browser_process)),
+ local_state_(browser_process_),
+ ui_thread_(content::BrowserThread::UI, &loop_),
+ file_thread_(content::BrowserThread::FILE, &loop_),
+ io_thread_(local_state_.Get()),
+ prepared_profile_(NULL) {}
+
+ virtual void SetUp() OVERRIDE {
+ ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
+ // BrowserPolicyConnector makes the UserPolicyCache read relative to this
+ // path. Make sure it's in a clean state.
+ PathService::Override(chrome::DIR_USER_DATA, scoped_temp_dir_.path());
+
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ command_line->AppendSwitch(switches::kEnableDevicePolicy);
+ command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, kDMServer);
+ command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
+
+ local_state_.Get()->RegisterStringPref(prefs::kApplicationLocale, "");
+
+ browser_process_->SetIOThread(&io_thread_);
+
+ DBusThreadManager::InitializeForTesting(&dbus_thread_manager_);
+
+ MockSessionManagerClient* session_managed_client =
+ dbus_thread_manager_.mock_session_manager_client();
+ EXPECT_CALL(*session_managed_client, RetrievePolicy(_))
+ .WillRepeatedly(MockSessionManagerClientPolicyCallback(""));
+
+ CrosLibrary::TestApi* test_api = CrosLibrary::Get()->GetTestApi();
+ ASSERT_TRUE(test_api);
+
+ MockLibraryLoader* loader = new MockLibraryLoader();
+ ON_CALL(*loader, Load(_)).WillByDefault(Return(true));
+ test_api->SetLibraryLoader(loader, true);
+
+ cryptohome_ = new MockCryptohomeLibrary();
+ EXPECT_CALL(*cryptohome_, InstallAttributesIsReady())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*cryptohome_, InstallAttributesIsInvalid())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*cryptohome_, InstallAttributesIsFirstInstall())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*cryptohome_, TpmIsEnabled())
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(*cryptohome_, IsMounted())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*cryptohome_, InstallAttributesSet(kAttributeOwned, kTrue))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*cryptohome_, InstallAttributesSet(kAttributeOwner,
+ kUsername))
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*cryptohome_, InstallAttributesFinalize())
+ .WillRepeatedly(Return(true));
+ EXPECT_CALL(*cryptohome_, InstallAttributesGet(kAttributeOwned, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kTrue),
+ Return(true)));
+ EXPECT_CALL(*cryptohome_, InstallAttributesGet(kAttributeOwner, _))
+ .WillRepeatedly(DoAll(SetArgPointee<1>(kUsername),
+ Return(true)));
+ test_api->SetCryptohomeLibrary(cryptohome_, true);
+
+ browser_process_->SetProfileManager(
+ new ProfileManagerWithoutInit(scoped_temp_dir_.path()));
+ connector_ = policy::BrowserPolicyConnector::Create();
+ browser_process_->SetBrowserPolicyConnector(connector_);
+
+ loop_.RunAllPending();
+ }
+
+ virtual void TearDown() OVERRIDE {
+ loop_.RunAllPending();
+ {
+ // chrome_browser_net::Predictor usually skips its shutdown routines on
+ // unit_tests, but does the full thing when
+ // g_browser_process->profile_manager() is valid during initialization.
+ // Run a task on a temporary BrowserThread::IO that allows skipping
+ // these routines.
+ io_thread_.set_message_loop(&loop_);
+ loop_.PostTask(FROM_HERE,
+ base::Bind(&LoginUtilsTestBase::TearDownOnIO,
+ base::Unretained(this)));
+ loop_.RunAllPending();
+ io_thread_.set_message_loop(NULL);
+ }
+
+ // These trigger some tasks that have to run while BrowserThread::UI
+ // exists.
+ connector_ = NULL;
+ browser_process_->SetBrowserPolicyConnector(NULL);
+ browser_process_->SetProfileManager(NULL);
+ loop_.RunAllPending();
+ }
+
+ void TearDownOnIO() {
+ std::vector<Profile*> profiles =
+ browser_process_->profile_manager()->GetLoadedProfiles();
+ for (size_t i = 0; i < profiles.size(); ++i) {
+ chrome_browser_net::Predictor* predictor =
+ profiles[i]->GetNetworkPredictor();
+ if (predictor) {
+ predictor->EnablePredictorOnIOThread(false);
+ predictor->Shutdown();
+ }
+ }
+ }
+
+ virtual void OnProfilePrepared(Profile* profile) OVERRIDE {
+ EXPECT_FALSE(prepared_profile_);
+ prepared_profile_ = profile;
+ }
+
+ virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE {
+ FAIL() << "OnLoginFailure not expected";
+ }
+
+ virtual void OnLoginSuccess(const std::string& username,
+ const std::string& password,
+ const GaiaAuthConsumer::ClientLoginResult& creds,
+ bool pending_requests,
+ bool using_oauth) OVERRIDE {
+ FAIL() << "OnLoginSuccess not expected";
+ }
+
+ void LockDevice(const std::string& username) {
+ EXPECT_CALL(*cryptohome_, InstallAttributesIsFirstInstall())
+ .WillOnce(Return(true))
+ .WillRepeatedly(Return(false));
+ EXPECT_EQ(policy::EnterpriseInstallAttributes::LOCK_SUCCESS,
+ connector_->LockDevice(username));
+ loop_.RunAllPending();
+ }
+
+ void PrepareProfile(const std::string& username) {
+ MockSessionManagerClient* session_managed_client =
+ dbus_thread_manager_.mock_session_manager_client();
+ EXPECT_CALL(*session_managed_client, StartSession(_));
+
+ // crypto::Encryptor::SetCounter wants exactly 128 bits, and
+ // ParallelAuthenticator CHECKs on that.
+ CryptohomeBlob blob;
+ for (size_t i = 0; i < 16; ++i)
+ blob.push_back(i);
+ EXPECT_CALL(*cryptohome_, GetSystemSalt())
+ .WillRepeatedly(Return(blob));
+ EXPECT_CALL(*cryptohome_, AsyncMount(_, _, _, _))
+ .WillRepeatedly(Return(true));
+
+ scoped_refptr<Authenticator> authenticator =
+ LoginUtils::Get()->CreateAuthenticator(this);
+ authenticator->CompleteLogin(ProfileManager::GetDefaultProfile(),
+ username,
+ "password");
+
+ GaiaAuthConsumer::ClientLoginResult credentials;
+ LoginUtils::Get()->PrepareProfile(
+ username, "password", credentials, false, true, false, this);
+ loop_.RunAllPending();
+ }
+
+ TestURLFetcher* PrepareOAuthFetcher(const std::string& expected_url) {
+ TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0);
+ EXPECT_TRUE(fetcher);
+ EXPECT_TRUE(fetcher->delegate());
+ EXPECT_TRUE(StartsWithASCII(fetcher->GetOriginalURL().spec(),
+ expected_url,
+ true));
+ fetcher->set_url(fetcher->GetOriginalURL());
+ fetcher->set_response_code(200);
+ fetcher->set_status(net::URLRequestStatus());
+ return fetcher;
+ }
+
+ TestURLFetcher* PrepareDMServiceFetcher(
+ const std::string& expected_url,
+ const em::DeviceManagementResponse& response) {
+ TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0);
+ EXPECT_TRUE(fetcher);
+ EXPECT_TRUE(fetcher->delegate());
+ EXPECT_TRUE(StartsWithASCII(fetcher->GetOriginalURL().spec(),
+ expected_url,
+ true));
+ fetcher->set_url(fetcher->GetOriginalURL());
+ fetcher->set_response_code(200);
+ fetcher->set_status(net::URLRequestStatus());
+ std::string data;
+ EXPECT_TRUE(response.SerializeToString(&data));
+ fetcher->SetResponseString(data);
+ return fetcher;
+ }
+
+ TestURLFetcher* PrepareDMRegisterFetcher() {
+ em::DeviceManagementResponse response;
+ em::DeviceRegisterResponse* register_response =
+ response.mutable_register_response();
+ register_response->set_device_management_token(kDMToken);
+ return PrepareDMServiceFetcher(kDMRegisterRequest, response);
+ }
+
+ TestURLFetcher* PrepareDMPolicyFetcher() {
+ em::DeviceManagementResponse response;
+ response.mutable_policy_response()->add_response();
+ return PrepareDMServiceFetcher(kDMPolicyRequest, response);
+ }
+
+ protected:
+ ScopedStubCrosEnabler stub_cros_enabler_;
+
+ MessageLoop loop_;
+ TestingBrowserProcess* browser_process_;
+ ScopedTestingLocalState local_state_;
+
+ content::TestBrowserThread ui_thread_;
+ content::TestBrowserThread file_thread_;
+ TestIOThread io_thread_;
+
+ MockDBusThreadManager dbus_thread_manager_;
+ TestURLFetcherFactory test_url_fetcher_factory_;
+
+ policy::BrowserPolicyConnector* connector_;
+ MockCryptohomeLibrary* cryptohome_;
+ Profile* prepared_profile_;
+
+ private:
+ ScopedTempDir scoped_temp_dir_;
+
+ DISALLOW_COPY_AND_ASSIGN(LoginUtilsTestBase);
+};
+
+class LoginUtilsTest : public LoginUtilsTestBase<testing::Test> {
+};
+
+class LoginUtilsBlockingLoginTest
+ : public LoginUtilsTestBase<testing::TestWithParam<int> > {
+};
+
+TEST_F(LoginUtilsTest, NormalLoginDoesntBlock) {
+ UserManager* user_manager = UserManager::Get();
+ EXPECT_FALSE(user_manager->user_is_logged_in());
+ EXPECT_FALSE(connector_->IsEnterpriseManaged());
+ EXPECT_FALSE(prepared_profile_);
+
+ // The profile will be created without waiting for a policy response.
+ PrepareProfile(kUsername);
+
+ EXPECT_TRUE(prepared_profile_);
+ EXPECT_TRUE(user_manager->user_is_logged_in());
+ EXPECT_EQ(kUsername, user_manager->logged_in_user().email());
+}
+
+TEST_F(LoginUtilsTest, EnterpriseLoginDoesntBlockForNormalUser) {
+ UserManager* user_manager = UserManager::Get();
+ EXPECT_FALSE(user_manager->user_is_logged_in());
+ EXPECT_FALSE(connector_->IsEnterpriseManaged());
+ EXPECT_FALSE(prepared_profile_);
+
+ // Enroll the device.
+ LockDevice(kUsername);
+
+ EXPECT_FALSE(user_manager->user_is_logged_in());
+ EXPECT_TRUE(connector_->IsEnterpriseManaged());
+ EXPECT_EQ(kDomain, connector_->GetEnterpriseDomain());
+ EXPECT_FALSE(prepared_profile_);
+
+ // Login with a non-enterprise user shouldn't block.
+ PrepareProfile(kUsernameOtherDomain);
+
+ EXPECT_TRUE(prepared_profile_);
+ EXPECT_TRUE(user_manager->user_is_logged_in());
+ EXPECT_EQ(kUsernameOtherDomain, user_manager->logged_in_user().email());
+}
+
+TEST_P(LoginUtilsBlockingLoginTest, EnterpriseLoginBlocksForEnterpriseUser) {
+ UserManager* user_manager = UserManager::Get();
+ EXPECT_FALSE(user_manager->user_is_logged_in());
+ EXPECT_FALSE(connector_->IsEnterpriseManaged());
+ EXPECT_FALSE(prepared_profile_);
+
+ // Enroll the device.
+ LockDevice(kUsername);
+
+ EXPECT_FALSE(user_manager->user_is_logged_in());
+ EXPECT_TRUE(connector_->IsEnterpriseManaged());
+ EXPECT_EQ(kDomain, connector_->GetEnterpriseDomain());
+ EXPECT_FALSE(prepared_profile_);
+
+ // Login with a user of the enterprise domain waits for policy.
+ PrepareProfile(kUsername);
+
+ EXPECT_FALSE(prepared_profile_);
+ EXPECT_TRUE(user_manager->user_is_logged_in());
+
+ GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
+ TestURLFetcher* fetcher;
+
+ // |steps| is the test parameter, and is the number of successful fetches.
+ // The first incomplete fetch will fail. In any case, the profile creation
+ // should resume.
+ int steps = GetParam();
+
+ do {
+ if (steps < 1) break;
+
+ // Fake OAuth token retrieval:
+ fetcher = PrepareOAuthFetcher(gaia_urls->get_oauth_token_url());
+ net::ResponseCookies cookies;
+ cookies.push_back(kOAuthTokenCookie);
+ fetcher->set_cookies(cookies);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ if (steps < 2) break;
+
+ // Fake OAuth access token retrieval:
+ fetcher = PrepareOAuthFetcher(gaia_urls->oauth_get_access_token_url());
+ fetcher->SetResponseString(kOAuthGetAccessTokenData);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ if (steps < 3) break;
+
+ // Fake OAuth service token retrieval:
+ fetcher = PrepareOAuthFetcher(gaia_urls->oauth_wrap_bridge_url());
+ fetcher->SetResponseString(kOAuthServiceTokenData);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+
+ // The cloud policy subsystem is now ready to fetch the dmtoken and the user
+ // policy.
+ loop_.RunAllPending();
+ if (steps < 4) break;
+
+ fetcher = PrepareDMRegisterFetcher();
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ // The policy fetch job has now been scheduled, run it:
+ loop_.RunAllPending();
+ if (steps < 5) break;
+
+ // Verify that there is no profile prepared just before the policy fetch.
+ EXPECT_FALSE(prepared_profile_);
+
+ fetcher = PrepareDMPolicyFetcher();
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ } while (0);
+
+ if (steps < 5) {
+ // Verify that the profile hasn't been created yet.
+ EXPECT_FALSE(prepared_profile_);
+
+ // Make the current fetcher fail.
+ TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0);
+ EXPECT_TRUE(fetcher);
+ EXPECT_TRUE(fetcher->delegate());
+ fetcher->set_url(fetcher->GetOriginalURL());
+ fetcher->set_response_code(500);
+ fetcher->delegate()->OnURLFetchComplete(fetcher);
+ }
+
+ // The profile is finally ready:
+ EXPECT_TRUE(prepared_profile_);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ LoginUtilsBlockingLoginTestInstance,
+ LoginUtilsBlockingLoginTest,
+ testing::Values(0, 1, 2, 3, 4, 5));
+
+} // namespace
+
+}

Powered by Google App Engine
This is Rietveld 408576698