1 // Copyright (c) 2012 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/ui/webui/chromeos/login/enrollment_screen_handler.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/compiler_specific.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/values.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/browsing_data/browsing_data_helper.h" 16 #include "chrome/browser/browsing_data/browsing_data_remover.h" 17 #include "chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h" 18 #include "chrome/browser/profiles/profile.h" 19 #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" 20 #include "components/policy/core/browser/cloud/message_util.h" 21 #include "content/public/browser/web_contents.h" 22 #include "google_apis/gaia/gaia_auth_fetcher.h" 23 #include "google_apis/gaia/gaia_auth_util.h" 24 #include "google_apis/gaia/gaia_constants.h" 25 #include "google_apis/gaia/gaia_urls.h" 26 #include "google_apis/gaia/google_service_auth_error.h" 27 #include "grit/chromium_strings.h" 28 #include "grit/generated_resources.h" 29 #include "ui/base/l10n/l10n_util.h" 30 31 namespace { 32 33 const char kJsScreenPath[] = "login.OAuthEnrollmentScreen"; 34 35 // Start page of GAIA authentication extension. 36 const char kGaiaExtStartPage[] = 37 "chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/main.html"; 38 39 // Enrollment step names. 40 const char kEnrollmentStepSignin[] = "signin"; 41 const char kEnrollmentStepSuccess[] = "success"; 42 43 // A helper class that takes care of asynchronously revoking a given token. 44 class TokenRevoker : public GaiaAuthConsumer { 45 public: 46 TokenRevoker() 47 : gaia_fetcher_(this, 48 GaiaConstants::kChromeOSSource, 49 g_browser_process->system_request_context()) {} 50 virtual ~TokenRevoker() {} 51 52 void Start(const std::string& token) { 53 gaia_fetcher_.StartRevokeOAuth2Token(token); 54 } 55 56 // GaiaAuthConsumer: 57 virtual void OnOAuth2RevokeTokenCompleted() OVERRIDE { 58 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 59 } 60 61 private: 62 GaiaAuthFetcher gaia_fetcher_; 63 64 DISALLOW_COPY_AND_ASSIGN(TokenRevoker); 65 }; 66 67 } // namespace 68 69 namespace chromeos { 70 71 // EnrollmentScreenHandler, public ------------------------------ 72 73 EnrollmentScreenHandler::EnrollmentScreenHandler() 74 : BaseScreenHandler(kJsScreenPath), 75 controller_(NULL), 76 show_on_init_(false), 77 is_auto_enrollment_(false), 78 can_exit_enrollment_(true), 79 browsing_data_remover_(NULL) { 80 set_async_assets_load_id(OobeUI::kScreenOobeEnrollment); 81 } 82 83 EnrollmentScreenHandler::~EnrollmentScreenHandler() { 84 if (browsing_data_remover_) 85 browsing_data_remover_->RemoveObserver(this); 86 } 87 88 // EnrollmentScreenHandler, WebUIMessageHandler implementation -- 89 90 void EnrollmentScreenHandler::RegisterMessages() { 91 AddCallback("oauthEnrollClose", 92 &EnrollmentScreenHandler::HandleClose); 93 AddCallback("oauthEnrollCompleteLogin", 94 &EnrollmentScreenHandler::HandleCompleteLogin); 95 AddCallback("oauthEnrollRetry", 96 &EnrollmentScreenHandler::HandleRetry); 97 } 98 99 // EnrollmentScreenHandler 100 // EnrollmentScreenActor implementation ----------------------------------- 101 102 void EnrollmentScreenHandler::SetParameters(Controller* controller, 103 bool is_auto_enrollment, 104 bool can_exit_enrollment, 105 const std::string& user) { 106 controller_ = controller; 107 is_auto_enrollment_ = is_auto_enrollment; 108 can_exit_enrollment_ = can_exit_enrollment; 109 if (is_auto_enrollment_) 110 user_ = user; 111 } 112 113 void EnrollmentScreenHandler::PrepareToShow() { 114 } 115 116 void EnrollmentScreenHandler::Show() { 117 if (!page_is_ready()) 118 show_on_init_ = true; 119 else 120 DoShow(); 121 } 122 123 void EnrollmentScreenHandler::Hide() { 124 } 125 126 void EnrollmentScreenHandler::FetchOAuthToken() { 127 Profile* profile = Profile::FromWebUI(web_ui()); 128 oauth_fetcher_.reset( 129 new policy::PolicyOAuth2TokenFetcher( 130 profile->GetRequestContext(), 131 g_browser_process->system_request_context(), 132 base::Bind(&EnrollmentScreenHandler::OnTokenFetched, 133 base::Unretained(this)))); 134 oauth_fetcher_->Start(); 135 } 136 137 void EnrollmentScreenHandler::ResetAuth(const base::Closure& callback) { 138 auth_reset_callbacks_.push_back(callback); 139 if (browsing_data_remover_) 140 return; 141 142 if (oauth_fetcher_) { 143 if (!oauth_fetcher_->oauth2_access_token().empty()) 144 (new TokenRevoker())->Start(oauth_fetcher_->oauth2_access_token()); 145 146 if (!oauth_fetcher_->oauth2_refresh_token().empty()) 147 (new TokenRevoker())->Start(oauth_fetcher_->oauth2_refresh_token()); 148 } 149 150 Profile* profile = Profile::FromBrowserContext( 151 web_ui()->GetWebContents()->GetBrowserContext()); 152 browsing_data_remover_ = 153 BrowsingDataRemover::CreateForUnboundedRange(profile); 154 browsing_data_remover_->AddObserver(this); 155 browsing_data_remover_->Remove(BrowsingDataRemover::REMOVE_SITE_DATA, 156 BrowsingDataHelper::UNPROTECTED_WEB); 157 } 158 159 void EnrollmentScreenHandler::ShowSigninScreen() { 160 ShowStep(kEnrollmentStepSignin); 161 } 162 163 void EnrollmentScreenHandler::ShowEnrollmentSpinnerScreen() { 164 ShowWorking(IDS_ENTERPRISE_ENROLLMENT_WORKING); 165 } 166 167 void EnrollmentScreenHandler::ShowLoginSpinnerScreen() { 168 ShowWorking(IDS_ENTERPRISE_ENROLLMENT_RESUMING_LOGIN); 169 } 170 171 void EnrollmentScreenHandler::ShowAuthError( 172 const GoogleServiceAuthError& error) { 173 switch (error.state()) { 174 case GoogleServiceAuthError::NONE: 175 case GoogleServiceAuthError::CAPTCHA_REQUIRED: 176 case GoogleServiceAuthError::TWO_FACTOR: 177 case GoogleServiceAuthError::HOSTED_NOT_ALLOWED: 178 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: 179 case GoogleServiceAuthError::REQUEST_CANCELED: 180 case GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE: 181 case GoogleServiceAuthError::SERVICE_ERROR: 182 ShowError(IDS_ENTERPRISE_ENROLLMENT_AUTH_FATAL_ERROR, false); 183 return; 184 case GoogleServiceAuthError::USER_NOT_SIGNED_UP: 185 case GoogleServiceAuthError::ACCOUNT_DELETED: 186 case GoogleServiceAuthError::ACCOUNT_DISABLED: 187 ShowError(IDS_ENTERPRISE_ENROLLMENT_AUTH_ACCOUNT_ERROR, true); 188 return; 189 case GoogleServiceAuthError::CONNECTION_FAILED: 190 case GoogleServiceAuthError::SERVICE_UNAVAILABLE: 191 ShowError(IDS_ENTERPRISE_ENROLLMENT_AUTH_NETWORK_ERROR, true); 192 return; 193 case GoogleServiceAuthError::NUM_STATES: 194 break; 195 } 196 NOTREACHED(); 197 } 198 199 void EnrollmentScreenHandler::ShowUIError(UIError error) { 200 switch (error) { 201 case UI_ERROR_DOMAIN_MISMATCH: 202 ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_LOCK_WRONG_USER, true); 203 return; 204 case UI_ERROR_AUTO_ENROLLMENT_BAD_MODE: 205 ShowError(IDS_ENTERPRISE_AUTO_ENROLLMENT_BAD_MODE, true); 206 return; 207 case UI_ERROR_FATAL: 208 ShowError(IDS_ENTERPRISE_ENROLLMENT_FATAL_ENROLLMENT_ERROR, true); 209 return; 210 } 211 NOTREACHED(); 212 } 213 214 void EnrollmentScreenHandler::ShowEnrollmentStatus( 215 policy::EnrollmentStatus status) { 216 switch (status.status()) { 217 case policy::EnrollmentStatus::STATUS_SUCCESS: 218 ShowStep(kEnrollmentStepSuccess); 219 return; 220 case policy::EnrollmentStatus::STATUS_REGISTRATION_FAILED: 221 // Some special cases for generating a nicer message that's more helpful. 222 switch (status.client_status()) { 223 case policy::DM_STATUS_SERVICE_MISSING_LICENSES: 224 ShowError(IDS_ENTERPRISE_ENROLLMENT_MISSING_LICENSES_ERROR, true); 225 break; 226 case policy::DM_STATUS_SERVICE_DEPROVISIONED: 227 ShowError(IDS_ENTERPRISE_ENROLLMENT_DEPROVISIONED_ERROR, true); 228 break; 229 case policy::DM_STATUS_SERVICE_MANAGEMENT_NOT_SUPPORTED: 230 ShowError(IDS_ENTERPRISE_ENROLLMENT_ACCOUNT_ERROR, true); 231 break; 232 default: 233 ShowErrorMessage( 234 l10n_util::GetStringFUTF8( 235 IDS_ENTERPRISE_ENROLLMENT_STATUS_REGISTRATION_FAILED, 236 policy::FormatDeviceManagementStatus(status.client_status())), 237 true); 238 } 239 return; 240 case policy::EnrollmentStatus::STATUS_ROBOT_AUTH_FETCH_FAILED: 241 ShowError(IDS_ENTERPRISE_ENROLLMENT_ROBOT_AUTH_FETCH_FAILED, true); 242 return; 243 case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_FETCH_FAILED: 244 ShowError(IDS_ENTERPRISE_ENROLLMENT_ROBOT_REFRESH_FETCH_FAILED, true); 245 return; 246 case policy::EnrollmentStatus::STATUS_ROBOT_REFRESH_STORE_FAILED: 247 ShowError(IDS_ENTERPRISE_ENROLLMENT_ROBOT_REFRESH_STORE_FAILED, true); 248 return; 249 case policy::EnrollmentStatus::STATUS_REGISTRATION_BAD_MODE: 250 ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_REGISTRATION_BAD_MODE, false); 251 return; 252 case policy::EnrollmentStatus::STATUS_POLICY_FETCH_FAILED: 253 ShowErrorMessage( 254 l10n_util::GetStringFUTF8( 255 IDS_ENTERPRISE_ENROLLMENT_STATUS_POLICY_FETCH_FAILED, 256 policy::FormatDeviceManagementStatus(status.client_status())), 257 true); 258 return; 259 case policy::EnrollmentStatus::STATUS_VALIDATION_FAILED: 260 ShowErrorMessage( 261 l10n_util::GetStringFUTF8( 262 IDS_ENTERPRISE_ENROLLMENT_STATUS_VALIDATION_FAILED, 263 policy::FormatValidationStatus(status.validation_status())), 264 true); 265 return; 266 case policy::EnrollmentStatus::STATUS_LOCK_ERROR: 267 ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_LOCK_ERROR, false); 268 return; 269 case policy::EnrollmentStatus::STATUS_LOCK_TIMEOUT: 270 ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_LOCK_TIMEOUT, false); 271 return; 272 case policy::EnrollmentStatus::STATUS_LOCK_WRONG_USER: 273 ShowError(IDS_ENTERPRISE_ENROLLMENT_STATUS_LOCK_WRONG_USER, true); 274 return; 275 case policy::EnrollmentStatus::STATUS_STORE_ERROR: 276 ShowErrorMessage( 277 l10n_util::GetStringFUTF8( 278 IDS_ENTERPRISE_ENROLLMENT_STATUS_STORE_ERROR, 279 policy::FormatStoreStatus(status.store_status(), 280 status.validation_status())), 281 true); 282 return; 283 } 284 NOTREACHED(); 285 } 286 287 // EnrollmentScreenHandler BaseScreenHandler implementation ----- 288 289 void EnrollmentScreenHandler::Initialize() { 290 if (show_on_init_) { 291 Show(); 292 show_on_init_ = false; 293 } 294 } 295 296 void EnrollmentScreenHandler::DeclareLocalizedValues( 297 LocalizedValuesBuilder* builder) { 298 builder->Add("oauthEnrollScreenTitle", 299 IDS_ENTERPRISE_ENROLLMENT_SCREEN_TITLE); 300 builder->Add("oauthEnrollRetry", IDS_ENTERPRISE_ENROLLMENT_RETRY); 301 builder->Add("oauthEnrollCancel", IDS_ENTERPRISE_ENROLLMENT_CANCEL); 302 builder->Add("oauthEnrollDone", IDS_ENTERPRISE_ENROLLMENT_DONE); 303 builder->Add("oauthEnrollSuccess", IDS_ENTERPRISE_ENROLLMENT_SUCCESS); 304 builder->Add("oauthEnrollExplain", IDS_ENTERPRISE_ENROLLMENT_EXPLAIN); 305 builder->Add("oauthEnrollExplainLink", 306 IDS_ENTERPRISE_ENROLLMENT_EXPLAIN_LINK); 307 builder->Add("oauthEnrollExplainButton", 308 IDS_ENTERPRISE_ENROLLMENT_EXPLAIN_BUTTON); 309 builder->Add("oauthEnrollCancelAutoEnrollmentReally", 310 IDS_ENTERPRISE_ENROLLMENT_CANCEL_AUTO_REALLY); 311 builder->Add("oauthEnrollCancelAutoEnrollmentConfirm", 312 IDS_ENTERPRISE_ENROLLMENT_CANCEL_AUTO_CONFIRM); 313 builder->Add("oauthEnrollCancelAutoEnrollmentGoBack", 314 IDS_ENTERPRISE_ENROLLMENT_CANCEL_AUTO_GO_BACK); 315 } 316 317 void EnrollmentScreenHandler::OnBrowsingDataRemoverDone() { 318 browsing_data_remover_->RemoveObserver(this); 319 browsing_data_remover_ = NULL; 320 321 std::vector<base::Closure> callbacks_to_run; 322 callbacks_to_run.swap(auth_reset_callbacks_); 323 for (std::vector<base::Closure>::iterator callback(callbacks_to_run.begin()); 324 callback != callbacks_to_run.end(); ++callback) { 325 callback->Run(); 326 } 327 } 328 329 // EnrollmentScreenHandler, private ----------------------------- 330 331 void EnrollmentScreenHandler::HandleClose(const std::string& reason) { 332 if (!controller_) { 333 NOTREACHED(); 334 return; 335 } 336 337 if (reason == "cancel" || reason == "autocancel") 338 controller_->OnCancel(); 339 else if (reason == "done") 340 controller_->OnConfirmationClosed(); 341 else 342 NOTREACHED(); 343 } 344 345 void EnrollmentScreenHandler::HandleCompleteLogin(const std::string& user) { 346 if (!controller_) { 347 NOTREACHED(); 348 return; 349 } 350 controller_->OnLoginDone(gaia::SanitizeEmail(user)); 351 } 352 353 void EnrollmentScreenHandler::HandleRetry() { 354 if (!controller_) { 355 NOTREACHED(); 356 return; 357 } 358 controller_->OnRetry(); 359 } 360 361 void EnrollmentScreenHandler::ShowStep(const char* step) { 362 CallJS("showStep", std::string(step)); 363 } 364 365 void EnrollmentScreenHandler::ShowError(int message_id, bool retry) { 366 ShowErrorMessage(l10n_util::GetStringUTF8(message_id), retry); 367 } 368 369 void EnrollmentScreenHandler::ShowErrorMessage(const std::string& message, 370 bool retry) { 371 CallJS("showError", message, retry); 372 } 373 374 void EnrollmentScreenHandler::ShowWorking(int message_id) { 375 CallJS("showWorking", l10n_util::GetStringUTF16(message_id)); 376 } 377 378 void EnrollmentScreenHandler::OnTokenFetched( 379 const std::string& token, 380 const GoogleServiceAuthError& error) { 381 if (!controller_) 382 return; 383 384 if (error.state() != GoogleServiceAuthError::NONE) 385 controller_->OnAuthError(error); 386 else 387 controller_->OnOAuthTokenAvailable(token); 388 } 389 390 void EnrollmentScreenHandler::DoShow() { 391 DictionaryValue screen_data; 392 screen_data.SetString("signin_url", kGaiaExtStartPage); 393 screen_data.SetString("gaiaUrl", GaiaUrls::GetInstance()->gaia_url().spec()); 394 screen_data.SetBoolean("is_auto_enrollment", is_auto_enrollment_); 395 screen_data.SetBoolean("prevent_cancellation", !can_exit_enrollment_); 396 397 ShowScreen(OobeUI::kScreenOobeEnrollment, &screen_data); 398 } 399 400 } // namespace chromeos 401