Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / signin / user_manager_screen_handler.cc
1 // Copyright 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/ui/webui/signin/user_manager_screen_handler.h"
6
7 #include "base/bind.h"
8 #include "base/value_conversions.h"
9 #include "base/values.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/profiles/avatar_menu.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/profiles/profile_info_cache.h"
14 #include "chrome/browser/profiles/profile_info_cache_observer.h"
15 #include "chrome/browser/profiles/profile_info_util.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "chrome/browser/profiles/profile_window.h"
18 #include "chrome/browser/profiles/profiles_state.h"
19 #include "chrome/browser/signin/local_auth.h"
20 #include "chrome/browser/ui/browser_dialogs.h"
21 #include "chrome/browser/ui/browser_finder.h"
22 #include "chrome/browser/ui/singleton_tabs.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_view.h"
25 #include "content/public/browser/web_ui.h"
26 #include "google_apis/gaia/gaia_auth_fetcher.h"
27 #include "google_apis/gaia/gaia_constants.h"
28 #include "grit/browser_resources.h"
29 #include "grit/chromium_strings.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/base/webui/web_ui_util.h"
34 #include "ui/gfx/image/image_util.h"
35
36 #if defined(ENABLE_MANAGED_USERS)
37 #include "chrome/browser/managed_mode/managed_user_service.h"
38 #endif
39
40 namespace {
41 // User dictionary keys.
42 const char kKeyUsername[] = "username";
43 const char kKeyDisplayName[]= "displayName";
44 const char kKeyEmailAddress[] = "emailAddress";
45 const char kKeyProfilePath[] = "profilePath";
46 const char kKeyPublicAccount[] = "publicAccount";
47 const char kKeyLocallyManagedUser[] = "locallyManagedUser";
48 const char kKeySignedIn[] = "signedIn";
49 const char kKeyCanRemove[] = "canRemove";
50 const char kKeyIsOwner[] = "isOwner";
51 const char kKeyIsDesktop[] = "isDesktopUser";
52 const char kKeyAvatarUrl[] = "userImage";
53 const char kKeyNeedsSignin[] = "needsSignin";
54
55 // JS API callback names.
56 const char kJsApiUserManagerInitialize[] = "userManagerInitialize";
57 const char kJsApiUserManagerAddUser[] = "addUser";
58 const char kJsApiUserManagerAuthLaunchUser[] = "authenticatedLaunchUser";
59 const char kJsApiUserManagerLaunchGuest[] = "launchGuest";
60 const char kJsApiUserManagerLaunchUser[] = "launchUser";
61 const char kJsApiUserManagerRemoveUser[] = "removeUser";
62
63 const size_t kAvatarIconSize = 180;
64
65 void HandleAndDoNothing(const base::ListValue* args) {
66 }
67
68 // This callback is run if the only profile has been deleted, and a new
69 // profile has been created to replace it.
70 void OpenNewWindowForProfile(
71     chrome::HostDesktopType desktop_type,
72     Profile* profile,
73     Profile::CreateStatus status) {
74   if (status != Profile::CREATE_STATUS_INITIALIZED)
75     return;
76   profiles::FindOrCreateNewWindowForProfile(
77     profile,
78     chrome::startup::IS_PROCESS_STARTUP,
79     chrome::startup::IS_FIRST_RUN,
80     desktop_type,
81     false);
82 }
83
84 std::string GetAvatarImageAtIndex(
85     size_t index, const ProfileInfoCache& info_cache) {
86   bool is_gaia_picture =
87       info_cache.IsUsingGAIAPictureOfProfileAtIndex(index) &&
88       info_cache.GetGAIAPictureOfProfileAtIndex(index);
89
90   gfx::Image icon = profiles::GetSizedAvatarIconWithBorder(
91       info_cache.GetAvatarIconOfProfileAtIndex(index),
92       is_gaia_picture, kAvatarIconSize, kAvatarIconSize);
93   return webui::GetBitmapDataUrl(icon.AsBitmap());
94 }
95
96 size_t GetIndexOfProfileWithEmailAndName(const ProfileInfoCache& info_cache,
97                                          const base::string16& email,
98                                          const base::string16& name) {
99   for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
100     if (info_cache.GetUserNameOfProfileAtIndex(i) == email &&
101         info_cache.GetNameOfProfileAtIndex(i) == name) {
102       return i;
103     }
104   }
105   return std::string::npos;
106 }
107
108 } // namespace
109
110 // ProfileUpdateObserver ------------------------------------------------------
111
112 class UserManagerScreenHandler::ProfileUpdateObserver
113     : public ProfileInfoCacheObserver {
114  public:
115   ProfileUpdateObserver(
116       ProfileManager* profile_manager, UserManagerScreenHandler* handler)
117       : profile_manager_(profile_manager),
118         user_manager_handler_(handler) {
119     DCHECK(profile_manager_);
120     DCHECK(user_manager_handler_);
121     profile_manager_->GetProfileInfoCache().AddObserver(this);
122   }
123
124   virtual ~ProfileUpdateObserver() {
125     DCHECK(profile_manager_);
126     profile_manager_->GetProfileInfoCache().RemoveObserver(this);
127   }
128
129  private:
130   // ProfileInfoCacheObserver implementation:
131   // If any change has been made to a profile, propagate it to all the
132   // visible user manager screens.
133   virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE {
134     user_manager_handler_->SendUserList();
135   }
136
137   virtual void OnProfileWasRemoved(
138       const base::FilePath& profile_path,
139       const base::string16& profile_name) OVERRIDE {
140     // TODO(noms): Change 'SendUserList' to 'removeUser' JS-call when
141     // UserManager is able to find pod belonging to removed user.
142     user_manager_handler_->SendUserList();
143   }
144
145   virtual void OnProfileNameChanged(
146       const base::FilePath& profile_path,
147       const base::string16& old_profile_name) OVERRIDE {
148     user_manager_handler_->SendUserList();
149   }
150
151   virtual void OnProfileAvatarChanged(
152       const base::FilePath& profile_path) OVERRIDE {
153     user_manager_handler_->SendUserList();
154   }
155
156   virtual void OnProfileSigninRequiredChanged(
157       const base::FilePath& profile_path) OVERRIDE {
158     user_manager_handler_->SendUserList();
159   }
160
161   ProfileManager* profile_manager_;
162
163   UserManagerScreenHandler* user_manager_handler_;  // Weak; owns us.
164
165   DISALLOW_COPY_AND_ASSIGN(ProfileUpdateObserver);
166 };
167
168 // UserManagerScreenHandler ---------------------------------------------------
169
170 UserManagerScreenHandler::UserManagerScreenHandler()
171     : desktop_type_(chrome::GetActiveDesktop()) {
172   profileInfoCacheObserver_.reset(
173       new UserManagerScreenHandler::ProfileUpdateObserver(
174           g_browser_process->profile_manager(), this));
175 }
176
177 UserManagerScreenHandler::~UserManagerScreenHandler() {
178 }
179
180 void UserManagerScreenHandler::HandleInitialize(const base::ListValue* args) {
181   SendUserList();
182   web_ui()->CallJavascriptFunction("cr.ui.Oobe.showUserManagerScreen");
183   desktop_type_ = chrome::GetHostDesktopTypeForNativeView(
184       web_ui()->GetWebContents()->GetView()->GetNativeView());
185 }
186
187 void UserManagerScreenHandler::HandleAddUser(const base::ListValue* args) {
188   profiles::CreateAndSwitchToNewProfile(desktop_type_,
189                                         base::Bind(&chrome::HideUserManager));
190 }
191
192 void UserManagerScreenHandler::HandleAuthenticatedLaunchUser(
193     const base::ListValue* args) {
194   base::string16 email_address;
195   if (!args->GetString(0, &email_address))
196     return;
197
198   base::string16 display_name;
199   if (!args->GetString(1, &display_name))
200     return;
201
202   std::string password;
203   if (!args->GetString(2, &password))
204     return;
205
206   ProfileInfoCache& info_cache =
207       g_browser_process->profile_manager()->GetProfileInfoCache();
208   size_t profile_index = GetIndexOfProfileWithEmailAndName(
209       info_cache, email_address, display_name);
210   if (profile_index >= info_cache.GetNumberOfProfiles()) {
211     NOTREACHED();
212     return;
213   }
214
215   authenticating_profile_index_ = profile_index;
216   if (!chrome::ValidateLocalAuthCredentials(profile_index, password)) {
217     // Make a second attempt via an on-line authentication call.  This handles
218     // profiles that are missing sign-in credentials and also cases where the
219     // password has been changed externally.
220     client_login_.reset(new GaiaAuthFetcher(
221         this,
222         GaiaConstants::kChromeSource,
223         web_ui()->GetWebContents()->GetBrowserContext()->GetRequestContext()));
224     std::string email_string;
225     args->GetString(0, &email_string);
226     client_login_->StartClientLogin(
227         email_string,
228         password,
229         GaiaConstants::kSyncService,
230         std::string(),
231         std::string(),
232         GaiaAuthFetcher::HostedAccountsAllowed);
233     password_attempt_ = password;
234     return;
235   }
236
237   ReportAuthenticationResult(true);
238 }
239
240 void UserManagerScreenHandler::HandleRemoveUser(const base::ListValue* args) {
241   DCHECK(args);
242   const base::Value* profile_path_value;
243   if (!args->Get(0, &profile_path_value))
244     return;
245
246   base::FilePath profile_path;
247   if (!base::GetValueAsFilePath(*profile_path_value, &profile_path))
248     return;
249
250   // This handler could have been called in managed mode, for example because
251   // the user fiddled with the web inspector. Silently return in this case.
252   if (Profile::FromWebUI(web_ui())->IsManaged())
253     return;
254
255   if (!profiles::IsMultipleProfilesEnabled())
256     return;
257
258   g_browser_process->profile_manager()->ScheduleProfileForDeletion(
259       profile_path,
260       base::Bind(&OpenNewWindowForProfile, desktop_type_));
261 }
262
263 void UserManagerScreenHandler::HandleLaunchGuest(const base::ListValue* args) {
264   profiles::SwitchToGuestProfile(desktop_type_,
265                                  base::Bind(&chrome::HideUserManager));
266 }
267
268 void UserManagerScreenHandler::HandleLaunchUser(const base::ListValue* args) {
269   base::string16 email_address;
270   base::string16 display_name;
271
272   if (!args->GetString(0, &email_address) ||
273       !args->GetString(1, &display_name)) {
274     NOTREACHED();
275     return;
276   }
277
278   ProfileInfoCache& info_cache =
279       g_browser_process->profile_manager()->GetProfileInfoCache();
280   size_t profile_index = GetIndexOfProfileWithEmailAndName(
281       info_cache, email_address, display_name);
282
283   if (profile_index >= info_cache.GetNumberOfProfiles()) {
284     NOTREACHED();
285     return;
286   }
287
288   // It's possible that a user breaks into the user-manager page using the
289   // JavaScript Inspector and causes a "locked" profile to call this
290   // unauthenticated version of "launch" instead of the proper one.  Thus,
291   // we have to validate in (secure) C++ code that it really is a profile
292   // not needing authentication.  If it is, just ignore the "launch" request.
293   if (info_cache.ProfileIsSigninRequiredAtIndex(profile_index))
294     return;
295
296   base::FilePath path = info_cache.GetPathOfProfileAtIndex(profile_index);
297   profiles::SwitchToProfile(
298       path, desktop_type_, true, base::Bind(&chrome::HideUserManager));
299 }
300
301 void UserManagerScreenHandler::OnClientLoginSuccess(
302     const ClientLoginResult& result) {
303   chrome::SetLocalAuthCredentials(authenticating_profile_index_,
304                                   password_attempt_);
305   ReportAuthenticationResult(true);
306 }
307
308 void UserManagerScreenHandler::OnClientLoginFailure(
309     const GoogleServiceAuthError& error) {
310   ReportAuthenticationResult(false);
311 }
312
313 void UserManagerScreenHandler::RegisterMessages() {
314   web_ui()->RegisterMessageCallback(kJsApiUserManagerInitialize,
315       base::Bind(&UserManagerScreenHandler::HandleInitialize,
316                  base::Unretained(this)));
317   web_ui()->RegisterMessageCallback(kJsApiUserManagerAddUser,
318       base::Bind(&UserManagerScreenHandler::HandleAddUser,
319                  base::Unretained(this)));
320   web_ui()->RegisterMessageCallback(kJsApiUserManagerAuthLaunchUser,
321       base::Bind(&UserManagerScreenHandler::HandleAuthenticatedLaunchUser,
322                  base::Unretained(this)));
323   web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchGuest,
324       base::Bind(&UserManagerScreenHandler::HandleLaunchGuest,
325                  base::Unretained(this)));
326   web_ui()->RegisterMessageCallback(kJsApiUserManagerLaunchUser,
327       base::Bind(&UserManagerScreenHandler::HandleLaunchUser,
328                  base::Unretained(this)));
329   web_ui()->RegisterMessageCallback(kJsApiUserManagerRemoveUser,
330       base::Bind(&UserManagerScreenHandler::HandleRemoveUser,
331                  base::Unretained(this)));
332
333   const content::WebUI::MessageCallback& kDoNothingCallback =
334       base::Bind(&HandleAndDoNothing);
335
336   // Unused callbacks from screen_account_picker.js
337   web_ui()->RegisterMessageCallback("accountPickerReady", kDoNothingCallback);
338   web_ui()->RegisterMessageCallback("loginUIStateChanged", kDoNothingCallback);
339   web_ui()->RegisterMessageCallback("hideCaptivePortal", kDoNothingCallback);
340   // Unused callbacks from display_manager.js
341   web_ui()->RegisterMessageCallback("showAddUser", kDoNothingCallback);
342   web_ui()->RegisterMessageCallback("loadWallpaper", kDoNothingCallback);
343   web_ui()->RegisterMessageCallback("updateCurrentScreen", kDoNothingCallback);
344   web_ui()->RegisterMessageCallback("loginVisible", kDoNothingCallback);
345   // Unused callbacks from user_pod_row.js
346   web_ui()->RegisterMessageCallback("focusPod", kDoNothingCallback);
347 }
348
349 void UserManagerScreenHandler::GetLocalizedValues(
350     base::DictionaryValue* localized_strings) {
351   // For Control Bar.
352   localized_strings->SetString("signedIn",
353       l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_ACTIVE_USER));
354   localized_strings->SetString("signinButton",
355       l10n_util::GetStringUTF16(IDS_LOGIN_BUTTON));
356   localized_strings->SetString("addUser",
357       l10n_util::GetStringUTF16(IDS_ADD_USER_BUTTON));
358   localized_strings->SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
359   localized_strings->SetString("browseAsGuest",
360       l10n_util::GetStringUTF16(IDS_GO_INCOGNITO_BUTTON));
361   localized_strings->SetString("signOutUser",
362       l10n_util::GetStringUTF16(IDS_SCREEN_LOCK_SIGN_OUT));
363
364   // For AccountPickerScreen.
365   localized_strings->SetString("screenType", "login-add-user");
366   localized_strings->SetString("highlightStrength", "normal");
367   localized_strings->SetString("title",
368       l10n_util::GetStringUTF16(IDS_USER_MANAGER_SCREEN_TITLE));
369   localized_strings->SetString("passwordHint",
370       l10n_util::GetStringUTF16(IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT));
371   localized_strings->SetString("podMenuButtonAccessibleName",
372       l10n_util::GetStringUTF16(IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME));
373   localized_strings->SetString("podMenuRemoveItemAccessibleName",
374       l10n_util::GetStringUTF16(
375           IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME));
376   localized_strings->SetString("removeUser",
377       l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON));
378   localized_strings->SetString("passwordFieldAccessibleName",
379       l10n_util::GetStringUTF16(IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME));
380   localized_strings->SetString("bootIntoWallpaper", "off");
381
382   // For AccountPickerScreen, the remove user warning overlay.
383   localized_strings->SetString("removeUserWarningButtonTitle",
384       l10n_util::GetStringUTF16(IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON));
385   localized_strings->SetString("removeUserWarningText",
386       l10n_util::GetStringUTF16(
387            IDS_LOGIN_POD_USER_REMOVE_WARNING));
388
389   // Strings needed for the user_pod_template public account div, but not ever
390   // actually displayed for desktop users.
391   localized_strings->SetString("publicAccountReminder", base::string16());
392   localized_strings->SetString("publicAccountEnter", base::string16());
393   localized_strings->SetString("publicAccountEnterAccessibleName",
394                                base::string16());
395   localized_strings->SetString("multiple-signin-banner-text",
396                                base::string16());
397 }
398
399 void UserManagerScreenHandler::SendUserList() {
400   base::ListValue users_list;
401   base::FilePath active_profile_path =
402       web_ui()->GetWebContents()->GetBrowserContext()->GetPath();
403   const ProfileInfoCache& info_cache =
404       g_browser_process->profile_manager()->GetProfileInfoCache();
405
406   // If the active user is a managed user, then they may not perform
407   // certain actions (i.e. delete another user).
408   bool active_user_is_managed = Profile::FromWebUI(web_ui())->IsManaged();
409   for (size_t i = 0; i < info_cache.GetNumberOfProfiles(); ++i) {
410     base::DictionaryValue* profile_value = new base::DictionaryValue();
411
412     base::FilePath profile_path = info_cache.GetPathOfProfileAtIndex(i);
413     bool is_active_user = (profile_path == active_profile_path);
414
415     profile_value->SetString(
416         kKeyUsername, info_cache.GetUserNameOfProfileAtIndex(i));
417     profile_value->SetString(
418         kKeyEmailAddress, info_cache.GetUserNameOfProfileAtIndex(i));
419     profile_value->SetString(
420         kKeyDisplayName, info_cache.GetNameOfProfileAtIndex(i));
421     profile_value->SetString(kKeyProfilePath, profile_path.MaybeAsASCII());
422     profile_value->SetBoolean(kKeyPublicAccount, false);
423     profile_value->SetBoolean(kKeyLocallyManagedUser, false);
424     profile_value->SetBoolean(kKeySignedIn, is_active_user);
425     profile_value->SetBoolean(
426         kKeyNeedsSignin, info_cache.ProfileIsSigninRequiredAtIndex(i));
427     profile_value->SetBoolean(kKeyIsOwner, false);
428     profile_value->SetBoolean(kKeyCanRemove, !active_user_is_managed);
429     profile_value->SetBoolean(kKeyIsDesktop, true);
430     profile_value->SetString(
431         kKeyAvatarUrl, GetAvatarImageAtIndex(i, info_cache));
432
433     // The row of user pods should display the active user first.
434     if (is_active_user)
435       users_list.Insert(0, profile_value);
436     else
437       users_list.Append(profile_value);
438   }
439
440   web_ui()->CallJavascriptFunction("login.AccountPickerScreen.loadUsers",
441     users_list, base::FundamentalValue(false), base::FundamentalValue(true));
442 }
443
444 void UserManagerScreenHandler::ReportAuthenticationResult(bool success) {
445   if (success) {
446     ProfileInfoCache& info_cache =
447         g_browser_process->profile_manager()->GetProfileInfoCache();
448     info_cache.SetProfileSigninRequiredAtIndex(
449         authenticating_profile_index_, false);
450     base::FilePath path = info_cache.GetPathOfProfileAtIndex(
451         authenticating_profile_index_);
452     profiles::SwitchToProfile(path, desktop_type_, true,
453                               base::Bind(&chrome::HideUserManager));
454   } else {
455     web_ui()->CallJavascriptFunction(
456         "cr.ui.Oobe.showSignInError",
457         base::FundamentalValue(0),
458         base::StringValue(
459             l10n_util::GetStringUTF8(IDS_LOGIN_ERROR_AUTHENTICATING)),
460         base::StringValue(""),
461         base::FundamentalValue(0));
462   }
463
464   password_attempt_.clear();
465 }