This source file includes following definitions.
- BlockLoop
- CopyLockResult
- prepared_profile_
- SetUp
- TearDown
- TearDownOnIO
- RunUntilIdle
- InvokeOnIO
- QuitIOLoop
- DoIOWork
- OnProfilePrepared
- OnRlzInitialized
- OnLoginFailure
- OnLoginSuccess
- EnrollDevice
- PrepareProfile
- PrepareOAuthFetcher
- PrepareDMServiceFetcher
- PrepareDMRegisterFetcher
- PrepareDMPolicyFetcher
- SetUp
- TEST_P
- TEST_P
- TEST_P
- TEST_P
#include "chrome/browser/chromeos/login/login_utils.h"
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "base/path_service.h"
#include "base/prefs/pref_registry_simple.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
#include "chrome/browser/chrome_content_browser_client.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/input_method/input_method_configuration.h"
#include "chrome/browser/chromeos/input_method/mock_input_method_manager.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/chromeos/policy/browser_policy_connector_chromeos.h"
#include "chrome/browser/chromeos/policy/enterprise_install_attributes.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/device_settings_service.h"
#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
#include "chrome/browser/chromeos/settings/mock_owner_key_util.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/predictor.h"
#include "chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/rlz/rlz.h"
#include "chrome/common/chrome_content_client.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/chrome_unit_test_suite.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/cryptohome/mock_async_method_caller.h"
#include "chromeos/cryptohome/system_salt_getter.h"
#include "chromeos/dbus/fake_dbus_thread_manager.h"
#include "chromeos/disks/disk_mount_manager.h"
#include "chromeos/disks/mock_disk_mount_manager.h"
#include "chromeos/login/login_state.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/system/mock_statistics_provider.h"
#include "chromeos/system/statistics_provider.h"
#include "components/policy/core/common/cloud/device_management_service.h"
#include "components/policy/core/common/policy_service.h"
#include "components/policy/core/common/policy_switches.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_utils.h"
#include "google_apis/gaia/gaia_auth_consumer.h"
#include "google_apis/gaia/gaia_urls.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_fetcher_delegate.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_test_util.h"
#include "policy/proto/device_management_backend.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/message_center/message_center.h"
#if defined(ENABLE_RLZ)
#include "rlz/lib/rlz_value_store.h"
#endif
using ::testing::AnyNumber;
namespace chromeos {
namespace {
namespace em = enterprise_management;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SetArgPointee;
using ::testing::_;
using content::BrowserThread;
const char kDomain[] = "domain.com";
const char kUsername[] = "user@domain.com";
const char kDeviceId[] = "100200300";
const char kUsernameOtherDomain[] = "user@other.com";
const char kOAuthTokenCookie[] = "oauth_token=1234";
const char kGaiaAccountDisabledResponse[] = "Error=AccountDeleted";
const char kOAuth2TokenPairData[] =
"{"
" \"refresh_token\": \"1234\","
" \"access_token\": \"5678\","
" \"expires_in\": 3600"
"}";
const char kOAuth2AccessTokenData[] =
"{"
" \"access_token\": \"5678\","
" \"expires_in\": 3600"
"}";
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";
void BlockLoop(base::WaitableEvent* completion, base::Callback<bool()> work) {
do {
completion->Wait();
} while (work.Run());
base::MessageLoop::current()->QuitNow();
}
void CopyLockResult(base::RunLoop* loop,
policy::EnterpriseInstallAttributes::LockResult* out,
policy::EnterpriseInstallAttributes::LockResult result) {
*out = result;
loop->Quit();
}
class LoginUtilsTest : public testing::Test,
public LoginUtils::Delegate,
public LoginStatusConsumer {
public:
LoginUtilsTest()
: fake_io_thread_completion_(false, false),
fake_io_thread_("fake_io_thread"),
browser_process_(TestingBrowserProcess::GetGlobal()),
local_state_(browser_process_),
ui_thread_(BrowserThread::UI, &loop_),
db_thread_(BrowserThread::DB, &loop_),
file_thread_(BrowserThread::FILE, &loop_),
mock_input_method_manager_(NULL),
mock_async_method_caller_(NULL),
connector_(NULL),
prepared_profile_(NULL) {}
virtual void SetUp() OVERRIDE {
ChromeUnitTestSuite::InitializeProviders();
ChromeUnitTestSuite::InitializeResourceBundle();
content_client_.reset(new ChromeContentClient);
content::SetContentClient(content_client_.get());
browser_content_client_.reset(new chrome::ChromeContentBrowserClient());
content::SetBrowserClientForTesting(browser_content_client_.get());
fake_io_thread_.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
base::MessageLoop* fake_io_loop = fake_io_thread_.message_loop();
fake_io_thread_.StopSoon();
fake_io_loop->PostTask(
FROM_HERE,
base::Bind(
BlockLoop,
&fake_io_thread_completion_,
base::Bind(&LoginUtilsTest::DoIOWork, base::Unretained(this))));
io_thread_.reset(
new content::TestBrowserThread(BrowserThread::IO, fake_io_loop));
ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir());
CommandLine* command_line = CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(
policy::switches::kDeviceManagementUrl, kDMServer);
if (!command_line->HasSwitch(::switches::kMultiProfiles))
command_line->AppendSwitchASCII(switches::kLoginProfile, "user");
DBusThreadManager::InitializeWithStub();
SystemSaltGetter::Initialize();
LoginState::Initialize();
EXPECT_CALL(mock_statistics_provider_, GetMachineStatistic(_, _))
.WillRepeatedly(Return(false));
chromeos::system::StatisticsProvider::SetTestProvider(
&mock_statistics_provider_);
mock_input_method_manager_ = new input_method::MockInputMethodManager();
input_method::InitializeForTesting(mock_input_method_manager_);
disks::DiskMountManager::InitializeForTesting(&mock_disk_mount_manager_);
mock_disk_mount_manager_.SetupDefaultReplies();
mock_async_method_caller_ = new cryptohome::MockAsyncMethodCaller;
cryptohome::AsyncMethodCaller::InitializeForTesting(
mock_async_method_caller_);
test_device_settings_service_.reset(new ScopedTestDeviceSettingsService);
test_cros_settings_.reset(new ScopedTestCrosSettings);
test_user_manager_.reset(new ScopedTestUserManager);
NetworkHandler::Initialize();
browser_process_->SetProfileManager(
new ProfileManagerWithoutInit(scoped_temp_dir_.path()));
browser_process_->SetSystemRequestContext(
new net::TestURLRequestContextGetter(
base::MessageLoopProxy::current()));
connector_ =
browser_process_->platform_part()->browser_policy_connector_chromeos();
connector_->Init(local_state_.Get(),
browser_process_->system_request_context());
io_thread_state_.reset(new IOThread(local_state_.Get(),
browser_process_->policy_service(),
NULL, NULL));
browser_process_->SetIOThread(io_thread_state_.get());
#if defined(ENABLE_RLZ)
rlz_initialized_cb_ = base::Bind(&base::DoNothing);
rlz_lib::testing::SetRlzStoreDirectory(scoped_temp_dir_.path());
RLZTracker::EnableZeroDelayForTesting();
#endif
message_center::MessageCenter::Initialize();
RunUntilIdle();
}
virtual void TearDown() OVERRIDE {
cryptohome::AsyncMethodCaller::Shutdown();
mock_async_method_caller_ = NULL;
message_center::MessageCenter::Shutdown();
test_user_manager_.reset();
InvokeOnIO(
base::Bind(&LoginUtilsTest::TearDownOnIO, base::Unretained(this)));
LoginUtils::Set(NULL);
system::StatisticsProvider::SetTestProvider(NULL);
input_method::Shutdown();
LoginState::Shutdown();
SystemSaltGetter::Shutdown();
browser_process_->SetProfileManager(NULL);
connector_ = NULL;
browser_process_->SetBrowserPolicyConnector(NULL);
QuitIOLoop();
RunUntilIdle();
browser_content_client_.reset();
content_client_.reset();
content::SetContentClient(NULL);
}
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();
}
}
}
void RunUntilIdle() {
loop_.RunUntilIdle();
BrowserThread::GetBlockingPool()->FlushForTesting();
loop_.RunUntilIdle();
}
void InvokeOnIO(const base::Closure& task) {
fake_io_thread_work_ = task;
fake_io_thread_completion_.Signal();
content::RunMessageLoop();
}
void QuitIOLoop() {
fake_io_thread_completion_.Signal();
content::RunMessageLoop();
}
bool DoIOWork() {
bool has_work = !fake_io_thread_work_.is_null();
if (has_work)
fake_io_thread_work_.Run();
fake_io_thread_work_.Reset();
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::MessageLoop::QuitWhenIdleClosure());
return has_work;
}
virtual void OnProfilePrepared(Profile* profile) OVERRIDE {
EXPECT_FALSE(prepared_profile_);
prepared_profile_ = profile;
}
#if defined(ENABLE_RLZ)
virtual void OnRlzInitialized(Profile* profile) OVERRIDE {
rlz_initialized_cb_.Run();
}
#endif
virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE {
FAIL() << "OnLoginFailure not expected";
}
virtual void OnLoginSuccess(const UserContext& user_context) OVERRIDE {
FAIL() << "OnLoginSuccess not expected";
}
void EnrollDevice(const std::string& username) {
base::RunLoop loop;
policy::EnterpriseInstallAttributes::LockResult result;
connector_->GetInstallAttributes()->LockDevice(
username, policy::DEVICE_MODE_ENTERPRISE, kDeviceId,
base::Bind(&CopyLockResult, &loop, &result));
loop.Run();
EXPECT_EQ(policy::EnterpriseInstallAttributes::LOCK_SUCCESS, result);
RunUntilIdle();
}
void PrepareProfile(const std::string& username) {
ChromeBrowserMainExtraPartsProfiles::
EnsureBrowserContextKeyedServiceFactoriesBuilt();
DeviceSettingsTestHelper device_settings_test_helper;
DeviceSettingsService::Get()->SetSessionManager(
&device_settings_test_helper, new MockOwnerKeyUtil());
EXPECT_CALL(*mock_async_method_caller_, AsyncMount(_, _, _, _))
.WillRepeatedly(Return());
EXPECT_CALL(*mock_async_method_caller_, AsyncGetSanitizedUsername(_, _))
.WillRepeatedly(Return());
scoped_refptr<Authenticator> authenticator =
LoginUtils::Get()->CreateAuthenticator(this);
authenticator->CompleteLogin(ProfileHelper::GetSigninProfile(),
UserContext(username,
"password",
std::string(),
username));
const bool kUsingOAuth = true;
const bool kHasCookies = false;
const bool kHasActiveSession = false;
LoginUtils::Get()->PrepareProfile(
UserContext(username,
"password",
std::string(),
username,
kUsingOAuth,
UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML),
std::string(), kHasCookies, kHasActiveSession, this);
device_settings_test_helper.Flush();
RunUntilIdle();
DeviceSettingsService::Get()->UnsetSessionManager();
}
net::TestURLFetcher* PrepareOAuthFetcher(const GURL& expected_url) {
net::TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(0);
EXPECT_TRUE(fetcher);
if (!fetcher)
return NULL;
EXPECT_TRUE(fetcher->delegate());
EXPECT_TRUE(StartsWithASCII(fetcher->GetOriginalURL().spec(),
expected_url.spec(),
true));
fetcher->set_url(fetcher->GetOriginalURL());
fetcher->set_response_code(200);
fetcher->set_status(net::URLRequestStatus());
return fetcher;
}
net::TestURLFetcher* PrepareDMServiceFetcher(
const std::string& expected_url,
const em::DeviceManagementResponse& response) {
net::TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(
policy::DeviceManagementService::kURLFetcherID);
EXPECT_TRUE(fetcher);
if (!fetcher)
return NULL;
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;
}
net::TestURLFetcher* PrepareDMRegisterFetcher() {
em::DeviceManagementResponse response;
em::DeviceRegisterResponse* register_response =
response.mutable_register_response();
register_response->set_device_management_token(kDMToken);
register_response->set_enrollment_type(
em::DeviceRegisterResponse::ENTERPRISE);
return PrepareDMServiceFetcher(kDMRegisterRequest, response);
}
net::TestURLFetcher* PrepareDMPolicyFetcher() {
em::DeviceManagementResponse response;
response.mutable_policy_response()->add_response();
return PrepareDMServiceFetcher(kDMPolicyRequest, response);
}
protected:
TestingBrowserProcessInitializer initializer_;
scoped_ptr<ChromeContentClient> content_client_;
scoped_ptr<chrome::ChromeContentBrowserClient> browser_content_client_;
base::Closure fake_io_thread_work_;
base::WaitableEvent fake_io_thread_completion_;
base::Thread fake_io_thread_;
base::MessageLoopForIO loop_;
TestingBrowserProcess* browser_process_;
ScopedTestingLocalState local_state_;
content::TestBrowserThread ui_thread_;
content::TestBrowserThread db_thread_;
content::TestBrowserThread file_thread_;
scoped_ptr<content::TestBrowserThread> io_thread_;
scoped_ptr<IOThread> io_thread_state_;
input_method::MockInputMethodManager* mock_input_method_manager_;
disks::MockDiskMountManager mock_disk_mount_manager_;
net::TestURLFetcherFactory test_url_fetcher_factory_;
cryptohome::MockAsyncMethodCaller* mock_async_method_caller_;
chromeos::system::MockStatisticsProvider mock_statistics_provider_;
policy::BrowserPolicyConnectorChromeOS* connector_;
scoped_ptr<ScopedTestDeviceSettingsService> test_device_settings_service_;
scoped_ptr<ScopedTestCrosSettings> test_cros_settings_;
scoped_ptr<ScopedTestUserManager> test_user_manager_;
Profile* prepared_profile_;
base::Closure rlz_initialized_cb_;
private:
base::ScopedTempDir scoped_temp_dir_;
std::string device_policy_;
std::string user_policy_;
DISALLOW_COPY_AND_ASSIGN(LoginUtilsTest);
};
class LoginUtilsParamTest
: public LoginUtilsTest,
public testing::WithParamInterface<bool> {
public:
LoginUtilsParamTest() {}
virtual void SetUp() OVERRIDE {
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (GetParam())
command_line->AppendSwitch(::switches::kMultiProfiles);
LoginUtilsTest::SetUp();
}
private:
DISALLOW_COPY_AND_ASSIGN(LoginUtilsParamTest);
};
class LoginUtilsBlockingLoginTest
: public LoginUtilsTest,
public testing::WithParamInterface<int> {};
TEST_P(LoginUtilsParamTest, NormalLoginDoesntBlock) {
UserManager* user_manager = UserManager::Get();
EXPECT_FALSE(user_manager->IsUserLoggedIn());
EXPECT_FALSE(connector_->IsEnterpriseManaged());
EXPECT_FALSE(prepared_profile_);
EXPECT_EQ(policy::USER_AFFILIATION_NONE,
connector_->GetUserAffiliation(kUsername));
PrepareProfile(kUsername);
EXPECT_TRUE(prepared_profile_);
ASSERT_TRUE(user_manager->IsUserLoggedIn());
EXPECT_EQ(kUsername, user_manager->GetLoggedInUser()->email());
}
TEST_P(LoginUtilsParamTest, EnterpriseLoginDoesntBlockForNormalUser) {
UserManager* user_manager = UserManager::Get();
EXPECT_FALSE(user_manager->IsUserLoggedIn());
EXPECT_FALSE(connector_->IsEnterpriseManaged());
EXPECT_FALSE(prepared_profile_);
EnrollDevice(kUsername);
EXPECT_FALSE(user_manager->IsUserLoggedIn());
EXPECT_TRUE(connector_->IsEnterpriseManaged());
EXPECT_EQ(kDomain, connector_->GetEnterpriseDomain());
EXPECT_FALSE(prepared_profile_);
EXPECT_EQ(policy::USER_AFFILIATION_NONE,
connector_->GetUserAffiliation(kUsernameOtherDomain));
PrepareProfile(kUsernameOtherDomain);
EXPECT_TRUE(prepared_profile_);
ASSERT_TRUE(user_manager->IsUserLoggedIn());
EXPECT_EQ(kUsernameOtherDomain, user_manager->GetLoggedInUser()->email());
}
#if defined(ENABLE_RLZ)
TEST_P(LoginUtilsParamTest, RlzInitialized) {
EXPECT_FALSE(local_state_.Get()->HasPrefPath(prefs::kRLZBrand));
base::RunLoop wait_for_rlz_init;
rlz_initialized_cb_ = wait_for_rlz_init.QuitClosure();
PrepareProfile(kUsername);
wait_for_rlz_init.Run();
RunUntilIdle();
EXPECT_TRUE(local_state_.Get()->HasPrefPath(prefs::kRLZBrand));
EXPECT_EQ(std::string(), local_state_.Get()->GetString(prefs::kRLZBrand));
base::string16 rlz_string;
EXPECT_TRUE(RLZTracker::GetAccessPointRlz(
RLZTracker::CHROME_HOME_PAGE, &rlz_string));
EXPECT_EQ(base::string16(), rlz_string);
}
#endif
TEST_P(LoginUtilsBlockingLoginTest, EnterpriseLoginBlocksForEnterpriseUser) {
UserManager* user_manager = UserManager::Get();
EXPECT_FALSE(user_manager->IsUserLoggedIn());
EXPECT_FALSE(connector_->IsEnterpriseManaged());
EXPECT_FALSE(prepared_profile_);
EnrollDevice(kUsername);
EXPECT_FALSE(user_manager->IsUserLoggedIn());
EXPECT_TRUE(connector_->IsEnterpriseManaged());
EXPECT_EQ(kDomain, connector_->GetEnterpriseDomain());
EXPECT_FALSE(prepared_profile_);
EXPECT_EQ(policy::USER_AFFILIATION_MANAGED,
connector_->GetUserAffiliation(kUsername));
EXPECT_FALSE(user_manager->IsKnownUser(kUsername));
PrepareProfile(kUsername);
EXPECT_FALSE(prepared_profile_);
ASSERT_TRUE(user_manager->IsUserLoggedIn());
EXPECT_TRUE(user_manager->IsCurrentUserNew());
GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
net::TestURLFetcher* fetcher;
int steps = GetParam();
int next_expected_fetcher_id = 0;
do {
if (steps < 1) break;
fetcher = PrepareOAuthFetcher(gaia_urls->client_login_to_oauth2_url());
ASSERT_TRUE(fetcher);
net::ResponseCookies cookies;
cookies.push_back(kOAuthTokenCookie);
fetcher->set_cookies(cookies);
fetcher->delegate()->OnURLFetchComplete(fetcher);
if (steps < 2) break;
fetcher = PrepareOAuthFetcher(gaia_urls->oauth2_token_url());
ASSERT_TRUE(fetcher);
fetcher->SetResponseString(kOAuth2TokenPairData);
fetcher->delegate()->OnURLFetchComplete(fetcher);
if (steps < 3) break;
fetcher = PrepareOAuthFetcher(gaia_urls->oauth2_token_url());
ASSERT_TRUE(fetcher);
fetcher->SetResponseString(kOAuth2AccessTokenData);
fetcher->delegate()->OnURLFetchComplete(fetcher);
next_expected_fetcher_id = policy::DeviceManagementService::kURLFetcherID;
RunUntilIdle();
if (steps < 4) break;
fetcher = PrepareDMRegisterFetcher();
ASSERT_TRUE(fetcher);
fetcher->delegate()->OnURLFetchComplete(fetcher);
RunUntilIdle();
if (steps < 5) break;
EXPECT_FALSE(prepared_profile_);
fetcher = PrepareDMPolicyFetcher();
ASSERT_TRUE(fetcher);
fetcher->delegate()->OnURLFetchComplete(fetcher);
RunUntilIdle();
} while (0);
if (steps < 5) {
EXPECT_FALSE(prepared_profile_);
net::TestURLFetcher* fetcher = test_url_fetcher_factory_.GetFetcherByID(
next_expected_fetcher_id);
ASSERT_TRUE(fetcher);
EXPECT_TRUE(fetcher->delegate());
fetcher->set_url(fetcher->GetOriginalURL());
fetcher->set_response_code(401);
fetcher->SetResponseString(kGaiaAccountDisabledResponse);
fetcher->delegate()->OnURLFetchComplete(fetcher);
RunUntilIdle();
}
EXPECT_TRUE(prepared_profile_);
}
INSTANTIATE_TEST_CASE_P(
LoginUtilsBlockingLoginTestInstance,
LoginUtilsBlockingLoginTest,
testing::Values(0, 1, 2, 3, 4, 5));
INSTANTIATE_TEST_CASE_P(LoginUtilsParamTestInstantiation,
LoginUtilsParamTest,
testing::Bool());
}
}