1 // Copyright 2014 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.
5 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_screen.h"
7 #include "ash/desktop_background/desktop_background_controller.h"
9 #include "base/rand_util.h"
10 #include "base/values.h"
11 #include "chrome/browser/chromeos/camera_detector.h"
12 #include "chrome/browser/chromeos/login/existing_user_controller.h"
13 #include "chrome/browser/chromeos/login/screen_manager.h"
14 #include "chrome/browser/chromeos/login/screens/error_screen.h"
15 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
16 #include "chrome/browser/chromeos/login/signin_specifics.h"
17 #include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
18 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller.h"
19 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h"
20 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h"
21 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
22 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
23 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
24 #include "chrome/browser/chromeos/login/wizard_controller.h"
25 #include "chrome/browser/supervised_user/supervised_user_constants.h"
26 #include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
27 #include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h"
28 #include "chrome/browser/supervised_user/supervised_user_sync_service.h"
29 #include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
30 #include "chrome/grit/generated_resources.h"
31 #include "chromeos/login/auth/key.h"
32 #include "chromeos/login/auth/user_context.h"
33 #include "chromeos/network/network_state.h"
34 #include "components/user_manager/user.h"
35 #include "components/user_manager/user_image/user_image.h"
36 #include "content/public/browser/browser_thread.h"
37 #include "third_party/skia/include/core/SkBitmap.h"
38 #include "ui/base/l10n/l10n_util.h"
39 #include "ui/gfx/image/image_skia.h"
45 // Key for (boolean) value that indicates that user already exists on device.
46 const char kUserExists[] = "exists";
47 // Key for value that indicates why user can not be imported.
48 const char kUserConflict[] = "conflict";
49 // User is already imported.
50 const char kUserConflictImported[] = "imported";
51 // There is another supervised user with same name.
52 const char kUserConflictName[] = "name";
54 const char kUserNeedPassword[] = "needPassword";
56 const char kAvatarURLKey[] = "avatarurl";
57 const char kRandomAvatarKey[] = "randomAvatar";
58 const char kNameOfIntroScreen[] = "intro";
59 const char kNameOfNewUserParametersScreen[] = "username";
61 void ConfigureErrorScreen(ErrorScreen* screen,
62 const NetworkState* network,
63 const NetworkPortalDetector::CaptivePortalStatus status) {
65 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
66 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE:
69 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
70 screen->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
73 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
74 screen->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
75 network ? network->name() : std::string());
76 screen->FixCaptivePortal();
78 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
79 screen->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
91 SupervisedUserCreationScreen* SupervisedUserCreationScreen::Get(
92 ScreenManager* manager) {
93 return static_cast<SupervisedUserCreationScreen*>(
94 manager->GetScreen(WizardController::kSupervisedUserCreationScreenName));
97 SupervisedUserCreationScreen::SupervisedUserCreationScreen(
98 ScreenObserver* observer,
99 SupervisedUserCreationScreenHandler* actor)
100 : WizardScreen(observer),
102 on_error_screen_(false),
103 manager_signin_in_progress_(false),
104 last_page_(kNameOfIntroScreen),
106 image_decoder_(NULL),
107 apply_photo_after_decoding_(false),
109 weak_factory_(this) {
112 actor_->SetDelegate(this);
115 SupervisedUserCreationScreen::~SupervisedUserCreationScreen() {
116 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
118 sync_service_->RemoveObserver(this);
120 actor_->SetDelegate(NULL);
121 if (image_decoder_.get())
122 image_decoder_->set_delegate(NULL);
123 NetworkPortalDetector::Get()->RemoveObserver(this);
126 void SupervisedUserCreationScreen::PrepareToShow() {
128 actor_->PrepareToShow();
131 void SupervisedUserCreationScreen::Show() {
132 CameraPresenceNotifier::GetInstance()->AddObserver(this);
135 // TODO(antrim) : temorary hack (until upcoming hackaton). Should be
136 // removed once we have screens reworked.
137 if (on_error_screen_)
138 actor_->ShowPage(last_page_);
140 actor_->ShowIntroPage();
143 if (!on_error_screen_)
144 NetworkPortalDetector::Get()->AddAndFireObserver(this);
145 on_error_screen_ = false;
148 void SupervisedUserCreationScreen::OnPageSelected(const std::string& page) {
152 void SupervisedUserCreationScreen::OnPortalDetectionCompleted(
153 const NetworkState* network,
154 const NetworkPortalDetector::CaptivePortalState& state) {
155 if (state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) {
156 get_screen_observer()->HideErrorScreen(this);
158 on_error_screen_ = true;
159 ErrorScreen* screen = get_screen_observer()->GetErrorScreen();
160 ConfigureErrorScreen(screen, network, state.status);
161 screen->SetUIState(ErrorScreen::UI_STATE_SUPERVISED);
162 get_screen_observer()->ShowErrorScreen();
166 void SupervisedUserCreationScreen::ShowManagerInconsistentStateErrorScreen() {
167 manager_signin_in_progress_ = false;
170 actor_->ShowErrorPage(
171 l10n_util::GetStringUTF16(
172 IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE_TITLE),
173 l10n_util::GetStringUTF16(
174 IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE),
175 l10n_util::GetStringUTF16(
176 IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE_BUTTON));
179 void SupervisedUserCreationScreen::ShowInitialScreen() {
181 actor_->ShowIntroPage();
184 void SupervisedUserCreationScreen::Hide() {
185 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
188 if (!on_error_screen_)
189 NetworkPortalDetector::Get()->RemoveObserver(this);
192 std::string SupervisedUserCreationScreen::GetName() const {
193 return WizardController::kSupervisedUserCreationScreenName;
196 void SupervisedUserCreationScreen::AbortFlow() {
197 controller_->CancelCreation();
200 void SupervisedUserCreationScreen::FinishFlow() {
201 controller_->FinishCreation();
204 void SupervisedUserCreationScreen::AuthenticateManager(
205 const std::string& manager_id,
206 const std::string& manager_password) {
207 if (manager_signin_in_progress_)
209 manager_signin_in_progress_ = true;
211 UserFlow* flow = new SupervisedUserCreationFlow(manager_id);
212 ChromeUserManager::Get()->SetUserFlow(manager_id, flow);
214 // Make sure no two controllers exist at the same time.
217 controller_.reset(new SupervisedUserCreationControllerNew(this, manager_id));
219 UserContext user_context(manager_id);
220 user_context.SetKey(Key(manager_password));
221 ExistingUserController::current_controller()->Login(user_context,
225 void SupervisedUserCreationScreen::CreateSupervisedUser(
226 const base::string16& display_name,
227 const std::string& supervised_user_password) {
228 DCHECK(controller_.get());
230 if (selected_image_ == user_manager::User::USER_IMAGE_EXTERNAL)
231 // TODO(dzhioev): crbug/249660
232 image = SupervisedUserCreationController::kDummyAvatarIndex;
234 image = selected_image_;
235 controller_->StartCreation(display_name, supervised_user_password, image);
238 void SupervisedUserCreationScreen::ImportSupervisedUser(
239 const std::string& user_id) {
240 DCHECK(controller_.get());
241 DCHECK(existing_users_.get());
242 VLOG(1) << "Importing user " << user_id;
243 base::DictionaryValue* user_info;
244 if (!existing_users_->GetDictionary(user_id, &user_info)) {
245 LOG(ERROR) << "Can not import non-existing user " << user_id;
248 base::string16 display_name;
249 std::string master_key;
250 std::string signature_key;
251 std::string encryption_key;
254 int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
255 user_info->GetString(SupervisedUserSyncService::kName, &display_name);
256 user_info->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
257 user_info->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
259 user_info->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
261 user_info->GetString(SupervisedUserSyncService::kChromeOsAvatar, &avatar);
262 user_info->GetBoolean(kUserExists, &exists);
264 // We should not get here with existing user selected, so just display error.
266 actor_->ShowErrorPage(
267 l10n_util::GetStringUTF16(
268 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE),
269 l10n_util::GetStringUTF16(
270 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR),
271 l10n_util::GetStringUTF16(
272 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON));
276 SupervisedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
278 const base::DictionaryValue* password_data = NULL;
279 SupervisedUserSharedSettingsService* shared_settings_service =
280 SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
281 controller_->GetManagerProfile());
282 const base::Value* value = shared_settings_service->GetValue(
283 user_id, supervised_users::kChromeOSPasswordData);
285 bool password_right_here = value && value->GetAsDictionary(&password_data) &&
286 !password_data->empty();
288 if (password_right_here) {
289 controller_->StartImport(display_name,
297 NOTREACHED() << " Oops, no password";
301 // TODO(antrim): Code duplication with previous method will be removed once
302 // password sync is implemented.
303 void SupervisedUserCreationScreen::ImportSupervisedUserWithPassword(
304 const std::string& user_id,
305 const std::string& password) {
306 DCHECK(controller_.get());
307 DCHECK(existing_users_.get());
308 VLOG(1) << "Importing user " << user_id;
309 base::DictionaryValue* user_info;
310 if (!existing_users_->GetDictionary(user_id, &user_info)) {
311 LOG(ERROR) << "Can not import non-existing user " << user_id;
314 base::string16 display_name;
315 std::string master_key;
318 int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
319 user_info->GetString(SupervisedUserSyncService::kName, &display_name);
320 user_info->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
321 user_info->GetString(SupervisedUserSyncService::kChromeOsAvatar, &avatar);
322 user_info->GetBoolean(kUserExists, &exists);
324 // We should not get here with existing user selected, so just display error.
326 actor_->ShowErrorPage(
327 l10n_util::GetStringUTF16(
328 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE),
329 l10n_util::GetStringUTF16(
330 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR),
331 l10n_util::GetStringUTF16(
332 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON));
336 SupervisedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
338 controller_->StartImport(display_name,
345 void SupervisedUserCreationScreen::OnManagerLoginFailure() {
346 manager_signin_in_progress_ = false;
348 actor_->ShowManagerPasswordError();
351 void SupervisedUserCreationScreen::OnManagerFullyAuthenticated(
352 Profile* manager_profile) {
353 manager_signin_in_progress_ = false;
354 DCHECK(controller_.get());
355 // For manager user, move desktop to locked container so that windows created
356 // during the user image picker step are below it.
357 ash::Shell::GetInstance()->
358 desktop_background_controller()->MoveDesktopToLockedContainer();
360 controller_->SetManagerProfile(manager_profile);
362 actor_->ShowUsernamePage();
364 last_page_ = kNameOfNewUserParametersScreen;
365 CHECK(!sync_service_);
366 sync_service_ = SupervisedUserSyncServiceFactory::GetForProfile(
368 sync_service_->AddObserver(this);
369 OnSupervisedUsersChanged();
372 void SupervisedUserCreationScreen::OnSupervisedUsersChanged() {
373 CHECK(sync_service_);
374 sync_service_->GetSupervisedUsersAsync(
375 base::Bind(&SupervisedUserCreationScreen::OnGetSupervisedUsers,
376 weak_factory_.GetWeakPtr()));
379 void SupervisedUserCreationScreen::OnManagerCryptohomeAuthenticated() {
381 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
382 IDS_CREATE_SUPERVISED_USER_CREATION_AUTH_PROGRESS_MESSAGE));
386 void SupervisedUserCreationScreen::OnActorDestroyed(
387 SupervisedUserCreationScreenHandler* actor) {
392 void SupervisedUserCreationScreen::OnCreationError(
393 SupervisedUserCreationController::ErrorCode code) {
394 LOG(ERROR) << "Supervised user creation failure, code: " << code;
396 base::string16 title;
397 base::string16 message;
398 base::string16 button;
399 // TODO(antrim) : find out which errors do we really have.
400 // We might reuse some error messages from ordinary user flow.
402 case SupervisedUserCreationController::CRYPTOHOME_NO_MOUNT:
403 case SupervisedUserCreationController::CRYPTOHOME_FAILED_MOUNT:
404 case SupervisedUserCreationController::CRYPTOHOME_FAILED_TPM:
405 title = l10n_util::GetStringUTF16(
406 IDS_CREATE_SUPERVISED_USER_TPM_ERROR_TITLE);
407 message = l10n_util::GetStringUTF16(
408 IDS_CREATE_SUPERVISED_USER_TPM_ERROR);
409 button = l10n_util::GetStringUTF16(
410 IDS_CREATE_SUPERVISED_USER_TPM_ERROR_BUTTON);
412 case SupervisedUserCreationController::CLOUD_SERVER_ERROR:
413 case SupervisedUserCreationController::TOKEN_WRITE_FAILED:
414 title = l10n_util::GetStringUTF16(
415 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE);
416 message = l10n_util::GetStringUTF16(
417 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR);
418 button = l10n_util::GetStringUTF16(
419 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON);
421 case SupervisedUserCreationController::NO_ERROR:
425 actor_->ShowErrorPage(title, message, button);
428 void SupervisedUserCreationScreen::OnCreationTimeout() {
430 actor_->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16(
431 IDS_CREATE_SUPERVISED_USER_CREATION_CREATION_TIMEOUT_MESSAGE));
435 void SupervisedUserCreationScreen::OnLongCreationWarning() {
437 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
438 IDS_PROFILES_CREATE_SUPERVISED_JUST_SIGNED_IN));
442 bool SupervisedUserCreationScreen::FindUserByDisplayName(
443 const base::string16& display_name,
444 std::string *out_id) const {
445 if (!existing_users_.get())
447 for (base::DictionaryValue::Iterator it(*existing_users_.get());
448 !it.IsAtEnd(); it.Advance()) {
449 const base::DictionaryValue* user_info =
450 static_cast<const base::DictionaryValue*>(&it.value());
451 base::string16 user_display_name;
452 if (user_info->GetString(SupervisedUserSyncService::kName,
453 &user_display_name)) {
454 if (display_name == user_display_name) {
464 // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
465 // It should be removed by issue 251179.
467 void SupervisedUserCreationScreen::ApplyPicture() {
468 std::string user_id = controller_->GetSupervisedUserId();
469 UserImageManager* image_manager =
470 ChromeUserManager::Get()->GetUserImageManager(user_id);
471 switch (selected_image_) {
472 case user_manager::User::USER_IMAGE_EXTERNAL:
473 // Photo decoding may not have been finished yet.
474 if (user_photo_.isNull()) {
475 apply_photo_after_decoding_ = true;
478 image_manager->SaveUserImage(
479 user_manager::UserImage::CreateAndEncode(user_photo_));
481 case user_manager::User::USER_IMAGE_PROFILE:
482 NOTREACHED() << "Supervised users have no profile pictures";
485 DCHECK(selected_image_ >= 0 &&
486 selected_image_ < user_manager::kDefaultImagesCount);
487 image_manager->SaveUserDefaultImageIndex(selected_image_);
490 // Proceed to tutorial.
491 actor_->ShowTutorialPage();
494 void SupervisedUserCreationScreen::OnCreationSuccess() {
498 void SupervisedUserCreationScreen::OnCameraPresenceCheckDone(
499 bool is_camera_present) {
501 actor_->SetCameraPresent(is_camera_present);
504 void SupervisedUserCreationScreen::OnGetSupervisedUsers(
505 const base::DictionaryValue* users) {
506 // Copy for passing to WebUI, contains only id, name and avatar URL.
507 scoped_ptr<base::ListValue> ui_users(new base::ListValue());
508 SupervisedUserManager* supervised_user_manager =
509 ChromeUserManager::Get()->GetSupervisedUserManager();
511 // Stored copy, contains all necessary information.
512 existing_users_.reset(new base::DictionaryValue());
513 for (base::DictionaryValue::Iterator it(*users); !it.IsAtEnd();
515 // Copy that would be stored in this class.
516 base::DictionaryValue* local_copy =
517 static_cast<base::DictionaryValue*>(it.value().DeepCopy());
518 // Copy that would be passed to WebUI. It has some extra values for
519 // displaying, but does not contain sensitive data, such as master password.
520 base::DictionaryValue* ui_copy =
521 static_cast<base::DictionaryValue*>(new base::DictionaryValue());
523 int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
524 std::string chromeos_avatar;
525 if (local_copy->GetString(SupervisedUserSyncService::kChromeOsAvatar,
527 !chromeos_avatar.empty() &&
528 SupervisedUserSyncService::GetAvatarIndex(
529 chromeos_avatar, &avatar_index)) {
530 ui_copy->SetString(kAvatarURLKey,
531 user_manager::GetDefaultImageUrl(avatar_index));
533 int i = base::RandInt(user_manager::kFirstDefaultImageIndex,
534 user_manager::kDefaultImagesCount - 1);
535 local_copy->SetString(
536 SupervisedUserSyncService::kChromeOsAvatar,
537 SupervisedUserSyncService::BuildAvatarString(i));
538 local_copy->SetBoolean(kRandomAvatarKey, true);
539 ui_copy->SetString(kAvatarURLKey, user_manager::GetDefaultImageUrl(i));
542 local_copy->SetBoolean(kUserExists, false);
543 ui_copy->SetBoolean(kUserExists, false);
545 base::string16 display_name;
546 local_copy->GetString(SupervisedUserSyncService::kName, &display_name);
548 if (supervised_user_manager->FindBySyncId(it.key())) {
549 local_copy->SetBoolean(kUserExists, true);
550 ui_copy->SetBoolean(kUserExists, true);
551 local_copy->SetString(kUserConflict, kUserConflictImported);
552 ui_copy->SetString(kUserConflict, kUserConflictImported);
553 } else if (supervised_user_manager->FindByDisplayName(display_name)) {
554 local_copy->SetBoolean(kUserExists, true);
555 ui_copy->SetBoolean(kUserExists, true);
556 local_copy->SetString(kUserConflict, kUserConflictName);
557 ui_copy->SetString(kUserConflict, kUserConflictName);
559 ui_copy->SetString(SupervisedUserSyncService::kName, display_name);
561 std::string signature_key;
563 local_copy->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
565 !signature_key.empty();
567 ui_copy->SetBoolean(kUserNeedPassword, !has_password);
568 ui_copy->SetString("id", it.key());
570 existing_users_->Set(it.key(), local_copy);
571 ui_users->Append(ui_copy);
573 actor_->ShowExistingSupervisedUsers(ui_users.get());
576 void SupervisedUserCreationScreen::OnPhotoTaken(
577 const std::string& raw_data) {
578 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
579 user_photo_ = gfx::ImageSkia();
580 if (image_decoder_.get())
581 image_decoder_->set_delegate(NULL);
582 image_decoder_ = new ImageDecoder(this, raw_data,
583 ImageDecoder::DEFAULT_CODEC);
584 scoped_refptr<base::MessageLoopProxy> task_runner =
585 content::BrowserThread::GetMessageLoopProxyForThread(
586 content::BrowserThread::UI);
587 image_decoder_->Start(task_runner);
590 void SupervisedUserCreationScreen::OnImageDecoded(
591 const ImageDecoder* decoder,
592 const SkBitmap& decoded_image) {
593 DCHECK_EQ(image_decoder_.get(), decoder);
594 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
595 if (apply_photo_after_decoding_)
599 void SupervisedUserCreationScreen::OnDecodeImageFailed(
600 const ImageDecoder* decoder) {
601 NOTREACHED() << "Failed to decode PNG image from WebUI";
604 void SupervisedUserCreationScreen::OnImageSelected(
605 const std::string& image_type,
606 const std::string& image_url) {
607 if (image_url.empty())
609 int user_image_index = user_manager::User::USER_IMAGE_INVALID;
610 if (image_type == "default" &&
611 user_manager::IsDefaultImageUrl(image_url, &user_image_index)) {
612 selected_image_ = user_image_index;
613 } else if (image_type == "camera") {
614 selected_image_ = user_manager::User::USER_IMAGE_EXTERNAL;
616 NOTREACHED() << "Unexpected image type: " << image_type;
620 void SupervisedUserCreationScreen::OnImageAccepted() {
623 } // namespace chromeos