0

Implement a policy to autologin a public account.

This introduces a policy to automatically login a public account on
Chrome OS after a specified period of time has elapsed at the login
screen.  There are two new policy settings:
"DeviceLocalAccountAutoLoginUsername", which determines which public
account will be logged in, and "DeviceLocalAccountAutoLoginTimerMillis",
which specifies the amount of time that should elapse before autologin
takes place.

The autologin timer is started in ExistingUserController when either the
sign-in screen UI is finished loading or the aforementioned policy
settings are changed.

BUG=152933


Review URL: https://chromiumcodereview.appspot.com/12218078

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@188331 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
dconnelly@chromium.org
2013-03-15 10:56:47 +00:00
parent 5502530968
commit 60697c6530
29 changed files with 1409 additions and 85 deletions

@ -112,7 +112,7 @@
# persistent IDs for all fields (but not for groups!) are needed. These are
# specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs,
# because doing so would break the deployed wire format!
# For your editing convenience: highest ID currently used: 191
# For your editing convenience: highest ID currently used: 193
#
# Placeholders:
# The following placeholder strings are automatically substituted:
@ -3542,6 +3542,46 @@
Every list entry specifies an identifier, which is used internally to tell the different device-local accounts apart.''',
},
{
'name': 'DeviceLocalAccountAutoLoginId',
'type': 'string',
'schema': { 'type': 'string' },
'supported_on': ['chrome_os:26-'],
'device_only': True,
'features': {
'dynamic_refresh': True,
},
'example_value': "public@example.com",
'id': 192,
'caption': '''Public session for auto-login''',
'desc': '''A public session to auto-login after a delay.
If this policy is set, the specified session will be automatically logged in after a period of time has elapsed at the login screen without user interaction. The public session must already be configured (see |DeviceLocalAccounts|).
If this policy is unset, there will be no auto-login.''',
},
{
'name': 'DeviceLocalAccountAutoLoginDelay',
'type': 'int',
'schema': { 'type': 'integer' },
'supported_on': ['chrome_os:26-'],
'device_only': True,
'features': {
'dynamic_refresh': True,
},
'example_value': 180000,
'id': 193,
'caption': '''Public session auto-login timer''',
'desc': '''The public session auto-login delay.
If the |DeviceLocalAccountAutoLoginId| policy is unset, this policy has no effect. Otherwise:
If this policy is set, it determines the amount of time without user activity that should elapse before automatically logging into the public session specified by the |DeviceLocalAccountAutoLoginId| policy.
If this policy is unset, 0 milliseconds will be used as the timeout.
This policy is specified in milliseconds.'''
},
{
'name': 'BackgroundModeEnabled',
'type': 'main',

@ -32,6 +32,7 @@
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/net/connectivity_state_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/cros_settings_names.h"
#include "chrome/browser/chromeos/system/statistics_provider.h"
#include "chrome/browser/google/google_util.h"
#include "chrome/browser/policy/policy_service.h"
@ -143,7 +144,8 @@ ExistingUserController::ExistingUserController(LoginDisplayHost* host)
offline_failed_(false),
is_login_in_progress_(false),
password_changed_(false),
do_auto_enrollment_(false) {
do_auto_enrollment_(false),
signin_screen_ready_(false) {
DCHECK(current_controller_ == NULL);
current_controller_ = this;
@ -163,11 +165,18 @@ ExistingUserController::ExistingUserController(LoginDisplayHost* host)
cros_settings_->AddSettingsObserver(kAccountsPrefAllowNewUser, this);
cros_settings_->AddSettingsObserver(kAccountsPrefAllowGuest, this);
cros_settings_->AddSettingsObserver(kAccountsPrefUsers, this);
cros_settings_->AddSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginId,
this);
cros_settings_->AddSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
this);
}
void ExistingUserController::Init(const UserList& users) {
time_init_ = base::Time::Now();
UpdateLoginDisplay(users);
ConfigurePublicSessionAutoLogin();
LoginUtils::Get()->PrewarmAuthentication();
DBusThreadManager::Get()->GetSessionManagerClient()->EmitLoginPromptReady();
@ -237,6 +246,14 @@ void ExistingUserController::Observe(
registrar_.RemoveAll();
return;
}
if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED) {
const std::string setting = *content::Details<const std::string>(
details).ptr();
if (setting == kAccountsPrefDeviceLocalAccountAutoLoginId ||
setting == kAccountsPrefDeviceLocalAccountAutoLoginDelay) {
ConfigurePublicSessionAutoLogin();
}
}
if (type == chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED ||
type == chrome::NOTIFICATION_USER_LIST_CHANGED) {
if (host_ != NULL) {
@ -286,6 +303,12 @@ ExistingUserController::~ExistingUserController() {
cros_settings_->RemoveSettingsObserver(kAccountsPrefAllowNewUser, this);
cros_settings_->RemoveSettingsObserver(kAccountsPrefAllowGuest, this);
cros_settings_->RemoveSettingsObserver(kAccountsPrefUsers, this);
cros_settings_->RemoveSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginId,
this);
cros_settings_->RemoveSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
this);
if (current_controller_ == this) {
current_controller_ = NULL;
@ -302,6 +325,7 @@ ExistingUserController::~ExistingUserController() {
void ExistingUserController::CancelPasswordChangedFlow() {
login_performer_.reset(NULL);
login_display_->SetUIEnabled(true);
StartPublicSessionAutoLoginTimer();
}
void ExistingUserController::CreateAccount() {
@ -319,6 +343,7 @@ void ExistingUserController::CreateLocallyManagedUser(
return;
// Disable clicking on other windows.
StopPublicSessionAutoLoginTimer();
login_display_->SetUIEnabled(false);
LoginPerformer::Delegate* delegate = this;
@ -340,6 +365,9 @@ void ExistingUserController::CompleteLogin(const std::string& username,
return;
}
// Stop the auto-login timer when attempting login.
StopPublicSessionAutoLoginTimer();
// Disable UI while loading user profile.
login_display_->SetUIEnabled(false);
@ -396,6 +424,10 @@ void ExistingUserController::Login(const std::string& username,
const std::string& password) {
if (username.empty() || password.empty())
return;
// Stop the auto-login timer when attempting login.
StopPublicSessionAutoLoginTimer();
// Disable clicking on other windows.
login_display_->SetUIEnabled(false);
@ -443,6 +475,9 @@ void ExistingUserController::PerformLogin(
}
void ExistingUserController::LoginAsRetailModeUser() {
// Stop the auto-login timer when attempting login.
StopPublicSessionAutoLoginTimer();
// Disable clicking on other windows.
login_display_->SetUIEnabled(false);
// TODO(rkc): Add a CHECK to make sure retail mode logins are allowed once
@ -458,6 +493,9 @@ void ExistingUserController::LoginAsRetailModeUser() {
}
void ExistingUserController::LoginAsGuest() {
// Stop the auto-login timer when attempting login.
StopPublicSessionAutoLoginTimer();
// Disable clicking on other windows.
login_display_->SetUIEnabled(false);
@ -471,6 +509,7 @@ void ExistingUserController::LoginAsGuest() {
HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
// Reenable clicking on other windows and status area.
login_display_->SetUIEnabled(true);
StartPublicSessionAutoLoginTimer();
display_email_.clear();
return;
} else if (status != CrosSettingsProvider::TRUSTED) {
@ -489,6 +528,7 @@ void ExistingUserController::LoginAsGuest() {
HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT);
// Reenable clicking on other windows and status area.
login_display_->SetUIEnabled(true);
StartPublicSessionAutoLoginTimer();
display_email_.clear();
return;
}
@ -510,6 +550,9 @@ void ExistingUserController::MigrateUserData(const std::string& old_password) {
void ExistingUserController::LoginAsPublicAccount(
const std::string& username) {
// Stop the auto-login timer when attempting login.
StopPublicSessionAutoLoginTimer();
// Disable clicking on other windows.
login_display_->SetUIEnabled(false);
@ -539,6 +582,7 @@ void ExistingUserController::LoginAsPublicAccount(
if (!user || user->GetType() != User::USER_TYPE_PUBLIC_ACCOUNT) {
// Re-enable clicking on other windows.
login_display_->SetUIEnabled(true);
StartPublicSessionAutoLoginTimer();
return;
}
@ -551,6 +595,11 @@ void ExistingUserController::LoginAsPublicAccount(
l10n_util::GetStringUTF8(IDS_CHROMEOS_ACC_LOGIN_SIGNIN_PUBLIC_ACCOUNT));
}
void ExistingUserController::OnSigninScreenReady() {
signin_screen_ready_ = true;
StartPublicSessionAutoLoginTimer();
}
void ExistingUserController::OnUserSelected(const std::string& username) {
login_performer_.reset(NULL);
num_login_attempts_ = 0;
@ -686,6 +735,7 @@ void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
}
// Reenable clicking on other windows and status area.
login_display_->SetUIEnabled(true);
StartPublicSessionAutoLoginTimer();
}
// Reset user flow to default, so that special flow will not affect next
@ -707,6 +757,8 @@ void ExistingUserController::OnLoginSuccess(
is_login_in_progress_ = false;
offline_failed_ = false;
StopPublicSessionAutoLoginTimer();
bool has_cookies =
login_performer_->auth_mode() == LoginPerformer::AUTH_MODE_EXTENSION;
@ -832,6 +884,8 @@ void ExistingUserController::WhiteListCheckFailed(const std::string& email) {
}
display_email_.clear();
StartPublicSessionAutoLoginTimer();
}
void ExistingUserController::PolicyLoadFailed() {
@ -841,6 +895,9 @@ void ExistingUserController::PolicyLoadFailed() {
login_display_->SetUIEnabled(true);
display_email_.clear();
// Policy load failure stops login attempts -- restart the timer.
StartPublicSessionAutoLoginTimer();
}
void ExistingUserController::OnOnlineChecked(const std::string& username,
@ -865,6 +922,64 @@ void ExistingUserController::ActivateWizard(const std::string& screen_name) {
host_->StartWizard(screen_name, params);
}
void ExistingUserController::ConfigurePublicSessionAutoLogin() {
if (!cros_settings_->GetString(
kAccountsPrefDeviceLocalAccountAutoLoginId,
&public_session_auto_login_username_)) {
public_session_auto_login_username_.clear();
}
if (!cros_settings_->GetInteger(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
&public_session_auto_login_delay_)) {
public_session_auto_login_delay_ = 0;
}
if (!public_session_auto_login_username_.empty())
StartPublicSessionAutoLoginTimer();
else
StopPublicSessionAutoLoginTimer();
}
void ExistingUserController::ResetPublicSessionAutoLoginTimer() {
// Only restart the auto-login timer if it's already running.
if (auto_login_timer_ && auto_login_timer_->IsRunning()) {
StopPublicSessionAutoLoginTimer();
StartPublicSessionAutoLoginTimer();
}
}
void ExistingUserController::OnPublicSessionAutoLoginTimerFire() {
CHECK(signin_screen_ready_ &&
!is_login_in_progress_ &&
!public_session_auto_login_username_.empty());
LoginAsPublicAccount(public_session_auto_login_username_);
}
void ExistingUserController::StopPublicSessionAutoLoginTimer() {
if (auto_login_timer_)
auto_login_timer_->Stop();
}
void ExistingUserController::StartPublicSessionAutoLoginTimer() {
if (!signin_screen_ready_ ||
is_login_in_progress_ ||
public_session_auto_login_username_.empty()) {
return;
}
// Start the auto-login timer.
if (!auto_login_timer_)
auto_login_timer_.reset(new base::OneShotTimer<ExistingUserController>);
auto_login_timer_->Start(
FROM_HERE,
base::TimeDelta::FromMilliseconds(
public_session_auto_login_delay_),
base::Bind(
&ExistingUserController::OnPublicSessionAutoLoginTimerFire,
weak_factory_.GetWeakPtr()));
}
gfx::NativeWindow ExistingUserController::GetNativeWindow() const {
return host_->GetNativeWindow();
}

@ -7,6 +7,7 @@
#include <string>
#include "base/basictypes.h"
#include "base/callback_forward.h"
#include "base/compiler_specific.h"
#include "base/gtest_prod_util.h"
@ -67,6 +68,12 @@ class ExistingUserController : public LoginDisplay::Delegate,
// Invoked when a kiosk app launch is failed.
void OnKioskAppLaunchFailed();
// Start the public session auto-login timer.
void StartPublicSessionAutoLoginTimer();
// Stop the public session auto-login timer when a login attempt begins.
void StopPublicSessionAutoLoginTimer();
// LoginDisplay::Delegate: implementation
virtual void CancelPasswordChangedFlow() OVERRIDE;
virtual void CreateAccount() OVERRIDE;
@ -81,9 +88,11 @@ class ExistingUserController : public LoginDisplay::Delegate,
virtual void LoginAsRetailModeUser() OVERRIDE;
virtual void LoginAsGuest() OVERRIDE;
virtual void LoginAsPublicAccount(const std::string& username) OVERRIDE;
virtual void OnSigninScreenReady() OVERRIDE;
virtual void OnUserSelected(const std::string& username) OVERRIDE;
virtual void OnStartEnterpriseEnrollment() OVERRIDE;
virtual void OnStartDeviceReset() OVERRIDE;
virtual void ResetPublicSessionAutoLoginTimer() OVERRIDE;
virtual void ResyncUserData() OVERRIDE;
virtual void SetDisplayEmail(const std::string& email) OVERRIDE;
virtual void ShowWrongHWIDScreen() OVERRIDE;
@ -113,8 +122,16 @@ class ExistingUserController : public LoginDisplay::Delegate,
private:
friend class ExistingUserControllerTest;
friend class ExistingUserControllerAutoLoginTest;
friend class ExistingUserControllerPublicSessionTest;
friend class MockLoginPerformerDelegate;
// Retrieve public session auto-login policy and update the timer.
void ConfigurePublicSessionAutoLogin();
// Trigger public session auto-login.
void OnPublicSessionAutoLoginTimerFire();
// LoginPerformer::Delegate implementation:
virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE;
virtual void OnLoginSuccess(
@ -195,6 +212,15 @@ class ExistingUserController : public LoginDisplay::Delegate,
// Updates the |login_display_| attached to this controller.
void UpdateLoginDisplay(const UserList& users);
// Public session auto-login timer.
scoped_ptr<base::OneShotTimer<ExistingUserController> > auto_login_timer_;
// Public session auto-login timeout, in milliseconds.
int public_session_auto_login_delay_;
// Username for public session auto-login.
std::string public_session_auto_login_username_;
// Used to execute login operations.
scoped_ptr<LoginPerformer> login_performer_;
@ -255,6 +281,9 @@ class ExistingUserController : public LoginDisplay::Delegate,
// session.
bool do_auto_enrollment_;
// Whether the sign-in UI is finished loading.
bool signin_screen_ready_;
// The username used for auto-enrollment, if it was triggered.
std::string auto_enrollment_username_;

@ -0,0 +1,246 @@
// 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 "base/message_loop.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/mock_login_display.h"
#include "chrome/browser/chromeos/login/mock_login_display_host.h"
#include "chrome/browser/chromeos/login/mock_login_utils.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/cros_settings_names.h"
#include "chrome/browser/chromeos/settings/device_settings_test_helper.h"
#include "chrome/test/base/scoped_testing_local_state.h"
#include "chrome/test/base/testing_browser_process.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::Return;
using testing::_;
namespace chromeos {
namespace {
const char kAutoLoginUsername[] = "public_session_user@localhost";
// These values are only used to test the configuration. They don't
// delay the test.
const int kAutoLoginNoDelay = 0;
const int kAutoLoginDelay1 = 60000;
const int kAutoLoginDelay2 = 180000;
} // namespace
class ExistingUserControllerAutoLoginTest : public ::testing::Test {
protected:
ExistingUserControllerAutoLoginTest()
: message_loop_(MessageLoop::TYPE_UI),
ui_thread_(content::BrowserThread::UI, &message_loop_),
local_state_(TestingBrowserProcess::GetGlobal()) {
}
virtual void SetUp() {
mock_login_display_host_.reset(new MockLoginDisplayHost);
mock_login_display_ = new MockLoginDisplay();
mock_login_utils_ = new MockLoginUtils();
LoginUtils::Set(mock_login_utils_);
EXPECT_CALL(*mock_login_display_host_.get(), CreateLoginDisplay(_))
.Times(1)
.WillOnce(Return(mock_login_display_));
existing_user_controller_.reset(
new ExistingUserController(mock_login_display_host_.get()));
// Prevent settings changes from auto-starting the timer.
CrosSettings::Get()->RemoveSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginId,
existing_user_controller());
CrosSettings::Get()->RemoveSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
existing_user_controller());
}
const ExistingUserController* existing_user_controller() const {
return ExistingUserController::current_controller();
}
ExistingUserController* existing_user_controller() {
return ExistingUserController::current_controller();
}
void SetAutoLoginSettings(const std::string& username, int delay) {
CrosSettings::Get()->SetString(
kAccountsPrefDeviceLocalAccountAutoLoginId,
username);
CrosSettings::Get()->SetInteger(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
delay);
}
// ExistingUserController private member accessors.
base::OneShotTimer<ExistingUserController>* auto_login_timer() {
return existing_user_controller()->auto_login_timer_.get();
}
const std::string& auto_login_username() const {
return existing_user_controller()->public_session_auto_login_username_;
}
void set_auto_login_username(const std::string& username) {
existing_user_controller()->public_session_auto_login_username_ = username;
}
int auto_login_delay() const {
return existing_user_controller()->public_session_auto_login_delay_;
}
void set_auto_login_delay(int delay) {
existing_user_controller()->public_session_auto_login_delay_ = delay;
}
bool is_login_in_progress() const {
return existing_user_controller()->is_login_in_progress_;
}
void set_is_login_in_progress(bool is_login_in_progress) {
existing_user_controller()->is_login_in_progress_ = is_login_in_progress;
}
void ConfigureAutoLogin() {
existing_user_controller()->ConfigurePublicSessionAutoLogin();
}
private:
// Owned by LoginUtilsWrapper.
MockLoginUtils* mock_login_utils_;
// |mock_login_display_| is owned by the ExistingUserController, which calls
// CreateLoginDisplay() on the |mock_login_display_host_| to get it.
MockLoginDisplay* mock_login_display_;
scoped_ptr<MockLoginDisplayHost> mock_login_display_host_;
scoped_ptr<ExistingUserController> existing_user_controller_;
MessageLoop message_loop_;
content::TestBrowserThread ui_thread_;
ScopedTestingLocalState local_state_;
ScopedDeviceSettingsTestHelper device_settings_test_helper_;
};
TEST_F(ExistingUserControllerAutoLoginTest, StartAutoLoginTimer) {
// Timer shouldn't start until signin screen is ready.
set_auto_login_username(kAutoLoginUsername);
set_auto_login_delay(kAutoLoginDelay2);
existing_user_controller()->StartPublicSessionAutoLoginTimer();
EXPECT_FALSE(auto_login_timer());
// Timer shouldn't start if the policy isn't set.
set_auto_login_username("");
existing_user_controller()->OnSigninScreenReady();
existing_user_controller()->StartPublicSessionAutoLoginTimer();
EXPECT_FALSE(auto_login_timer());
// Timer shouldn't fire in the middle of a login attempt.
set_auto_login_username(kAutoLoginUsername);
set_is_login_in_progress(true);
existing_user_controller()->StartPublicSessionAutoLoginTimer();
EXPECT_FALSE(auto_login_timer());
// Otherwise start.
set_is_login_in_progress(false);
existing_user_controller()->StartPublicSessionAutoLoginTimer();
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
EXPECT_EQ(auto_login_timer()->GetCurrentDelay().InMilliseconds(),
kAutoLoginDelay2);
}
TEST_F(ExistingUserControllerAutoLoginTest, StopAutoLoginTimer) {
existing_user_controller()->OnSigninScreenReady();
set_auto_login_username(kAutoLoginUsername);
set_auto_login_delay(kAutoLoginDelay2);
existing_user_controller()->StartPublicSessionAutoLoginTimer();
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
existing_user_controller()->StopPublicSessionAutoLoginTimer();
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
TEST_F(ExistingUserControllerAutoLoginTest, ResetAutoLoginTimer) {
existing_user_controller()->OnSigninScreenReady();
set_auto_login_username(kAutoLoginUsername);
// Timer starts off not running.
EXPECT_FALSE(auto_login_timer());
// When the timer isn't running, nothing should happen.
existing_user_controller()->ResetPublicSessionAutoLoginTimer();
EXPECT_FALSE(auto_login_timer());
// Start the timer.
set_auto_login_delay(kAutoLoginDelay2);
existing_user_controller()->StartPublicSessionAutoLoginTimer();
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
EXPECT_EQ(auto_login_timer()->GetCurrentDelay().InMilliseconds(),
kAutoLoginDelay2);
// User activity should restart the timer, so check to see that the
// timer delay was modified.
set_auto_login_delay(kAutoLoginDelay1);
existing_user_controller()->ResetPublicSessionAutoLoginTimer();
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
EXPECT_EQ(auto_login_timer()->GetCurrentDelay().InMilliseconds(),
kAutoLoginDelay1);
}
TEST_F(ExistingUserControllerAutoLoginTest, ConfigureAutoLogin) {
existing_user_controller()->OnSigninScreenReady();
// Timer shouldn't start when the policy is disabled.
ConfigureAutoLogin();
EXPECT_FALSE(auto_login_timer());
EXPECT_EQ(auto_login_delay(), 0);
EXPECT_EQ(auto_login_username(), "");
// Timer shouldn't start when the delay alone is set.
SetAutoLoginSettings("", kAutoLoginDelay1);
ConfigureAutoLogin();
EXPECT_FALSE(auto_login_timer());
EXPECT_EQ(auto_login_delay(), kAutoLoginDelay1);
EXPECT_EQ(auto_login_username(), "");
// Timer should start when the username is set.
SetAutoLoginSettings(kAutoLoginUsername, kAutoLoginDelay1);
ConfigureAutoLogin();
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
EXPECT_EQ(auto_login_timer()->GetCurrentDelay().InMilliseconds(),
kAutoLoginDelay1);
EXPECT_EQ(auto_login_delay(), kAutoLoginDelay1);
EXPECT_EQ(auto_login_username(), kAutoLoginUsername);
// Timer should restart when the delay is changed.
SetAutoLoginSettings(kAutoLoginUsername, kAutoLoginDelay2);
ConfigureAutoLogin();
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
EXPECT_EQ(auto_login_timer()->GetCurrentDelay().InMilliseconds(),
kAutoLoginDelay2);
EXPECT_EQ(auto_login_delay(), kAutoLoginDelay2);
EXPECT_EQ(auto_login_username(), kAutoLoginUsername);
// Timer should stop when the username is unset.
SetAutoLoginSettings("", kAutoLoginDelay2);
ConfigureAutoLogin();
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
EXPECT_EQ(auto_login_timer()->GetCurrentDelay().InMilliseconds(),
kAutoLoginDelay2);
EXPECT_EQ(auto_login_username(), "");
EXPECT_EQ(auto_login_delay(), kAutoLoginDelay2);
}
} // namespace chromeos

@ -2,31 +2,60 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/location.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/stl_util.h"
#include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h"
#include "chrome/browser/chromeos/cros/cros_mock.h"
#include "chrome/browser/chromeos/cros/mock_network_library.h"
#include "chrome/browser/chromeos/login/authenticator.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/login_display.h"
#include "chrome/browser/chromeos/login/login_display_host.h"
#include "chrome/browser/chromeos/login/login_performer.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/login_utils.h"
#include "chrome/browser/chromeos/login/mock_authenticator.h"
#include "chrome/browser/chromeos/login/mock_login_display.h"
#include "chrome/browser/chromeos/login/mock_login_display_host.h"
#include "chrome/browser/chromeos/login/mock_login_utils.h"
#include "chrome/browser/chromeos/login/mock_url_fetchers.h"
#include "chrome/browser/chromeos/login/mock_user_manager.h"
#include "chrome/browser/chromeos/login/user_manager.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/browser/chromeos/policy/device_local_account_policy_service.h"
#include "chrome/browser/chromeos/policy/device_policy_builder.h"
#include "chrome/browser/chromeos/policy/proto/chrome_device_policy.pb.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/settings/cros_settings_names.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/browser/policy/cloud/cloud_policy_constants.h"
#include "chrome/browser/policy/cloud/cloud_policy_core.h"
#include "chrome/browser/policy/cloud/cloud_policy_store.h"
#include "chrome/browser/policy/cloud/mock_cloud_policy_store.h"
#include "chrome/browser/policy/cloud/policy_builder.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chromeos/dbus/fake_session_manager_client.h"
#include "chromeos/dbus/mock_dbus_thread_manager.h"
#include "chromeos/dbus/mock_session_manager_client.h"
#include "chromeos/dbus/mock_shill_manager_client.h"
#include "content/public/browser/notification_details.h"
#include "content/public/test/mock_notification_observer.h"
#include "content/public/test/test_utils.h"
#include "crypto/rsa_private_key.h"
#include "google_apis/gaia/mock_url_fetcher_factory.h"
#include "grit/generated_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
@ -43,6 +72,8 @@ using ::testing::ReturnNull;
using ::testing::Sequence;
using ::testing::WithArg;
namespace em = enterprise_management;
namespace chromeos {
namespace {
@ -51,56 +82,10 @@ const char kUsername[] = "test_user@gmail.com";
const char kNewUsername[] = "test_new_user@gmail.com";
const char kPassword[] = "test_password";
class MockLoginDisplay : public LoginDisplay {
public:
MockLoginDisplay()
: LoginDisplay(NULL, gfx::Rect()) {
}
MOCK_METHOD4(Init, void(const UserList&, bool, bool, bool));
MOCK_METHOD0(OnPreferencesChanged, void(void));
MOCK_METHOD1(OnUserImageChanged, void(const User&));
MOCK_METHOD0(OnFadeOut, void(void));
MOCK_METHOD1(OnLoginSuccess, void(const std::string&));
MOCK_METHOD1(SetUIEnabled, void(bool));
MOCK_METHOD1(SelectPod, void(int));
MOCK_METHOD3(ShowError, void(int, int, HelpAppLauncher::HelpTopic));
MOCK_METHOD1(ShowErrorScreen, void(LoginDisplay::SigninError));
MOCK_METHOD1(ShowGaiaPasswordChanged, void(const std::string&));
MOCK_METHOD1(ShowPasswordChangedDialog, void(bool));
MOCK_METHOD1(ShowSigninUI, void(const std::string&));
MOCK_METHOD1(OnBeforeUserRemoved, void(const std::string&));
MOCK_METHOD1(OnUserRemoved, void(const std::string&));
private:
DISALLOW_COPY_AND_ASSIGN(MockLoginDisplay);
};
class MockLoginDisplayHost : public LoginDisplayHost {
public:
MockLoginDisplayHost() {
}
MOCK_METHOD1(CreateLoginDisplay, LoginDisplay*(LoginDisplay::Delegate*));
MOCK_CONST_METHOD0(GetNativeWindow, gfx::NativeWindow(void));
MOCK_CONST_METHOD0(GetWidget, views::Widget*(void));
MOCK_METHOD0(BeforeSessionStart, void(void));
MOCK_METHOD0(OnSessionStart, void(void));
MOCK_METHOD0(OnCompleteLogin, void(void));
MOCK_METHOD0(OpenProxySettings, void(void));
MOCK_METHOD1(SetOobeProgressBarVisible, void(bool));
MOCK_METHOD1(SetShutdownButtonEnabled, void(bool));
MOCK_METHOD1(SetStatusAreaVisible, void(bool));
MOCK_METHOD0(ShowBackground, void(void));
MOCK_METHOD0(CheckForAutoEnrollment, void(void));
MOCK_METHOD2(StartWizard, void(const std::string&, DictionaryValue*));
MOCK_METHOD0(StartSignInScreen, void(void));
MOCK_METHOD0(ResumeSignInScreen, void(void));
MOCK_METHOD0(OnPreferencesChanged, void(void));
private:
DISALLOW_COPY_AND_ASSIGN(MockLoginDisplayHost);
};
const char kAutoLoginUsername[] = "public_session_user@localhost";
const int kAutoLoginNoDelay = 0;
const int kAutoLoginShortDelay = 1;
const int kAutoLoginLongDelay = 10000;
scoped_refptr<Authenticator> CreateAuthenticator(
LoginStatusConsumer* consumer) {
@ -112,6 +97,49 @@ scoped_refptr<Authenticator> CreateAuthenticatorNewUser(
return new MockAuthenticator(consumer, kNewUsername, kPassword);
}
scoped_refptr<Authenticator> CreateAuthenticatorForPublicSession(
LoginStatusConsumer* consumer) {
return new MockAuthenticator(consumer, kAutoLoginUsername, "");
}
// Observes a specific notification type and quits the message loop once a
// condition holds.
class NotificationWatcher : public content::NotificationObserver {
public:
// Callback invoked on notifications. Should return true when the condition
// that the caller is waiting for is satisfied.
typedef base::Callback<bool(void)> ConditionTestCallback;
explicit NotificationWatcher(int notification_type,
const ConditionTestCallback& callback)
: type_(notification_type),
callback_(callback) {}
void Run() {
if (callback_.Run())
return;
content::NotificationRegistrar registrar;
registrar.Add(this, type_, content::NotificationService::AllSources());
run_loop_.Run();
}
// content::NotificationObserver:
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE {
if (callback_.Run())
run_loop_.Quit();
}
private:
int type_;
ConditionTestCallback callback_;
base::RunLoop run_loop_;
DISALLOW_COPY_AND_ASSIGN(NotificationWatcher);
};
} // namespace
class ExistingUserControllerTest : public CrosInProcessBrowserTest {
@ -127,6 +155,10 @@ class ExistingUserControllerTest : public CrosInProcessBrowserTest {
return ExistingUserController::current_controller();
}
const ExistingUserController* existing_user_controller() const {
return ExistingUserController::current_controller();
}
virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
MockDBusThreadManager* mock_dbus_thread_manager =
new MockDBusThreadManager;
@ -144,6 +176,9 @@ class ExistingUserControllerTest : public CrosInProcessBrowserTest {
EXPECT_CALL(*mock_dbus_thread_manager->mock_shill_manager_client(),
RemovePropertyChangedObserver(_))
.Times(AnyNumber());
SetUpSessionManager(mock_dbus_thread_manager);
DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager);
CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture();
cros_mock_->InitStatusAreaMocks();
@ -155,13 +190,6 @@ class ExistingUserControllerTest : public CrosInProcessBrowserTest {
EXPECT_CALL(*mock_network_library_, LoadOncNetworks(_, _, _, _))
.WillRepeatedly(Return(true));
MockSessionManagerClient* mock_session_manager_client =
mock_dbus_thread_manager->mock_session_manager_client();
EXPECT_CALL(*mock_session_manager_client, EmitLoginPromptReady())
.Times(1);
EXPECT_CALL(*mock_session_manager_client, RetrieveDevicePolicy(_))
.Times(AnyNumber());
mock_login_utils_ = new MockLoginUtils();
LoginUtils::Set(mock_login_utils_);
EXPECT_CALL(*mock_login_utils_, PrewarmAuthentication())
@ -172,32 +200,50 @@ class ExistingUserControllerTest : public CrosInProcessBrowserTest {
.Times(1);
mock_login_display_host_.reset(new MockLoginDisplayHost());
mock_login_display_ = new MockLoginDisplay();
SetUpLoginDisplay();
}
EXPECT_CALL(*mock_user_manager_.user_manager(), IsKnownUser(kUsername))
virtual void SetUpSessionManager(
MockDBusThreadManager* mock_dbus_thread_manager) {
mock_user_manager_.reset(new ScopedMockUserManagerEnabler);
EXPECT_CALL(*mock_user_manager_->user_manager(), IsKnownUser(kUsername))
.Times(AnyNumber())
.WillRepeatedly(Return(true));
EXPECT_CALL(*mock_user_manager_.user_manager(), IsKnownUser(kNewUsername))
EXPECT_CALL(*mock_user_manager_->user_manager(), IsKnownUser(kNewUsername))
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_user_manager_.user_manager(), IsUserLoggedIn())
EXPECT_CALL(*mock_user_manager_->user_manager(), IsUserLoggedIn())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_user_manager_.user_manager(), IsLoggedInAsGuest())
EXPECT_CALL(*mock_user_manager_->user_manager(), IsLoggedInAsGuest())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_user_manager_.user_manager(), IsLoggedInAsDemoUser())
EXPECT_CALL(*mock_user_manager_->user_manager(), IsLoggedInAsDemoUser())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_user_manager_.user_manager(), IsLoggedInAsPublicAccount())
EXPECT_CALL(*mock_user_manager_->user_manager(),
IsLoggedInAsPublicAccount())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_user_manager_.user_manager(), IsSessionStarted())
EXPECT_CALL(*mock_user_manager_->user_manager(), IsSessionStarted())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_user_manager_->user_manager(), IsCurrentUserNew())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
EXPECT_CALL(*mock_user_manager_->user_manager(), Shutdown())
.Times(1);
// |mock_login_display_| is owned by the ExistingUserController, which calls
// CreateLoginDisplay() on the |mock_login_display_host_| to get it.
mock_login_display_ = new MockLoginDisplay();
MockSessionManagerClient* mock_session_manager_client =
mock_dbus_thread_manager->mock_session_manager_client();
EXPECT_CALL(*mock_session_manager_client, EmitLoginPromptReady())
.Times(1);
EXPECT_CALL(*mock_session_manager_client, RetrieveDevicePolicy(_))
.Times(AnyNumber());
}
virtual void SetUpLoginDisplay() {
EXPECT_CALL(*mock_login_display_host_.get(), CreateLoginDisplay(_))
.Times(1)
.WillOnce(Return(mock_login_display_));
@ -227,6 +273,12 @@ class ExistingUserControllerTest : public CrosInProcessBrowserTest {
}
virtual void CleanUpOnMainThread() OVERRIDE {
// ExistingUserController must be deleted before the thread is cleaned up:
// If there is an outstanding login attempt when ExistingUserController is
// deleted, its LoginPerformer instance will be deleted, which in turn
// deletes its OnlineAttemptHost instance. However, OnlineAttemptHost must
// be deleted on the UI thread.
existing_user_controller_.reset();
CrosInProcessBrowserTest::CleanUpOnMainThread();
testing_profile_.reset(NULL);
}
@ -236,15 +288,34 @@ class ExistingUserControllerTest : public CrosInProcessBrowserTest {
DBusThreadManager::Shutdown();
}
// ExistingUserController private member accessors.
base::OneShotTimer<ExistingUserController>* auto_login_timer() {
return existing_user_controller()->auto_login_timer_.get();
}
const std::string& auto_login_username() const {
return existing_user_controller()->public_session_auto_login_username_;
}
int auto_login_delay() const {
return existing_user_controller()->public_session_auto_login_delay_;
}
bool is_login_in_progress() const {
return existing_user_controller()->is_login_in_progress_;
}
scoped_ptr<ExistingUserController> existing_user_controller_;
// These mocks are owned by CrosLibrary class.
MockNetworkLibrary* mock_network_library_;
// |mock_login_display_| is owned by the ExistingUserController, which calls
// CreateLoginDisplay() on the |mock_login_display_host_| to get it.
MockLoginDisplay* mock_login_display_;
scoped_ptr<MockLoginDisplayHost> mock_login_display_host_;
ScopedMockUserManagerEnabler mock_user_manager_;
scoped_ptr<ScopedMockUserManagerEnabler> mock_user_manager_;
// Owned by LoginUtilsWrapper.
MockLoginUtils* mock_login_utils_;
@ -286,7 +357,7 @@ IN_PROC_BROWSER_TEST_F(ExistingUserControllerTest, ExistingUserLogin) {
EXPECT_CALL(*mock_login_display_host_,
StartWizard(WizardController::kTermsOfServiceScreenName, NULL))
.Times(0);
EXPECT_CALL(*mock_user_manager_.user_manager(), IsCurrentUserNew())
EXPECT_CALL(*mock_user_manager_->user_manager(), IsCurrentUserNew())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
existing_user_controller()->Login(kUsername, kPassword);
@ -301,7 +372,7 @@ IN_PROC_BROWSER_TEST_F(ExistingUserControllerTest, AutoEnrollAfterSignIn) {
.Times(1);
EXPECT_CALL(*mock_login_display_host_.get(), OnCompleteLogin())
.Times(1);
EXPECT_CALL(*mock_user_manager_.user_manager(), IsCurrentUserNew())
EXPECT_CALL(*mock_user_manager_->user_manager(), IsCurrentUserNew())
.Times(AnyNumber())
.WillRepeatedly(Return(false));
// The order of these expected calls matters: the UI if first disabled
@ -346,7 +417,7 @@ IN_PROC_BROWSER_TEST_F(ExistingUserControllerTest,
.Times(1);
EXPECT_CALL(*mock_login_display_host_.get(), OnCompleteLogin())
.Times(1);
EXPECT_CALL(*mock_user_manager_.user_manager(), IsCurrentUserNew())
EXPECT_CALL(*mock_user_manager_->user_manager(), IsCurrentUserNew())
.Times(AnyNumber())
.WillRepeatedly(Return(true));
@ -366,4 +437,373 @@ IN_PROC_BROWSER_TEST_F(ExistingUserControllerTest,
content::RunAllPendingInMessageLoop();
}
MATCHER_P(HasDetails, expected, "") {
return expected == *content::Details<const std::string>(arg).ptr();
}
class ExistingUserControllerPublicSessionTest
: public ExistingUserControllerTest {
protected:
ExistingUserControllerPublicSessionTest() {
}
virtual void SetUpOnMainThread() OVERRIDE {
ExistingUserControllerTest::SetUpOnMainThread();
// Wait for the public session user to be created.
if (!chromeos::UserManager::Get()->IsKnownUser(kAutoLoginUsername)) {
NotificationWatcher(
chrome::NOTIFICATION_USER_LIST_CHANGED,
base::Bind(&chromeos::UserManager::IsKnownUser,
base::Unretained(chromeos::UserManager::Get()),
kAutoLoginUsername)).Run();
}
// Wait for the device local account policy to be installed.
policy::MockCloudPolicyStoreObserver observer;
scoped_refptr<content::MessageLoopRunner> runner =
new content::MessageLoopRunner;
policy::CloudPolicyStore* store = TestingBrowserProcess::GetGlobal()->
browser_policy_connector()->GetDeviceLocalAccountPolicyService()->
GetBrokerForAccount(kAutoLoginUsername)->core()->store();
store->AddObserver(&observer);
EXPECT_CALL(observer, OnStoreLoaded(store))
.Times(1)
.WillOnce(InvokeWithoutArgs(runner.get(),
&content::MessageLoopRunner::Quit));
runner->Run();
store->RemoveObserver(&observer);
}
virtual void SetUpSessionManager(
MockDBusThreadManager* mock_dbus_thread_manager) OVERRIDE {
EXPECT_CALL(*mock_dbus_thread_manager, GetSessionManagerClient())
.WillRepeatedly(Return(&session_manager_client_));
// Install the owner key.
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
base::FilePath owner_key_file = temp_dir_.path().AppendASCII("owner.key");
std::vector<uint8> owner_key_bits;
ASSERT_TRUE(device_policy_.signing_key()->ExportPublicKey(&owner_key_bits));
ASSERT_EQ(
file_util::WriteFile(
owner_key_file,
reinterpret_cast<const char*>(vector_as_array(&owner_key_bits)),
owner_key_bits.size()),
static_cast<int>(owner_key_bits.size()));
ASSERT_TRUE(PathService::Override(chrome::FILE_OWNER_KEY, owner_key_file));
// Setup the device policy.
em::ChromeDeviceSettingsProto& proto(device_policy_.payload());
proto.mutable_device_local_accounts()->add_account()->set_id(
kAutoLoginUsername);
RefreshDevicePolicy();
// Setup the device local account policy.
policy::UserPolicyBuilder device_local_account_policy;
device_local_account_policy.policy_data().set_username(kAutoLoginUsername);
device_local_account_policy.policy_data().set_policy_type(
policy::dm_protocol::kChromePublicAccountPolicyType);
device_local_account_policy.policy_data().set_settings_entity_id(
kAutoLoginUsername);
device_local_account_policy.Build();
session_manager_client_.set_device_local_account_policy(
kAutoLoginUsername,
device_local_account_policy.GetBlob());
}
virtual void SetUpLoginDisplay() OVERRIDE {
EXPECT_CALL(*mock_login_display_host_.get(), CreateLoginDisplay(_))
.Times(1)
.WillOnce(Return(mock_login_display_));
EXPECT_CALL(*mock_login_display_host_.get(), GetNativeWindow())
.Times(AnyNumber())
.WillRepeatedly(ReturnNull());
EXPECT_CALL(*mock_login_display_host_.get(), OnPreferencesChanged())
.Times(AnyNumber());
EXPECT_CALL(*mock_login_display_, Init(_, _, _, _))
.Times(AnyNumber());
}
void ExpectSuccessfulLogin(const std::string& username,
const std::string& password,
scoped_refptr<Authenticator> create_authenticator(
LoginStatusConsumer* consumer)) {
EXPECT_CALL(*mock_login_display_, SetUIEnabled(false))
.Times(AnyNumber());
EXPECT_CALL(*mock_login_utils_, CreateAuthenticator(_))
.Times(1)
.WillOnce(WithArg<0>(Invoke(create_authenticator)));
EXPECT_CALL(*mock_login_utils_,
PrepareProfile(username, _, password, _, _, _))
.Times(1)
.WillOnce(InvokeWithoutArgs(&profile_prepared_cb_,
&base::Callback<void(void)>::Run));
EXPECT_CALL(*mock_login_utils_,
DoBrowserLaunch(testing_profile_.get(),
mock_login_display_host_.get()))
.Times(1);
EXPECT_CALL(*mock_login_display_, OnLoginSuccess(username))
.Times(1);
EXPECT_CALL(*mock_login_display_, SetUIEnabled(true))
.Times(1);
EXPECT_CALL(*mock_login_display_, OnFadeOut())
.Times(1);
EXPECT_CALL(*mock_login_display_host_,
StartWizard(WizardController::kTermsOfServiceScreenName, NULL))
.Times(0);
}
scoped_refptr<content::MessageLoopRunner> CreateSettingsObserverRunLoop(
content::MockNotificationObserver& observer, const char* setting) {
scoped_refptr<content::MessageLoopRunner> runner =
new content::MessageLoopRunner;
EXPECT_CALL(observer, Observe(chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED,
_, HasDetails(setting)))
.Times(1)
.WillOnce(InvokeWithoutArgs(runner.get(),
&content::MessageLoopRunner::Quit));
CrosSettings::Get()->AddSettingsObserver(setting, &observer);
return runner;
}
void RefreshDevicePolicy() {
// Reset the key to its original state.
device_policy_.set_signing_key(
policy::PolicyBuilder::CreateTestSigningKey());
device_policy_.Build();
// Trick the device into thinking it's enterprise-enrolled by
// removing the local private key. This will allow it to accept
// cloud policy for device owner settings.
device_policy_.set_signing_key(
make_scoped_ptr<crypto::RSAPrivateKey>(NULL));
device_policy_.set_new_signing_key(
make_scoped_ptr<crypto::RSAPrivateKey>(NULL));
session_manager_client_.set_device_policy(device_policy_.GetBlob());
session_manager_client_.OnPropertyChangeComplete(true);
}
void SetAutoLoginPolicy(const std::string& username, int delay) {
// Wait until ExistingUserController has finished auto-login
// configuration by observing the same settings that trigger
// ConfigurePublicSessionAutoLogin.
content::MockNotificationObserver observer;
em::ChromeDeviceSettingsProto& proto(device_policy_.payload());
// If both settings have changed we need to wait for both to
// propagate, so check the new values against the old ones.
scoped_refptr<content::MessageLoopRunner> runner1 = NULL;
if (!proto.has_device_local_accounts() ||
!proto.device_local_accounts().has_auto_login_id() ||
proto.device_local_accounts().auto_login_id() != username) {
runner1 = CreateSettingsObserverRunLoop(
observer, kAccountsPrefDeviceLocalAccountAutoLoginId);
}
scoped_refptr<content::MessageLoopRunner> runner2 = NULL;
if (!proto.has_device_local_accounts() ||
!proto.device_local_accounts().has_auto_login_delay() ||
proto.device_local_accounts().auto_login_delay() != delay) {
runner2 = CreateSettingsObserverRunLoop(
observer, kAccountsPrefDeviceLocalAccountAutoLoginDelay);
}
// Update the policy.
proto.mutable_device_local_accounts()->set_auto_login_id(username);
proto.mutable_device_local_accounts()->set_auto_login_delay(delay);
RefreshDevicePolicy();
// Wait for ExistingUserController to read the updated settings.
if (runner1)
runner1->Run();
if (runner2)
runner2->Run();
// Clean up.
CrosSettings::Get()->RemoveSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginId,
&observer);
CrosSettings::Get()->RemoveSettingsObserver(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
&observer);
}
void ConfigureAutoLogin() {
existing_user_controller()->ConfigurePublicSessionAutoLogin();
}
void FireAutoLogin() {
existing_user_controller()->OnPublicSessionAutoLoginTimerFire();
}
// Mock out policy loads/stores from/to the device.
FakeSessionManagerClient session_manager_client_;
// Stores the device owner key.
base::ScopedTempDir temp_dir_;
// Carries Chrome OS device policies for tests.
policy::DevicePolicyBuilder device_policy_;
private:
DISALLOW_COPY_AND_ASSIGN(ExistingUserControllerPublicSessionTest);
};
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
ConfigureAutoLoginUsingPolicy) {
existing_user_controller()->OnSigninScreenReady();
EXPECT_EQ("", auto_login_username());
EXPECT_EQ(0, auto_login_delay());
EXPECT_FALSE(auto_login_timer());
// Set the policy.
SetAutoLoginPolicy(kAutoLoginUsername, kAutoLoginLongDelay);
EXPECT_EQ(kAutoLoginUsername, auto_login_username());
EXPECT_EQ(kAutoLoginLongDelay, auto_login_delay());
ASSERT_TRUE(auto_login_timer());
EXPECT_TRUE(auto_login_timer()->IsRunning());
// Unset the policy.
SetAutoLoginPolicy("", 0);
EXPECT_EQ("", auto_login_username());
EXPECT_EQ(0, auto_login_delay());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
AutoLoginNoDelay) {
// Set up mocks to check login success.
ExpectSuccessfulLogin(kAutoLoginUsername, "",
CreateAuthenticatorForPublicSession);
existing_user_controller()->OnSigninScreenReady();
// Start auto-login and wait for login tasks to complete.
SetAutoLoginPolicy(kAutoLoginUsername, kAutoLoginNoDelay);
content::RunAllPendingInMessageLoop();
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
AutoLoginShortDelay) {
// Set up mocks to check login success.
ExpectSuccessfulLogin(kAutoLoginUsername, "",
CreateAuthenticatorForPublicSession);
existing_user_controller()->OnSigninScreenReady();
SetAutoLoginPolicy(kAutoLoginUsername, kAutoLoginShortDelay);
ASSERT_TRUE(auto_login_timer());
// Don't assert that timer is running: with the short delay sometimes
// the trigger happens before the assert. We've already tested that
// the timer starts when it should.
// Wait for the timer to fire.
scoped_refptr<content::MessageLoopRunner> runner
= new content::MessageLoopRunner;
base::OneShotTimer<content::MessageLoopRunner> timer;
timer.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(kAutoLoginShortDelay + 1),
base::Bind(&content::MessageLoopRunner::Quit, runner));
runner->Run();
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
LoginStopsAutoLogin) {
// Set up mocks to check login success.
ExpectSuccessfulLogin(kUsername, kPassword, CreateAuthenticator);
existing_user_controller()->OnSigninScreenReady();
SetAutoLoginPolicy(kAutoLoginUsername, kAutoLoginLongDelay);
ASSERT_TRUE(auto_login_timer());
// Login and check that it stopped the timer.
existing_user_controller()->Login(kUsername, kPassword);
EXPECT_TRUE(is_login_in_progress());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
GuestModeLoginStopsAutoLogin) {
EXPECT_CALL(*mock_login_display_, SetUIEnabled(false))
.Times(1);
EXPECT_CALL(*mock_login_utils_, CreateAuthenticator(_))
.Times(1)
.WillOnce(WithArg<0>(Invoke(CreateAuthenticator)));
EXPECT_CALL(*mock_login_utils_, CompleteOffTheRecordLogin(_))
.Times(1);
existing_user_controller()->OnSigninScreenReady();
SetAutoLoginPolicy(kAutoLoginUsername, kAutoLoginLongDelay);
ASSERT_TRUE(auto_login_timer());
// Login and check that it stopped the timer.
existing_user_controller()->LoginAsGuest();
EXPECT_TRUE(is_login_in_progress());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
CompleteLoginStopsAutoLogin) {
// Set up mocks to check login success.
ExpectSuccessfulLogin(kUsername, kPassword, CreateAuthenticator);
EXPECT_CALL(*mock_login_display_host_, OnCompleteLogin())
.Times(1);
existing_user_controller()->OnSigninScreenReady();
SetAutoLoginPolicy(kAutoLoginUsername, kAutoLoginLongDelay);
ASSERT_TRUE(auto_login_timer());
// Check that login completes and stops the timer.
existing_user_controller()->CompleteLogin(kUsername, kPassword);
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
IN_PROC_BROWSER_TEST_F(ExistingUserControllerPublicSessionTest,
PublicSessionLoginStopsAutoLogin) {
// Set up mocks to check login success.
ExpectSuccessfulLogin(kAutoLoginUsername, "",
CreateAuthenticatorForPublicSession);
existing_user_controller()->OnSigninScreenReady();
SetAutoLoginPolicy(kAutoLoginUsername, kAutoLoginLongDelay);
ASSERT_TRUE(auto_login_timer());
// Login and check that it stopped the timer.
existing_user_controller()->LoginAsPublicAccount(kAutoLoginUsername);
EXPECT_TRUE(is_login_in_progress());
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
// Wait for login tasks to complete.
content::RunAllPendingInMessageLoop();
// Timer should still be stopped after login completes.
ASSERT_TRUE(auto_login_timer());
EXPECT_FALSE(auto_login_timer()->IsRunning());
}
} // namespace chromeos

@ -67,6 +67,9 @@ class LoginDisplay : public RemoveUserDelegate {
// Sign in into the public account identified by |username|.
virtual void LoginAsPublicAccount(const std::string& username) = 0;
// Notify the delegate when the sign-in UI is finished loading.
virtual void OnSigninScreenReady() = 0;
// Called when existing user pod is selected in the UI.
virtual void OnUserSelected(const std::string& username) = 0;
@ -79,6 +82,9 @@ class LoginDisplay : public RemoveUserDelegate {
// Shows wrong HWID screen.
virtual void ShowWrongHWIDScreen() = 0;
// Restarts the public-session auto-login timer if it is running.
virtual void ResetPublicSessionAutoLoginTimer() = 0;
// Ignore password change, remove existing cryptohome and
// force full sync of user data.
virtual void ResyncUserData() = 0;

@ -0,0 +1,20 @@
// 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/mock_login_display.h"
#include "chrome/browser/chromeos/login/help_app_launcher.h"
#include "chrome/browser/chromeos/login/user.h"
#include "chrome/test/base/ui_test_utils.h"
#include "ui/gfx/rect.h"
namespace chromeos {
MockLoginDisplay::MockLoginDisplay() : LoginDisplay(NULL, gfx::Rect()) {
}
MockLoginDisplay::~MockLoginDisplay() {
}
} // namespace chromeos

@ -0,0 +1,40 @@
// 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.
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_LOGIN_DISPLAY_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_LOGIN_DISPLAY_H_
#include "base/basictypes.h"
#include "chrome/browser/chromeos/login/login_display.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace chromeos {
class MockLoginDisplay : public LoginDisplay {
public:
MockLoginDisplay();
~MockLoginDisplay();
MOCK_METHOD4(Init, void(const UserList&, bool, bool, bool));
MOCK_METHOD0(OnPreferencesChanged, void(void));
MOCK_METHOD1(OnUserImageChanged, void(const User&));
MOCK_METHOD0(OnFadeOut, void(void));
MOCK_METHOD1(OnLoginSuccess, void(const std::string&));
MOCK_METHOD1(SetUIEnabled, void(bool));
MOCK_METHOD1(SelectPod, void(int));
MOCK_METHOD3(ShowError, void(int, int, HelpAppLauncher::HelpTopic));
MOCK_METHOD1(ShowErrorScreen, void(LoginDisplay::SigninError));
MOCK_METHOD1(ShowGaiaPasswordChanged, void(const std::string&));
MOCK_METHOD1(ShowPasswordChangedDialog, void(bool));
MOCK_METHOD1(ShowSigninUI, void(const std::string&));
MOCK_METHOD1(OnBeforeUserRemoved, void(const std::string&));
MOCK_METHOD1(OnUserRemoved, void(const std::string&));
private:
DISALLOW_COPY_AND_ASSIGN(MockLoginDisplay);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_LOGIN_DISPLAY_H_

@ -0,0 +1,17 @@
// 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/mock_login_display_host.h"
#include "chrome/test/base/ui_test_utils.h"
namespace chromeos {
MockLoginDisplayHost::MockLoginDisplayHost() {
}
MockLoginDisplayHost::~MockLoginDisplayHost() {
}
} // namespace chromeos

@ -0,0 +1,42 @@
// 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.
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_LOGIN_DISPLAY_HOST_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_LOGIN_DISPLAY_HOST_H_
#include "base/basictypes.h"
#include "chrome/browser/chromeos/login/login_display_host.h"
#include "testing/gmock/include/gmock/gmock.h"
namespace chromeos {
class MockLoginDisplayHost : public LoginDisplayHost {
public:
MockLoginDisplayHost();
virtual ~MockLoginDisplayHost();
MOCK_METHOD1(CreateLoginDisplay, LoginDisplay*(LoginDisplay::Delegate*));
MOCK_CONST_METHOD0(GetNativeWindow, gfx::NativeWindow(void));
MOCK_CONST_METHOD0(GetWidget, views::Widget*(void));
MOCK_METHOD0(BeforeSessionStart, void(void));
MOCK_METHOD0(OnSessionStart, void(void));
MOCK_METHOD0(OnCompleteLogin, void(void));
MOCK_METHOD0(OpenProxySettings, void(void));
MOCK_METHOD1(SetOobeProgressBarVisible, void(bool));
MOCK_METHOD1(SetShutdownButtonEnabled, void(bool));
MOCK_METHOD1(SetStatusAreaVisible, void(bool));
MOCK_METHOD0(ShowBackground, void(void));
MOCK_METHOD0(CheckForAutoEnrollment, void(void));
MOCK_METHOD2(StartWizard, void(const std::string&, DictionaryValue*));
MOCK_METHOD0(StartSignInScreen, void(void));
MOCK_METHOD0(ResumeSignInScreen, void(void));
MOCK_METHOD0(OnPreferencesChanged, void(void));
private:
DISALLOW_COPY_AND_ASSIGN(MockLoginDisplayHost);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_MOCK_LOGIN_DISPLAY_HOST_H_

@ -39,6 +39,10 @@ UserFlow* MockUserManager::GetUserFlow(const std::string&) const {
return user_flow_.get();
}
User* MockUserManager::CreatePublicAccountUser(const std::string& email) {
return User::CreatePublicAccountUser(email);
}
ScopedMockUserManagerEnabler::ScopedMockUserManagerEnabler() {
user_manager_.reset(new MockUserManager());
old_user_manager_ = UserManager::Set(user_manager_.get());

@ -98,6 +98,9 @@ class MockUserManager : public UserManager {
// Sets a new User instance.
void SetLoggedInUser(const std::string& email);
// Creates a new public session user.
User* CreatePublicAccountUser(const std::string& email);
User* user_;
scoped_ptr<MockUserImageManager> user_image_manager_;
scoped_ptr<UserFlow> user_flow_;

@ -278,6 +278,11 @@ void WebUILoginDisplay::LoadSigninWallpaper() {
WallpaperManager::Get()->SetDefaultWallpaper();
}
void WebUILoginDisplay::OnSigninScreenReady() {
if (delegate_)
delegate_->OnSigninScreenReady();
}
void WebUILoginDisplay::RemoveUser(const std::string& username) {
UserManager::Get()->RemoveUser(username, this);
}
@ -344,6 +349,8 @@ void WebUILoginDisplay::OnUserActivity() {
if (!password_clear_timer_.IsRunning())
StartPasswordClearTimer();
password_clear_timer_.Reset();
if (delegate_)
delegate_->ResetPublicSessionAutoLoginTimer();
}
void WebUILoginDisplay::StartPasswordClearTimer() {

@ -66,6 +66,7 @@ class WebUILoginDisplay : public LoginDisplay,
virtual void LoginAsPublicAccount(const std::string& username) OVERRIDE;
virtual void LoadWallpaper(const std::string& username) OVERRIDE;
virtual void LoadSigninWallpaper() OVERRIDE;
virtual void OnSigninScreenReady() OVERRIDE;
virtual void RemoveUser(const std::string& username) OVERRIDE;
virtual void ResyncUserData() OVERRIDE;
virtual void ShowEnterpriseEnrollmentScreen() OVERRIDE;

@ -227,6 +227,9 @@ void WebUIScreenLocker::LoginAsPublicAccount(const std::string& username) {
NOTREACHED();
}
void WebUIScreenLocker::OnSigninScreenReady() {
}
void WebUIScreenLocker::OnUserSelected(const std::string& username) {
}
@ -242,6 +245,9 @@ void WebUIScreenLocker::ShowWrongHWIDScreen() {
NOTREACHED();
}
void WebUIScreenLocker::ResetPublicSessionAutoLoginTimer() {
}
void WebUIScreenLocker::ResyncUserData() {
NOTREACHED();
}

@ -75,10 +75,12 @@ class WebUIScreenLocker : public WebUILoginView,
virtual void LoginAsGuest() OVERRIDE;
virtual void MigrateUserData(const std::string& old_password) OVERRIDE;
virtual void LoginAsPublicAccount(const std::string& username) OVERRIDE;
virtual void OnSigninScreenReady() OVERRIDE;
virtual void OnUserSelected(const std::string& username) OVERRIDE;
virtual void OnStartEnterpriseEnrollment() OVERRIDE;
virtual void OnStartDeviceReset() OVERRIDE;
virtual void ShowWrongHWIDScreen() OVERRIDE;
virtual void ResetPublicSessionAutoLoginTimer() OVERRIDE;
virtual void ResyncUserData() OVERRIDE;
virtual void SetDisplayEmail(const std::string& email) OVERRIDE;
virtual void Signout() OVERRIDE;

@ -150,7 +150,7 @@ void DeviceLocalAccountPolicyStore::Validate(
DCHECK_NE(chromeos::DeviceSettingsService::OWNERSHIP_UNKNOWN,
ownership_status);
chromeos::OwnerKey* key = device_settings_service_->GetOwnerKey();
if (!key->public_key()) {
if (!key || !key->public_key()) {
status_ = CloudPolicyStore::STATUS_BAD_STATE;
NotifyStoreLoaded();
return;

@ -117,8 +117,10 @@ void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy,
}
if (policy.has_device_local_accounts()) {
const em::DeviceLocalAccountsProto& container(
policy.device_local_accounts());
const RepeatedPtrField<em::DeviceLocalAccountInfoProto>& accounts =
policy.device_local_accounts().account();
container.account();
if (accounts.size() > 0) {
ListValue* account_list = new ListValue();
RepeatedPtrField<em::DeviceLocalAccountInfoProto>::const_iterator entry;
@ -131,6 +133,18 @@ void DecodeLoginPolicies(const em::ChromeDeviceSettingsProto& policy,
POLICY_SCOPE_MACHINE,
account_list);
}
if (container.has_auto_login_id()) {
policies->Set(key::kDeviceLocalAccountAutoLoginId,
POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE,
Value::CreateStringValue(container.auto_login_id()));
}
if (container.has_auto_login_delay()) {
policies->Set(key::kDeviceLocalAccountAutoLoginDelay,
POLICY_LEVEL_MANDATORY,
POLICY_SCOPE_MACHINE,
DecodeIntegerValue(container.auto_login_delay()));
}
}
}

@ -231,6 +231,15 @@ message DeviceLocalAccountsProto {
// The list of device-local accounts (i.e. accounts without an associated
// cloud-backed profile) that are available on the device.
repeated DeviceLocalAccountInfoProto account = 1;
// The identifier of the device-local account to which the device
// should be logged in automatically. Should be equal to one of the
// ids in DeviceLocalAccountInfoProto.
optional string auto_login_id = 2;
// The amount of time, in milliseconds, that should elapse at the signin
// screen without user interaction before automatically logging in.
optional int64 auto_login_delay = 3;
}
message AllowRedeemChromeOsRegistrationOffersProto {

@ -18,6 +18,10 @@ const char kAccountsPrefEphemeralUsersEnabled[] =
"cros.accounts.ephemeralUsersEnabled";
const char kAccountsPrefDeviceLocalAccounts[] =
"cros.accounts.deviceLocalAccounts";
const char kAccountsPrefDeviceLocalAccountAutoLoginId[] =
"cros.accounts.deviceLocalAccountAutoLoginId";
const char kAccountsPrefDeviceLocalAccountAutoLoginDelay[] =
"cros.accounts.deviceLocalAccountAutoLoginDelay";
// Name of signed setting persisted on device, writeable only by owner.
const char kSettingProxyEverywhere[] = "cros.proxy.everywhere";

@ -15,6 +15,8 @@ extern const char kAccountsPrefShowUserNamesOnSignIn[];
extern const char kAccountsPrefUsers[];
extern const char kAccountsPrefEphemeralUsersEnabled[];
extern const char kAccountsPrefDeviceLocalAccounts[];
extern const char kAccountsPrefDeviceLocalAccountAutoLoginId[];
extern const char kAccountsPrefDeviceLocalAccountAutoLoginDelay[];
extern const char kSettingProxyEverywhere[];

@ -41,10 +41,12 @@ namespace {
const char* kKnownSettings[] = {
kAccountsPrefAllowGuest,
kAccountsPrefAllowNewUser,
kAccountsPrefDeviceLocalAccounts,
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
kAccountsPrefDeviceLocalAccountAutoLoginId,
kAccountsPrefEphemeralUsersEnabled,
kAccountsPrefShowUserNamesOnSignIn,
kAccountsPrefUsers,
kAccountsPrefDeviceLocalAccounts,
kAllowRedeemChromeOsRegistrationOffers,
kAppPack,
kDeviceOwner,
@ -235,6 +237,22 @@ void DeviceSettingsProvider::SetInPolicy() {
} else {
NOTREACHED();
}
} else if (prop == kAccountsPrefDeviceLocalAccountAutoLoginId) {
em::DeviceLocalAccountsProto* device_local_accounts =
device_settings_.mutable_device_local_accounts();
std::string id;
if (value->GetAsString(&id))
device_local_accounts->set_auto_login_id(id);
else
NOTREACHED();
} else if (prop == kAccountsPrefDeviceLocalAccountAutoLoginDelay) {
em::DeviceLocalAccountsProto* device_local_accounts =
device_settings_.mutable_device_local_accounts();
int delay;
if (value->GetAsInteger(&delay))
device_local_accounts->set_auto_login_delay(delay);
else
NOTREACHED();
} else if (prop == kSignedDataRoamingEnabled) {
em::DataRoamingEnabledProto* roam =
device_settings_.mutable_data_roaming_enabled();
@ -411,8 +429,10 @@ void DeviceSettingsProvider::DecodeLoginPolicies(
base::ListValue* account_list = new base::ListValue();
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (!command_line->HasSwitch(switches::kDisableLocalAccounts)) {
const em::DeviceLocalAccountsProto device_local_accounts_proto =
policy.device_local_accounts();
const RepeatedPtrField<em::DeviceLocalAccountInfoProto>& accounts =
policy.device_local_accounts().account();
device_local_accounts_proto.account();
RepeatedPtrField<em::DeviceLocalAccountInfoProto>::const_iterator entry;
for (entry = accounts.begin(); entry != accounts.end(); ++entry) {
if (entry->has_id())
@ -431,6 +451,19 @@ void DeviceSettingsProvider::DecodeLoginPolicies(
}
new_values_cache->SetValue(kStartUpFlags, list);
}
if (policy.has_device_local_accounts()) {
if (policy.device_local_accounts().has_auto_login_id()) {
new_values_cache->SetString(
kAccountsPrefDeviceLocalAccountAutoLoginId,
policy.device_local_accounts().auto_login_id());
}
if (policy.device_local_accounts().has_auto_login_delay()) {
new_values_cache->SetInteger(
kAccountsPrefDeviceLocalAccountAutoLoginDelay,
policy.device_local_accounts().auto_login_delay());
}
}
}
void DeviceSettingsProvider::DecodeKioskPolicies(

@ -1459,6 +1459,9 @@ void SigninScreenHandler::HandleAccountPickerReady(
content::NotificationService::AllSources(),
content::NotificationService::NoDetails());
}
if (delegate_)
delegate_->OnSigninScreenReady();
}
void SigninScreenHandler::HandleWallpaperReady(

@ -106,6 +106,9 @@ class SigninScreenHandlerDelegate {
// Loads the default sign-in wallpaper.
virtual void LoadSigninWallpaper() = 0;
// Notify the delegate when the sign-in UI is finished loading.
virtual void OnSigninScreenReady() = 0;
// Attempts to remove given user.
virtual void RemoveUser(const std::string& username) = 0;

@ -80,6 +80,10 @@
'browser/chromeos/input_method/mock_input_method_manager.h',
'browser/chromeos/input_method/mock_xkeyboard.cc',
'browser/chromeos/input_method/mock_xkeyboard.h',
'browser/chromeos/login/mock_login_display.cc',
'browser/chromeos/login/mock_login_display.h',
'browser/chromeos/login/mock_login_display_host.cc',
'browser/chromeos/login/mock_login_display_host.h',
'browser/chromeos/login/mock_login_status_consumer.cc',
'browser/chromeos/login/mock_login_status_consumer.h',
'browser/chromeos/login/mock_login_utils.cc',
@ -147,6 +151,8 @@
'browser/password_manager/password_form_data.h',
'browser/policy/cloud/mock_cloud_policy_client.cc',
'browser/policy/cloud/mock_cloud_policy_client.h',
'browser/policy/cloud/mock_cloud_policy_store.cc',
'browser/policy/cloud/mock_cloud_policy_store.h',
'browser/policy/cloud/policy_builder.cc',
'browser/policy/cloud/policy_builder.h',
'browser/policy/mock_configuration_policy_provider.cc',
@ -598,6 +604,7 @@
'browser/chromeos/kiosk_mode/kiosk_mode_idle_logout_unittest.cc',
'browser/chromeos/kiosk_mode/kiosk_mode_settings_unittest.cc',
'browser/chromeos/language_preferences_unittest.cc',
'browser/chromeos/login/existing_user_controller_auto_login_unittest.cc',
'browser/chromeos/login/hwid_checker_unittest.cc',
'browser/chromeos/login/merge_session_load_page_unittest.cc',
'browser/chromeos/login/mock_auth_attempt_state_resolver.cc',
@ -940,8 +947,6 @@
'browser/policy/cloud/component_cloud_policy_store_unittest.cc',
'browser/policy/cloud/component_cloud_policy_updater_unittest.cc',
'browser/policy/cloud/device_management_service_unittest.cc',
'browser/policy/cloud/mock_cloud_policy_store.cc',
'browser/policy/cloud/mock_cloud_policy_store.h',
'browser/policy/cloud/mock_device_management_service.cc',
'browser/policy/cloud/mock_device_management_service.h',
'browser/policy/cloud/mock_user_cloud_policy_store.cc',

@ -1812,6 +1812,12 @@
"DeviceLocalAccounts": {
},
"DeviceLocalAccountAutoLoginId": {
},
"DeviceLocalAccountAutoLoginDelay": {
},
"DeviceAllowRedeemChromeOsRegistrationOffers": {
},

@ -241,6 +241,8 @@
'chromeos_test_utils.h',
'cryptohome/mock_async_method_caller.cc',
'cryptohome/mock_async_method_caller.h',
'dbus/fake_session_manager_client.cc',
'dbus/fake_session_manager_client.h',
'dbus/mock_bluetooth_adapter_client.cc',
'dbus/mock_bluetooth_adapter_client.h',
'dbus/mock_bluetooth_device_client.cc',

@ -0,0 +1,144 @@
// 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 "chromeos/dbus/fake_session_manager_client.h"
#include "base/bind.h"
#include "base/location.h"
#include "base/message_loop.h"
#include "base/string_util.h"
namespace chromeos {
FakeSessionManagerClient::FakeSessionManagerClient() {
}
FakeSessionManagerClient::~FakeSessionManagerClient() {
}
void FakeSessionManagerClient::AddObserver(Observer* observer) {
observers_.AddObserver(observer);
}
void FakeSessionManagerClient::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
bool FakeSessionManagerClient::HasObserver(Observer* observer) {
return observers_.HasObserver(observer);
}
void FakeSessionManagerClient::EmitLoginPromptReady() {
}
void FakeSessionManagerClient::EmitLoginPromptVisible() {
}
void FakeSessionManagerClient::RestartJob(int pid,
const std::string& command_line) {
}
void FakeSessionManagerClient::RestartEntd() {
}
void FakeSessionManagerClient::StartSession(const std::string& user_email) {
}
void FakeSessionManagerClient::StopSession() {
}
void FakeSessionManagerClient::StartDeviceWipe() {
}
void FakeSessionManagerClient::RequestLockScreen() {
}
void FakeSessionManagerClient::NotifyLockScreenShown() {
}
void FakeSessionManagerClient::RequestUnlockScreen() {
}
void FakeSessionManagerClient::NotifyLockScreenDismissed() {
}
void FakeSessionManagerClient::RetrieveDevicePolicy(
const RetrievePolicyCallback& callback) {
MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(callback, device_policy_));
}
void FakeSessionManagerClient::RetrieveUserPolicy(
const RetrievePolicyCallback& callback) {
MessageLoop::current()->PostTask(FROM_HERE,
base::Bind(callback, user_policy_));
}
void FakeSessionManagerClient::RetrieveDeviceLocalAccountPolicy(
const std::string& account_id,
const RetrievePolicyCallback& callback) {
MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(callback, device_local_account_policy_[account_id]));
}
void FakeSessionManagerClient::StoreDevicePolicy(
const std::string& policy_blob,
const StorePolicyCallback& callback) {
device_policy_ = policy_blob;
MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
FOR_EACH_OBSERVER(Observer, observers_, PropertyChangeComplete(true));
}
void FakeSessionManagerClient::StoreUserPolicy(
const std::string& policy_blob,
const StorePolicyCallback& callback) {
user_policy_ = policy_blob;
MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
}
void FakeSessionManagerClient::StoreDeviceLocalAccountPolicy(
const std::string& account_id,
const std::string& policy_blob,
const StorePolicyCallback& callback) {
device_local_account_policy_[account_id] = policy_blob;
MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
}
const std::string& FakeSessionManagerClient::device_policy() const {
return device_policy_;
}
void FakeSessionManagerClient::set_device_policy(
const std::string& policy_blob) {
device_policy_ = policy_blob;
}
const std::string& FakeSessionManagerClient::user_policy() const {
return user_policy_;
}
void FakeSessionManagerClient::set_user_policy(const std::string& policy_blob) {
user_policy_ = policy_blob;
}
const std::string& FakeSessionManagerClient::device_local_account_policy(
const std::string& account_id) const {
std::map<std::string, std::string>::const_iterator entry =
device_local_account_policy_.find(account_id);
return entry != device_local_account_policy_.end() ? entry->second
: EmptyString();
}
void FakeSessionManagerClient::set_device_local_account_policy(
const std::string& account_id,
const std::string& policy_blob) {
device_local_account_policy_[account_id] = policy_blob;
}
void FakeSessionManagerClient::OnPropertyChangeComplete(bool success) {
FOR_EACH_OBSERVER(Observer, observers_, PropertyChangeComplete(success));
}
} // namespace chromeos

@ -0,0 +1,81 @@
// 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.
#ifndef CHROMEOS_DBUS_FAKE_SESSION_MANAGER_CLIENT_H_
#define CHROMEOS_DBUS_FAKE_SESSION_MANAGER_CLIENT_H_
#include <map>
#include <string>
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/observer_list.h"
#include "chromeos/dbus/session_manager_client.h"
namespace chromeos {
// A fake implementation of session_manager. Accepts policy blobs to be set and
// returns them unmodified.
class FakeSessionManagerClient : public chromeos::SessionManagerClient {
public:
FakeSessionManagerClient();
virtual ~FakeSessionManagerClient();
// SessionManagerClient:
virtual void AddObserver(Observer* observer) OVERRIDE;
virtual void RemoveObserver(Observer* observer) OVERRIDE;
virtual bool HasObserver(Observer* observer) OVERRIDE;
virtual void EmitLoginPromptReady() OVERRIDE;
virtual void EmitLoginPromptVisible() OVERRIDE;
virtual void RestartJob(int pid, const std::string& command_line) OVERRIDE;
virtual void RestartEntd() OVERRIDE;
virtual void StartSession(const std::string& user_email) OVERRIDE;
virtual void StopSession() OVERRIDE;
virtual void StartDeviceWipe() OVERRIDE;
virtual void RequestLockScreen() OVERRIDE;
virtual void NotifyLockScreenShown() OVERRIDE;
virtual void RequestUnlockScreen() OVERRIDE;
virtual void NotifyLockScreenDismissed() OVERRIDE;
virtual void RetrieveDevicePolicy(
const RetrievePolicyCallback& callback) OVERRIDE;
virtual void RetrieveUserPolicy(
const RetrievePolicyCallback& callback) OVERRIDE;
virtual void RetrieveDeviceLocalAccountPolicy(
const std::string& account_id,
const RetrievePolicyCallback& callback) OVERRIDE;
virtual void StoreDevicePolicy(const std::string& policy_blob,
const StorePolicyCallback& callback) OVERRIDE;
virtual void StoreUserPolicy(const std::string& policy_blob,
const StorePolicyCallback& callback) OVERRIDE;
virtual void StoreDeviceLocalAccountPolicy(
const std::string& account_id,
const std::string& policy_blob,
const StorePolicyCallback& callback) OVERRIDE;
const std::string& device_policy() const;
void set_device_policy(const std::string& policy_blob);
const std::string& user_policy() const;
void set_user_policy(const std::string& policy_blob);
const std::string& device_local_account_policy(
const std::string& account_id) const;
void set_device_local_account_policy(const std::string& account_id,
const std::string& policy_blob);
// Notify observers about a property change completion.
void OnPropertyChangeComplete(bool success);
private:
std::string device_policy_;
std::string user_policy_;
std::map<std::string, std::string> device_local_account_policy_;
ObserverList<Observer> observers_;
DISALLOW_COPY_AND_ASSIGN(FakeSessionManagerClient);
};
} // namespace chromeos
#endif // CHROMEOS_DBUS_FAKE_SESSION_MANAGER_CLIENT_H_