// Copyright (c) 2011 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/enterprise_enrollment_screen.h"
#include "base/logging.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/cros/cros_library.h"
#include "chrome/browser/chromeos/cros/cryptohome_library.h"
#include "chrome/browser/chromeos/login/screen_observer.h"
#include "chrome/browser/policy/browser_policy_connector.h"
#include "chrome/common/net/gaia/gaia_constants.h"
namespace chromeos {
// Retry for InstallAttrs initialization every 500ms.
const int kLockRetryIntervalMs = 500;
EnterpriseEnrollmentScreen::EnterpriseEnrollmentScreen(
WizardScreenDelegate* delegate)
: ViewScreen<EnterpriseEnrollmentView>(delegate),
ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this)) {
// Init the TPM if it has not been done until now (in debug build we might
// have not done that yet).
chromeos::CryptohomeLibrary* cryptohome =
chromeos::CrosLibrary::Get()->GetCryptohomeLibrary();
if (cryptohome) {
if (cryptohome->TpmIsEnabled() &&
!cryptohome->TpmIsBeingOwned() &&
!cryptohome->TpmIsOwned()) {
cryptohome->TpmCanAttemptOwnership();
}
}
}
EnterpriseEnrollmentScreen::~EnterpriseEnrollmentScreen() {}
void EnterpriseEnrollmentScreen::Authenticate(const std::string& user,
const std::string& password,
const std::string& captcha,
const std::string& access_code) {
captcha_token_.clear();
user_ = user;
auth_fetcher_.reset(
new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
g_browser_process->system_request_context()));
if (access_code.empty()) {
auth_fetcher_->StartClientLogin(user, password,
GaiaConstants::kDeviceManagementService,
captcha_token_, captcha,
GaiaAuthFetcher::HostedAccountsAllowed);
} else {
auth_fetcher_->StartClientLogin(user, access_code,
GaiaConstants::kDeviceManagementService,
std::string(), std::string(),
GaiaAuthFetcher::HostedAccountsAllowed);
}
}
void EnterpriseEnrollmentScreen::CancelEnrollment() {
auth_fetcher_.reset();
registrar_.reset();
g_browser_process->browser_policy_connector()->StopAutoRetry();
ScreenObserver* observer = delegate()->GetObserver(this);
observer->OnExit(ScreenObserver::ENTERPRISE_ENROLLMENT_CANCELLED);
}
void EnterpriseEnrollmentScreen::CloseConfirmation() {
auth_fetcher_.reset();
ScreenObserver* observer = delegate()->GetObserver(this);
observer->OnExit(ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED);
}
bool EnterpriseEnrollmentScreen::GetInitialUser(std::string* user) {
chromeos::CryptohomeLibrary* cryptohome =
chromeos::CrosLibrary::Get()->GetCryptohomeLibrary();
if (cryptohome &&
cryptohome->InstallAttributesIsReady() &&
!cryptohome->InstallAttributesIsFirstInstall()) {
std::string value;
if (cryptohome->InstallAttributesGet("enterprise.owned", &value) &&
value == "true") {
if (cryptohome->InstallAttributesGet("enterprise.user", &value)) {
// If we landed in the enrollment dialogue with a locked InstallAttrs
// this means we might only want to reenroll with the DMServer so lock
// the username to what has been stored in the InstallAttrs already.
*user = value;
if (view())
view()->set_editable_user(false);
return true;
}
}
LOG(ERROR) << "Enrollment will not finish because the InstallAttrs has "
<< "been locked already but does not contain valid data.";
}
return false;
}
void EnterpriseEnrollmentScreen::OnClientLoginSuccess(
const ClientLoginResult& result) {
auth_fetcher_->StartIssueAuthToken(
result.sid, result.lsid, GaiaConstants::kDeviceManagementService);
}
void EnterpriseEnrollmentScreen::OnClientLoginFailure(
const GoogleServiceAuthError& error) {
HandleAuthError(error);
}
void EnterpriseEnrollmentScreen::OnIssueAuthTokenSuccess(
const std::string& service,
const std::string& auth_token) {
if (service != GaiaConstants::kDeviceManagementService) {
NOTREACHED() << service;
return;
}
scoped_ptr<GaiaAuthFetcher> auth_fetcher(auth_fetcher_.release());
policy::BrowserPolicyConnector* connector =
g_browser_process->browser_policy_connector();
if (!connector->cloud_policy_subsystem()) {
NOTREACHED() << "Cloud policy subsystem not initialized.";
if (view())
view()->ShowFatalEnrollmentError();
return;
}
registrar_.reset(new policy::CloudPolicySubsystem::ObserverRegistrar(
connector->cloud_policy_subsystem(), this));
// Push the credentials to the policy infrastructure. It'll start enrollment
// and notify us of progress through CloudPolicySubsystem::Observer.
connector->SetCredentials(user_, auth_token);
}
void EnterpriseEnrollmentScreen::OnIssueAuthTokenFailure(
const std::string& service,
const GoogleServiceAuthError& error) {
if (service != GaiaConstants::kDeviceManagementService) {
NOTREACHED() << service;
return;
}
HandleAuthError(error);
}
void EnterpriseEnrollmentScreen::OnPolicyStateChanged(
policy::CloudPolicySubsystem::PolicySubsystemState state,
policy::CloudPolicySubsystem::ErrorDetails error_details) {
if (view()) {
switch (state) {
case policy::CloudPolicySubsystem::UNENROLLED:
// Still working...
return;
case policy::CloudPolicySubsystem::BAD_GAIA_TOKEN:
case policy::CloudPolicySubsystem::LOCAL_ERROR:
view()->ShowFatalEnrollmentError();
break;
case policy::CloudPolicySubsystem::UNMANAGED:
view()->ShowAccountError();
break;
case policy::CloudPolicySubsystem::NETWORK_ERROR:
view()->ShowNetworkEnrollmentError();
break;
case policy::CloudPolicySubsystem::TOKEN_FETCHED:
WriteInstallAttributesData();
return;
case policy::CloudPolicySubsystem::SUCCESS:
// Success!
registrar_.reset();
view()->ShowConfirmationScreen();
return;
}
// We have an error.
LOG(WARNING) << "Policy subsystem error during enrollment: " << state
<< " details: " << error_details;
}
// Stop the policy infrastructure.
registrar_.reset();
g_browser_process->browser_policy_connector()->StopAutoRetry();
}
EnterpriseEnrollmentView* EnterpriseEnrollmentScreen::AllocateView() {
return new EnterpriseEnrollmentView(this);
}
void EnterpriseEnrollmentScreen::HandleAuthError(
const GoogleServiceAuthError& error) {
scoped_ptr<GaiaAuthFetcher> scoped_killer(auth_fetcher_.release());
if (!view())
return;
switch (error.state()) {
case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
case GoogleServiceAuthError::CONNECTION_FAILED:
case GoogleServiceAuthError::CAPTCHA_REQUIRED:
case GoogleServiceAuthError::TWO_FACTOR:
view()->ShowAuthError(error);
return;
case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
case GoogleServiceAuthError::ACCOUNT_DELETED:
case GoogleServiceAuthError::ACCOUNT_DISABLED:
case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
view()->ShowAccountError();
return;
case GoogleServiceAuthError::NONE:
case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
NOTREACHED() << error.state();
// fall through.
case GoogleServiceAuthError::REQUEST_CANCELED:
LOG(ERROR) << "Unexpected GAIA auth error: " << error.state();
view()->ShowFatalAuthError();
return;
}
NOTREACHED() << error.state();
}
void EnterpriseEnrollmentScreen::WriteInstallAttributesData() {
// Since this method is also called directly.
runnable_method_factory_.RevokeAll();
if (!view())
return;
switch (g_browser_process->browser_policy_connector()->LockDevice(user_)) {
case policy::EnterpriseInstallAttributes::LOCK_SUCCESS: {
// Proceed with policy fetch.
policy::BrowserPolicyConnector* connector =
g_browser_process->browser_policy_connector();
connector->FetchPolicy();
return;
}
case policy::EnterpriseInstallAttributes::LOCK_NOT_READY: {
// InstallAttributes not ready yet, retry later.
LOG(WARNING) << "Install Attributes not ready yet will retry in "
<< kLockRetryIntervalMs << "ms.";
MessageLoop::current()->PostDelayedTask(
FROM_HERE,
runnable_method_factory_.NewRunnableMethod(
&EnterpriseEnrollmentScreen::WriteInstallAttributesData),
kLockRetryIntervalMs);
return;
}
case policy::EnterpriseInstallAttributes::LOCK_BACKEND_ERROR: {
view()->ShowFatalEnrollmentError();
return;
}
case policy::EnterpriseInstallAttributes::LOCK_WRONG_USER: {
LOG(ERROR) << "Enrollment can not proceed because the InstallAttrs "
<< "has been locked already!";
view()->ShowFatalEnrollmentError();
return;
}
}
NOTREACHED();
}
} // namespace chromeos