blob: 39097b85d65a9d828cb7df643b3cde8a3651cbda [file] [log] [blame]
// Copyright 2013 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/multi_profile_user_controller.h"
#include "base/memory/scoped_ptr.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/chromeos/login/fake_user_manager.h"
#include "chrome/browser/chromeos/login/multi_profile_user_controller_delegate.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/policy/policy_cert_service.h"
#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_pref_service_syncable.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/testing_profile_manager.h"
#include "content/public/test/test_browser_thread_bundle.h"
#include "net/cert/x509_certificate.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace {
const char* kUsers[] = {"a@gmail.com", "b@gmail.com" };
struct BehaviorTestCase {
const char* primary;
const char* secondary;
bool expected_allowed;
};
const BehaviorTestCase kBehaviorTestCases[] = {
{
MultiProfileUserController::kBehaviorUnrestricted,
MultiProfileUserController::kBehaviorUnrestricted,
true,
},
{
MultiProfileUserController::kBehaviorUnrestricted,
MultiProfileUserController::kBehaviorPrimaryOnly,
false,
},
{
MultiProfileUserController::kBehaviorUnrestricted,
MultiProfileUserController::kBehaviorNotAllowed,
false,
},
{
MultiProfileUserController::kBehaviorPrimaryOnly,
MultiProfileUserController::kBehaviorUnrestricted,
true,
},
{
MultiProfileUserController::kBehaviorPrimaryOnly,
MultiProfileUserController::kBehaviorPrimaryOnly,
false,
},
{
MultiProfileUserController::kBehaviorPrimaryOnly,
MultiProfileUserController::kBehaviorNotAllowed,
false,
},
{
MultiProfileUserController::kBehaviorNotAllowed,
MultiProfileUserController::kBehaviorUnrestricted,
false,
},
{
MultiProfileUserController::kBehaviorNotAllowed,
MultiProfileUserController::kBehaviorPrimaryOnly,
false,
},
{
MultiProfileUserController::kBehaviorNotAllowed,
MultiProfileUserController::kBehaviorNotAllowed,
false,
},
};
policy::PolicyCertVerifier* g_policy_cert_verifier_for_factory = NULL;
BrowserContextKeyedService* TestPolicyCertServiceFactory(
content::BrowserContext* context) {
return policy::PolicyCertService::CreateForTesting(
kUsers[0], g_policy_cert_verifier_for_factory, UserManager::Get())
.release();
}
} // namespace
class MultiProfileUserControllerTest
: public testing::Test,
public MultiProfileUserControllerDelegate {
public:
MultiProfileUserControllerTest()
: profile_manager_(TestingBrowserProcess::GetGlobal()),
fake_user_manager_(new FakeUserManager),
user_manager_enabler_(fake_user_manager_),
user_not_allowed_count_(0) {}
virtual ~MultiProfileUserControllerTest() {}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(profile_manager_.SetUp());
controller_.reset(new MultiProfileUserController(
this, TestingBrowserProcess::GetGlobal()->local_state()));
for (size_t i = 0; i < arraysize(kUsers); ++i) {
const std::string user_email(kUsers[i]);
const User* user = fake_user_manager_->AddUser(user_email);
// Note that user profiles are created after user login in reality.
TestingProfile* user_profile =
profile_manager_.CreateTestingProfile(user_email);
user_profile->set_profile_name(user_email);
user_profiles_.push_back(user_profile);
fake_user_manager_->SetProfileForUser(user, user_profile);
}
}
void LoginUser(size_t user_index) {
ASSERT_LT(user_index, arraysize(kUsers));
fake_user_manager_->LoginUser(kUsers[user_index]);
controller_->StartObserving(user_profiles_[user_index]);
}
void SetOwner(size_t user_index) {
fake_user_manager_->set_owner_email(kUsers[user_index]);
}
PrefService* GetUserPrefs(size_t user_index) {
return user_profiles_[user_index]->GetPrefs();
}
void SetPrefBehavior(size_t user_index, const std::string& behavior) {
GetUserPrefs(user_index)->SetString(prefs::kMultiProfileUserBehavior,
behavior);
}
std::string GetCachedBehavior(size_t user_index) {
return controller_->GetCachedValue(kUsers[user_index]);
}
void SetCachedBehavior(size_t user_index,
const std::string& behavior) {
controller_->SetCachedValue(kUsers[user_index], behavior);
}
void ResetCounts() {
user_not_allowed_count_ = 0;
}
// MultiProfileUserControllerDeleagte overrides:
virtual void OnUserNotAllowed() OVERRIDE {
++user_not_allowed_count_;
}
MultiProfileUserController* controller() { return controller_.get(); }
int user_not_allowed_count() const { return user_not_allowed_count_; }
TestingProfile* profile(int index) {
return user_profiles_[index];
}
private:
content::TestBrowserThreadBundle threads_;
TestingProfileManager profile_manager_;
FakeUserManager* fake_user_manager_; // Not owned
ScopedUserManagerEnabler user_manager_enabler_;
scoped_ptr<MultiProfileUserController> controller_;
std::vector<TestingProfile*> user_profiles_;
int user_not_allowed_count_;
DISALLOW_COPY_AND_ASSIGN(MultiProfileUserControllerTest);
};
// Tests that everyone is allowed before a session starts.
TEST_F(MultiProfileUserControllerTest, AllAllowedBeforeLogin) {
const char* kTestCases[] = {
MultiProfileUserController::kBehaviorUnrestricted,
MultiProfileUserController::kBehaviorPrimaryOnly,
MultiProfileUserController::kBehaviorNotAllowed,
};
for (size_t i = 0; i < arraysize(kTestCases); ++i) {
SetCachedBehavior(0, kTestCases[i]);
EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[0]))
<< "Case " << i;
}
}
// Tests that invalid cache value would become the default "unrestricted".
TEST_F(MultiProfileUserControllerTest, InvalidCacheBecomesDefault) {
const char kBad[] = "some invalid value";
SetCachedBehavior(0, kBad);
EXPECT_EQ(MultiProfileUserController::kBehaviorUnrestricted,
GetCachedBehavior(0));
}
// Tests that cached behavior value changes with user pref after login.
TEST_F(MultiProfileUserControllerTest, CachedBehaviorUpdate) {
LoginUser(0);
const char* kTestCases[] = {
MultiProfileUserController::kBehaviorUnrestricted,
MultiProfileUserController::kBehaviorPrimaryOnly,
MultiProfileUserController::kBehaviorNotAllowed,
MultiProfileUserController::kBehaviorUnrestricted,
};
for (size_t i = 0; i < arraysize(kTestCases); ++i) {
SetPrefBehavior(0, kTestCases[i]);
EXPECT_EQ(kTestCases[i], GetCachedBehavior(0));
}
}
// Tests that compromised cache value would be fixed and pref value is checked
// upon login.
TEST_F(MultiProfileUserControllerTest, CompromisedCacheFixedOnLogin) {
SetPrefBehavior(0, MultiProfileUserController::kBehaviorPrimaryOnly);
SetCachedBehavior(0, MultiProfileUserController::kBehaviorUnrestricted);
EXPECT_EQ(MultiProfileUserController::kBehaviorUnrestricted,
GetCachedBehavior(0));
LoginUser(0);
EXPECT_EQ(MultiProfileUserController::kBehaviorPrimaryOnly,
GetCachedBehavior(0));
EXPECT_EQ(0, user_not_allowed_count());
SetPrefBehavior(1, MultiProfileUserController::kBehaviorPrimaryOnly);
SetCachedBehavior(1, MultiProfileUserController::kBehaviorUnrestricted);
EXPECT_EQ(MultiProfileUserController::kBehaviorUnrestricted,
GetCachedBehavior(1));
LoginUser(1);
EXPECT_EQ(MultiProfileUserController::kBehaviorPrimaryOnly,
GetCachedBehavior(1));
EXPECT_EQ(1, user_not_allowed_count());
}
// Tests cases before the second user login.
TEST_F(MultiProfileUserControllerTest, IsSecondaryAllowed) {
LoginUser(0);
for (size_t i = 0; i < arraysize(kBehaviorTestCases); ++i) {
SetPrefBehavior(0, kBehaviorTestCases[i].primary);
SetCachedBehavior(1, kBehaviorTestCases[i].secondary);
EXPECT_EQ(kBehaviorTestCases[i].expected_allowed,
controller()->IsUserAllowedInSession(kUsers[1])) << "Case " << i;
}
}
// Tests user behavior changes within a two-user session.
TEST_F(MultiProfileUserControllerTest, PrimaryBehaviorChange) {
LoginUser(0);
LoginUser(1);
for (size_t i = 0; i < arraysize(kBehaviorTestCases); ++i) {
SetPrefBehavior(0, MultiProfileUserController::kBehaviorUnrestricted);
SetPrefBehavior(1, MultiProfileUserController::kBehaviorUnrestricted);
ResetCounts();
SetPrefBehavior(0, kBehaviorTestCases[i].primary);
SetPrefBehavior(1, kBehaviorTestCases[i].secondary);
EXPECT_EQ(kBehaviorTestCases[i].expected_allowed,
user_not_allowed_count() == 0) << "Case " << i;
}
}
// Tests that owner could not be a secondary user.
TEST_F(MultiProfileUserControllerTest, NoSecondaryOwner) {
LoginUser(0);
SetOwner(1);
EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[1]));
EXPECT_EQ(0, user_not_allowed_count());
LoginUser(1);
EXPECT_EQ(1, user_not_allowed_count());
}
TEST_F(MultiProfileUserControllerTest,
UsedPolicyCertificatesAllowedForPrimary) {
// Verifies that any user can sign-in as the primary user, regardless of the
// tainted state.
policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[0]);
EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[0]));
EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[1]));
}
TEST_F(MultiProfileUserControllerTest,
UsedPolicyCertificatesDisallowedForSecondary) {
// Verifies that if a regular user is signed-in then other regular users can
// be added but tainted users can't.
LoginUser(1);
// TODO(xiyuan): Remove the following SetPrefBehavor when default is
// changed back to enabled.
SetPrefBehavior(1, MultiProfileUserController::kBehaviorUnrestricted);
EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[0]));
policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[0]);
EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[0]));
}
TEST_F(MultiProfileUserControllerTest,
UsedPolicyCertificatesDisallowsSecondaries) {
// Verifies that if a tainted user is signed-in then no other users can
// be added.
policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[0]);
LoginUser(0);
// Double parenthesis to avoid http://en.wikipedia.org/wiki/Most_vexing_parse.
policy::PolicyCertVerifier verifier((base::Closure()));
g_policy_cert_verifier_for_factory = &verifier;
ASSERT_TRUE(
policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile(0), TestPolicyCertServiceFactory));
EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[1]));
policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[1]);
EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[1]));
// Flush tasks posted to IO.
base::RunLoop().RunUntilIdle();
}
TEST_F(MultiProfileUserControllerTest,
PolicyCertificatesInMemoryDisallowsSecondaries) {
// Verifies that if a user is signed-in and has policy certificates installed
// then no other users can be added.
LoginUser(0);
// TODO(xiyuan): Remove the following SetPrefBehavor when default is
// changed back to enabled.
SetPrefBehavior(0, MultiProfileUserController::kBehaviorUnrestricted);
// Double parenthesis to avoid http://en.wikipedia.org/wiki/Most_vexing_parse.
policy::PolicyCertVerifier verifier((base::Closure()));
g_policy_cert_verifier_for_factory = &verifier;
ASSERT_TRUE(
policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
profile(0), TestPolicyCertServiceFactory));
policy::PolicyCertService* service =
policy::PolicyCertServiceFactory::GetForProfile(profile(0));
ASSERT_TRUE(service);
EXPECT_FALSE(service->has_policy_certificates());
EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[1]));
net::CertificateList certificates;
certificates.push_back(new net::X509Certificate(
"subject", "issuer", base::Time(), base::Time()));
service->OnTrustAnchorsChanged(certificates);
EXPECT_TRUE(service->has_policy_certificates());
EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[1]));
// Flush tasks posted to IO.
base::RunLoop().RunUntilIdle();
}
} // namespace chromeos