blob: be3d0c34b0fcd7f73699c98f0d13b0efa679cfde [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS 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 "login_manager/session_manager_impl.h"
#include <glib.h>
#include <signal.h>
#include <unistd.h>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <base/basictypes.h>
#include <base/command_line.h>
#include <base/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/memory/ref_counted.h>
#include <base/message_loop.h>
#include <base/message_loop_proxy.h>
#include <base/string_util.h>
#include <chromeos/cryptohome.h>
#include <chromeos/dbus/dbus.h>
#include <chromeos/dbus/error_constants.h>
#include <chromeos/dbus/service_constants.h>
#include <chromeos/glib/object.h>
#include <crypto/scoped_nss_types.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "login_manager/device_local_account_policy_service.h"
#include "login_manager/device_management_backend.pb.h"
#include "login_manager/file_checker.h"
#include "login_manager/matchers.h"
#include "login_manager/mock_device_policy_service.h"
#include "login_manager/mock_file_checker.h"
#include "login_manager/mock_key_generator.h"
#include "login_manager/mock_metrics.h"
#include "login_manager/mock_nss_util.h"
#include "login_manager/mock_policy_service.h"
#include "login_manager/mock_process_manager_service.h"
#include "login_manager/mock_system_utils.h"
#include "login_manager/mock_upstart_signal_emitter.h"
#include "login_manager/mock_user_policy_service_factory.h"
using ::testing::AnyNumber;
using ::testing::AtMost;
using ::testing::DoAll;
using ::testing::ElementsAre;
using ::testing::ElementsAreArray;
using ::testing::HasSubstr;
using ::testing::InvokeWithoutArgs;
using ::testing::Mock;
using ::testing::Return;
using ::testing::SetArgumentPointee;
using ::testing::StrEq;
using ::testing::_;
using chromeos::Resetter;
using chromeos::cryptohome::home::kGuestUserName;
using chromeos::cryptohome::home::SanitizeUserName;
using chromeos::cryptohome::home::SetSystemSalt;
using chromeos::glib::ScopedError;
using std::map;
using std::string;
using std::vector;
namespace login_manager {
class SessionManagerImplTest : public ::testing::Test {
public:
SessionManagerImplTest()
: upstart_(new MockUpstartSignalEmitter),
device_policy_service_(new MockDevicePolicyService),
impl_(scoped_ptr<UpstartSignalEmitter>(upstart_),
&manager_,
&metrics_,
&nss_,
&utils_),
fake_salt_("fake salt") {
}
virtual ~SessionManagerImplTest() {}
virtual void SetUp() OVERRIDE {
ASSERT_TRUE(tmpdir_.CreateUniqueTempDir());
SetSystemSalt(&fake_salt_);
MockUserPolicyServiceFactory* factory = new MockUserPolicyServiceFactory;
EXPECT_CALL(*factory, Create(_))
.WillRepeatedly(
Invoke(this, &SessionManagerImplTest::CreateUserPolicyService));
scoped_ptr<DeviceLocalAccountPolicyService> device_local_account_policy(
new DeviceLocalAccountPolicyService(tmpdir_.path(), NULL, NULL));
impl_.InjectPolicyServices(
scoped_ptr<DevicePolicyService>(device_policy_service_),
scoped_ptr<UserPolicyServiceFactory>(factory),
device_local_account_policy.Pass());
}
virtual void TearDown() OVERRIDE {
SetSystemSalt(NULL);
}
protected:
void ExpectStartSession(const string& email_string) {
ExpectSessionBoilerplate(email_string, false, false);
}
void ExpectGuestSession() {
ExpectSessionBoilerplate(kGuestUserName, true, false);
}
void ExpectStartOwnerSession(const string& email_string) {
ExpectSessionBoilerplate(email_string, false, true);
}
void ExpectStartSessionUnowned(const string& email_string) {
ExpectStartSessionUnownedBoilerplate(email_string, false, false);
}
void ExpectStartSessionOwningInProcess(const string& email_string) {
ExpectStartSessionUnownedBoilerplate(email_string, false, true);
}
void ExpectStartSessionOwnerLost(const string& email_string) {
ExpectStartSessionUnownedBoilerplate(email_string, true, false);
}
void ExpectStorePolicy(MockDevicePolicyService* service,
const string& policy,
int flags) {
EXPECT_CALL(*service, Store(CastEq(policy), policy.size(), _, flags))
.WillOnce(Return(true));
}
void ExpectAndRunStartSession(const string& const_email) {
gboolean out;
// Need a non-const gchar*.
gchar* email = g_strdup(const_email.c_str());
gchar nothing[] = "";
ExpectStartSession(email);
EXPECT_EQ(TRUE, impl_.StartSession(email, nothing, &out, NULL));
g_free(email);
}
void ExpectAndRunGuestSession() {
gboolean out;
// Need a non-const gchar*.
gchar* incognito = g_strdup(kGuestUserName);
gchar nothing[] = "";
ExpectGuestSession();
EXPECT_EQ(TRUE, impl_.StartSession(incognito, nothing, &out, NULL));
g_free(incognito);
}
PolicyService* CreateUserPolicyService(const string& username) {
user_policy_services_[username] = new MockPolicyService();
return user_policy_services_[username];
}
void VerifyAndClearExpectations() {
Mock::VerifyAndClearExpectations(upstart_);
Mock::VerifyAndClearExpectations(device_policy_service_);
for (map<string, MockPolicyService*>::iterator it =
user_policy_services_.begin();
it != user_policy_services_.end();
++it) {
Mock::VerifyAndClearExpectations(it->second);
}
Mock::VerifyAndClearExpectations(&manager_);
Mock::VerifyAndClearExpectations(&metrics_);
Mock::VerifyAndClearExpectations(&nss_);
Mock::VerifyAndClearExpectations(&utils_);
}
// Caller takes ownership.
GArray* CreateArray(const char* input, const int len) {
GArray* output = g_array_new(FALSE, FALSE, 1);
g_array_append_vals(output, input, len);
return output;
}
// These are bare pointers, not scoped_ptrs, because we need to give them
// to a SessionManagerImpl instance, but also be able to set expectations
// on them after we hand them off.
MockUpstartSignalEmitter* upstart_;
MockDevicePolicyService* device_policy_service_;
map<string, MockPolicyService*> user_policy_services_;
MockProcessManagerService manager_;
MockMetrics metrics_;
MockNssUtil nss_;
MockSystemUtils utils_;
SessionManagerImpl impl_;
base::ScopedTempDir tmpdir_;
static const pid_t kDummyPid;
private:
void ExpectSessionBoilerplate(const string& email_string,
bool guest,
bool for_owner) {
EXPECT_CALL(manager_,
SetBrowserSessionForUser(StrEq(email_string),
StrEq(SanitizeUserName(email_string))))
.Times(1);
// Expect initialization of the device policy service, return success.
EXPECT_CALL(*device_policy_service_,
CheckAndHandleOwnerLogin(StrEq(email_string), _, _, _))
.WillOnce(DoAll(SetArgumentPointee<2>(for_owner),
Return(true)));
// Confirm that the key is present.
EXPECT_CALL(*device_policy_service_, KeyMissing())
.WillOnce(Return(false));
EXPECT_CALL(metrics_, SendLoginUserType(false, guest, for_owner))
.Times(1);
EXPECT_CALL(utils_,
EmitSignalWithStringArgs(
StrEq(login_manager::kSessionStateChangedSignal),
ElementsAre(SessionManagerImpl::kStarted)))
.Times(1);
EXPECT_CALL(utils_, IsDevMode())
.WillOnce(Return(false));
}
void ExpectStartSessionUnownedBoilerplate(const string& email_string,
bool mitigating,
bool owning_in_progress) {
EXPECT_CALL(manager_,
SetBrowserSessionForUser(StrEq(email_string),
StrEq(SanitizeUserName(email_string))))
.Times(1);
// Expect initialization of the device policy service, return success.
EXPECT_CALL(*device_policy_service_,
CheckAndHandleOwnerLogin(StrEq(email_string), _, _, _))
.WillOnce(DoAll(SetArgumentPointee<2>(false),
Return(true)));
// Indicate that there is no owner key in order to trigger a new one to be
// generated.
EXPECT_CALL(*device_policy_service_, KeyMissing())
.WillOnce(Return(true));
EXPECT_CALL(*device_policy_service_, Mitigating())
.WillRepeatedly(Return(mitigating));
if (!mitigating && !owning_in_progress)
EXPECT_CALL(manager_, RunKeyGenerator(StrEq(email_string))).Times(1);
else
EXPECT_CALL(manager_, RunKeyGenerator(_)).Times(0);
EXPECT_CALL(utils_,
EmitSignalWithStringArgs(
StrEq(login_manager::kSessionStateChangedSignal),
ElementsAre(SessionManagerImpl::kStarted)))
.Times(1);
EXPECT_CALL(utils_, IsDevMode())
.WillOnce(Return(false));
}
DISALLOW_COPY_AND_ASSIGN(SessionManagerImplTest);
string fake_salt_;
};
const pid_t SessionManagerImplTest::kDummyPid = 4;
TEST_F(SessionManagerImplTest, EmitLoginPromptVisible) {
const char event_name[] = "login-prompt-visible";
EXPECT_CALL(metrics_, RecordStats(StrEq(event_name))).Times(1);
EXPECT_CALL(utils_,
EmitSignal(StrEq(login_manager::kLoginPromptVisibleSignal)))
.Times(1);
EXPECT_TRUE(impl_.EmitLoginPromptVisible(NULL));
}
TEST_F(SessionManagerImplTest, EnableChromeTesting) {
// DBus arrays are null-terminated.
const gchar* args1[] = {"--repeat-arg", "--one-time-arg", NULL};
gchar* testing_path = NULL;
base::FilePath expected = utils_.GetUniqueFilename();
ASSERT_FALSE(expected.empty());
string expected_testing_path = expected.value();
EXPECT_CALL(manager_,
RestartBrowserWithArgs(
ElementsAre(args1[0], args1[1],
HasSubstr(expected_testing_path)),
true))
.Times(1);
EXPECT_TRUE(impl_.EnableChromeTesting(false, args1, &testing_path, NULL));
ASSERT_TRUE(testing_path != NULL);
EXPECT_TRUE(EndsWith(testing_path, expected_testing_path, false));
// Calling again, without forcing relaunch, should not do anything.
testing_path = NULL;
EXPECT_TRUE(impl_.EnableChromeTesting(false, args1, &testing_path, NULL));
ASSERT_TRUE(testing_path != NULL);
EXPECT_TRUE(EndsWith(testing_path, expected_testing_path, false));
// Force relaunch. Should go through the whole path again.
const gchar* args2[] = {"--dummy", "--repeat-arg", NULL};
testing_path = NULL;
EXPECT_CALL(manager_,
RestartBrowserWithArgs(
ElementsAre(args2[0], args2[1],
HasSubstr(expected_testing_path)),
true))
.Times(1);
EXPECT_TRUE(impl_.EnableChromeTesting(true, args2, &testing_path, NULL));
ASSERT_TRUE(testing_path != NULL);
EXPECT_TRUE(EndsWith(testing_path, expected_testing_path, false));
}
TEST_F(SessionManagerImplTest, StartSession) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSession(email);
ScopedError error;
EXPECT_EQ(TRUE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
}
TEST_F(SessionManagerImplTest, StartSession_New) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSessionUnowned(email);
ScopedError error;
EXPECT_EQ(TRUE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
}
TEST_F(SessionManagerImplTest, StartSession_InvalidUser) {
gboolean out;
gchar email[] = "user";
gchar nothing[] = "";
ScopedError error;
EXPECT_EQ(FALSE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
EXPECT_EQ(CHROMEOS_LOGIN_ERROR_INVALID_EMAIL, error->code);
}
TEST_F(SessionManagerImplTest, StartSession_Twice) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSession(email);
ScopedError error;
EXPECT_EQ(TRUE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
EXPECT_EQ(FALSE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
EXPECT_EQ(CHROMEOS_LOGIN_ERROR_SESSION_EXISTS, error->code);
}
TEST_F(SessionManagerImplTest, StartSession_TwoUsers) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSession(email);
ScopedError error;
EXPECT_EQ(TRUE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
VerifyAndClearExpectations();
gchar email2[] = "user2@somewhere";
ExpectStartSession(email2);
EXPECT_EQ(TRUE, impl_.StartSession(email2,
nothing,
&out,
&Resetter(&error).lvalue()));
}
TEST_F(SessionManagerImplTest, StartSession_OwnerAndOther) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSessionUnowned(email);
EXPECT_EQ(TRUE, impl_.StartSession(email, nothing, &out, NULL));
VerifyAndClearExpectations();
gchar email2[] = "user2@somewhere";
ExpectStartSession(email2);
EXPECT_EQ(TRUE, impl_.StartSession(email2, nothing, &out, NULL));
}
TEST_F(SessionManagerImplTest, StartSession_OwnerRace) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSessionUnowned(email);
EXPECT_EQ(TRUE, impl_.StartSession(email, nothing, &out, NULL));
VerifyAndClearExpectations();
gchar email2[] = "user2@somewhere";
ExpectStartSessionOwningInProcess(email2);
EXPECT_EQ(TRUE, impl_.StartSession(email2, nothing, &out, NULL));
}
TEST_F(SessionManagerImplTest, StartSession_BadNssDB) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ScopedError error;
nss_.MakeBadDB();
EXPECT_EQ(FALSE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
EXPECT_EQ(CHROMEOS_LOGIN_ERROR_NO_USER_NSSDB, error->code);
}
TEST_F(SessionManagerImplTest, StartSession_DevicePolicyFailure) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ScopedError error;
// Upon the owner login check, return an error.
EXPECT_CALL(*device_policy_service_,
CheckAndHandleOwnerLogin(StrEq(email), _, _, _))
.WillOnce(Return(false));
EXPECT_EQ(FALSE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
}
TEST_F(SessionManagerImplTest, StartSession_Owner) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartOwnerSession(email);
ScopedError error;
EXPECT_EQ(TRUE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
}
TEST_F(SessionManagerImplTest, StartSession_KeyMitigation) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSessionOwnerLost(email);
ScopedError error;
EXPECT_EQ(TRUE, impl_.StartSession(email,
nothing,
&out,
&Resetter(&error).lvalue()));
}
TEST_F(SessionManagerImplTest, StopSession) {
gboolean out;
gchar nothing[] = "";
EXPECT_CALL(manager_, ScheduleShutdown()).Times(1);
impl_.StopSession(nothing, &out, NULL);
}
TEST_F(SessionManagerImplTest, StorePolicy_NoSession) {
const string fake_policy("fake policy");
GArray* policy_blob = CreateArray(fake_policy.c_str(), fake_policy.size());
ExpectStorePolicy(device_policy_service_,
fake_policy,
PolicyService::KEY_ROTATE |
PolicyService::KEY_INSTALL_NEW |
PolicyService::KEY_CLOBBER);
EXPECT_EQ(TRUE, impl_.StorePolicy(policy_blob, NULL));
g_array_free(policy_blob, TRUE);
}
TEST_F(SessionManagerImplTest, StorePolicy_SessionStarted) {
ExpectAndRunStartSession("user@somewhere");
const string fake_policy("fake policy");
GArray* policy_blob = CreateArray(fake_policy.c_str(), fake_policy.size());
ExpectStorePolicy(device_policy_service_,
fake_policy,
PolicyService::KEY_ROTATE);
EXPECT_EQ(TRUE, impl_.StorePolicy(policy_blob, NULL));
g_array_free(policy_blob, TRUE);
}
TEST_F(SessionManagerImplTest, RetrievePolicy) {
const string fake_policy("fake policy");
const vector<uint8> policy_data(fake_policy.begin(), fake_policy.end());
EXPECT_CALL(*device_policy_service_, Retrieve(_))
.WillOnce(DoAll(SetArgumentPointee<0>(policy_data),
Return(true)));
GArray* out_blob;
ScopedError error;
EXPECT_EQ(TRUE, impl_.RetrievePolicy(&out_blob,
&Resetter(&error).lvalue()));
EXPECT_EQ(fake_policy.size(), out_blob->len);
EXPECT_TRUE(
std::equal(fake_policy.begin(), fake_policy.end(), out_blob->data));
g_array_free(out_blob, TRUE);
}
TEST_F(SessionManagerImplTest, StoreUserPolicy_NoSession) {
EXPECT_CALL(utils_, SetAndSendGError(_, _, _));
gchar username[] = "user@somewhere.com";
const string fake_policy("fake policy");
GArray* policy_blob = CreateArray(fake_policy.c_str(), fake_policy.size());
EXPECT_EQ(FALSE, impl_.StorePolicyForUser(username, policy_blob, NULL));
g_array_free(policy_blob, TRUE);
}
TEST_F(SessionManagerImplTest, StoreUserPolicy_SessionStarted) {
gchar username[] = "user@somewhere.com";
ExpectAndRunStartSession(username);
const string fake_policy("fake policy");
GArray* policy_blob = CreateArray(fake_policy.c_str(), fake_policy.size());
EXPECT_CALL(*user_policy_services_[username],
Store(CastEq(fake_policy),
fake_policy.size(),
_,
PolicyService::KEY_ROTATE |
PolicyService::KEY_INSTALL_NEW))
.WillOnce(Return(true));
EXPECT_EQ(TRUE, impl_.StorePolicyForUser(username, policy_blob, NULL));
g_array_free(policy_blob, TRUE);
}
TEST_F(SessionManagerImplTest, StoreUserPolicy_SecondSession) {
EXPECT_CALL(utils_, SetAndSendGError(_, _, _));
gchar user1[] = "user1@somewhere.com";
ExpectAndRunStartSession(user1);
ASSERT_TRUE(user_policy_services_[user1]);
// Store policy for the signed-in user.
const std::string fake_policy("fake policy");
GArray* policy_blob = CreateArray(fake_policy.c_str(), fake_policy.size());
EXPECT_CALL(*user_policy_services_[user1],
Store(CastEq(fake_policy),
fake_policy.size(),
_,
PolicyService::KEY_ROTATE |
PolicyService::KEY_INSTALL_NEW))
.WillOnce(Return(true));
EXPECT_EQ(TRUE, impl_.StorePolicyForUser(user1, policy_blob, NULL));
Mock::VerifyAndClearExpectations(user_policy_services_[user1]);
// Storing policy for another username fails before his session starts.
gchar user2[] = "user2@somewhere.com";
EXPECT_EQ(FALSE, impl_.StorePolicyForUser(user2, policy_blob, NULL));
// Now start another session for the 2nd user.
ExpectAndRunStartSession(user2);
ASSERT_TRUE(user_policy_services_[user2]);
// Storing policy for that user now succeeds.
EXPECT_CALL(*user_policy_services_[user2],
Store(CastEq(fake_policy),
fake_policy.size(),
_,
PolicyService::KEY_ROTATE |
PolicyService::KEY_INSTALL_NEW))
.WillOnce(Return(true));
EXPECT_EQ(TRUE, impl_.StorePolicyForUser(user2, policy_blob, NULL));
Mock::VerifyAndClearExpectations(user_policy_services_[user2]);
// Cleanup.
g_array_free(policy_blob, TRUE);
}
TEST_F(SessionManagerImplTest, RetrieveUserPolicy_NoSession) {
gchar username[] = "user@somewhere.com";
GArray* out_blob = NULL;
ScopedError error;
EXPECT_EQ(FALSE, impl_.RetrievePolicyForUser(username,
&out_blob,
&Resetter(&error).lvalue()));
EXPECT_FALSE(out_blob);
}
TEST_F(SessionManagerImplTest, RetrieveUserPolicy_SessionStarted) {
gchar username[] = "user@somewhere.com";
ExpectAndRunStartSession(username);
const string fake_policy("fake policy");
const vector<uint8> policy_data(fake_policy.begin(), fake_policy.end());
EXPECT_CALL(*user_policy_services_[username], Retrieve(_))
.WillOnce(DoAll(SetArgumentPointee<0>(policy_data),
Return(true)));
GArray* out_blob = NULL;
ScopedError error;
EXPECT_EQ(TRUE, impl_.RetrievePolicyForUser(username,
&out_blob,
&Resetter(&error).lvalue()));
EXPECT_EQ(fake_policy.size(), out_blob->len);
EXPECT_TRUE(
std::equal(fake_policy.begin(), fake_policy.end(), out_blob->data));
g_array_free(out_blob, TRUE);
}
TEST_F(SessionManagerImplTest, RetrieveUserPolicy_SecondSession) {
gchar user1[] = "user1@somewhere.com";
ExpectAndRunStartSession(user1);
ASSERT_TRUE(user_policy_services_[user1]);
// Retrieve policy for the signed-in user.
const std::string fake_policy("fake policy");
const std::vector<uint8> policy_data(fake_policy.begin(), fake_policy.end());
EXPECT_CALL(*user_policy_services_[user1], Retrieve(_))
.WillOnce(DoAll(SetArgumentPointee<0>(policy_data),
Return(true)));
GArray* out_blob = NULL;
ScopedError error;
EXPECT_EQ(TRUE, impl_.RetrievePolicyForUser(user1,
&out_blob,
&Resetter(&error).lvalue()));
Mock::VerifyAndClearExpectations(user_policy_services_[user1]);
EXPECT_EQ(fake_policy.size(), out_blob->len);
EXPECT_TRUE(
std::equal(fake_policy.begin(), fake_policy.end(), out_blob->data));
g_array_free(out_blob, TRUE);
// Retrieving policy for another username fails before his session starts.
gchar user2[] = "user2@somewhere.com";
out_blob = NULL;
error.reset();
EXPECT_EQ(FALSE, impl_.RetrievePolicyForUser(user2,
&out_blob,
&Resetter(&error).lvalue()));
// Now start another session for the 2nd user.
ExpectAndRunStartSession(user2);
ASSERT_TRUE(user_policy_services_[user2]);
// Retrieving policy for that user now succeeds.
EXPECT_CALL(*user_policy_services_[user2], Retrieve(_))
.WillOnce(DoAll(SetArgumentPointee<0>(policy_data),
Return(true)));
out_blob = NULL;
error.reset();
EXPECT_EQ(TRUE, impl_.RetrievePolicyForUser(user2,
&out_blob,
&Resetter(&error).lvalue()));
Mock::VerifyAndClearExpectations(user_policy_services_[user2]);
EXPECT_EQ(fake_policy.size(), out_blob->len);
EXPECT_TRUE(
std::equal(fake_policy.begin(), fake_policy.end(), out_blob->data));
g_array_free(out_blob, TRUE);
}
TEST_F(SessionManagerImplTest, RetrieveActiveSessions) {
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartSession(email);
EXPECT_EQ(TRUE, impl_.StartSession(email, nothing, &out, NULL));
GHashTable* active_users = impl_.RetrieveActiveSessions();
EXPECT_EQ(g_hash_table_size(active_users), 1);
EXPECT_EQ(reinterpret_cast<char*>(g_hash_table_lookup(active_users, email)),
SanitizeUserName(email));
g_hash_table_unref(active_users);
VerifyAndClearExpectations();
gchar email2[] = "user2@somewhere";
ExpectStartSession(email2);
EXPECT_EQ(TRUE, impl_.StartSession(email2, nothing, &out, NULL));
active_users = impl_.RetrieveActiveSessions();
EXPECT_EQ(g_hash_table_size(active_users), 2);
EXPECT_EQ(reinterpret_cast<char*>(g_hash_table_lookup(active_users, email)),
SanitizeUserName(email));
EXPECT_EQ(reinterpret_cast<char*>(g_hash_table_lookup(active_users, email2)),
SanitizeUserName(email2));
g_hash_table_unref(active_users);
}
TEST_F(SessionManagerImplTest, RestartJob_UnknownPid) {
gboolean out;
gint pid = kDummyPid;
gchar arguments[] = "";
ScopedError error;
EXPECT_CALL(manager_, IsBrowser(pid)).WillOnce(Return(false));
EXPECT_EQ(FALSE, impl_.RestartJob(pid, arguments, &out,
&Resetter(&error).lvalue()));
EXPECT_EQ(CHROMEOS_LOGIN_ERROR_UNKNOWN_PID, error->code);
EXPECT_EQ(FALSE, out);
}
TEST_F(SessionManagerImplTest, RestartJob) {
gboolean out;
gint pid = kDummyPid;
gchar arguments[] = "dummy";
EXPECT_CALL(manager_, IsBrowser(pid)).WillOnce(Return(true));
EXPECT_CALL(manager_, RestartBrowserWithArgs(ElementsAre(arguments), false))
.Times(1);
ExpectGuestSession();
EXPECT_EQ(TRUE, impl_.RestartJob(pid, arguments, &out, NULL));
EXPECT_EQ(TRUE, out);
}
TEST_F(SessionManagerImplTest, RestartJobWithAuth_BadCookie) {
gboolean out;
gint pid = kDummyPid;
gchar cookie[] = "bogus-cookie";
gchar arguments[] = "dummy";
// Ensure there's no browser restarting.
EXPECT_CALL(manager_, RestartBrowserWithArgs(_, _)).Times(0);
EXPECT_EQ(FALSE, impl_.RestartJobWithAuth(pid, cookie, arguments, &out,
NULL));
EXPECT_EQ(FALSE, out);
}
TEST_F(SessionManagerImplTest, LockScreen) {
ExpectAndRunStartSession("user@somewhere");
EXPECT_CALL(utils_, EmitSignal(StrEq(chromium::kLockScreenSignal))).Times(1);
GError *error = NULL;
EXPECT_EQ(TRUE, impl_.LockScreen(&error));
EXPECT_EQ(TRUE, impl_.ScreenIsLocked());
}
TEST_F(SessionManagerImplTest, LockScreen_MultiSession) {
ExpectAndRunStartSession("user@somewhere");
ExpectAndRunStartSession("user2@somewhere");
EXPECT_CALL(utils_, EmitSignal(StrEq(chromium::kLockScreenSignal))).Times(1);
GError *error = NULL;
EXPECT_EQ(TRUE, impl_.LockScreen(&error));
EXPECT_EQ(TRUE, impl_.ScreenIsLocked());
}
TEST_F(SessionManagerImplTest, LockScreen_NoSession) {
EXPECT_CALL(utils_, EmitSignal(StrEq(chromium::kLockScreenSignal))).Times(0);
GError *error = NULL;
EXPECT_EQ(FALSE, impl_.LockScreen(&error));
}
TEST_F(SessionManagerImplTest, LockScreen_Guest) {
ExpectAndRunGuestSession();
EXPECT_CALL(utils_, EmitSignal(StrEq(chromium::kLockScreenSignal))).Times(0);
GError *error = NULL;
EXPECT_EQ(FALSE, impl_.LockScreen(&error));
}
TEST_F(SessionManagerImplTest, LockScreen_UserAndGuest) {
ExpectAndRunStartSession("user@somewhere");
ExpectAndRunGuestSession();
EXPECT_CALL(utils_, EmitSignal(StrEq(chromium::kLockScreenSignal))).Times(1);
GError *error = NULL;
EXPECT_EQ(TRUE, impl_.LockScreen(&error));
EXPECT_EQ(TRUE, impl_.ScreenIsLocked());
}
TEST_F(SessionManagerImplTest, LockUnlockScreen) {
ExpectAndRunStartSession("user@somewhere");
EXPECT_CALL(utils_, EmitSignal(StrEq(chromium::kLockScreenSignal))).Times(1);
GError *error = NULL;
EXPECT_EQ(TRUE, impl_.LockScreen(&error));
EXPECT_EQ(TRUE, impl_.ScreenIsLocked());
EXPECT_CALL(utils_, EmitSignal(StrEq(login_manager::kScreenIsLockedSignal)))
.Times(1);
EXPECT_EQ(TRUE, impl_.HandleLockScreenShown(&error));
EXPECT_EQ(TRUE, impl_.ScreenIsLocked());
EXPECT_CALL(utils_, EmitSignal(StrEq(login_manager::kScreenIsUnlockedSignal)))
.Times(1);
EXPECT_EQ(TRUE, impl_.HandleLockScreenDismissed(&error));
EXPECT_EQ(FALSE, impl_.ScreenIsLocked());
}
TEST_F(SessionManagerImplTest, StartDeviceWipe_AlreadyLoggedIn) {
FilePath logged_in_path(SessionManagerImpl::kLoggedInFlag);
ASSERT_FALSE(utils_.Exists(logged_in_path));
ASSERT_TRUE(utils_.AtomicFileWrite(logged_in_path, "1", 1));
GError *error = NULL;
gboolean done = FALSE;
EXPECT_EQ(FALSE, impl_.StartDeviceWipe(&done, &error));
}
TEST_F(SessionManagerImplTest, StartDeviceWipe) {
FilePath logged_in_path(SessionManagerImpl::kLoggedInFlag);
FilePath reset_path(SessionManagerImpl::kResetFile);
ASSERT_TRUE(utils_.RemoveFile(logged_in_path));
EXPECT_CALL(utils_, CallMethodOnPowerManager(_)).Times(1);
gboolean done = FALSE;
EXPECT_EQ(TRUE, impl_.StartDeviceWipe(&done, NULL));
EXPECT_TRUE(done);
}
TEST_F(SessionManagerImplTest, ImportValidateAndStoreGeneratedKey) {
base::ScopedTempDir tmpdir;
FilePath key_file_path;
string key("key_contents");
ASSERT_TRUE(tmpdir.CreateUniqueTempDir());
ASSERT_TRUE(file_util::CreateTemporaryFileInDir(tmpdir.path(),
&key_file_path));
ASSERT_EQ(file_util::WriteFile(key_file_path, key.c_str(), key.size()),
key.size());
// Start a session, to set up NSSDB for the user.
gboolean out;
gchar email[] = "user@somewhere";
gchar nothing[] = "";
ExpectStartOwnerSession(email);
ASSERT_EQ(TRUE, impl_.StartSession(email, nothing, &out, NULL));
EXPECT_CALL(*device_policy_service_,
ValidateAndStoreOwnerKey(StrEq(email),
StrEq(key),
nss_.GetSlot()))
.WillOnce(Return(true));
impl_.ImportValidateAndStoreGeneratedKey(email, key_file_path);
EXPECT_FALSE(file_util::PathExists(key_file_path));
}
class SessionManagerImplStaticTest : public ::testing::Test {
public:
SessionManagerImplStaticTest() {}
virtual ~SessionManagerImplStaticTest() {}
bool ValidateEmail(const string& email_address) {
return SessionManagerImpl::ValidateEmail(email_address);
}
};
TEST_F(SessionManagerImplStaticTest, EmailAddressTest) {
const char valid[] = "user_who+we.like@some-where.com";
EXPECT_TRUE(ValidateEmail(valid));
}
TEST_F(SessionManagerImplStaticTest, EmailAddressNonAsciiTest) {
char invalid[4] = "a@m";
invalid[2] = 254;
EXPECT_FALSE(ValidateEmail(invalid));
}
TEST_F(SessionManagerImplStaticTest, EmailAddressNoAtTest) {
const char no_at[] = "user";
EXPECT_FALSE(ValidateEmail(no_at));
}
TEST_F(SessionManagerImplStaticTest, EmailAddressTooMuchAtTest) {
const char extra_at[] = "user@what@where";
EXPECT_FALSE(ValidateEmail(extra_at));
}
} // namespace login_manager