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.
5 #include "chrome/browser/chromeos/login/managed/locally_managed_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/managed/managed_user_creation_controller.h"
14 #include "chrome/browser/chromeos/login/managed/managed_user_creation_controller_new.h"
15 #include "chrome/browser/chromeos/login/managed/managed_user_creation_controller_old.h"
16 #include "chrome/browser/chromeos/login/managed/supervised_user_authentication.h"
17 #include "chrome/browser/chromeos/login/screens/error_screen.h"
18 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
19 #include "chrome/browser/chromeos/login/supervised_user_manager.h"
20 #include "chrome/browser/chromeos/login/user_image.h"
21 #include "chrome/browser/chromeos/login/user_image_manager.h"
22 #include "chrome/browser/chromeos/login/wizard_controller.h"
23 #include "chrome/browser/managed_mode/managed_user_constants.h"
24 #include "chrome/browser/managed_mode/managed_user_shared_settings_service.h"
25 #include "chrome/browser/managed_mode/managed_user_shared_settings_service_factory.h"
26 #include "chrome/browser/managed_mode/managed_user_sync_service.h"
27 #include "chrome/browser/managed_mode/managed_user_sync_service_factory.h"
28 #include "chromeos/network/network_state.h"
29 #include "content/public/browser/browser_thread.h"
30 #include "grit/generated_resources.h"
31 #include "third_party/skia/include/core/SkBitmap.h"
32 #include "ui/base/l10n/l10n_util.h"
33 #include "ui/gfx/image/image_skia.h"
39 // Key for (boolean) value that indicates that user already exists on device.
40 const char kUserExists[] = "exists";
41 // Key for value that indicates why user can not be imported.
42 const char kUserConflict[] = "conflict";
43 // User is already imported.
44 const char kUserConflictImported[] = "imported";
45 // There is another supervised user with same name.
46 const char kUserConflictName[] = "name";
48 const char kUserNeedPassword[] = "needPassword";
50 const char kAvatarURLKey[] = "avatarurl";
51 const char kRandomAvatarKey[] = "randomAvatar";
52 const char kNameOfIntroScreen[] = "intro";
53 const char kNameOfNewUserParametersScreen[] = "username";
55 void ConfigureErrorScreen(ErrorScreen* screen,
56 const NetworkState* network,
57 const NetworkPortalDetector::CaptivePortalStatus status) {
59 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
60 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE:
63 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
64 screen->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
67 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
68 screen->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
69 network ? network->name() : std::string());
70 screen->FixCaptivePortal();
72 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
73 screen->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
84 LocallyManagedUserCreationScreen::LocallyManagedUserCreationScreen(
85 ScreenObserver* observer,
86 LocallyManagedUserCreationScreenHandler* actor)
87 : WizardScreen(observer),
90 on_error_screen_(false),
91 last_page_(kNameOfIntroScreen),
94 apply_photo_after_decoding_(false),
98 actor_->SetDelegate(this);
101 LocallyManagedUserCreationScreen::~LocallyManagedUserCreationScreen() {
102 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
104 sync_service_->RemoveObserver(this);
106 actor_->SetDelegate(NULL);
107 if (image_decoder_.get())
108 image_decoder_->set_delegate(NULL);
109 NetworkPortalDetector::Get()->RemoveObserver(this);
112 void LocallyManagedUserCreationScreen::PrepareToShow() {
114 actor_->PrepareToShow();
117 void LocallyManagedUserCreationScreen::Show() {
118 CameraPresenceNotifier::GetInstance()->AddObserver(this);
121 // TODO(antrim) : temorary hack (until upcoming hackaton). Should be
122 // removed once we have screens reworked.
123 if (on_error_screen_)
124 actor_->ShowPage(last_page_);
126 actor_->ShowIntroPage();
129 if (!on_error_screen_)
130 NetworkPortalDetector::Get()->AddAndFireObserver(this);
131 on_error_screen_ = false;
134 void LocallyManagedUserCreationScreen::OnPageSelected(const std::string& page) {
138 void LocallyManagedUserCreationScreen::OnPortalDetectionCompleted(
139 const NetworkState* network,
140 const NetworkPortalDetector::CaptivePortalState& state) {
141 if (state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) {
142 get_screen_observer()->HideErrorScreen(this);
144 on_error_screen_ = true;
145 ErrorScreen* screen = get_screen_observer()->GetErrorScreen();
146 ConfigureErrorScreen(screen, network, state.status);
147 screen->SetUIState(ErrorScreen::UI_STATE_LOCALLY_MANAGED);
148 get_screen_observer()->ShowErrorScreen();
152 void LocallyManagedUserCreationScreen::
153 ShowManagerInconsistentStateErrorScreen() {
156 actor_->ShowErrorPage(
157 l10n_util::GetStringUTF16(
158 IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE_TITLE),
159 l10n_util::GetStringUTF16(
160 IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE),
161 l10n_util::GetStringUTF16(
162 IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE_BUTTON));
165 void LocallyManagedUserCreationScreen::ShowInitialScreen() {
167 actor_->ShowIntroPage();
170 void LocallyManagedUserCreationScreen::Hide() {
171 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
174 if (!on_error_screen_)
175 NetworkPortalDetector::Get()->RemoveObserver(this);
178 std::string LocallyManagedUserCreationScreen::GetName() const {
179 return WizardController::kLocallyManagedUserCreationScreenName;
182 void LocallyManagedUserCreationScreen::AbortFlow() {
183 controller_->CancelCreation();
186 void LocallyManagedUserCreationScreen::FinishFlow() {
187 controller_->FinishCreation();
190 void LocallyManagedUserCreationScreen::AuthenticateManager(
191 const std::string& manager_id,
192 const std::string& manager_password) {
193 // Make sure no two controllers exist at the same time.
195 SupervisedUserAuthentication* authentication =
196 UserManager::Get()->GetSupervisedUserManager()->GetAuthentication();
198 if (authentication->GetStableSchema() ==
199 SupervisedUserAuthentication::SCHEMA_PLAIN) {
200 controller_.reset(new ManagedUserCreationControllerOld(this, manager_id));
202 controller_.reset(new ManagedUserCreationControllerNew(this, manager_id));
205 ExistingUserController::current_controller()->
206 Login(UserContext(manager_id,
208 std::string() /* auth_code */));
211 void LocallyManagedUserCreationScreen::CreateManagedUser(
212 const base::string16& display_name,
213 const std::string& managed_user_password) {
214 DCHECK(controller_.get());
216 if (selected_image_ == User::kExternalImageIndex)
217 // TODO(dzhioev): crbug/249660
218 image = ManagedUserCreationController::kDummyAvatarIndex;
220 image = selected_image_;
221 controller_->StartCreation(display_name, managed_user_password, image);
224 void LocallyManagedUserCreationScreen::ImportManagedUser(
225 const std::string& user_id) {
226 DCHECK(controller_.get());
227 DCHECK(existing_users_.get());
228 VLOG(1) << "Importing user " << user_id;
229 base::DictionaryValue* user_info;
230 if (!existing_users_->GetDictionary(user_id, &user_info)) {
231 LOG(ERROR) << "Can not import non-existing user " << user_id;
234 base::string16 display_name;
235 std::string master_key;
236 std::string signature_key;
237 std::string encryption_key;
240 int avatar_index = ManagedUserCreationController::kDummyAvatarIndex;
241 user_info->GetString(ManagedUserSyncService::kName, &display_name);
242 user_info->GetString(ManagedUserSyncService::kMasterKey, &master_key);
243 user_info->GetString(ManagedUserSyncService::kPasswordSignatureKey,
245 user_info->GetString(ManagedUserSyncService::kPasswordEncryptionKey,
247 user_info->GetString(ManagedUserSyncService::kChromeOsAvatar, &avatar);
248 user_info->GetBoolean(kUserExists, &exists);
250 // We should not get here with existing user selected, so just display error.
252 actor_->ShowErrorPage(
253 l10n_util::GetStringUTF16(
254 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE),
255 l10n_util::GetStringUTF16(
256 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR),
257 l10n_util::GetStringUTF16(
258 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON));
262 ManagedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
264 const base::DictionaryValue* password_data = NULL;
265 ManagedUserSharedSettingsService* shared_settings_service =
266 ManagedUserSharedSettingsServiceFactory::GetForBrowserContext(
267 controller_->GetManagerProfile());
268 const base::Value* value = shared_settings_service->GetValue(
269 user_id, managed_users::kChromeOSPasswordData);
271 bool password_right_here = value && value->GetAsDictionary(&password_data) &&
272 !password_data->empty();
274 if (password_right_here) {
275 controller_->StartImport(display_name,
283 NOTREACHED() << " Oops, no password";
287 // TODO(antrim): Code duplication with previous method will be removed once
288 // password sync is implemented.
289 void LocallyManagedUserCreationScreen::ImportManagedUserWithPassword(
290 const std::string& user_id,
291 const std::string& password) {
292 DCHECK(controller_.get());
293 DCHECK(existing_users_.get());
294 VLOG(1) << "Importing user " << user_id;
295 base::DictionaryValue* user_info;
296 if (!existing_users_->GetDictionary(user_id, &user_info)) {
297 LOG(ERROR) << "Can not import non-existing user " << user_id;
300 base::string16 display_name;
301 std::string master_key;
304 int avatar_index = ManagedUserCreationController::kDummyAvatarIndex;
305 user_info->GetString(ManagedUserSyncService::kName, &display_name);
306 user_info->GetString(ManagedUserSyncService::kMasterKey, &master_key);
307 user_info->GetString(ManagedUserSyncService::kChromeOsAvatar, &avatar);
308 user_info->GetBoolean(kUserExists, &exists);
310 // We should not get here with existing user selected, so just display error.
312 actor_->ShowErrorPage(
313 l10n_util::GetStringUTF16(
314 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE),
315 l10n_util::GetStringUTF16(
316 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR),
317 l10n_util::GetStringUTF16(
318 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON));
322 ManagedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
324 controller_->StartImport(display_name,
331 void LocallyManagedUserCreationScreen::OnManagerLoginFailure() {
333 actor_->ShowManagerPasswordError();
336 void LocallyManagedUserCreationScreen::OnManagerFullyAuthenticated(
337 Profile* manager_profile) {
338 LOG(ERROR) << "-----------------------------OnManagerFullyAuthenticated";
339 DCHECK(controller_.get());
340 // For manager user, move desktop to locked container so that windows created
341 // during the user image picker step are below it.
342 ash::Shell::GetInstance()->
343 desktop_background_controller()->MoveDesktopToLockedContainer();
345 controller_->SetManagerProfile(manager_profile);
347 actor_->ShowUsernamePage();
349 last_page_ = kNameOfNewUserParametersScreen;
350 CHECK(!sync_service_);
351 sync_service_ = ManagedUserSyncServiceFactory::GetForProfile(manager_profile);
352 sync_service_->AddObserver(this);
353 OnManagedUsersChanged();
356 void LocallyManagedUserCreationScreen::OnManagedUsersChanged() {
357 CHECK(sync_service_);
358 sync_service_->GetManagedUsersAsync(
359 base::Bind(&LocallyManagedUserCreationScreen::OnGetManagedUsers,
360 weak_factory_.GetWeakPtr()));
363 void LocallyManagedUserCreationScreen::OnManagerCryptohomeAuthenticated() {
365 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
366 IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_AUTH_PROGRESS_MESSAGE));
370 void LocallyManagedUserCreationScreen::OnActorDestroyed(
371 LocallyManagedUserCreationScreenHandler* actor) {
376 void LocallyManagedUserCreationScreen::OnCreationError(
377 ManagedUserCreationController::ErrorCode code) {
378 base::string16 title;
379 base::string16 message;
380 base::string16 button;
381 // TODO(antrim) : find out which errors do we really have.
382 // We might reuse some error messages from ordinary user flow.
384 case ManagedUserCreationController::CRYPTOHOME_NO_MOUNT:
385 case ManagedUserCreationController::CRYPTOHOME_FAILED_MOUNT:
386 case ManagedUserCreationController::CRYPTOHOME_FAILED_TPM:
387 title = l10n_util::GetStringUTF16(
388 IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR_TITLE);
389 message = l10n_util::GetStringUTF16(
390 IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR);
391 button = l10n_util::GetStringUTF16(
392 IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR_BUTTON);
394 case ManagedUserCreationController::CLOUD_SERVER_ERROR:
395 case ManagedUserCreationController::TOKEN_WRITE_FAILED:
396 title = l10n_util::GetStringUTF16(
397 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE);
398 message = l10n_util::GetStringUTF16(
399 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR);
400 button = l10n_util::GetStringUTF16(
401 IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON);
403 case ManagedUserCreationController::NO_ERROR:
407 actor_->ShowErrorPage(title, message, button);
410 void LocallyManagedUserCreationScreen::OnCreationTimeout() {
412 actor_->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16(
413 IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_CREATION_TIMEOUT_MESSAGE));
417 void LocallyManagedUserCreationScreen::OnLongCreationWarning() {
419 actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
420 IDS_PROFILES_CREATE_MANAGED_JUST_SIGNED_IN));
424 bool LocallyManagedUserCreationScreen::FindUserByDisplayName(
425 const base::string16& display_name,
426 std::string *out_id) const {
427 if (!existing_users_.get())
429 for (base::DictionaryValue::Iterator it(*existing_users_.get());
430 !it.IsAtEnd(); it.Advance()) {
431 const base::DictionaryValue* user_info =
432 static_cast<const base::DictionaryValue*>(&it.value());
433 base::string16 user_display_name;
434 if (user_info->GetString(ManagedUserSyncService::kName,
435 &user_display_name)) {
436 if (display_name == user_display_name) {
446 // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
447 // It should be removed by issue 251179.
449 void LocallyManagedUserCreationScreen::ApplyPicture() {
450 std::string user_id = controller_->GetManagedUserId();
451 UserManager* user_manager = UserManager::Get();
452 UserImageManager* image_manager = user_manager->GetUserImageManager(user_id);
453 switch (selected_image_) {
454 case User::kExternalImageIndex:
455 // Photo decoding may not have been finished yet.
456 if (user_photo_.isNull()) {
457 apply_photo_after_decoding_ = true;
460 image_manager->SaveUserImage(UserImage::CreateAndEncode(user_photo_));
462 case User::kProfileImageIndex:
463 NOTREACHED() << "Supervised users have no profile pictures";
466 DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
467 image_manager->SaveUserDefaultImageIndex(selected_image_);
470 // Proceed to tutorial.
471 actor_->ShowTutorialPage();
474 void LocallyManagedUserCreationScreen::OnCreationSuccess() {
478 void LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone(
479 bool is_camera_present) {
481 actor_->SetCameraPresent(is_camera_present);
484 void LocallyManagedUserCreationScreen::OnGetManagedUsers(
485 const base::DictionaryValue* users) {
486 // Copy for passing to WebUI, contains only id, name and avatar URL.
487 scoped_ptr<base::ListValue> ui_users(new base::ListValue());
488 SupervisedUserManager* supervised_user_manager =
489 UserManager::Get()->GetSupervisedUserManager();
491 // Stored copy, contains all necessary information.
492 existing_users_.reset(new base::DictionaryValue());
493 for (base::DictionaryValue::Iterator it(*users); !it.IsAtEnd();
495 // Copy that would be stored in this class.
496 base::DictionaryValue* local_copy =
497 static_cast<base::DictionaryValue*>(it.value().DeepCopy());
498 // Copy that would be passed to WebUI. It has some extra values for
499 // displaying, but does not contain sensitive data, such as master password.
500 base::DictionaryValue* ui_copy =
501 static_cast<base::DictionaryValue*>(new base::DictionaryValue());
503 int avatar_index = ManagedUserCreationController::kDummyAvatarIndex;
504 std::string chromeos_avatar;
505 if (local_copy->GetString(ManagedUserSyncService::kChromeOsAvatar,
507 !chromeos_avatar.empty() &&
508 ManagedUserSyncService::GetAvatarIndex(
509 chromeos_avatar, &avatar_index)) {
510 ui_copy->SetString(kAvatarURLKey, GetDefaultImageUrl(avatar_index));
512 int i = base::RandInt(kFirstDefaultImageIndex, kDefaultImagesCount - 1);
513 local_copy->SetString(
514 ManagedUserSyncService::kChromeOsAvatar,
515 ManagedUserSyncService::BuildAvatarString(i));
516 local_copy->SetBoolean(kRandomAvatarKey, true);
517 ui_copy->SetString(kAvatarURLKey, GetDefaultImageUrl(i));
520 local_copy->SetBoolean(kUserExists, false);
521 ui_copy->SetBoolean(kUserExists, false);
523 base::string16 display_name;
524 local_copy->GetString(ManagedUserSyncService::kName, &display_name);
526 if (supervised_user_manager->FindBySyncId(it.key())) {
527 local_copy->SetBoolean(kUserExists, true);
528 ui_copy->SetBoolean(kUserExists, true);
529 local_copy->SetString(kUserConflict, kUserConflictImported);
530 ui_copy->SetString(kUserConflict, kUserConflictImported);
531 } else if (supervised_user_manager->FindByDisplayName(display_name)) {
532 local_copy->SetBoolean(kUserExists, true);
533 ui_copy->SetBoolean(kUserExists, true);
534 local_copy->SetString(kUserConflict, kUserConflictName);
535 ui_copy->SetString(kUserConflict, kUserConflictName);
537 ui_copy->SetString(ManagedUserSyncService::kName, display_name);
539 std::string signature_key;
541 local_copy->GetString(ManagedUserSyncService::kPasswordSignatureKey,
543 !signature_key.empty();
545 ui_copy->SetBoolean(kUserNeedPassword, !has_password);
546 ui_copy->SetString("id", it.key());
548 existing_users_->Set(it.key(), local_copy);
549 ui_users->Append(ui_copy);
551 actor_->ShowExistingManagedUsers(ui_users.get());
554 void LocallyManagedUserCreationScreen::OnPhotoTaken(
555 const std::string& raw_data) {
556 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
557 user_photo_ = gfx::ImageSkia();
558 if (image_decoder_.get())
559 image_decoder_->set_delegate(NULL);
560 image_decoder_ = new ImageDecoder(this, raw_data,
561 ImageDecoder::DEFAULT_CODEC);
562 scoped_refptr<base::MessageLoopProxy> task_runner =
563 content::BrowserThread::GetMessageLoopProxyForThread(
564 content::BrowserThread::UI);
565 image_decoder_->Start(task_runner);
568 void LocallyManagedUserCreationScreen::OnImageDecoded(
569 const ImageDecoder* decoder,
570 const SkBitmap& decoded_image) {
571 DCHECK_EQ(image_decoder_.get(), decoder);
572 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
573 if (apply_photo_after_decoding_)
577 void LocallyManagedUserCreationScreen::OnDecodeImageFailed(
578 const ImageDecoder* decoder) {
579 NOTREACHED() << "Failed to decode PNG image from WebUI";
582 void LocallyManagedUserCreationScreen::OnImageSelected(
583 const std::string& image_type,
584 const std::string& image_url) {
585 if (image_url.empty())
587 int user_image_index = User::kInvalidImageIndex;
588 if (image_type == "default" &&
589 IsDefaultImageUrl(image_url, &user_image_index)) {
590 selected_image_ = user_image_index;
591 } else if (image_type == "camera") {
592 selected_image_ = User::kExternalImageIndex;
594 NOTREACHED() << "Unexpected image type: " << image_type;
598 void LocallyManagedUserCreationScreen::OnImageAccepted() {
601 } // namespace chromeos