1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/login/enterprise_enrollment_screen.h"
6
7#include "base/logging.h"
8#include "chrome/browser/browser_process.h"
9#include "chrome/browser/chromeos/cros/cros_library.h"
10#include "chrome/browser/chromeos/cros/cryptohome_library.h"
11#include "chrome/browser/chromeos/login/screen_observer.h"
12#include "chrome/browser/policy/browser_policy_connector.h"
13#include "chrome/common/net/gaia/gaia_constants.h"
14
15namespace chromeos {
16
17// Retry for InstallAttrs initialization every 500ms.
18const int kLockRetryIntervalMs = 500;
19
20EnterpriseEnrollmentScreen::EnterpriseEnrollmentScreen(
21    WizardScreenDelegate* delegate)
22    : ViewScreen<EnterpriseEnrollmentView>(delegate),
23      ALLOW_THIS_IN_INITIALIZER_LIST(runnable_method_factory_(this)) {
24  // Init the TPM if it has not been done until now (in debug build we might
25  // have not done that yet).
26  chromeos::CryptohomeLibrary* cryptohome =
27      chromeos::CrosLibrary::Get()->GetCryptohomeLibrary();
28  if (cryptohome) {
29    if (cryptohome->TpmIsEnabled() &&
30        !cryptohome->TpmIsBeingOwned() &&
31        !cryptohome->TpmIsOwned()) {
32      cryptohome->TpmCanAttemptOwnership();
33    }
34  }
35}
36
37EnterpriseEnrollmentScreen::~EnterpriseEnrollmentScreen() {}
38
39void EnterpriseEnrollmentScreen::Authenticate(const std::string& user,
40                                              const std::string& password,
41                                              const std::string& captcha,
42                                              const std::string& access_code) {
43  captcha_token_.clear();
44  user_ = user;
45  auth_fetcher_.reset(
46      new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
47                          g_browser_process->system_request_context()));
48
49  if (access_code.empty()) {
50    auth_fetcher_->StartClientLogin(user, password,
51                                    GaiaConstants::kDeviceManagementService,
52                                    captcha_token_, captcha,
53                                    GaiaAuthFetcher::HostedAccountsAllowed);
54  } else {
55    auth_fetcher_->StartClientLogin(user, access_code,
56                                    GaiaConstants::kDeviceManagementService,
57                                    std::string(), std::string(),
58                                    GaiaAuthFetcher::HostedAccountsAllowed);
59  }
60}
61
62void EnterpriseEnrollmentScreen::CancelEnrollment() {
63  auth_fetcher_.reset();
64  registrar_.reset();
65  g_browser_process->browser_policy_connector()->StopAutoRetry();
66  ScreenObserver* observer = delegate()->GetObserver(this);
67  observer->OnExit(ScreenObserver::ENTERPRISE_ENROLLMENT_CANCELLED);
68}
69
70void EnterpriseEnrollmentScreen::CloseConfirmation() {
71  auth_fetcher_.reset();
72  ScreenObserver* observer = delegate()->GetObserver(this);
73  observer->OnExit(ScreenObserver::ENTERPRISE_ENROLLMENT_COMPLETED);
74}
75
76bool EnterpriseEnrollmentScreen::GetInitialUser(std::string* user) {
77  chromeos::CryptohomeLibrary* cryptohome =
78      chromeos::CrosLibrary::Get()->GetCryptohomeLibrary();
79  if (cryptohome &&
80      cryptohome->InstallAttributesIsReady() &&
81      !cryptohome->InstallAttributesIsFirstInstall()) {
82    std::string value;
83    if (cryptohome->InstallAttributesGet("enterprise.owned", &value) &&
84        value == "true") {
85      if (cryptohome->InstallAttributesGet("enterprise.user", &value)) {
86        // If we landed in the enrollment dialogue with a locked InstallAttrs
87        // this means we might only want to reenroll with the DMServer so lock
88        // the username to what has been stored in the InstallAttrs already.
89        *user = value;
90        if (view())
91          view()->set_editable_user(false);
92        return true;
93      }
94    }
95    LOG(ERROR) << "Enrollment will not finish because the InstallAttrs has "
96               << "been locked already but does not contain valid data.";
97  }
98  return false;
99}
100
101void EnterpriseEnrollmentScreen::OnClientLoginSuccess(
102    const ClientLoginResult& result) {
103  auth_fetcher_->StartIssueAuthToken(
104          result.sid, result.lsid, GaiaConstants::kDeviceManagementService);
105}
106
107void EnterpriseEnrollmentScreen::OnClientLoginFailure(
108    const GoogleServiceAuthError& error) {
109  HandleAuthError(error);
110}
111
112void EnterpriseEnrollmentScreen::OnIssueAuthTokenSuccess(
113    const std::string& service,
114    const std::string& auth_token) {
115  if (service != GaiaConstants::kDeviceManagementService) {
116    NOTREACHED() << service;
117    return;
118  }
119
120  scoped_ptr<GaiaAuthFetcher> auth_fetcher(auth_fetcher_.release());
121
122  policy::BrowserPolicyConnector* connector =
123      g_browser_process->browser_policy_connector();
124  if (!connector->cloud_policy_subsystem()) {
125    NOTREACHED() << "Cloud policy subsystem not initialized.";
126    if (view())
127      view()->ShowFatalEnrollmentError();
128    return;
129  }
130
131  registrar_.reset(new policy::CloudPolicySubsystem::ObserverRegistrar(
132      connector->cloud_policy_subsystem(), this));
133
134  // Push the credentials to the policy infrastructure. It'll start enrollment
135  // and notify us of progress through CloudPolicySubsystem::Observer.
136  connector->SetCredentials(user_, auth_token);
137}
138
139void EnterpriseEnrollmentScreen::OnIssueAuthTokenFailure(
140    const std::string& service,
141    const GoogleServiceAuthError& error) {
142  if (service != GaiaConstants::kDeviceManagementService) {
143    NOTREACHED() << service;
144    return;
145  }
146
147  HandleAuthError(error);
148}
149
150void EnterpriseEnrollmentScreen::OnPolicyStateChanged(
151    policy::CloudPolicySubsystem::PolicySubsystemState state,
152    policy::CloudPolicySubsystem::ErrorDetails error_details) {
153
154  if (view()) {
155    switch (state) {
156      case policy::CloudPolicySubsystem::UNENROLLED:
157        // Still working...
158        return;
159      case policy::CloudPolicySubsystem::BAD_GAIA_TOKEN:
160      case policy::CloudPolicySubsystem::LOCAL_ERROR:
161        view()->ShowFatalEnrollmentError();
162        break;
163      case policy::CloudPolicySubsystem::UNMANAGED:
164        view()->ShowAccountError();
165        break;
166      case policy::CloudPolicySubsystem::NETWORK_ERROR:
167        view()->ShowNetworkEnrollmentError();
168        break;
169      case policy::CloudPolicySubsystem::TOKEN_FETCHED:
170        WriteInstallAttributesData();
171        return;
172      case policy::CloudPolicySubsystem::SUCCESS:
173        // Success!
174        registrar_.reset();
175        view()->ShowConfirmationScreen();
176        return;
177    }
178
179    // We have an error.
180    LOG(WARNING) << "Policy subsystem error during enrollment: " << state
181                 << " details: " << error_details;
182  }
183
184  // Stop the policy infrastructure.
185  registrar_.reset();
186  g_browser_process->browser_policy_connector()->StopAutoRetry();
187}
188
189EnterpriseEnrollmentView* EnterpriseEnrollmentScreen::AllocateView() {
190  return new EnterpriseEnrollmentView(this);
191}
192
193void EnterpriseEnrollmentScreen::HandleAuthError(
194    const GoogleServiceAuthError& error) {
195  scoped_ptr<GaiaAuthFetcher> scoped_killer(auth_fetcher_.release());
196
197  if (!view())
198    return;
199
200  switch (error.state()) {
201    case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
202    case GoogleServiceAuthError::CONNECTION_FAILED:
203    case GoogleServiceAuthError::CAPTCHA_REQUIRED:
204    case GoogleServiceAuthError::TWO_FACTOR:
205      view()->ShowAuthError(error);
206      return;
207    case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
208    case GoogleServiceAuthError::ACCOUNT_DELETED:
209    case GoogleServiceAuthError::ACCOUNT_DISABLED:
210    case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
211      view()->ShowAccountError();
212      return;
213    case GoogleServiceAuthError::NONE:
214    case GoogleServiceAuthError::HOSTED_NOT_ALLOWED:
215      NOTREACHED() << error.state();
216      // fall through.
217    case GoogleServiceAuthError::REQUEST_CANCELED:
218      LOG(ERROR) << "Unexpected GAIA auth error: " << error.state();
219      view()->ShowFatalAuthError();
220      return;
221  }
222
223  NOTREACHED() << error.state();
224}
225
226void EnterpriseEnrollmentScreen::WriteInstallAttributesData() {
227  // Since this method is also called directly.
228  runnable_method_factory_.RevokeAll();
229
230  if (!view())
231    return;
232
233  switch (g_browser_process->browser_policy_connector()->LockDevice(user_)) {
234    case policy::EnterpriseInstallAttributes::LOCK_SUCCESS: {
235      // Proceed with policy fetch.
236      policy::BrowserPolicyConnector* connector =
237          g_browser_process->browser_policy_connector();
238      connector->FetchPolicy();
239      return;
240    }
241    case policy::EnterpriseInstallAttributes::LOCK_NOT_READY: {
242      // InstallAttributes not ready yet, retry later.
243      LOG(WARNING) << "Install Attributes not ready yet will retry in "
244                   << kLockRetryIntervalMs << "ms.";
245      MessageLoop::current()->PostDelayedTask(
246          FROM_HERE,
247          runnable_method_factory_.NewRunnableMethod(
248              &EnterpriseEnrollmentScreen::WriteInstallAttributesData),
249          kLockRetryIntervalMs);
250      return;
251    }
252    case policy::EnterpriseInstallAttributes::LOCK_BACKEND_ERROR: {
253      view()->ShowFatalEnrollmentError();
254      return;
255    }
256    case policy::EnterpriseInstallAttributes::LOCK_WRONG_USER: {
257      LOG(ERROR) << "Enrollment can not proceed because the InstallAttrs "
258                 << "has been locked already!";
259      view()->ShowFatalEnrollmentError();
260      return;
261    }
262  }
263
264  NOTREACHED();
265}
266
267}  // namespace chromeos
268