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