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