diff options
author | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-26 11:06:56 +0000 |
---|---|---|
committer | mnissler@chromium.org <mnissler@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-03-26 11:06:56 +0000 |
commit | 021160cc936c32c5dc29b255e137fbf972faae89 (patch) | |
tree | cd48e0ea0d09318a794a580412d2c8c11553241a | |
parent | 58c32a4dc3c18fa98444073fe87fbd3d4b34dbea (diff) | |
download | chromium_src-021160cc936c32c5dc29b255e137fbf972faae89.zip chromium_src-021160cc936c32c5dc29b255e137fbf972faae89.tar.gz chromium_src-021160cc936c32c5dc29b255e137fbf972faae89.tar.bz2 |
Add proper captive portal handling for forced re-enrollment.
This moves main auto enrollment oversight into the new class
AutoEnrollmentController. The OOBE flow after AU is driven by
AutoEnrollmentCheckStep, which now also correctly handles captive
portal detection.
BUG=chromium:352310
R=joaodasilva@chromium.org, ygorshenin@chromium.org
Review URL: https://codereview.chromium.org/208593003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@259551 0039d316-1c4b-4281-b951-d872f2087c98
19 files changed, 743 insertions, 414 deletions
diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_step.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_step.cc new file mode 100644 index 0000000..cd512d5 --- /dev/null +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_step.cc @@ -0,0 +1,175 @@ +// Copyright 2014 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/enrollment/auto_enrollment_check_step.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "chrome/browser/chromeos/login/screens/screen_observer.h" +#include "chromeos/chromeos_switches.h" +#include "chromeos/network/network_state.h" +#include "chromeos/network/network_state_handler.h" + +namespace chromeos { + +AutoEnrollmentCheckStep::AutoEnrollmentCheckStep( + ScreenObserver* screen_observer, + AutoEnrollmentController* auto_enrollment_controller) + : screen_observer_(screen_observer), + auto_enrollment_controller_(auto_enrollment_controller), + captive_portal_status_( + NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN), + auto_enrollment_state_(policy::AUTO_ENROLLMENT_STATE_IDLE) {} + +AutoEnrollmentCheckStep::~AutoEnrollmentCheckStep() { + NetworkPortalDetector::Get()->RemoveObserver(this); +} + +void AutoEnrollmentCheckStep::Start() { + if (!CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnterpriseEnableForcedReEnrollment)) { + SignalCompletion(); + return; + } + + // Make sure the auto-enrollment client is running. + auto_enrollment_controller_->Start(); + + auto_enrollment_progress_subscription_ = + auto_enrollment_controller_->RegisterProgressCallback( + base::Bind(&AutoEnrollmentCheckStep::OnAutoEnrollmentCheckProgressed, + base::Unretained(this))); + auto_enrollment_state_ = auto_enrollment_controller_->state(); + + // NB: AddAndFireObserver below call back into OnPortalDetectionCompleted. + // This guarantees that the UI gets synced to current state. + NetworkPortalDetector* portal_detector = NetworkPortalDetector::Get(); + portal_detector->StartDetectionIfIdle(); + portal_detector->AddAndFireObserver(this); +} + +void AutoEnrollmentCheckStep::OnPortalDetectionCompleted( + const NetworkState* /* network */, + const NetworkPortalDetector::CaptivePortalState& state) { + UpdateState(state.status, auto_enrollment_state_); +} + +void AutoEnrollmentCheckStep::OnAutoEnrollmentCheckProgressed( + policy::AutoEnrollmentState state) { + UpdateState(captive_portal_status_, state); +} + +void AutoEnrollmentCheckStep::UpdateState( + NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status, + policy::AutoEnrollmentState new_auto_enrollment_state) { + // Configure the error screen to show the approriate error message. + if (!UpdateCaptivePortalStatus(new_captive_portal_status)) + UpdateAutoEnrollmentState(new_auto_enrollment_state); + + // Update the connecting indicator. + ErrorScreen* error_screen = screen_observer_->GetErrorScreen(); + error_screen->ShowConnectingIndicator( + new_auto_enrollment_state == policy::AUTO_ENROLLMENT_STATE_PENDING); + + // Determine whether a retry is in order. + bool retry = (new_captive_portal_status == + NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) && + (captive_portal_status_ != + NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE); + + // Save the new state. + captive_portal_status_ = new_captive_portal_status; + auto_enrollment_state_ = new_auto_enrollment_state; + + // Check whether a decision got made. + switch (new_auto_enrollment_state) { + case policy::AUTO_ENROLLMENT_STATE_IDLE: + NOTREACHED(); + // fall through. + case policy::AUTO_ENROLLMENT_STATE_PENDING: + case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR: + break; + case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR: + // Server errors don't block OOBE. + case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT: + case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT: + // Decision made, ready to proceed. + SignalCompletion(); + return; + } + + // Retry if applicable. This is last so eventual callbacks find consistent + // state. + if (retry) + auto_enrollment_controller_->Retry(); +} + +bool AutoEnrollmentCheckStep::UpdateCaptivePortalStatus( + NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status) { + switch (new_captive_portal_status) { + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN: + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE: + return false; + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE: + ShowErrorScreen(ErrorScreen::ERROR_STATE_OFFLINE); + return true; + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL: + ShowErrorScreen(ErrorScreen::ERROR_STATE_PORTAL); + if (captive_portal_status_ != new_captive_portal_status) + screen_observer_->GetErrorScreen()->FixCaptivePortal(); + return true; + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED: + ShowErrorScreen(ErrorScreen::ERROR_STATE_PROXY); + return true; + case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT: + // Trigger NOTREACHED() below. + break; + } + + NOTREACHED() << "Bad status " << new_captive_portal_status; + return false; +} + +bool AutoEnrollmentCheckStep::UpdateAutoEnrollmentState( + policy::AutoEnrollmentState new_auto_enrollment_state) { + switch (new_auto_enrollment_state) { + case policy::AUTO_ENROLLMENT_STATE_IDLE: + // The client should have been started already. + NOTREACHED(); + return false; + case policy::AUTO_ENROLLMENT_STATE_PENDING: + case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR: + case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT: + case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT: + return false; + case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR: + ShowErrorScreen(ErrorScreen::ERROR_STATE_OFFLINE); + return true; + } + + NOTREACHED() << "bad state " << new_auto_enrollment_state; + return false; +} + +void AutoEnrollmentCheckStep::ShowErrorScreen( + ErrorScreen::ErrorState error_state) { + const NetworkState* network = + NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); + ErrorScreen* error_screen = screen_observer_->GetErrorScreen(); + error_screen->SetUIState(ErrorScreen::UI_STATE_AUTO_ENROLLMENT_ERROR); + error_screen->SetErrorState(error_state, + network ? network->name() : std::string()); + screen_observer_->ShowErrorScreen(); +} + +void AutoEnrollmentCheckStep::SignalCompletion() { + NetworkPortalDetector::Get()->RemoveObserver(this); + auto_enrollment_progress_subscription_.reset(); + screen_observer_->OnExit( + ScreenObserver::ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_step.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_step.h new file mode 100644 index 0000000..baa3931 --- /dev/null +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_check_step.h @@ -0,0 +1,79 @@ +// Copyright 2014 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_ENROLLMENT_AUTO_ENROLLMENT_CHECK_STEP_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_ENROLLMENT_AUTO_ENROLLMENT_CHECK_STEP_H_ + +#include "base/compiler_specific.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h" +#include "chrome/browser/chromeos/login/screens/error_screen.h" +#include "chrome/browser/chromeos/net/network_portal_detector.h" + +namespace chromeos { + +class ScreenObserver; + +// Handles the control flow after OOBE auto-update completes to wait for the +// enterprise auto-enrollment check that happens as part of OOBE. This includes +// keeping track of current auto-enrollment state and displaying and updating +// the error screen upon failures. Similar to a screen controller, but it +// doesn't actually drive a dedicated screen. +class AutoEnrollmentCheckStep : NetworkPortalDetector::Observer { + public: + AutoEnrollmentCheckStep(ScreenObserver* screen_observer, + AutoEnrollmentController* auto_enrollment_controller); + virtual ~AutoEnrollmentCheckStep(); + + // Hands over OOBE control to this AutoEnrollmentCheckStep. It'll return the + // flow back to the caller via the |screen_observer_|'s OnExit function. + void Start(); + + // NetworkPortalDetector::Observer implementation: + virtual void OnPortalDetectionCompleted( + const NetworkState* network, + const NetworkPortalDetector::CaptivePortalState& state) OVERRIDE; + + private: + // Handles update notifications regarding the auto-enrollment check. + void OnAutoEnrollmentCheckProgressed(policy::AutoEnrollmentState state); + + // Handles a state update, updating the UI and saving the state. + void UpdateState( + NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status, + policy::AutoEnrollmentState new_auto_enrollment_state); + + // Configures the UI to reflect |new_captive_portal_status|. Returns true if + // and only if a UI change has been made. + bool UpdateCaptivePortalStatus( + NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status); + + // Configures the UI to reflect |auto_enrollment_state|. Returns true if and + // only if a UI change has been made. + bool UpdateAutoEnrollmentState( + policy::AutoEnrollmentState auto_enrollment_state); + + // Configures the error screen. + void ShowErrorScreen(ErrorScreen::ErrorState error_state); + + // Signals completion. No further code should run after a call to this + // function as the owner might destroy |this| in response. + void SignalCompletion(); + + ScreenObserver* screen_observer_; + AutoEnrollmentController* auto_enrollment_controller_; + + scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription> + auto_enrollment_progress_subscription_; + + NetworkPortalDetector::CaptivePortalStatus captive_portal_status_; + policy::AutoEnrollmentState auto_enrollment_state_; + + DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentCheckStep); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_ENROLLMENT_AUTO_ENROLLMENT_CHECK_STEP_H_ diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc new file mode 100644 index 0000000..3c273ad --- /dev/null +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.cc @@ -0,0 +1,170 @@ +// Copyright 2014 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/enrollment/auto_enrollment_controller.h" + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/command_line.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" +#include "chromeos/chromeos_switches.h" +#include "components/policy/core/browser/browser_policy_connector.h" +#include "components/policy/core/common/cloud/device_management_service.h" +#include "net/url_request/url_request_context_getter.h" + +namespace chromeos { + +namespace { + +// Returns the int value of the |switch_name| argument, clamped to the [0, 62] +// interval. Returns 0 if the argument doesn't exist or isn't an int value. +int GetSanitizedArg(const std::string& switch_name) { + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (!command_line->HasSwitch(switch_name)) + return 0; + std::string value = command_line->GetSwitchValueASCII(switch_name); + int int_value; + if (!base::StringToInt(value, &int_value)) { + LOG(ERROR) << "Switch \"" << switch_name << "\" is not a valid int. " + << "Defaulting to 0."; + return 0; + } + if (int_value < 0) { + LOG(ERROR) << "Switch \"" << switch_name << "\" can't be negative. " + << "Using 0"; + return 0; + } + if (int_value > policy::AutoEnrollmentClient::kMaximumPower) { + LOG(ERROR) << "Switch \"" << switch_name << "\" can't be greater than " + << policy::AutoEnrollmentClient::kMaximumPower << ". Using " + << policy::AutoEnrollmentClient::kMaximumPower; + return policy::AutoEnrollmentClient::kMaximumPower; + } + return int_value; +} + +} // namespace + +AutoEnrollmentController::AutoEnrollmentController() + : state_(policy::AUTO_ENROLLMENT_STATE_IDLE), + weak_factory_(this) {} + +AutoEnrollmentController::~AutoEnrollmentController() {} + +void AutoEnrollmentController::Start() { + // This method is called at the point in the OOBE/login flow at which the + // auto-enrollment check can start. This happens either after the EULA is + // accepted, or right after a reboot if the EULA has already been accepted. + + // Do not communicate auto-enrollment data to the server if + // 1. we are running integration or perf tests with telemetry. + // 2. modulus configuration is not present. + CommandLine* command_line = CommandLine::ForCurrentProcess(); + if (command_line->HasSwitch(chromeos::switches::kOobeSkipPostLogin) || + (!command_line->HasSwitch( + chromeos::switches::kEnterpriseEnrollmentInitialModulus) && + !command_line->HasSwitch( + chromeos::switches::kEnterpriseEnrollmentModulusLimit))) { + VLOG(1) << "Auto-enrollment disabled."; + UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT); + return; + } + + // If there already is a client, bail out. + if (client_) + return; + + // Start by checking if the device has already been owned. + UpdateState(policy::AUTO_ENROLLMENT_STATE_PENDING); + weak_factory_.InvalidateWeakPtrs(); + DeviceSettingsService::Get()->GetOwnershipStatusAsync( + base::Bind(&AutoEnrollmentController::OnOwnershipStatusCheckDone, + weak_factory_.GetWeakPtr())); +} + +void AutoEnrollmentController::Cancel() { + if (client_) { + // Cancelling the |client_| allows it to determine whether + // its protocol finished before login was complete. + client_.release()->CancelAndDeleteSoon(); + } +} + +void AutoEnrollmentController::Retry() { + if (client_) + client_->Retry(); +} + +scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription> +AutoEnrollmentController::RegisterProgressCallback( + const ProgressCallbackList::CallbackType& callback) { + return progress_callbacks_.Add(callback); +} + +bool AutoEnrollmentController::ShouldEnrollSilently() { + return !CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnterpriseEnableForcedReEnrollment) && + state_ == policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT; +} + +void AutoEnrollmentController::OnOwnershipStatusCheckDone( + DeviceSettingsService::OwnershipStatus status) { + if (status != DeviceSettingsService::OWNERSHIP_NONE) { + // The device is already owned. No need for auto-enrollment checks. + VLOG(1) << "Device already owned, skipping auto-enrollment check"; + UpdateState(policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT); + return; + } + + policy::BrowserPolicyConnector* connector = + g_browser_process->browser_policy_connector(); + policy::DeviceManagementService* service = + connector->device_management_service(); + service->ScheduleInitialization(0); + + int power_initial = GetSanitizedArg( + chromeos::switches::kEnterpriseEnrollmentInitialModulus); + int power_limit = GetSanitizedArg( + chromeos::switches::kEnterpriseEnrollmentModulusLimit); + if (power_initial > power_limit) { + LOG(ERROR) << "Initial auto-enrollment modulus is larger than the limit, " + << "clamping to the limit."; + power_initial = power_limit; + } + + bool retrieve_device_state = false; + std::string device_id; + if (CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kEnterpriseEnableForcedReEnrollment)) { + retrieve_device_state = true; + device_id = policy::DeviceCloudPolicyManagerChromeOS::GetDeviceStateKey(); + } else { + device_id = policy::DeviceCloudPolicyManagerChromeOS::GetMachineID(); + } + + client_.reset(new policy::AutoEnrollmentClient( + base::Bind(&AutoEnrollmentController::UpdateState, + base::Unretained(this)), + service, + g_browser_process->local_state(), + g_browser_process->system_request_context(), + device_id, + retrieve_device_state, + power_initial, + power_limit)); + + VLOG(1) << "Starting auto-enrollment client."; + client_->Start(); +} + +void AutoEnrollmentController::UpdateState( + policy::AutoEnrollmentState new_state) { + state_ = new_state; + progress_callbacks_.Notify(state_); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h new file mode 100644 index 0000000..2b48dfd --- /dev/null +++ b/chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h @@ -0,0 +1,65 @@ +// Copyright 2014 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_ENROLLMENT_AUTO_ENROLLMENT_CONTROLLER_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_ENROLLMENT_AUTO_ENROLLMENT_CONTROLLER_H_ + +#include "base/callback_list.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/policy/auto_enrollment_client.h" +#include "chrome/browser/chromeos/settings/device_settings_service.h" + +namespace chromeos { + +// Drives the auto-enrollment check, running an AutoEnrollmentClient if +// appropriate to make a decision. +class AutoEnrollmentController { + public: + typedef base::CallbackList<void(policy::AutoEnrollmentState)> + ProgressCallbackList; + + AutoEnrollmentController(); + ~AutoEnrollmentController(); + + // Starts the auto-enrollment check. + void Start(); + + // Stops any pending auto-enrollment checking. + void Cancel(); + + // Retry checking. + void Retry(); + + // Registers a callback to invoke on state changes. + scoped_ptr<ProgressCallbackList::Subscription> RegisterProgressCallback( + const ProgressCallbackList::CallbackType& callback); + + // Checks whether legacy auto-enrollment should be performed. + bool ShouldEnrollSilently(); + + policy::AutoEnrollmentState state() const { return state_; } + + private: + // Callback for the ownership status check. + void OnOwnershipStatusCheckDone( + DeviceSettingsService::OwnershipStatus status); + + // Sets |state_| and notifies |progress_callbacks_|. + void UpdateState(policy::AutoEnrollmentState state); + + policy::AutoEnrollmentState state_; + ProgressCallbackList progress_callbacks_; + + base::WeakPtrFactory<AutoEnrollmentController> weak_factory_; + + scoped_ptr<policy::AutoEnrollmentClient> client_; + + DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentController); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_ENROLLMENT_AUTO_ENROLLMENT_CONTROLLER_H_ diff --git a/chrome/browser/chromeos/login/login_display_host.h b/chrome/browser/chromeos/login/login_display_host.h index f045313..9a7a3fc 100644 --- a/chrome/browser/chromeos/login/login_display_host.h +++ b/chrome/browser/chromeos/login/login_display_host.h @@ -13,7 +13,6 @@ #include "base/values.h" #include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/login/login_display.h" -#include "chrome/browser/chromeos/policy/auto_enrollment_client.h" #include "ui/gfx/native_widget_types.h" namespace views { @@ -23,6 +22,7 @@ class Widget; namespace chromeos { class AppLaunchController; +class AutoEnrollmentController; class LoginScreenContext; class WebUILoginView; class WizardController; @@ -32,15 +32,6 @@ class WizardController; // UI implementation (such as LoginDisplay). class LoginDisplayHost { public: - // Callback for RegisterAutoEnrollmentProgressHandler. It is invoked with when - // the auto-enrollment check progresses. - typedef base::Callback<void(policy::AutoEnrollmentClient::State)> - AutoEnrollmentProgressCallback; - typedef base::CallbackList<void(policy::AutoEnrollmentClient::State)> - AutoEnrollmentProgressCallbackList; - typedef AutoEnrollmentProgressCallbackList::Subscription - AutoEnrollmentProgressCallbackSubscription; - virtual ~LoginDisplayHost() {} // Creates UI implementation specific login display instance (views/WebUI). @@ -70,16 +61,8 @@ class LoginDisplayHost { // Toggles status area visibility. virtual void SetStatusAreaVisible(bool visible) = 0; - // Signals the LoginDisplayHost that it can proceed with the Enterprise - // Auto-Enrollment checks now. - virtual void CheckForAutoEnrollment() = 0; - - // Registers a callback for auto enrollment state changes. The callback will - // be invoked synchronously once to report the initial state and then whenever - // the state changes until the subscription is dropped. - virtual scoped_ptr<AutoEnrollmentProgressCallbackSubscription> - RegisterAutoEnrollmentProgressHandler( - const AutoEnrollmentProgressCallback& callback) = 0; + // Gets the auto-enrollment client. + virtual AutoEnrollmentController* GetAutoEnrollmentController() = 0; // Starts out-of-box-experience flow or shows other screen handled by // Wizard controller i.e. camera, recovery. diff --git a/chrome/browser/chromeos/login/login_display_host_impl.cc b/chrome/browser/chromeos/login/login_display_host_impl.cc index 3672626..89ec4c8 100644 --- a/chrome/browser/chromeos/login/login_display_host_impl.cc +++ b/chrome/browser/chromeos/login/login_display_host_impl.cc @@ -275,7 +275,6 @@ content::RenderFrameHost* LoginDisplayHostImpl::GetGaiaAuthIframe( LoginDisplayHostImpl::LoginDisplayHostImpl(const gfx::Rect& background_bounds) : background_bounds_(background_bounds), pointer_factory_(this), - auto_enrollment_state_(policy::AutoEnrollmentClient::STATE_PENDING), shutting_down_(false), oobe_progress_bar_visible_(false), session_starting_(false), @@ -454,10 +453,8 @@ void LoginDisplayHostImpl::Finalize() { } void LoginDisplayHostImpl::OnCompleteLogin() { - // Cancelling the |auto_enrollment_client_| now allows it to determine whether - // its protocol finished before login was complete. - if (auto_enrollment_client_.get()) - auto_enrollment_client_.release()->CancelAndDeleteSoon(); + if (auto_enrollment_controller_) + auto_enrollment_controller_->Cancel(); } void LoginDisplayHostImpl::OpenProxySettings() { @@ -472,34 +469,15 @@ void LoginDisplayHostImpl::SetStatusAreaVisible(bool visible) { login_view_->SetStatusAreaVisible(visible); } -void LoginDisplayHostImpl::CheckForAutoEnrollment() { - // This method is called when the controller determines that the - // auto-enrollment check can start. This happens either after the EULA is - // accepted, or right after a reboot if the EULA has already been accepted. - - if (policy::AutoEnrollmentClient::IsDisabled()) { - VLOG(1) << "CheckForAutoEnrollment: auto-enrollment disabled"; - SetAutoEnrollmentState(policy::AutoEnrollmentClient::STATE_NO_ENROLLMENT); - return; +AutoEnrollmentController* LoginDisplayHostImpl::GetAutoEnrollmentController() { + if (!auto_enrollment_controller_) { + auto_enrollment_controller_.reset(new AutoEnrollmentController()); + auto_enrollment_progress_subscription_ = + auto_enrollment_controller_->RegisterProgressCallback( + base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentProgress, + base::Unretained(this))); } - - // Start by checking if the device has already been owned. - pointer_factory_.InvalidateWeakPtrs(); - DeviceSettingsService::Get()->GetOwnershipStatusAsync( - base::Bind(&LoginDisplayHostImpl::OnOwnershipStatusCheckDone, - pointer_factory_.GetWeakPtr())); -} - -scoped_ptr<LoginDisplayHost::AutoEnrollmentProgressCallbackSubscription> -LoginDisplayHostImpl::RegisterAutoEnrollmentProgressHandler( - const AutoEnrollmentProgressCallback& callback) { - DCHECK(!callback.is_null()); - - scoped_ptr<AutoEnrollmentProgressCallbackSubscription> - subscription(auto_enrollment_progress_callbacks_.Add(callback)); - - callback.Run(auto_enrollment_state_); - return subscription.Pass(); + return auto_enrollment_controller_.get(); } void LoginDisplayHostImpl::StartWizard( @@ -626,7 +604,10 @@ void LoginDisplayHostImpl::StartSignInScreen( // We might be here after a reboot that was triggered after OOBE was complete, // so check for auto-enrollment again. This might catch a cached decision from // a previous oobe flow, or might start a new check with the server. - CheckForAutoEnrollment(); + if (GetAutoEnrollmentController()->ShouldEnrollSilently()) + sign_in_controller_->DoAutoEnrollment(); + else + GetAutoEnrollmentController()->Start(); // Initiate mobile config load. MobileConfig::GetInstance(); @@ -860,56 +841,14 @@ void LoginDisplayHostImpl::ScheduleFadeOutAnimation() { layer->SetOpacity(0); } -void LoginDisplayHostImpl::OnOwnershipStatusCheckDone( - DeviceSettingsService::OwnershipStatus status) { - if (status != DeviceSettingsService::OWNERSHIP_NONE) { - // The device is already owned. No need for auto-enrollment checks. - VLOG(1) << "CheckForAutoEnrollment: device already owned"; - SetAutoEnrollmentState(policy::AutoEnrollmentClient::STATE_NO_ENROLLMENT); - return; - } - - // Kick off the auto-enrollment client. - if (auto_enrollment_client_.get()) { - // They client might have been started after the EULA screen, but we made - // it to the login screen before it finished. In that case let the current - // client proceed. - // - // CheckForAutoEnrollment() is also called when we reach the sign-in screen, - // because that's what happens after an auto-update. - VLOG(1) << "CheckForAutoEnrollment: client already started"; - - // If the client already started and already finished too, pass the decision - // to the |sign_in_controller_| now. - if (ShouldEnrollSilently()) - ForceAutoEnrollment(); - } else { - VLOG(1) << "CheckForAutoEnrollment: starting auto-enrollment client"; - auto_enrollment_client_.reset(policy::AutoEnrollmentClient::Create( - base::Bind(&LoginDisplayHostImpl::OnAutoEnrollmentClientProgress, - base::Unretained(this)))); - auto_enrollment_client_->Start(); - } -} - -void LoginDisplayHostImpl::OnAutoEnrollmentClientProgress( - policy::AutoEnrollmentClient::State state) { - VLOG(1) << "OnAutoEnrollmentClientProgress, state " << state; - SetAutoEnrollmentState(state); - - if (ShouldEnrollSilently()) - ForceAutoEnrollment(); -} - -void LoginDisplayHostImpl::SetAutoEnrollmentState( - policy::AutoEnrollmentClient::State new_state) { - auto_enrollment_state_ = new_state; - auto_enrollment_progress_callbacks_.Notify(auto_enrollment_state_); -} +void LoginDisplayHostImpl::OnAutoEnrollmentProgress( + policy::AutoEnrollmentState state) { + VLOG(1) << "OnAutoEnrollmentProgress, state " << state; -void LoginDisplayHostImpl::ForceAutoEnrollment() { - if (sign_in_controller_.get()) + if (sign_in_controller_ && + auto_enrollment_controller_->ShouldEnrollSilently()) { sign_in_controller_->DoAutoEnrollment(); + } } void LoginDisplayHostImpl::LoadURL(const GURL& url) { @@ -1088,13 +1027,6 @@ void LoginDisplayHostImpl::OnLoginPromptVisible() { TryToPlayStartupSound(); } -bool LoginDisplayHostImpl::ShouldEnrollSilently() { - return !CommandLine::ForCurrentProcess()->HasSwitch( - chromeos::switches::kEnterpriseEnableForcedReEnrollment) && - auto_enrollment_state_ == - policy::AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT; -} - //////////////////////////////////////////////////////////////////////////////// // external diff --git a/chrome/browser/chromeos/login/login_display_host_impl.h b/chrome/browser/chromeos/login/login_display_host_impl.h index 049da91..6c0bbab 100644 --- a/chrome/browser/chromeos/login/login_display_host_impl.h +++ b/chrome/browser/chromeos/login/login_display_host_impl.h @@ -33,10 +33,6 @@ class RenderFrameHost; class WebContents; } -namespace policy { -class AutoEnrollmentClient; -} // namespace policy - namespace chromeos { class FocusRingController; @@ -75,10 +71,7 @@ class LoginDisplayHostImpl : public LoginDisplayHost, virtual void OnCompleteLogin() OVERRIDE; virtual void OpenProxySettings() OVERRIDE; virtual void SetStatusAreaVisible(bool visible) OVERRIDE; - virtual void CheckForAutoEnrollment() OVERRIDE; - virtual scoped_ptr<AutoEnrollmentProgressCallbackSubscription> - RegisterAutoEnrollmentProgressHandler( - const AutoEnrollmentProgressCallback& callback) OVERRIDE; + virtual AutoEnrollmentController* GetAutoEnrollmentController() OVERRIDE; virtual void StartWizard( const std::string& first_screen_name, scoped_ptr<base::DictionaryValue> screen_parameters) OVERRIDE; @@ -153,19 +146,8 @@ class LoginDisplayHostImpl : public LoginDisplayHost, // Schedules fade out animation. void ScheduleFadeOutAnimation(); - // Callback for the ownership status check. - void OnOwnershipStatusCheckDone( - DeviceSettingsService::OwnershipStatus status); - - // Progress callback registered with |auto_enrollment_client_|. - void OnAutoEnrollmentClientProgress( - policy::AutoEnrollmentClient::State state); - - // Records auto-enrollment progress and notifies subscribers. - void SetAutoEnrollmentState(policy::AutoEnrollmentClient::State new_state); - - // Forces auto-enrollment on the appropriate controller. - void ForceAutoEnrollment(); + // Progress callback registered with |auto_enrollment_controller_|. + void OnAutoEnrollmentProgress(policy::AutoEnrollmentState state); // Loads given URL. Creates WebUILoginView if needed. void LoadURL(const GURL& url); @@ -197,9 +179,6 @@ class LoginDisplayHostImpl : public LoginDisplayHost, // Called when login-prompt-visible signal is caught. void OnLoginPromptVisible(); - // Checks whether to silently enroll on login. - bool ShouldEnrollSilently(); - // Used to calculate position of the screens and background. gfx::Rect background_bounds_; @@ -207,12 +186,6 @@ class LoginDisplayHostImpl : public LoginDisplayHost, base::WeakPtrFactory<LoginDisplayHostImpl> pointer_factory_; - // Current auto-enrollment check state. - policy::AutoEnrollmentClient::State auto_enrollment_state_; - - // Callbacks to notify when auto enrollment client progresses. - AutoEnrollmentProgressCallbackList auto_enrollment_progress_callbacks_; - // Default LoginDisplayHost. static LoginDisplayHost* default_host_; @@ -228,8 +201,12 @@ class LoginDisplayHostImpl : public LoginDisplayHost, // Demo app launcher. scoped_ptr<DemoAppLauncher> demo_app_launcher_; - // Client for enterprise auto-enrollment check. - scoped_ptr<policy::AutoEnrollmentClient> auto_enrollment_client_; + // The controller driving the auto-enrollment check. + scoped_ptr<AutoEnrollmentController> auto_enrollment_controller_; + + // Subscription for progress callbacks from |auto_enrollement_controller_|. + scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription> + auto_enrollment_progress_subscription_; // Has ShutdownDisplayHost() already been called? Used to avoid posting our // own deletion to the message loop twice if the user logs out while we're diff --git a/chrome/browser/chromeos/login/mock_login_display_host.cc b/chrome/browser/chromeos/login/mock_login_display_host.cc index 832eab2..9cb6df1 100644 --- a/chrome/browser/chromeos/login/mock_login_display_host.cc +++ b/chrome/browser/chromeos/login/mock_login_display_host.cc @@ -14,12 +14,6 @@ MockLoginDisplayHost::MockLoginDisplayHost() { MockLoginDisplayHost::~MockLoginDisplayHost() { } -scoped_ptr<LoginDisplayHost::AutoEnrollmentProgressCallbackSubscription> -MockLoginDisplayHost::RegisterAutoEnrollmentProgressHandler( - const AutoEnrollmentProgressCallback& callback) { - return make_scoped_ptr(RegisterAutoEnrollmentProgressHandlerPtr(callback)); -} - void MockLoginDisplayHost::StartWizard( const std::string& name, scoped_ptr<base::DictionaryValue> value) { diff --git a/chrome/browser/chromeos/login/mock_login_display_host.h b/chrome/browser/chromeos/login/mock_login_display_host.h index 43da398..a653802 100644 --- a/chrome/browser/chromeos/login/mock_login_display_host.h +++ b/chrome/browser/chromeos/login/mock_login_display_host.h @@ -27,15 +27,9 @@ class MockLoginDisplayHost : public LoginDisplayHost { MOCK_METHOD0(OpenProxySettings, void(void)); MOCK_METHOD1(SetStatusAreaVisible, void(bool)); MOCK_METHOD0(ShowBackground, void(void)); - MOCK_METHOD0(CheckForAutoEnrollment, void(void)); + MOCK_METHOD0(GetAutoEnrollmentController, AutoEnrollmentController*(void)); // GMock currently doesn't support move-only arguments, so we have // to use this hack here. - MOCK_METHOD1(RegisterAutoEnrollmentProgressHandlerPtr, - AutoEnrollmentProgressCallbackSubscription*( - const AutoEnrollmentProgressCallback&)); - virtual scoped_ptr<AutoEnrollmentProgressCallbackSubscription>( - RegisterAutoEnrollmentProgressHandler( - const AutoEnrollmentProgressCallback& callback)) OVERRIDE; MOCK_METHOD2(StartWizardPtr, void(const std::string&, base::DictionaryValue*)); virtual void StartWizard(const std::string& name, diff --git a/chrome/browser/chromeos/login/screens/screen_observer.h b/chrome/browser/chromeos/login/screens/screen_observer.h index c8ad239..4138f89 100644 --- a/chrome/browser/chromeos/login/screens/screen_observer.h +++ b/chrome/browser/chromeos/login/screens/screen_observer.h @@ -33,6 +33,7 @@ class ScreenObserver { USER_IMAGE_SELECTED, EULA_ACCEPTED, EULA_BACK, + ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED, ENTERPRISE_ENROLLMENT_COMPLETED, ENTERPRISE_AUTO_MAGIC_ENROLLMENT_COMPLETED, ENTERPRISE_ENROLLMENT_BACK, diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 0ac5f1e..84de164 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc @@ -12,7 +12,6 @@ #include <vector> #include "base/bind.h" -#include "base/command_line.h" #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/prefs/pref_registry_simple.h" @@ -25,6 +24,7 @@ #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include "chrome/browser/chromeos/customization_document.h" +#include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_step.h" #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h" #include "chrome/browser/chromeos/login/existing_user_controller.h" #include "chrome/browser/chromeos/login/helper.h" @@ -60,7 +60,6 @@ #include "chrome/common/pref_names.h" #include "chromeos/audio/cras_audio_handler.h" #include "chromeos/chromeos_constants.h" -#include "chromeos/chromeos_switches.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/session_manager_client.h" #include "chromeos/network/network_state.h" @@ -443,7 +442,7 @@ void WizardController::SkipToLoginForTesting( const LoginScreenContext& context) { StartupUtils::MarkEulaAccepted(); PerformPostEulaActions(); - PerformPostUpdateActions(); + PerformOOBECompletedActions(); ShowLoginScreen(context); } @@ -493,7 +492,7 @@ void WizardController::OnConnectionFailed() { } void WizardController::OnUpdateCompleted() { - CheckAutoEnrollmentState(); + StartAutoEnrollmentCheck(); } void WizardController::OnEulaAccepted() { @@ -513,7 +512,7 @@ void WizardController::OnEulaAccepted() { if (skip_update_enroll_after_eula_) { PerformPostEulaActions(); - PerformPostUpdateActions(); + PerformOOBECompletedActions(); ShowEnrollmentScreen(); } else { InitiateOOBEUpdate(); @@ -569,7 +568,7 @@ void WizardController::OnEnrollmentDone() { // Mark OOBE as completed only if enterprise enrollment was part of the // forced flow (i.e. app kiosk). if (ShouldAutoStartEnrollment()) - PerformPostUpdateActions(); + PerformOOBECompletedActions(); // TODO(mnissler): Unify the logic for auto-login for Public Sessions and // Kiosk Apps and make this code cover both cases: http://crbug.com/234694. @@ -612,10 +611,11 @@ void WizardController::OnAutoEnrollmentDone() { } void WizardController::OnOOBECompleted() { + auto_enrollment_check_step_.reset(); if (ShouldAutoStartEnrollment()) { ShowEnrollmentScreen(); } else { - PerformPostUpdateActions(); + PerformOOBECompletedActions(); ShowLoginScreen(LoginScreenContext()); } } @@ -652,12 +652,12 @@ void WizardController::PerformPostEulaActions() { // ChromiumOS builds would go though this code path too. NetworkHandler::Get()->network_state_handler()->SetCheckPortalList( NetworkStateHandler::kDefaultCheckPortalList); - host_->CheckForAutoEnrollment(); + host_->GetAutoEnrollmentController()->Start(); host_->PrewarmAuthentication(); NetworkPortalDetector::Get()->Enable(true); } -void WizardController::PerformPostUpdateActions() { +void WizardController::PerformOOBECompletedActions() { StartupUtils::MarkOobeCompleted(); } @@ -782,6 +782,9 @@ void WizardController::OnExit(ExitCodes exit_code) { case EULA_BACK: ShowNetworkScreen(); break; + case ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED: + OnOOBECompleted(); + break; case ENTERPRISE_ENROLLMENT_COMPLETED: OnEnrollmentDone(); break; @@ -916,53 +919,10 @@ void WizardController::OnLocalStateInitialized(bool /* succeeded */) { ShowErrorScreen(); } -void WizardController::CheckAutoEnrollmentState() { - if (CommandLine::ForCurrentProcess()->HasSwitch( - chromeos::switches::kEnterpriseEnableForcedReEnrollment)) { - auto_enrollment_progress_subscription_ = - host_->RegisterAutoEnrollmentProgressHandler( - base::Bind(&WizardController::OnAutoEnrollmentCheckProgressed, - weak_factory_.GetWeakPtr())); - } else { - OnOOBECompleted(); - } -} - -void WizardController::OnAutoEnrollmentCheckProgressed( - policy::AutoEnrollmentClient::State state) { - ErrorScreen* error_screen = GetErrorScreen(); - switch (state) { - case policy::AutoEnrollmentClient::STATE_PENDING: - if (current_screen_ == error_screen && - error_screen->GetUIState() == - ErrorScreen::UI_STATE_AUTO_ENROLLMENT_ERROR) { - error_screen->ShowConnectingIndicator(true); - } - return; - case policy::AutoEnrollmentClient::STATE_CONNECTION_ERROR: { - // Show an error screen and ask the user to fix the network connection. - const NetworkState* default_network = - NetworkHandler::Get()->network_state_handler()->DefaultNetwork(); - DCHECK(default_network); - error_screen->SetUIState(ErrorScreen::UI_STATE_AUTO_ENROLLMENT_ERROR); - error_screen->SetErrorState( - ErrorScreen::ERROR_STATE_OFFLINE, - default_network ? default_network->name() : std::string()); - error_screen->ShowConnectingIndicator(false); - ShowErrorScreen(); - return; - } - case policy::AutoEnrollmentClient::STATE_SERVER_ERROR: - // Server errors don't block OOBE. - case policy::AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT: - case policy::AutoEnrollmentClient::STATE_NO_ENROLLMENT: - // Decision made, ready to proceed. - auto_enrollment_progress_subscription_.reset(); - OnOOBECompleted(); - return; - } - - NOTREACHED(); +void WizardController::StartAutoEnrollmentCheck() { + auto_enrollment_check_step_.reset( + new AutoEnrollmentCheckStep(this, host_->GetAutoEnrollmentController())); + auto_enrollment_check_step_->Start(); } PrefService* WizardController::GetLocalState() { diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h index 3f42385..9634a81 100644 --- a/chrome/browser/chromeos/login/wizard_controller.h +++ b/chrome/browser/chromeos/login/wizard_controller.h @@ -15,7 +15,6 @@ #include "base/time/time.h" #include "base/timer/timer.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" -#include "chrome/browser/chromeos/login/login_display_host.h" #include "chrome/browser/chromeos/login/screens/screen_observer.h" #include "chrome/browser/chromeos/login/screens/wizard_screen.h" #include "chrome/browser/chromeos/policy/auto_enrollment_client.h" @@ -36,12 +35,14 @@ struct Geoposition; namespace chromeos { +class AutoEnrollmentCheckStep; class EnrollmentScreen; class ErrorScreen; class EulaScreen; class KioskAutolaunchScreen; class KioskEnableScreen; class LocallyManagedUserCreationScreen; +class LoginDisplayHost; class LoginScreenContext; class NetworkScreen; class OobeDisplay; @@ -224,7 +225,7 @@ class WizardController : public ScreenObserver { void PerformPostEulaActions(); // Actions that should be done right after update stage is finished. - void PerformPostUpdateActions(); + void PerformOOBECompletedActions(); // Overridden from ScreenObserver: virtual void OnExit(ExitCodes exit_code) OVERRIDE; @@ -263,12 +264,9 @@ class WizardController : public ScreenObserver { // Called when LocalState is initialized. void OnLocalStateInitialized(bool /* succeeded */); - // Checks auto enrollment state and eventually triggers the next wizard step. - void CheckAutoEnrollmentState(); - - // Handles update notifications regarding the auto-enrollment check. - void OnAutoEnrollmentCheckProgressed( - policy::AutoEnrollmentClient::State state); + // Kicks off the auto-enrollment check step. Once it finishes, it'll call + // back via ScreenObserver::OnExit(). + void StartAutoEnrollmentCheck(); // Returns local state. PrefService* GetLocalState(); @@ -332,6 +330,9 @@ class WizardController : public ScreenObserver { // Default WizardController. static WizardController* default_controller_; + // The auto-enrollment check step, currently active. + scoped_ptr<AutoEnrollmentCheckStep> auto_enrollment_check_step_; + // Parameters for the first screen. May be NULL. scoped_ptr<base::DictionaryValue> screen_parameters_; @@ -369,8 +370,6 @@ class WizardController : public ScreenObserver { friend class WizardControllerBrokenLocalStateTest; scoped_ptr<AccessibilityStatusSubscription> accessibility_subscription_; - scoped_ptr<LoginDisplayHost::AutoEnrollmentProgressCallbackSubscription> - auto_enrollment_progress_subscription_; base::WeakPtrFactory<WizardController> weak_factory_; diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc index 13716db..d856dc4 100644 --- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc @@ -36,11 +36,13 @@ #include "chrome/browser/chromeos/login/webui_login_view.h" #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/chromeos/login/wizard_in_process_browser_test.h" +#include "chrome/browser/chromeos/policy/server_backed_device_state.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" #include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/audio/cras_audio_handler.h" #include "chromeos/chromeos_switches.h" @@ -137,6 +139,25 @@ void SetUpCrasAndEnableChromeVox(int volume_percent, bool mute_on) { base::RunLoop().RunUntilIdle(); } +void QuitLoopOnAutoEnrollmentProgress( + policy::AutoEnrollmentState expected_state, + base::RunLoop* loop, + policy::AutoEnrollmentState actual_state) { + if (expected_state == actual_state) + loop->Quit(); +} + +void WaitForAutoEnrollmentState(policy::AutoEnrollmentState state) { + base::RunLoop loop; + AutoEnrollmentController* auto_enrollment_controller = + LoginDisplayHostImpl::default_host()->GetAutoEnrollmentController(); + scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription> + progress_subscription( + auto_enrollment_controller->RegisterProgressCallback( + base::Bind(&QuitLoopOnAutoEnrollmentProgress, state, &loop))); + loop.Run(); +} + } // namespace using ::testing::_; @@ -176,6 +197,11 @@ class WizardControllerTest : public WizardInProcessBrowserTest { WizardInProcessBrowserTest::SetUpOnMainThread(); } + ErrorScreen* GetErrorScreen() { + return static_cast<ScreenObserver*>(WizardController::default_controller()) + ->GetErrorScreen(); + } + private: DISALLOW_COPY_AND_ASSIGN(WizardControllerTest); }; @@ -490,6 +516,63 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, EXPECT_FALSE(ExistingUserController::current_controller() == NULL); } +IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, + ControlFlowForcedReEnrollment) { + CommandLine::ForCurrentProcess()->AppendSwitch( + switches::kEnterpriseEnableForcedReEnrollment); + CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kEnterpriseEnrollmentInitialModulus, "1"); + CommandLine::ForCurrentProcess()->AppendSwitchASCII( + switches::kEnterpriseEnrollmentModulusLimit, "2"); + + EXPECT_EQ(WizardController::default_controller()->GetNetworkScreen(), + WizardController::default_controller()->current_screen()); + EXPECT_CALL(*mock_network_screen_, Hide()).Times(1); + EXPECT_CALL(*mock_eula_screen_, Show()).Times(1); + OnExit(ScreenObserver::NETWORK_CONNECTED); + + EXPECT_EQ(WizardController::default_controller()->GetEulaScreen(), + WizardController::default_controller()->current_screen()); + EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); + EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); + EXPECT_CALL(*mock_update_screen_, Show()).Times(1); + OnExit(ScreenObserver::EULA_ACCEPTED); + // Let update screen smooth time process (time = 0ms). + content::RunAllPendingInMessageLoop(); + + EXPECT_EQ(WizardController::default_controller()->GetUpdateScreen(), + WizardController::default_controller()->current_screen()); + EXPECT_CALL(*mock_update_screen_, Hide()).Times(1); + OnExit(ScreenObserver::UPDATE_INSTALLED); + + // Wait for auto-enrollment controller to encounter the connection error. + WaitForAutoEnrollmentState(policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR); + + // The error screen shows up if there's no auto-enrollment decision. + EXPECT_FALSE(StartupUtils::IsOobeCompleted()); + EXPECT_EQ(GetErrorScreen(), + WizardController::default_controller()->current_screen()); + base::DictionaryValue device_state; + device_state.SetString(policy::kDeviceStateRestoreMode, + policy::kDeviceStateRestoreModeReEnrollmentEnforced); + g_browser_process->local_state()->Set(prefs::kServerBackedDeviceState, + device_state); + EXPECT_CALL(*mock_enrollment_screen_, Show()).Times(1); + EXPECT_CALL(*mock_enrollment_screen_->actor(), + SetParameters(mock_enrollment_screen_, + false, // auto_start_enrollmetn + false, // can_exit_enrollment + "")).Times(1); + OnExit(ScreenObserver::ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED); + + // Make sure enterprise enrollment page shows up. + EXPECT_EQ(WizardController::default_controller()->GetEnrollmentScreen(), + WizardController::default_controller()->current_screen()); + OnExit(ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED); + + EXPECT_TRUE(StartupUtils::IsOobeCompleted()); +} + class WizardControllerBrokenLocalStateTest : public WizardControllerTest { protected: WizardControllerBrokenLocalStateTest() @@ -526,11 +609,6 @@ class WizardControllerBrokenLocalStateTest : public WizardControllerTest { WizardControllerTest::TearDownInProcessBrowserTestFixture(); } - ErrorScreen* GetErrorScreen() { - return ((ScreenObserver*) WizardController::default_controller())-> - GetErrorScreen(); - } - content::WebContents* GetWebContents() { LoginDisplayHostImpl* host = static_cast<LoginDisplayHostImpl*>( LoginDisplayHostImpl::default_host()); @@ -761,7 +839,7 @@ IN_PROC_BROWSER_TEST_F(WizardControllerKioskFlowTest, // TODO(nkostylev): Add test for WebUI accelerators http://crosbug.com/22571 -COMPILE_ASSERT(ScreenObserver::EXIT_CODES_COUNT == 19, +COMPILE_ASSERT(ScreenObserver::EXIT_CODES_COUNT == 20, add_tests_for_new_control_flow_you_just_introduced); } // namespace chromeos diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.cc b/chrome/browser/chromeos/policy/auto_enrollment_client.cc index ac7ee69..2b7bdde 100644 --- a/chrome/browser/chromeos/policy/auto_enrollment_client.cc +++ b/chrome/browser/chromeos/policy/auto_enrollment_client.cc @@ -5,7 +5,6 @@ #include "chrome/browser/chromeos/policy/auto_enrollment_client.h" #include "base/bind.h" -#include "base/command_line.h" #include "base/guid.h" #include "base/location.h" #include "base/logging.h" @@ -15,14 +14,10 @@ #include "base/prefs/pref_registry_simple.h" #include "base/prefs/pref_service.h" #include "base/prefs/scoped_user_pref_update.h" -#include "base/strings/string_number_conversions.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/policy/server_backed_device_state.h" #include "chrome/common/chrome_content_client.h" #include "chrome/common/pref_names.h" -#include "chromeos/chromeos_switches.h" -#include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/cloud/system_policy_request_context.h" #include "content/public/browser/browser_thread.h" @@ -46,45 +41,14 @@ const char kUMARequestStatus[] = "Enterprise.AutoEnrollmentRequestStatus"; const char kUMANetworkErrorCode[] = "Enterprise.AutoEnrollmentRequestNetworkErrorCode"; -// The modulus value is sent in an int64 field in the protobuf, whose maximum -// value is 2^63-1. So 2^64 and 2^63 can't be represented as moduli and the -// max is 2^62 (when the moduli are restricted to powers-of-2). -const int kMaximumPower = 62; - -// Returns the int value of the |switch_name| argument, clamped to the [0, 62] -// interval. Returns 0 if the argument doesn't exist or isn't an int value. -int GetSanitizedArg(const std::string& switch_name) { - CommandLine* command_line = CommandLine::ForCurrentProcess(); - if (!command_line->HasSwitch(switch_name)) - return 0; - std::string value = command_line->GetSwitchValueASCII(switch_name); - int int_value; - if (!base::StringToInt(value, &int_value)) { - LOG(ERROR) << "Switch \"" << switch_name << "\" is not a valid int. " - << "Defaulting to 0."; - return 0; - } - if (int_value < 0) { - LOG(ERROR) << "Switch \"" << switch_name << "\" can't be negative. " - << "Using 0"; - return 0; - } - if (int_value > kMaximumPower) { - LOG(ERROR) << "Switch \"" << switch_name << "\" can't be greater than " - << kMaximumPower << ". Using " << kMaximumPower; - return kMaximumPower; - } - return int_value; -} - // Returns the power of the next power-of-2 starting at |value|. int NextPowerOf2(int64 value) { - for (int i = 0; i <= kMaximumPower; ++i) { + for (int i = 0; i <= AutoEnrollmentClient::kMaximumPower; ++i) { if ((GG_INT64_C(1) << i) >= value) return i; } // No other value can be represented in an int64. - return kMaximumPower + 1; + return AutoEnrollmentClient::kMaximumPower + 1; } // Sets or clears a value in a dictionary. @@ -128,7 +92,7 @@ AutoEnrollmentClient::AutoEnrollmentClient( int power_initial, int power_limit) : progress_callback_(callback), - state_(STATE_PENDING), + state_(AUTO_ENROLLMENT_STATE_IDLE), has_server_state_(false), device_state_available_(false), device_id_(base::GenerateGUID()), @@ -148,7 +112,6 @@ AutoEnrollmentClient::AutoEnrollmentClient( server_backed_state_key_hash_ = crypto::SHA256HashString(server_backed_state_key_); } - net::NetworkChangeNotifier::AddNetworkChangeObserver(this); } AutoEnrollmentClient::~AutoEnrollmentClient() { @@ -162,64 +125,6 @@ void AutoEnrollmentClient::RegisterPrefs(PrefRegistrySimple* registry) { } // static -bool AutoEnrollmentClient::IsDisabled() { - CommandLine* command_line = CommandLine::ForCurrentProcess(); - // Do not communicate auto-enrollment data to the server if - // 1. we are running integration or perf tests with telemetry. - // 2. modulus configuration is not present. - return command_line->HasSwitch(chromeos::switches::kOobeSkipPostLogin) || - (!command_line->HasSwitch( - chromeos::switches::kEnterpriseEnrollmentInitialModulus) && - !command_line->HasSwitch( - chromeos::switches::kEnterpriseEnrollmentModulusLimit)); -} - -// static -AutoEnrollmentClient* AutoEnrollmentClient::Create( - const ProgressCallback& progress_callback) { - // The client won't do anything if |service| is NULL. - DeviceManagementService* service = NULL; - if (IsDisabled()) { - VLOG(1) << "Auto-enrollment is disabled"; - } else { - BrowserPolicyConnector* connector = - g_browser_process->browser_policy_connector(); - service = connector->device_management_service(); - service->ScheduleInitialization(0); - } - - int power_initial = GetSanitizedArg( - chromeos::switches::kEnterpriseEnrollmentInitialModulus); - int power_limit = GetSanitizedArg( - chromeos::switches::kEnterpriseEnrollmentModulusLimit); - if (power_initial > power_limit) { - LOG(ERROR) << "Initial auto-enrollment modulus is larger than the limit, " - << "clamping to the limit."; - power_initial = power_limit; - } - - bool retrieve_device_state = false; - std::string device_id; - if (CommandLine::ForCurrentProcess()->HasSwitch( - chromeos::switches::kEnterpriseEnableForcedReEnrollment)) { - retrieve_device_state = true; - device_id = DeviceCloudPolicyManagerChromeOS::GetDeviceStateKey(); - } else { - device_id = DeviceCloudPolicyManagerChromeOS::GetMachineID(); - } - - return new AutoEnrollmentClient( - progress_callback, - service, - g_browser_process->local_state(), - g_browser_process->system_request_context(), - device_id, - retrieve_device_state, - power_initial, - power_limit); -} - -// static void AutoEnrollmentClient::CancelAutoEnrollment() { PrefService* local_state = g_browser_process->local_state(); local_state->SetBoolean(prefs::kShouldAutoEnroll, false); @@ -228,9 +133,13 @@ void AutoEnrollmentClient::CancelAutoEnrollment() { } void AutoEnrollmentClient::Start() { + // (Re-)register the network change observer. + net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this); + net::NetworkChangeNotifier::AddNetworkChangeObserver(this); + // Drop the previous job and reset state. request_job_.reset(); - state_ = STATE_PENDING; + state_ = AUTO_ENROLLMENT_STATE_PENDING; time_start_ = base::Time::Now(); modulus_updates_received_ = 0; has_server_state_ = false; @@ -239,6 +148,10 @@ void AutoEnrollmentClient::Start() { NextStep(); } +void AutoEnrollmentClient::Retry() { + RetryStep(); +} + void AutoEnrollmentClient::CancelAndDeleteSoon() { if (time_start_.is_null() || !request_job_) { // The client isn't running, just delete it. @@ -305,7 +218,7 @@ bool AutoEnrollmentClient::RetryStep() { return false; } -void AutoEnrollmentClient::ReportProgress(State state) { +void AutoEnrollmentClient::ReportProgress(AutoEnrollmentState state) { state_ = state; if (progress_callback_.is_null()) { base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this); @@ -330,8 +243,8 @@ void AutoEnrollmentClient::NextStep() { trigger_enrollment = has_server_state_; } - ReportProgress(trigger_enrollment ? STATE_TRIGGER_ENROLLMENT - : STATE_NO_ENROLLMENT); + ReportProgress(trigger_enrollment ? AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT + : AUTO_ENROLLMENT_STATE_NO_ENROLLMENT); } } @@ -348,7 +261,7 @@ bool AutoEnrollmentClient::SendBucketDownloadRequest() { } remainder = remainder & ((GG_UINT64_C(1) << current_power_) - 1); - ReportProgress(STATE_PENDING); + ReportProgress(AUTO_ENROLLMENT_STATE_PENDING); request_job_.reset( device_management_service_->CreateJob( @@ -367,7 +280,7 @@ bool AutoEnrollmentClient::SendBucketDownloadRequest() { } bool AutoEnrollmentClient::SendDeviceStateRequest() { - ReportProgress(STATE_PENDING); + ReportProgress(AUTO_ENROLLMENT_STATE_PENDING); request_job_.reset( device_management_service_->CreateJob( @@ -400,8 +313,9 @@ void AutoEnrollmentClient::HandleRequestCompletion( if (progress_callback_.is_null()) { base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE, this); } else { - ReportProgress(status == DM_STATUS_REQUEST_FAILED ? STATE_CONNECTION_ERROR - : STATE_SERVER_ERROR); + ReportProgress(status == DM_STATUS_REQUEST_FAILED + ? AUTO_ENROLLMENT_STATE_CONNECTION_ERROR + : AUTO_ENROLLMENT_STATE_SERVER_ERROR); } return; } @@ -411,7 +325,7 @@ void AutoEnrollmentClient::HandleRequestCompletion( if (progress) NextStep(); else - ReportProgress(STATE_SERVER_ERROR); + ReportProgress(AUTO_ENROLLMENT_STATE_SERVER_ERROR); } bool AutoEnrollmentClient::OnBucketDownloadRequestCompletion( diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client.h b/chrome/browser/chromeos/policy/auto_enrollment_client.h index 39c07f6..1adc415 100644 --- a/chrome/browser/chromeos/policy/auto_enrollment_client.h +++ b/chrome/browser/chromeos/policy/auto_enrollment_client.h @@ -32,28 +32,35 @@ namespace policy { class DeviceManagementRequestJob; class DeviceManagementService; +// Indicates the current state of the auto-enrollment check. +enum AutoEnrollmentState { + // Not yet started. + AUTO_ENROLLMENT_STATE_IDLE, + // Working, another event will be fired eventually. + AUTO_ENROLLMENT_STATE_PENDING, + // Failed to connect to DMServer. + AUTO_ENROLLMENT_STATE_CONNECTION_ERROR, + // Connection successful, but the server failed to generate a valid reply. + AUTO_ENROLLMENT_STATE_SERVER_ERROR, + // Check completed successfully, enrollment should be triggered. + AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, + // Check completed successfully, enrollment not applicable. + AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, +}; + // Interacts with the device management service and determines whether this // machine should automatically enter the Enterprise Enrollment screen during // OOBE. class AutoEnrollmentClient : public net::NetworkChangeNotifier::NetworkChangeObserver { public: - // Indicates the current state of the auto-enrollment check. - enum State { - // Working, another event will be fired eventually. - STATE_PENDING, - // Failed to connect to DMServer. - STATE_CONNECTION_ERROR, - // Connection successful, but the server failed to generate a valid reply. - STATE_SERVER_ERROR, - // Check completed successfully, enrollment should be triggered. - STATE_TRIGGER_ENROLLMENT, - // Check completed successfully, enrollment not applicable. - STATE_NO_ENROLLMENT, - }; + // The modulus value is sent in an int64 field in the protobuf, whose maximum + // value is 2^63-1. So 2^64 and 2^63 can't be represented as moduli and the + // max is 2^62 (when the moduli are restricted to powers-of-2). + static const int kMaximumPower = 62; // Used for signaling progress to a consumer. - typedef base::Callback<void(State)> ProgressCallback; + typedef base::Callback<void(AutoEnrollmentState)> ProgressCallback; // |progress_callback| will be invoked whenever some significant event happens // as part of the protocol, after Start() is invoked. @@ -74,14 +81,6 @@ class AutoEnrollmentClient // Registers preferences in local state. static void RegisterPrefs(PrefRegistrySimple* registry); - // Returns true if auto-enrollment is disabled in this device. In that case, - // instances returned by Create() fail immediately once Start() is invoked. - static bool IsDisabled(); - - // Convenience method to create instances of this class. - static AutoEnrollmentClient* Create( - const ProgressCallback& progress_callback); - // Cancels auto-enrollment. // This function does not interrupt a running auto-enrollment check. It only // stores a pref in |local_state| that prevents the client from entering @@ -93,6 +92,11 @@ class AutoEnrollmentClient // call can invoke the |progress_callback_| if errors occur. void Start(); + // Triggers a retry of the currently pending step. This is intended to be + // called by consumers when they become aware of environment changes (such as + // captive portal setup being complete). + void Retry(); + // Cancels any pending requests. |progress_callback_| will not be invoked. // |this| will delete itself. void CancelAndDeleteSoon(); @@ -102,7 +106,7 @@ class AutoEnrollmentClient std::string device_id() const { return device_id_; } // Current state. - State state() const { return state_; } + AutoEnrollmentState state() const { return state_; } // Implementation of net::NetworkChangeNotifier::NetworkChangeObserver: virtual void OnNetworkChanged( @@ -123,7 +127,7 @@ class AutoEnrollmentClient bool RetryStep(); // Cleans up and invokes |progress_callback_|. - void ReportProgress(State state); + void ReportProgress(AutoEnrollmentState state); // Calls RetryStep() to make progress or determine that all is done. In the // latter case, calls ReportProgress(). @@ -167,7 +171,7 @@ class AutoEnrollmentClient ProgressCallback progress_callback_; // Current state. - State state_; + AutoEnrollmentState state_; // Whether the hash bucket check succeeded, indicating that the server knows // this device and might have keep state for it. diff --git a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc index bfdb451..d8fb571 100644 --- a/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc +++ b/chrome/browser/chromeos/policy/auto_enrollment_client_unittest.cc @@ -46,7 +46,7 @@ class AutoEnrollmentClientTest : public testing::Test { : scoped_testing_local_state_( TestingBrowserProcess::GetGlobal()), local_state_(scoped_testing_local_state_.Get()), - state_(AutoEnrollmentClient::STATE_PENDING) {} + state_(AUTO_ENROLLMENT_STATE_PENDING) {} virtual void SetUp() OVERRIDE { CreateClient(kStateKey, true, 4, 8); @@ -63,7 +63,7 @@ class AutoEnrollmentClientTest : public testing::Test { bool retrieve_device_state, int power_initial, int power_limit) { - state_ = AutoEnrollmentClient::STATE_PENDING; + state_ = AUTO_ENROLLMENT_STATE_PENDING; service_.reset(new MockDeviceManagementService()); EXPECT_CALL(*service_, StartJob(_, _, _, _, _, _, _)) .WillRepeatedly(SaveArg<6>(&last_request_)); @@ -80,7 +80,7 @@ class AutoEnrollmentClientTest : public testing::Test { power_limit)); } - void ProgressCallback(AutoEnrollmentClient::State state) { + void ProgressCallback(AutoEnrollmentState state) { state_ = state; } @@ -158,7 +158,7 @@ class AutoEnrollmentClientTest : public testing::Test { scoped_ptr<MockDeviceManagementService> service_; scoped_ptr<AutoEnrollmentClient> client_; em::DeviceManagementRequest last_request_; - AutoEnrollmentClient::State state_; + AutoEnrollmentState state_; private: DISALLOW_COPY_AND_ASSIGN(AutoEnrollmentClientTest); @@ -167,21 +167,21 @@ class AutoEnrollmentClientTest : public testing::Test { TEST_F(AutoEnrollmentClientTest, NetworkFailure) { ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); } TEST_F(AutoEnrollmentClientTest, EmptyReply) { ServerWillReply(-1, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); VerifyCachedResult(false, 8); } TEST_F(AutoEnrollmentClientTest, ClientUploadsRightBits) { ServerWillReply(-1, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); EXPECT_TRUE(auto_enrollment_request().has_remainder()); EXPECT_TRUE(auto_enrollment_request().has_modulus()); @@ -195,7 +195,7 @@ TEST_F(AutoEnrollmentClientTest, AskForMoreThenFail) { ServerWillReply(32, false, false); ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); } @@ -204,7 +204,7 @@ TEST_F(AutoEnrollmentClientTest, AskForMoreThenEvenMore) { ServerWillReply(32, false, false); ServerWillReply(64, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); } @@ -216,7 +216,7 @@ TEST_F(AutoEnrollmentClientTest, AskForLess) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); VerifyCachedResult(true, 8); } @@ -228,7 +228,7 @@ TEST_F(AutoEnrollmentClientTest, AskForSame) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); VerifyCachedResult(true, 8); } @@ -237,14 +237,14 @@ TEST_F(AutoEnrollmentClientTest, AskForSameTwice) { ServerWillReply(16, false, false); ServerWillReply(16, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); } TEST_F(AutoEnrollmentClientTest, AskForTooMuch) { ServerWillReply(512, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); } @@ -253,7 +253,7 @@ TEST_F(AutoEnrollmentClientTest, AskNonPowerOf2) { ServerWillReply(100, false, false); ServerWillReply(-1, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); EXPECT_TRUE(auto_enrollment_request().has_remainder()); EXPECT_TRUE(auto_enrollment_request().has_modulus()); EXPECT_EQ(128, auto_enrollment_request().modulus()); @@ -264,13 +264,13 @@ TEST_F(AutoEnrollmentClientTest, AskNonPowerOf2) { TEST_F(AutoEnrollmentClientTest, ConsumerDevice) { ServerWillReply(-1, true, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); VerifyCachedResult(false, 8); // Network changes don't trigger retries after obtaining a response from // the server. client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); } TEST_F(AutoEnrollmentClientTest, EnterpriseDevice) { @@ -279,19 +279,19 @@ TEST_F(AutoEnrollmentClientTest, EnterpriseDevice) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); VerifyCachedResult(true, 8); // Network changes don't trigger retries after obtaining a response from // the server. client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); } TEST_F(AutoEnrollmentClientTest, NoSerial) { CreateClient("", true, 4, 8); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); EXPECT_FALSE(HasCachedDecision()); } @@ -299,7 +299,7 @@ TEST_F(AutoEnrollmentClientTest, NoBitsUploaded) { CreateClient(kStateKey, true, 0, 0); ServerWillReply(-1, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); EXPECT_TRUE(auto_enrollment_request().has_remainder()); EXPECT_TRUE(auto_enrollment_request().has_modulus()); EXPECT_EQ(1, auto_enrollment_request().modulus()); @@ -313,7 +313,7 @@ TEST_F(AutoEnrollmentClientTest, ManyBitsUploaded) { CreateClient(kStateKey, true, i, i); ServerWillReply(-1, false, false); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); EXPECT_TRUE(auto_enrollment_request().has_remainder()); EXPECT_TRUE(auto_enrollment_request().has_modulus()); EXPECT_EQ(GG_INT64_C(1) << i, auto_enrollment_request().modulus()); @@ -332,7 +332,7 @@ TEST_F(AutoEnrollmentClientTest, MoreThan32BitsUploaded) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); VerifyCachedResult(true, 37); } @@ -346,10 +346,10 @@ TEST_F(AutoEnrollmentClientTest, ReuseCachedDecision) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); AutoEnrollmentClient::CancelAutoEnrollment(); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_NO_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_NO_ENROLLMENT, state_); } TEST_F(AutoEnrollmentClientTest, RetryIfPowerLargerThanCached) { @@ -363,19 +363,19 @@ TEST_F(AutoEnrollmentClientTest, RetryIfPowerLargerThanCached) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); } TEST_F(AutoEnrollmentClientTest, NetworkChangeRetryAfterErrors) { ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE); client_->Start(); // Don't invoke the callback if there was a network failure. - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); // The client doesn't retry if no new connection became available. client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE); - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); // Retry once the network is back. @@ -384,13 +384,13 @@ TEST_F(AutoEnrollmentClientTest, NetworkChangeRetryAfterErrors) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); EXPECT_TRUE(HasCachedDecision()); // Subsequent network changes don't trigger retries. client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_NONE); client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); EXPECT_TRUE(HasCachedDecision()); } @@ -400,7 +400,7 @@ TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonWithPendingRequest) { EXPECT_FALSE(job); client_->Start(); ASSERT_TRUE(job); - EXPECT_EQ(AutoEnrollmentClient::STATE_PENDING, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_); // Cancel while a request is in flight. EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); @@ -412,7 +412,7 @@ TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonWithPendingRequest) { em::DeviceManagementResponse()); // The DeleteSoon task has been posted: EXPECT_FALSE(base::MessageLoop::current()->IsIdleForTesting()); - EXPECT_EQ(AutoEnrollmentClient::STATE_PENDING, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_); } TEST_F(AutoEnrollmentClientTest, NetworkChangedAfterCancelAndDeleteSoon) { @@ -421,7 +421,7 @@ TEST_F(AutoEnrollmentClientTest, NetworkChangedAfterCancelAndDeleteSoon) { EXPECT_FALSE(job); client_->Start(); ASSERT_TRUE(job); - EXPECT_EQ(AutoEnrollmentClient::STATE_PENDING, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_); // Cancel while a request is in flight. EXPECT_TRUE(base::MessageLoop::current()->IsIdleForTesting()); @@ -431,18 +431,18 @@ TEST_F(AutoEnrollmentClientTest, NetworkChangedAfterCancelAndDeleteSoon) { // Network change events are ignored while a request is pending. client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - EXPECT_EQ(AutoEnrollmentClient::STATE_PENDING, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_); // The client cleans itself up once a reply is received. job->SendResponse(DM_STATUS_TEMPORARY_UNAVAILABLE, em::DeviceManagementResponse()); // The DeleteSoon task has been posted: EXPECT_FALSE(base::MessageLoop::current()->IsIdleForTesting()); - EXPECT_EQ(AutoEnrollmentClient::STATE_PENDING, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_); // Network changes that have been posted before are also ignored: client->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - EXPECT_EQ(AutoEnrollmentClient::STATE_PENDING, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_PENDING, state_); } TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterCompletion) { @@ -451,7 +451,7 @@ TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterCompletion) { "example.com", em::DeviceStateRetrievalResponse::RESTORE_MODE_REENROLLMENT_ENFORCED); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); // The client will delete itself immediately if there are no pending // requests. @@ -463,7 +463,7 @@ TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterCompletion) { TEST_F(AutoEnrollmentClientTest, CancelAndDeleteSoonAfterNetworkFailure) { ServerWillFail(DM_STATUS_TEMPORARY_UNAVAILABLE); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_SERVER_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_SERVER_ERROR, state_); // The client will delete itself immediately if there are no pending // requests. @@ -480,7 +480,7 @@ TEST_F(AutoEnrollmentClientTest, NetworkFailureThenRequireUpdatedModulus) { ServerWillFail(DM_STATUS_REQUEST_FAILED); client_->Start(); // Callback should signal the connection error. - EXPECT_EQ(AutoEnrollmentClient::STATE_CONNECTION_ERROR, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_CONNECTION_ERROR, state_); EXPECT_FALSE(HasCachedDecision()); Mock::VerifyAndClearExpectations(service_.get()); @@ -499,7 +499,7 @@ TEST_F(AutoEnrollmentClientTest, NetworkFailureThenRequireUpdatedModulus) { // Trigger a network change event. client_->OnNetworkChanged(net::NetworkChangeNotifier::CONNECTION_ETHERNET); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); EXPECT_TRUE(HasCachedDecision()); Mock::VerifyAndClearExpectations(service_.get()); } @@ -511,7 +511,7 @@ TEST_F(AutoEnrollmentClientTest, NoDeviceStateRetrieval) { CreateJob(DeviceManagementRequestJob::TYPE_DEVICE_STATE_RETRIEVAL, _)).Times(0); client_->Start(); - EXPECT_EQ(AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT, state_); + EXPECT_EQ(AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT, state_); VerifyCachedResult(true, 8); } diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index f28d783..2d4afb9 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc @@ -29,6 +29,7 @@ #include "chrome/browser/chromeos/input_method/input_method_util.h" #include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h" #include "chrome/browser/chromeos/login/hwid_checker.h" +#include "chrome/browser/chromeos/login/login_display_host.h" #include "chrome/browser/chromeos/login/login_display_host_impl.h" #include "chrome/browser/chromeos/login/multi_profile_user_controller.h" #include "chrome/browser/chromeos/login/screen_locker.h" @@ -310,7 +311,6 @@ SigninScreenHandler::SigninScreenHandler( offline_login_active_(false), last_network_state_(NetworkStateInformer::UNKNOWN), has_pending_auth_ui_(false), - wait_for_auto_enrollment_check_(false), caps_lock_enabled_(false), gaia_screen_handler_(gaia_screen_handler) { DCHECK(network_state_informer_.get()); @@ -1258,11 +1258,13 @@ void SigninScreenHandler::HandleToggleKioskEnableScreen() { !auto_enrollment_progress_subscription_ && !connector->IsEnterpriseManaged() && LoginDisplayHostImpl::default_host()) { + AutoEnrollmentController* auto_enrollment_controller = + LoginDisplayHostImpl::default_host()->GetAutoEnrollmentController(); auto_enrollment_progress_subscription_ = - LoginDisplayHostImpl::default_host() - ->RegisterAutoEnrollmentProgressHandler( - base::Bind(&SigninScreenHandler::ContinueKioskEnableFlow, - weak_factory_.GetWeakPtr())); + auto_enrollment_controller->RegisterProgressCallback( + base::Bind(&SigninScreenHandler::ContinueKioskEnableFlow, + weak_factory_.GetWeakPtr())); + ContinueKioskEnableFlow(auto_enrollment_controller->state()); } } @@ -1717,23 +1719,24 @@ void SigninScreenHandler::SubmitLoginFormForTest() { } void SigninScreenHandler::ContinueKioskEnableFlow( - policy::AutoEnrollmentClient::State state) { + policy::AutoEnrollmentState state) { // Do not proceed with kiosk enable when auto enroll will be enforced. // TODO(xiyuan): Add an error UI feedkback so user knows what happens. switch (state) { - case policy::AutoEnrollmentClient::STATE_PENDING: - case policy::AutoEnrollmentClient::STATE_CONNECTION_ERROR: + case policy::AUTO_ENROLLMENT_STATE_IDLE: + case policy::AUTO_ENROLLMENT_STATE_PENDING: + case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR: // Wait for the next callback. return; - case policy::AutoEnrollmentClient::STATE_TRIGGER_ENROLLMENT: + case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT: // Auto-enrollment is on. LOG(WARNING) << "Kiosk enable flow aborted because auto enrollment is " "going to be enforced."; if (!kiosk_enable_flow_aborted_callback_for_test_.is_null()) kiosk_enable_flow_aborted_callback_for_test_.Run(); break; - case policy::AutoEnrollmentClient::STATE_SERVER_ERROR: - case policy::AutoEnrollmentClient::STATE_NO_ENROLLMENT: + case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR: + case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT: // Auto-enrollment not applicable. if (delegate_) delegate_->ShowKioskEnableScreen(); diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index 0af9107..d2967a3 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h @@ -15,12 +15,11 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" +#include "chrome/browser/chromeos/login/enrollment/auto_enrollment_controller.h" #include "chrome/browser/chromeos/login/login_display.h" -#include "chrome/browser/chromeos/login/login_display_host.h" #include "chrome/browser/chromeos/login/screens/error_screen_actor.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/net/network_portal_detector.h" -#include "chrome/browser/chromeos/policy/auto_enrollment_client.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/ui/webui/chromeos/login/base_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" @@ -438,7 +437,7 @@ class SigninScreenHandler // Invoked when auto enrollment check progresses to decide whether to // continue kiosk enable flow. Kiosk enable flow is resumed when // |state| indicates that enrollment is not applicable. - void ContinueKioskEnableFlow(policy::AutoEnrollmentClient::State state); + void ContinueKioskEnableFlow(policy::AutoEnrollmentState state); // Shows signin screen for |email|. void OnShowAddUser(const std::string& email); @@ -525,11 +524,9 @@ class SigninScreenHandler scoped_ptr<CrosSettings::ObserverSubscription> allow_new_user_subscription_; scoped_ptr<CrosSettings::ObserverSubscription> allow_guest_subscription_; - scoped_ptr<LoginDisplayHost::AutoEnrollmentProgressCallbackSubscription> + scoped_ptr<AutoEnrollmentController::ProgressCallbackList::Subscription> auto_enrollment_progress_subscription_; - bool wait_for_auto_enrollment_check_; - bool caps_lock_enabled_; base::Closure kiosk_enable_flow_aborted_callback_for_test_; diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index 9e52737..8baab56 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -466,6 +466,10 @@ 'browser/chromeos/login/default_user_images.h', 'browser/chromeos/login/demo_mode/demo_app_launcher.cc', 'browser/chromeos/login/demo_mode/demo_app_launcher.h', + 'browser/chromeos/login/enrollment/auto_enrollment_check_step.cc', + 'browser/chromeos/login/enrollment/auto_enrollment_check_step.h', + 'browser/chromeos/login/enrollment/auto_enrollment_controller.cc', + 'browser/chromeos/login/enrollment/auto_enrollment_controller.h', 'browser/chromeos/login/enrollment/enrollment_screen.cc', 'browser/chromeos/login/enrollment/enrollment_screen.h', 'browser/chromeos/login/enrollment/enrollment_screen_actor.h', |