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