1 // Copyright (c) 2013 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/managed/locally_managed_user_creation_screen.h" 6 7 #include "ash/desktop_background/desktop_background_controller.h" 8 #include "ash/shell.h" 9 #include "base/command_line.h" 10 #include "base/rand_util.h" 11 #include "base/values.h" 12 #include "chrome/browser/chromeos/camera_detector.h" 13 #include "chrome/browser/chromeos/login/existing_user_controller.h" 14 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h" 15 #include "chrome/browser/chromeos/login/screens/error_screen.h" 16 #include "chrome/browser/chromeos/login/screens/screen_observer.h" 17 #include "chrome/browser/chromeos/login/supervised_user_manager.h" 18 #include "chrome/browser/chromeos/login/user_image.h" 19 #include "chrome/browser/chromeos/login/user_image_manager.h" 20 #include "chrome/browser/chromeos/login/wizard_controller.h" 21 #include "chrome/browser/managed_mode/managed_user_sync_service.h" 22 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h" 23 #include "chrome/common/chrome_switches.h" 24 #include "chromeos/network/network_state.h" 25 #include "content/public/browser/browser_thread.h" 26 #include "grit/generated_resources.h" 27 #include "third_party/skia/include/core/SkBitmap.h" 28 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/gfx/image/image_skia.h" 30 31 namespace chromeos { 32 33 namespace { 34 35 // Key for (boolean) value that indicates that user already exists on device. 36 const char kUserExists[] = "exists"; 37 // Key for value that indicates why user can not be imported. 38 const char kUserConflict[] = "conflict"; 39 // User is already imported. 40 const char kUserConflictImported[] = "imported"; 41 // There is another supervised user with same name. 42 const char kUserConflictName[] = "name"; 43 44 const char kUserNeedPassword[] = "needPassword"; 45 46 const char kAvatarURLKey[] = "avatarurl"; 47 const char kRandomAvatarKey[] = "randomAvatar"; 48 const char kNameOfIntroScreen[] = "intro"; 49 const char kNameOfNewUserParametersScreen[] = "username"; 50 51 void ConfigureErrorScreen(ErrorScreen* screen, 52 const NetworkState* network, 53 const NetworkPortalDetector::CaptivePortalStatus status) { 54 switch (status) { 55 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN: 56 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE: 57 NOTREACHED(); 58 break; 59 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE: 60 screen->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE, 61 std::string()); 62 break; 63 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL: 64 screen->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL, 65 network->name()); 66 screen->FixCaptivePortal(); 67 break; 68 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED: 69 screen->SetErrorState(ErrorScreen::ERROR_STATE_PROXY, 70 std::string()); 71 break; 72 default: 73 NOTREACHED(); 74 break; 75 } 76 } 77 78 } // namespace 79 80 LocallyManagedUserCreationScreen::LocallyManagedUserCreationScreen( 81 ScreenObserver* observer, 82 LocallyManagedUserCreationScreenHandler* actor) 83 : WizardScreen(observer), 84 weak_factory_(this), 85 actor_(actor), 86 on_error_screen_(false), 87 last_page_(kNameOfIntroScreen), 88 image_decoder_(NULL), 89 apply_photo_after_decoding_(false), 90 selected_image_(0), 91 was_camera_present_(false) { 92 DCHECK(actor_); 93 if (actor_) 94 actor_->SetDelegate(this); 95 } 96 97 LocallyManagedUserCreationScreen::~LocallyManagedUserCreationScreen() { 98 if (actor_) 99 actor_->SetDelegate(NULL); 100 if (image_decoder_.get()) 101 image_decoder_->set_delegate(NULL); 102 NetworkPortalDetector::Get()->RemoveObserver(this); 103 } 104 105 void LocallyManagedUserCreationScreen::PrepareToShow() { 106 if (actor_) 107 actor_->PrepareToShow(); 108 } 109 110 void LocallyManagedUserCreationScreen::Show() { 111 if (actor_) { 112 actor_->Show(); 113 // TODO(antrim) : temorary hack (until upcoming hackaton). Should be 114 // removed once we have screens reworked. 115 if (on_error_screen_) 116 actor_->ShowPage(last_page_); 117 else 118 actor_->ShowIntroPage(); 119 } 120 121 if (!on_error_screen_) 122 NetworkPortalDetector::Get()->AddAndFireObserver(this); 123 on_error_screen_ = false; 124 } 125 126 void LocallyManagedUserCreationScreen::OnPageSelected(const std::string& page) { 127 last_page_ = page; 128 } 129 130 void LocallyManagedUserCreationScreen::OnPortalDetectionCompleted( 131 const NetworkState* network, 132 const NetworkPortalDetector::CaptivePortalState& state) { 133 if (state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) { 134 get_screen_observer()->HideErrorScreen(this); 135 } else { 136 on_error_screen_ = true; 137 ErrorScreen* screen = get_screen_observer()->GetErrorScreen(); 138 ConfigureErrorScreen(screen, network, state.status); 139 screen->SetUIState(ErrorScreen::UI_STATE_LOCALLY_MANAGED); 140 get_screen_observer()->ShowErrorScreen(); 141 } 142 } 143 144 void LocallyManagedUserCreationScreen:: 145 ShowManagerInconsistentStateErrorScreen() { 146 if (!actor_) 147 return; 148 actor_->ShowErrorPage( 149 l10n_util::GetStringUTF16( 150 IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE_TITLE), 151 l10n_util::GetStringUTF16( 152 IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE), 153 l10n_util::GetStringUTF16( 154 IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE_BUTTON)); 155 } 156 157 void LocallyManagedUserCreationScreen::ShowInitialScreen() { 158 if (actor_) 159 actor_->ShowIntroPage(); 160 } 161 162 void LocallyManagedUserCreationScreen::Hide() { 163 if (actor_) 164 actor_->Hide(); 165 if (!on_error_screen_) 166 NetworkPortalDetector::Get()->RemoveObserver(this); 167 } 168 169 std::string LocallyManagedUserCreationScreen::GetName() const { 170 return WizardController::kLocallyManagedUserCreationScreenName; 171 } 172 173 void LocallyManagedUserCreationScreen::AbortFlow() { 174 controller_->CancelCreation(); 175 } 176 177 void LocallyManagedUserCreationScreen::FinishFlow() { 178 controller_->FinishCreation(); 179 } 180 181 void LocallyManagedUserCreationScreen::AuthenticateManager( 182 const std::string& manager_id, 183 const std::string& manager_password) { 184 // Make sure no two controllers exist at the same time. 185 controller_.reset(); 186 controller_.reset(new LocallyManagedUserCreationController(this, manager_id)); 187 188 ExistingUserController::current_controller()-> 189 Login(UserContext(manager_id, 190 manager_password, 191 std::string() /* auth_code */)); 192 } 193 194 void LocallyManagedUserCreationScreen::CreateManagedUser( 195 const base::string16& display_name, 196 const std::string& managed_user_password) { 197 DCHECK(controller_.get()); 198 int image; 199 if (selected_image_ == User::kExternalImageIndex) 200 // TODO(dzhioev): crbug/249660 201 image = LocallyManagedUserCreationController::kDummyAvatarIndex; 202 else 203 image = selected_image_; 204 controller_->SetUpCreation(display_name, managed_user_password, image); 205 controller_->StartCreation(); 206 } 207 208 void LocallyManagedUserCreationScreen::ImportManagedUser( 209 const std::string& user_id) { 210 DCHECK(controller_.get()); 211 DCHECK(existing_users_.get()); 212 VLOG(1) << "Importing user " << user_id; 213 DictionaryValue* user_info; 214 if (!existing_users_->GetDictionary(user_id, &user_info)) { 215 LOG(ERROR) << "Can not import non-existing user " << user_id; 216 return; 217 } 218 base::string16 display_name; 219 std::string master_key; 220 std::string avatar; 221 bool exists; 222 int avatar_index = LocallyManagedUserCreationController::kDummyAvatarIndex; 223 user_info->GetString(ManagedUserSyncService::kName, &display_name); 224 user_info->GetString(ManagedUserSyncService::kMasterKey, &master_key); 225 user_info->GetString(ManagedUserSyncService::kChromeOsAvatar, &avatar); 226 user_info->GetBoolean(kUserExists, &exists); 227 228 // We should not get here with existing user selected, so just display error. 229 if (exists) { 230 actor_->ShowErrorPage( 231 l10n_util::GetStringUTF16( 232 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE), 233 l10n_util::GetStringUTF16( 234 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR), 235 l10n_util::GetStringUTF16( 236 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON)); 237 return; 238 } 239 240 ManagedUserSyncService::GetAvatarIndex(avatar, &avatar_index); 241 242 controller_->StartImport(display_name, 243 std::string(), 244 avatar_index, 245 user_id, 246 master_key); 247 } 248 249 // TODO(antrim): Code duplication with previous method will be removed once 250 // password sync is implemented. 251 void LocallyManagedUserCreationScreen::ImportManagedUserWithPassword( 252 const std::string& user_id, 253 const std::string& password) { 254 DCHECK(controller_.get()); 255 DCHECK(existing_users_.get()); 256 VLOG(1) << "Importing user " << user_id; 257 DictionaryValue* user_info; 258 if (!existing_users_->GetDictionary(user_id, &user_info)) { 259 LOG(ERROR) << "Can not import non-existing user " << user_id; 260 return; 261 } 262 base::string16 display_name; 263 std::string master_key; 264 std::string avatar; 265 bool exists; 266 int avatar_index = LocallyManagedUserCreationController::kDummyAvatarIndex; 267 user_info->GetString(ManagedUserSyncService::kName, &display_name); 268 user_info->GetString(ManagedUserSyncService::kMasterKey, &master_key); 269 user_info->GetString(ManagedUserSyncService::kChromeOsAvatar, &avatar); 270 user_info->GetBoolean(kUserExists, &exists); 271 272 // We should not get here with existing user selected, so just display error. 273 if (exists) { 274 actor_->ShowErrorPage( 275 l10n_util::GetStringUTF16( 276 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE), 277 l10n_util::GetStringUTF16( 278 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR), 279 l10n_util::GetStringUTF16( 280 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON)); 281 return; 282 } 283 284 ManagedUserSyncService::GetAvatarIndex(avatar, &avatar_index); 285 286 controller_->StartImport(display_name, 287 password, 288 avatar_index, 289 user_id, 290 master_key); 291 } 292 293 void LocallyManagedUserCreationScreen::OnManagerLoginFailure() { 294 if (actor_) 295 actor_->ShowManagerPasswordError(); 296 } 297 298 void LocallyManagedUserCreationScreen::OnManagerFullyAuthenticated( 299 Profile* manager_profile) { 300 DCHECK(controller_.get()); 301 // For manager user, move desktop to locked container so that windows created 302 // during the user image picker step are below it. 303 ash::Shell::GetInstance()-> 304 desktop_background_controller()->MoveDesktopToLockedContainer(); 305 306 controller_->SetManagerProfile(manager_profile); 307 if (actor_) 308 actor_->ShowUsernamePage(); 309 310 last_page_ = kNameOfNewUserParametersScreen; 311 312 CommandLine* command_line = CommandLine::ForCurrentProcess(); 313 if (!command_line->HasSwitch(::switches::kAllowCreateExistingManagedUsers)) 314 return; 315 316 ManagedUserSyncServiceFactory::GetForProfile(manager_profile)-> 317 GetManagedUsersAsync(base::Bind( 318 &LocallyManagedUserCreationScreen::OnGetManagedUsers, 319 weak_factory_.GetWeakPtr())); 320 } 321 322 void LocallyManagedUserCreationScreen::OnManagerCryptohomeAuthenticated() { 323 if (actor_) { 324 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16( 325 IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_AUTH_PROGRESS_MESSAGE)); 326 } 327 } 328 329 void LocallyManagedUserCreationScreen::OnActorDestroyed( 330 LocallyManagedUserCreationScreenHandler* actor) { 331 if (actor_ == actor) 332 actor_ = NULL; 333 } 334 335 void LocallyManagedUserCreationScreen::OnCreationError( 336 LocallyManagedUserCreationController::ErrorCode code) { 337 base::string16 title; 338 base::string16 message; 339 base::string16 button; 340 // TODO(antrim) : find out which errors do we really have. 341 // We might reuse some error messages from ordinary user flow. 342 switch (code) { 343 case LocallyManagedUserCreationController::CRYPTOHOME_NO_MOUNT: 344 case LocallyManagedUserCreationController::CRYPTOHOME_FAILED_MOUNT: 345 case LocallyManagedUserCreationController::CRYPTOHOME_FAILED_TPM: 346 title = l10n_util::GetStringUTF16( 347 IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR_TITLE); 348 message = l10n_util::GetStringUTF16( 349 IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR); 350 button = l10n_util::GetStringUTF16( 351 IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR_BUTTON); 352 break; 353 case LocallyManagedUserCreationController::CLOUD_SERVER_ERROR: 354 case LocallyManagedUserCreationController::TOKEN_WRITE_FAILED: 355 title = l10n_util::GetStringUTF16( 356 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE); 357 message = l10n_util::GetStringUTF16( 358 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR); 359 button = l10n_util::GetStringUTF16( 360 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON); 361 break; 362 case LocallyManagedUserCreationController::NO_ERROR: 363 NOTREACHED(); 364 } 365 if (actor_) 366 actor_->ShowErrorPage(title, message, button); 367 } 368 369 void LocallyManagedUserCreationScreen::OnCreationTimeout() { 370 if (actor_) { 371 actor_->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16( 372 IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_CREATION_TIMEOUT_MESSAGE)); 373 } 374 } 375 376 void LocallyManagedUserCreationScreen::OnLongCreationWarning() { 377 if (actor_) { 378 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16( 379 IDS_PROFILES_CREATE_MANAGED_JUST_SIGNED_IN)); 380 } 381 } 382 383 bool LocallyManagedUserCreationScreen::FindUserByDisplayName( 384 const base::string16& display_name, 385 std::string *out_id) const { 386 if (!existing_users_.get()) 387 return false; 388 for (base::DictionaryValue::Iterator it(*existing_users_.get()); 389 !it.IsAtEnd(); it.Advance()) { 390 const base::DictionaryValue* user_info = 391 static_cast<const base::DictionaryValue*>(&it.value()); 392 base::string16 user_display_name; 393 if (user_info->GetString(ManagedUserSyncService::kName, 394 &user_display_name)) { 395 if (display_name == user_display_name) { 396 if (out_id) 397 *out_id = it.key(); 398 return true; 399 } 400 } 401 } 402 return false; 403 } 404 405 // TODO(antrim) : this is an explicit code duplications with UserImageScreen. 406 // It should be removed by issue 251179. 407 408 void LocallyManagedUserCreationScreen::ApplyPicture() { 409 UserManager* user_manager = UserManager::Get(); 410 UserImageManager* image_manager = user_manager->GetUserImageManager(); 411 std::string user_id = controller_->GetManagedUserId(); 412 switch (selected_image_) { 413 case User::kExternalImageIndex: 414 // Photo decoding may not have been finished yet. 415 if (user_photo_.isNull()) { 416 apply_photo_after_decoding_ = true; 417 return; 418 } 419 image_manager-> 420 SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_)); 421 break; 422 case User::kProfileImageIndex: 423 NOTREACHED() << "Supervised users have no profile pictures"; 424 break; 425 default: 426 DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount); 427 image_manager->SaveUserDefaultImageIndex(user_id, selected_image_); 428 break; 429 } 430 // Proceed to tutorial. 431 actor_->ShowTutorialPage(); 432 } 433 434 void LocallyManagedUserCreationScreen::OnCreationSuccess() { 435 ApplyPicture(); 436 } 437 438 void LocallyManagedUserCreationScreen::CheckCameraPresence() { 439 CameraDetector::StartPresenceCheck( 440 base::Bind(&LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone, 441 weak_factory_.GetWeakPtr())); 442 } 443 444 void LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone() { 445 bool is_camera_present = CameraDetector::camera_presence() == 446 CameraDetector::kCameraPresent; 447 if (actor_) { 448 if (is_camera_present != was_camera_present_) { 449 actor_->SetCameraPresent(is_camera_present); 450 was_camera_present_ = is_camera_present; 451 } 452 } 453 } 454 455 void LocallyManagedUserCreationScreen::OnGetManagedUsers( 456 const base::DictionaryValue* users) { 457 // Copy for passing to WebUI, contains only id, name and avatar URL. 458 scoped_ptr<base::ListValue> ui_users(new base::ListValue()); 459 SupervisedUserManager* supervised_user_manager = 460 UserManager::Get()->GetSupervisedUserManager(); 461 462 // Stored copy, contains all necessary information. 463 existing_users_.reset(new base::DictionaryValue()); 464 for (base::DictionaryValue::Iterator it(*users); !it.IsAtEnd(); 465 it.Advance()) { 466 // Copy that would be stored in this class. 467 base::DictionaryValue* local_copy = 468 static_cast<base::DictionaryValue*>(it.value().DeepCopy()); 469 // Copy that would be passed to WebUI. It has some extra values for 470 // displaying, but does not contain sensitive data, such as master password. 471 base::DictionaryValue* ui_copy = 472 static_cast<base::DictionaryValue*>(new base::DictionaryValue()); 473 474 int avatar_index = LocallyManagedUserCreationController::kDummyAvatarIndex; 475 std::string chromeos_avatar; 476 if (local_copy->GetString(ManagedUserSyncService::kChromeOsAvatar, 477 &chromeos_avatar) && 478 !chromeos_avatar.empty() && 479 ManagedUserSyncService::GetAvatarIndex( 480 chromeos_avatar, &avatar_index)) { 481 ui_copy->SetString(kAvatarURLKey, GetDefaultImageUrl(avatar_index)); 482 } else { 483 int i = base::RandInt(kFirstDefaultImageIndex, kDefaultImagesCount - 1); 484 local_copy->SetString( 485 ManagedUserSyncService::kChromeOsAvatar, 486 ManagedUserSyncService::BuildAvatarString(i)); 487 local_copy->SetBoolean(kRandomAvatarKey, true); 488 ui_copy->SetString(kAvatarURLKey, GetDefaultImageUrl(i)); 489 } 490 491 local_copy->SetBoolean(kUserExists, false); 492 ui_copy->SetBoolean(kUserExists, false); 493 494 base::string16 display_name; 495 local_copy->GetString(ManagedUserSyncService::kName, &display_name); 496 497 if (supervised_user_manager->FindBySyncId(it.key())) { 498 local_copy->SetBoolean(kUserExists, true); 499 ui_copy->SetBoolean(kUserExists, true); 500 local_copy->SetString(kUserConflict, kUserConflictImported); 501 ui_copy->SetString(kUserConflict, kUserConflictImported); 502 } else if (supervised_user_manager->FindByDisplayName(display_name)) { 503 local_copy->SetBoolean(kUserExists, true); 504 ui_copy->SetBoolean(kUserExists, true); 505 local_copy->SetString(kUserConflict, kUserConflictName); 506 ui_copy->SetString(kUserConflict, kUserConflictName); 507 } 508 ui_copy->SetString(ManagedUserSyncService::kName, display_name); 509 // TODO(antrim): For now mark all users as having no password. 510 ui_copy->SetBoolean(kUserNeedPassword, true); 511 ui_copy->SetString("id", it.key()); 512 513 existing_users_->Set(it.key(), local_copy); 514 ui_users->Append(ui_copy); 515 } 516 actor_->ShowExistingManagedUsers(ui_users.get()); 517 } 518 519 void LocallyManagedUserCreationScreen::OnPhotoTaken( 520 const std::string& raw_data) { 521 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 522 user_photo_ = gfx::ImageSkia(); 523 if (image_decoder_.get()) 524 image_decoder_->set_delegate(NULL); 525 image_decoder_ = new ImageDecoder(this, raw_data, 526 ImageDecoder::DEFAULT_CODEC); 527 scoped_refptr<base::MessageLoopProxy> task_runner = 528 content::BrowserThread::GetMessageLoopProxyForThread( 529 content::BrowserThread::UI); 530 image_decoder_->Start(task_runner); 531 } 532 533 void LocallyManagedUserCreationScreen::OnImageDecoded( 534 const ImageDecoder* decoder, 535 const SkBitmap& decoded_image) { 536 DCHECK_EQ(image_decoder_.get(), decoder); 537 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image); 538 if (apply_photo_after_decoding_) 539 ApplyPicture(); 540 } 541 542 void LocallyManagedUserCreationScreen::OnDecodeImageFailed( 543 const ImageDecoder* decoder) { 544 NOTREACHED() << "Failed to decode PNG image from WebUI"; 545 } 546 547 void LocallyManagedUserCreationScreen::OnImageSelected( 548 const std::string& image_type, 549 const std::string& image_url) { 550 if (image_url.empty()) 551 return; 552 int user_image_index = User::kInvalidImageIndex; 553 if (image_type == "default" && 554 IsDefaultImageUrl(image_url, &user_image_index)) { 555 selected_image_ = user_image_index; 556 } else if (image_type == "camera") { 557 selected_image_ = User::kExternalImageIndex; 558 } else { 559 NOTREACHED() << "Unexpected image type: " << image_type; 560 } 561 } 562 563 void LocallyManagedUserCreationScreen::OnImageAccepted() { 564 } 565 566 } // namespace chromeos 567