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 "base/rand_util.h"
8 #include "base/values.h"
9 #include "chrome/browser/chromeos/camera_detector.h"
10 #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h"
11 #include "chrome/browser/chromeos/login/existing_user_controller.h"
12 #include "chrome/browser/chromeos/login/screen_manager.h"
13 #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
14 #include "chrome/browser/chromeos/login/screens/error_screen.h"
15 #include "chrome/browser/chromeos/login/signin_specifics.h"
16 #include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
17 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller.h"
18 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h"
19 #include "chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h"
20 #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
21 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
22 #include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
23 #include "chrome/browser/chromeos/login/wizard_controller.h"
24 #include "chrome/browser/supervised_user/supervised_user_constants.h"
25 #include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
26 #include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h"
27 #include "chrome/browser/supervised_user/supervised_user_sync_service.h"
28 #include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
29 #include "chrome/grit/generated_resources.h"
30 #include "chromeos/dbus/dbus_thread_manager.h"
31 #include "chromeos/dbus/session_manager_client.h"
32 #include "chromeos/login/auth/key.h"
33 #include "chromeos/login/auth/user_context.h"
34 #include "chromeos/network/network_state.h"
35 #include "components/user_manager/user.h"
36 #include "components/user_manager/user_image/user_image.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "third_party/skia/include/core/SkBitmap.h"
39 #include "ui/base/l10n/l10n_util.h"
40 #include "ui/gfx/image/image_skia.h"
42 #if !defined(USE_ATHENA)
43 #include "ash/desktop_background/desktop_background_controller.h"
44 #include "ash/shell.h"
51 // Key for (boolean) value that indicates that user already exists on device.
52 const char kUserExists[] = "exists";
53 // Key for value that indicates why user can not be imported.
54 const char kUserConflict[] = "conflict";
55 // User is already imported.
56 const char kUserConflictImported[] = "imported";
57 // There is another supervised user with same name.
58 const char kUserConflictName[] = "name";
60 const char kUserNeedPassword[] = "needPassword";
62 const char kAvatarURLKey[] = "avatarurl";
63 const char kRandomAvatarKey[] = "randomAvatar";
64 const char kNameOfIntroScreen[] = "intro";
65 const char kNameOfNewUserParametersScreen[] = "username";
67 void ConfigureErrorScreen(ErrorScreen* screen,
68 const NetworkState* network,
69 const NetworkPortalDetector::CaptivePortalStatus status) {
71 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
72 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE:
75 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
76 screen->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
79 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
80 screen->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
81 network ? network->name() : std::string());
82 screen->FixCaptivePortal();
84 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
85 screen->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
97 SupervisedUserCreationScreen* SupervisedUserCreationScreen::Get(
98 ScreenManager* manager) {
99 return static_cast<SupervisedUserCreationScreen*>(
100 manager->GetScreen(WizardController::kSupervisedUserCreationScreenName));
103 SupervisedUserCreationScreen::SupervisedUserCreationScreen(
104 BaseScreenDelegate* base_screen_delegate,
105 SupervisedUserCreationScreenHandler* actor)
106 : BaseScreen(base_screen_delegate),
108 on_error_screen_(false),
109 manager_signin_in_progress_(false),
110 last_page_(kNameOfIntroScreen),
112 image_decoder_(NULL),
113 apply_photo_after_decoding_(false),
115 histogram_helper_(new ErrorScreensHistogramHelper("Supervised")),
116 weak_factory_(this) {
119 actor_->SetDelegate(this);
122 SupervisedUserCreationScreen::~SupervisedUserCreationScreen() {
123 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
125 sync_service_->RemoveObserver(this);
127 actor_->SetDelegate(NULL);
128 if (image_decoder_.get())
129 image_decoder_->set_delegate(NULL);
130 NetworkPortalDetector::Get()->RemoveObserver(this);
133 void SupervisedUserCreationScreen::PrepareToShow() {
135 actor_->PrepareToShow();
138 void SupervisedUserCreationScreen::Show() {
139 CameraPresenceNotifier::GetInstance()->AddObserver(this);
142 // TODO(antrim) : temorary hack (until upcoming hackaton). Should be
143 // removed once we have screens reworked.
144 if (on_error_screen_)
145 actor_->ShowPage(last_page_);
147 actor_->ShowIntroPage();
150 if (!on_error_screen_)
151 NetworkPortalDetector::Get()->AddAndFireObserver(this);
152 on_error_screen_ = false;
153 histogram_helper_->OnScreenShow();
156 void SupervisedUserCreationScreen::OnPageSelected(const std::string& page) {
160 void SupervisedUserCreationScreen::OnPortalDetectionCompleted(
161 const NetworkState* network,
162 const NetworkPortalDetector::CaptivePortalState& state) {
163 if (state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) {
164 get_base_screen_delegate()->HideErrorScreen(this);
165 histogram_helper_->OnErrorHide();
167 on_error_screen_ = true;
168 ErrorScreen* screen = get_base_screen_delegate()->GetErrorScreen();
169 ConfigureErrorScreen(screen, network, state.status);
170 screen->SetUIState(ErrorScreen::UI_STATE_SUPERVISED);
171 get_base_screen_delegate()->ShowErrorScreen();
172 histogram_helper_->OnErrorShow(screen->GetErrorState());
176 void SupervisedUserCreationScreen::ShowManagerInconsistentStateErrorScreen() {
177 manager_signin_in_progress_ = false;
180 actor_->ShowErrorPage(
181 l10n_util::GetStringUTF16(
182 IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE_TITLE),
183 l10n_util::GetStringUTF16(
184 IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE),
185 l10n_util::GetStringUTF16(
186 IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE_BUTTON));
189 void SupervisedUserCreationScreen::ShowInitialScreen() {
191 actor_->ShowIntroPage();
194 void SupervisedUserCreationScreen::Hide() {
195 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
198 if (!on_error_screen_)
199 NetworkPortalDetector::Get()->RemoveObserver(this);
202 std::string SupervisedUserCreationScreen::GetName() const {
203 return WizardController::kSupervisedUserCreationScreenName;
206 void SupervisedUserCreationScreen::AbortFlow() {
207 DBusThreadManager::Get()
208 ->GetSessionManagerClient()
209 ->NotifySupervisedUserCreationFinished();
210 controller_->CancelCreation();
213 void SupervisedUserCreationScreen::FinishFlow() {
214 DBusThreadManager::Get()
215 ->GetSessionManagerClient()
216 ->NotifySupervisedUserCreationFinished();
217 controller_->FinishCreation();
220 void SupervisedUserCreationScreen::AuthenticateManager(
221 const std::string& manager_id,
222 const std::string& manager_password) {
223 if (manager_signin_in_progress_)
225 manager_signin_in_progress_ = true;
227 UserFlow* flow = new SupervisedUserCreationFlow(manager_id);
228 ChromeUserManager::Get()->SetUserFlow(manager_id, flow);
230 // Make sure no two controllers exist at the same time.
233 controller_.reset(new SupervisedUserCreationControllerNew(this, manager_id));
235 UserContext user_context(manager_id);
236 user_context.SetKey(Key(manager_password));
237 ExistingUserController::current_controller()->Login(user_context,
241 void SupervisedUserCreationScreen::CreateSupervisedUser(
242 const base::string16& display_name,
243 const std::string& supervised_user_password) {
244 DCHECK(controller_.get());
246 if (selected_image_ == user_manager::User::USER_IMAGE_EXTERNAL)
247 // TODO(dzhioev): crbug/249660
248 image = SupervisedUserCreationController::kDummyAvatarIndex;
250 image = selected_image_;
251 controller_->StartCreation(display_name, supervised_user_password, image);
254 void SupervisedUserCreationScreen::ImportSupervisedUser(
255 const std::string& user_id) {
256 DCHECK(controller_.get());
257 DCHECK(existing_users_.get());
258 VLOG(1) << "Importing user " << user_id;
259 base::DictionaryValue* user_info;
260 if (!existing_users_->GetDictionary(user_id, &user_info)) {
261 LOG(ERROR) << "Can not import non-existing user " << user_id;
264 base::string16 display_name;
265 std::string master_key;
266 std::string signature_key;
267 std::string encryption_key;
270 int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
271 user_info->GetString(SupervisedUserSyncService::kName, &display_name);
272 user_info->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
273 user_info->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
275 user_info->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
277 user_info->GetString(SupervisedUserSyncService::kChromeOsAvatar, &avatar);
278 user_info->GetBoolean(kUserExists, &exists);
280 // We should not get here with existing user selected, so just display error.
282 actor_->ShowErrorPage(
283 l10n_util::GetStringUTF16(
284 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE),
285 l10n_util::GetStringUTF16(
286 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR),
287 l10n_util::GetStringUTF16(
288 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON));
292 SupervisedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
294 const base::DictionaryValue* password_data = NULL;
295 SupervisedUserSharedSettingsService* shared_settings_service =
296 SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
297 controller_->GetManagerProfile());
298 const base::Value* value = shared_settings_service->GetValue(
299 user_id, supervised_users::kChromeOSPasswordData);
301 bool password_right_here = value && value->GetAsDictionary(&password_data) &&
302 !password_data->empty();
304 if (password_right_here) {
305 controller_->StartImport(display_name,
313 NOTREACHED() << " Oops, no password";
317 // TODO(antrim): Code duplication with previous method will be removed once
318 // password sync is implemented.
319 void SupervisedUserCreationScreen::ImportSupervisedUserWithPassword(
320 const std::string& user_id,
321 const std::string& password) {
322 DCHECK(controller_.get());
323 DCHECK(existing_users_.get());
324 VLOG(1) << "Importing user " << user_id;
325 base::DictionaryValue* user_info;
326 if (!existing_users_->GetDictionary(user_id, &user_info)) {
327 LOG(ERROR) << "Can not import non-existing user " << user_id;
330 base::string16 display_name;
331 std::string master_key;
334 int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
335 user_info->GetString(SupervisedUserSyncService::kName, &display_name);
336 user_info->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
337 user_info->GetString(SupervisedUserSyncService::kChromeOsAvatar, &avatar);
338 user_info->GetBoolean(kUserExists, &exists);
340 // We should not get here with existing user selected, so just display error.
342 actor_->ShowErrorPage(
343 l10n_util::GetStringUTF16(
344 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE),
345 l10n_util::GetStringUTF16(
346 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR),
347 l10n_util::GetStringUTF16(
348 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON));
352 SupervisedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
354 controller_->StartImport(display_name,
361 void SupervisedUserCreationScreen::OnManagerLoginFailure() {
362 manager_signin_in_progress_ = false;
364 actor_->ShowManagerPasswordError();
367 void SupervisedUserCreationScreen::OnManagerFullyAuthenticated(
368 Profile* manager_profile) {
369 DBusThreadManager::Get()
370 ->GetSessionManagerClient()
371 ->NotifySupervisedUserCreationStarted();
372 manager_signin_in_progress_ = false;
373 DCHECK(controller_.get());
374 // For manager user, move desktop to locked container so that windows created
375 // during the user image picker step are below it.
376 #if !defined(USE_ATHENA)
377 ash::Shell::GetInstance()->
378 desktop_background_controller()->MoveDesktopToLockedContainer();
381 controller_->SetManagerProfile(manager_profile);
383 actor_->ShowUsernamePage();
385 last_page_ = kNameOfNewUserParametersScreen;
386 CHECK(!sync_service_);
387 sync_service_ = SupervisedUserSyncServiceFactory::GetForProfile(
389 sync_service_->AddObserver(this);
390 OnSupervisedUsersChanged();
393 void SupervisedUserCreationScreen::OnSupervisedUsersChanged() {
394 CHECK(sync_service_);
395 sync_service_->GetSupervisedUsersAsync(
396 base::Bind(&SupervisedUserCreationScreen::OnGetSupervisedUsers,
397 weak_factory_.GetWeakPtr()));
400 void SupervisedUserCreationScreen::OnManagerCryptohomeAuthenticated() {
402 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
403 IDS_CREATE_SUPERVISED_USER_CREATION_AUTH_PROGRESS_MESSAGE));
407 void SupervisedUserCreationScreen::OnActorDestroyed(
408 SupervisedUserCreationScreenHandler* actor) {
413 void SupervisedUserCreationScreen::OnCreationError(
414 SupervisedUserCreationController::ErrorCode code) {
415 LOG(ERROR) << "Supervised user creation failure, code: " << code;
417 base::string16 title;
418 base::string16 message;
419 base::string16 button;
420 // TODO(antrim) : find out which errors do we really have.
421 // We might reuse some error messages from ordinary user flow.
423 case SupervisedUserCreationController::CRYPTOHOME_NO_MOUNT:
424 case SupervisedUserCreationController::CRYPTOHOME_FAILED_MOUNT:
425 case SupervisedUserCreationController::CRYPTOHOME_FAILED_TPM:
426 title = l10n_util::GetStringUTF16(
427 IDS_CREATE_SUPERVISED_USER_TPM_ERROR_TITLE);
428 message = l10n_util::GetStringUTF16(
429 IDS_CREATE_SUPERVISED_USER_TPM_ERROR);
430 button = l10n_util::GetStringUTF16(
431 IDS_CREATE_SUPERVISED_USER_TPM_ERROR_BUTTON);
433 case SupervisedUserCreationController::CLOUD_SERVER_ERROR:
434 case SupervisedUserCreationController::TOKEN_WRITE_FAILED:
435 title = l10n_util::GetStringUTF16(
436 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE);
437 message = l10n_util::GetStringUTF16(
438 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR);
439 button = l10n_util::GetStringUTF16(
440 IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON);
442 case SupervisedUserCreationController::NO_ERROR:
446 actor_->ShowErrorPage(title, message, button);
449 void SupervisedUserCreationScreen::OnCreationTimeout() {
451 actor_->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16(
452 IDS_CREATE_SUPERVISED_USER_CREATION_CREATION_TIMEOUT_MESSAGE));
456 void SupervisedUserCreationScreen::OnLongCreationWarning() {
458 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
459 IDS_PROFILES_CREATE_SUPERVISED_JUST_SIGNED_IN));
463 bool SupervisedUserCreationScreen::FindUserByDisplayName(
464 const base::string16& display_name,
465 std::string *out_id) const {
466 if (!existing_users_.get())
468 for (base::DictionaryValue::Iterator it(*existing_users_.get());
469 !it.IsAtEnd(); it.Advance()) {
470 const base::DictionaryValue* user_info =
471 static_cast<const base::DictionaryValue*>(&it.value());
472 base::string16 user_display_name;
473 if (user_info->GetString(SupervisedUserSyncService::kName,
474 &user_display_name)) {
475 if (display_name == user_display_name) {
485 // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
486 // It should be removed by issue 251179.
488 void SupervisedUserCreationScreen::ApplyPicture() {
489 std::string user_id = controller_->GetSupervisedUserId();
490 UserImageManager* image_manager =
491 ChromeUserManager::Get()->GetUserImageManager(user_id);
492 switch (selected_image_) {
493 case user_manager::User::USER_IMAGE_EXTERNAL:
494 // Photo decoding may not have been finished yet.
495 if (user_photo_.isNull()) {
496 apply_photo_after_decoding_ = true;
499 image_manager->SaveUserImage(
500 user_manager::UserImage::CreateAndEncode(user_photo_));
502 case user_manager::User::USER_IMAGE_PROFILE:
503 NOTREACHED() << "Supervised users have no profile pictures";
506 DCHECK(selected_image_ >= 0 &&
507 selected_image_ < user_manager::kDefaultImagesCount);
508 image_manager->SaveUserDefaultImageIndex(selected_image_);
511 // Proceed to tutorial.
512 actor_->ShowTutorialPage();
515 void SupervisedUserCreationScreen::OnCreationSuccess() {
519 void SupervisedUserCreationScreen::OnCameraPresenceCheckDone(
520 bool is_camera_present) {
522 actor_->SetCameraPresent(is_camera_present);
525 void SupervisedUserCreationScreen::OnGetSupervisedUsers(
526 const base::DictionaryValue* users) {
527 // Copy for passing to WebUI, contains only id, name and avatar URL.
528 scoped_ptr<base::ListValue> ui_users(new base::ListValue());
529 SupervisedUserManager* supervised_user_manager =
530 ChromeUserManager::Get()->GetSupervisedUserManager();
532 // Stored copy, contains all necessary information.
533 existing_users_.reset(new base::DictionaryValue());
534 for (base::DictionaryValue::Iterator it(*users); !it.IsAtEnd();
536 // Copy that would be stored in this class.
537 base::DictionaryValue* local_copy =
538 static_cast<base::DictionaryValue*>(it.value().DeepCopy());
539 // Copy that would be passed to WebUI. It has some extra values for
540 // displaying, but does not contain sensitive data, such as master password.
541 base::DictionaryValue* ui_copy =
542 static_cast<base::DictionaryValue*>(new base::DictionaryValue());
544 int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
545 std::string chromeos_avatar;
546 if (local_copy->GetString(SupervisedUserSyncService::kChromeOsAvatar,
548 !chromeos_avatar.empty() &&
549 SupervisedUserSyncService::GetAvatarIndex(
550 chromeos_avatar, &avatar_index)) {
551 ui_copy->SetString(kAvatarURLKey,
552 user_manager::GetDefaultImageUrl(avatar_index));
554 int i = base::RandInt(user_manager::kFirstDefaultImageIndex,
555 user_manager::kDefaultImagesCount - 1);
556 local_copy->SetString(
557 SupervisedUserSyncService::kChromeOsAvatar,
558 SupervisedUserSyncService::BuildAvatarString(i));
559 local_copy->SetBoolean(kRandomAvatarKey, true);
560 ui_copy->SetString(kAvatarURLKey, user_manager::GetDefaultImageUrl(i));
563 local_copy->SetBoolean(kUserExists, false);
564 ui_copy->SetBoolean(kUserExists, false);
566 base::string16 display_name;
567 local_copy->GetString(SupervisedUserSyncService::kName, &display_name);
569 if (supervised_user_manager->FindBySyncId(it.key())) {
570 local_copy->SetBoolean(kUserExists, true);
571 ui_copy->SetBoolean(kUserExists, true);
572 local_copy->SetString(kUserConflict, kUserConflictImported);
573 ui_copy->SetString(kUserConflict, kUserConflictImported);
574 } else if (supervised_user_manager->FindByDisplayName(display_name)) {
575 local_copy->SetBoolean(kUserExists, true);
576 ui_copy->SetBoolean(kUserExists, true);
577 local_copy->SetString(kUserConflict, kUserConflictName);
578 ui_copy->SetString(kUserConflict, kUserConflictName);
580 ui_copy->SetString(SupervisedUserSyncService::kName, display_name);
582 std::string signature_key;
584 local_copy->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
586 !signature_key.empty();
588 ui_copy->SetBoolean(kUserNeedPassword, !has_password);
589 ui_copy->SetString("id", it.key());
591 existing_users_->Set(it.key(), local_copy);
592 ui_users->Append(ui_copy);
594 actor_->ShowExistingSupervisedUsers(ui_users.get());
597 void SupervisedUserCreationScreen::OnPhotoTaken(
598 const std::string& raw_data) {
599 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
600 user_photo_ = gfx::ImageSkia();
601 if (image_decoder_.get())
602 image_decoder_->set_delegate(NULL);
603 image_decoder_ = new ImageDecoder(this, raw_data,
604 ImageDecoder::DEFAULT_CODEC);
605 scoped_refptr<base::MessageLoopProxy> task_runner =
606 content::BrowserThread::GetMessageLoopProxyForThread(
607 content::BrowserThread::UI);
608 image_decoder_->Start(task_runner);
611 void SupervisedUserCreationScreen::OnImageDecoded(
612 const ImageDecoder* decoder,
613 const SkBitmap& decoded_image) {
614 DCHECK_EQ(image_decoder_.get(), decoder);
615 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
616 if (apply_photo_after_decoding_)
620 void SupervisedUserCreationScreen::OnDecodeImageFailed(
621 const ImageDecoder* decoder) {
622 NOTREACHED() << "Failed to decode PNG image from WebUI";
625 void SupervisedUserCreationScreen::OnImageSelected(
626 const std::string& image_type,
627 const std::string& image_url) {
628 if (image_url.empty())
630 int user_image_index = user_manager::User::USER_IMAGE_INVALID;
631 if (image_type == "default" &&
632 user_manager::IsDefaultImageUrl(image_url, &user_image_index)) {
633 selected_image_ = user_image_index;
634 } else if (image_type == "camera") {
635 selected_image_ = user_manager::User::USER_IMAGE_EXTERNAL;
637 NOTREACHED() << "Unexpected image type: " << image_type;
641 void SupervisedUserCreationScreen::OnImageAccepted() {
644 } // namespace chromeos