Index: trunk/src/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc |
=================================================================== |
--- trunk/src/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc (revision 275548) |
+++ trunk/src/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc (working copy) |
@@ -63,6 +63,7 @@ |
#include "chromeos/ime/input_method_manager.h" |
#include "chromeos/network/network_state.h" |
#include "chromeos/network/network_state_handler.h" |
+#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/render_frame_host.h" |
#include "content/public/browser/web_contents.h" |
#include "google_apis/gaia/gaia_auth_util.h" |
@@ -95,6 +96,16 @@ |
const char kSourceGaiaSignin[] = "gaia-signin"; |
const char kSourceAccountPicker[] = "account-picker"; |
+// The Task posted to PostTaskAndReply in StartClearingDnsCache on the IO |
+// thread. |
+void ClearDnsCache(IOThread* io_thread) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ if (browser_shutdown::IsTryingToQuit()) |
+ return; |
+ |
+ io_thread->ClearHostCache(); |
+} |
+ |
static bool Contains(const std::vector<std::string>& container, |
const std::string& value) { |
return std::find(container.begin(), container.end(), value) != |
@@ -205,6 +216,10 @@ |
return true; |
} |
+void RecordSAMLScrapingVerificationResultInHistogram(bool success) { |
+ UMA_HISTOGRAM_BOOLEAN("ChromeOS.SAML.Scraping.VerificationResult", success); |
+} |
+ |
} // namespace |
// LoginScreenContext implementation ------------------------------------------ |
@@ -239,8 +254,16 @@ |
native_window_delegate_(NULL), |
show_on_init_(false), |
oobe_ui_(false), |
+ focus_stolen_(false), |
+ gaia_silent_load_(false), |
is_account_picker_showing_first_time_(false), |
+ dns_cleared_(false), |
+ dns_clear_task_running_(false), |
+ cookies_cleared_(false), |
network_state_informer_(network_state_informer), |
+ using_saml_api_(false), |
+ test_expects_complete_login_(false), |
+ weak_factory_(this), |
webui_visible_(false), |
preferences_changed_delayed_(false), |
error_screen_actor_(error_screen_actor), |
@@ -252,8 +275,7 @@ |
caps_lock_enabled_(chromeos::input_method::InputMethodManager::Get() |
->GetImeKeyboard() |
->CapsLockIsEnabled()), |
- gaia_screen_handler_(gaia_screen_handler), |
- weak_factory_(this) { |
+ gaia_screen_handler_(gaia_screen_handler) { |
DCHECK(network_state_informer_.get()); |
DCHECK(error_screen_actor_); |
DCHECK(core_oobe_actor_); |
@@ -404,7 +426,10 @@ |
// Just initialize internal fields from context and call ShowImpl(). |
oobe_ui_ = context.oobe_ui(); |
- gaia_screen_handler_->PopulateEmail(context.email()); |
+ if (!context.email().empty()) |
+ email_ = context.email(); |
+ else |
+ email_.clear(); |
ShowImpl(); |
} |
@@ -427,8 +452,7 @@ |
void SigninScreenHandler::OnNetworkReady() { |
LOG(WARNING) << "OnNetworkReady() call."; |
- DCHECK(gaia_screen_handler_); |
- gaia_screen_handler_->MaybePreloadAuthExtension(); |
+ MaybePreloadAuthExtension(); |
} |
void SigninScreenHandler::UpdateState(ErrorScreenActor::ErrorReason reason) { |
@@ -445,7 +469,7 @@ |
if (oobe_ui_) { |
// Shows new user sign-in for OOBE. |
- OnShowAddUser(); |
+ OnShowAddUser(email_); |
} else { |
// Populates account picker. Animation is turned off for now until we |
// figure out how to make it fast enough. |
@@ -688,8 +712,16 @@ |
} |
void SigninScreenHandler::RegisterMessages() { |
+ AddCallback("usingSAMLAPI", &SigninScreenHandler::HandleUsingSAMLAPI); |
+ AddCallback("scrapedPasswordCount", |
+ &SigninScreenHandler::HandleScrapedPasswordCount); |
+ AddCallback("scrapedPasswordVerificationFailed", |
+ &SigninScreenHandler::HandleScrapedPasswordVerificationFailed); |
AddCallback("authenticateUser", &SigninScreenHandler::HandleAuthenticateUser); |
AddCallback("attemptUnlock", &SigninScreenHandler::HandleAttemptUnlock); |
+ AddCallback("completeLogin", &SigninScreenHandler::HandleCompleteLogin); |
+ AddCallback("completeAuthentication", |
+ &SigninScreenHandler::HandleCompleteAuthentication); |
AddCallback("getUsers", &SigninScreenHandler::HandleGetUsers); |
AddCallback("launchDemoUser", &SigninScreenHandler::HandleLaunchDemoUser); |
AddCallback("launchIncognito", &SigninScreenHandler::HandleLaunchIncognito); |
@@ -711,6 +743,7 @@ |
AddCallback("accountPickerReady", |
&SigninScreenHandler::HandleAccountPickerReady); |
AddCallback("wallpaperReady", &SigninScreenHandler::HandleWallpaperReady); |
+ AddCallback("loginWebuiReady", &SigninScreenHandler::HandleLoginWebuiReady); |
AddCallback("signOutUser", &SigninScreenHandler::HandleSignOutUser); |
AddCallback("openProxySettings", |
&SigninScreenHandler::HandleOpenProxySettings); |
@@ -762,7 +795,7 @@ |
void SigninScreenHandler::OnUserRemoved(const std::string& username) { |
CallJS("login.AccountPickerScreen.removeUser", username); |
if (delegate_->GetUsers().empty()) |
- OnShowAddUser(); |
+ OnShowAddUser(""); |
} |
void SigninScreenHandler::OnUserImageChanged(const User& user) { |
@@ -817,9 +850,9 @@ |
} |
void SigninScreenHandler::ShowGaiaPasswordChanged(const std::string& username) { |
- gaia_screen_handler_->PasswordChangedFor(username); |
- gaia_screen_handler_->PopulateEmail(username); |
- core_oobe_actor_->ShowSignInUI(username); |
+ email_ = username; |
+ password_changed_for_.insert(email_); |
+ core_oobe_actor_->ShowSignInUI(email_); |
CallJS("login.setAuthType", |
username, |
static_cast<int>(ONLINE_SIGN_IN), |
@@ -833,10 +866,28 @@ |
void SigninScreenHandler::ShowSigninScreenForCreds( |
const std::string& username, |
const std::string& password) { |
- DCHECK(gaia_screen_handler_); |
- gaia_screen_handler_->ShowSigninScreenForCreds(username, password); |
+ VLOG(2) << "ShowSigninScreenForCreds for user " << username |
+ << ", frame_state=" << FrameState(); |
+ |
+ test_user_ = username; |
+ test_pass_ = password; |
+ test_expects_complete_login_ = true; |
+ |
+ // Submit login form for test if gaia is ready. If gaia is loading, login |
+ // will be attempted in HandleLoginWebuiReady after gaia is ready. Otherwise, |
+ // reload gaia then follow the loading case. |
+ if (FrameState() == GaiaScreenHandler::FRAME_STATE_LOADED) |
+ SubmitLoginFormForTest(); |
+ else if (FrameState() != GaiaScreenHandler::FRAME_STATE_LOADING) |
+ HandleShowAddUser(NULL); |
} |
+void SigninScreenHandler::OnCookiesCleared(base::Closure on_clear_callback) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ cookies_cleared_ = true; |
+ on_clear_callback.Run(); |
+} |
+ |
void SigninScreenHandler::OnKeyEvent(ui::KeyEvent* key) { |
if (key->type() == ui::ET_KEY_PRESSED && key->key_code() == ui::VKEY_CAPITAL) |
OnCapsLockChanged(!caps_lock_enabled_); |
@@ -925,12 +976,11 @@ |
ScreenLocker::Hide(); |
} |
-bool SigninScreenHandler::ShouldLoadGaia() const { |
- // Fetching of the extension is not started before account picker page is |
- // loaded because it can affect the loading speed. |
- // Do not load the extension for the screen locker, see crosbug.com/25018. |
- return !ScreenLocker::default_screen_locker() && |
- is_account_picker_showing_first_time_; |
+void SigninScreenHandler::OnDnsCleared() { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ dns_clear_task_running_ = false; |
+ dns_cleared_ = true; |
+ ShowSigninScreenIfReady(); |
} |
// Update keyboard layout to least recently used by the user. |
@@ -960,7 +1010,66 @@ |
} |
} |
+void SigninScreenHandler::ShowSigninScreenIfReady() { |
+ LOG(WARNING) << "ShowSigninScreenIfReady() call."; |
+ if (!dns_cleared_ || !cookies_cleared_ || !delegate_) |
+ return; |
+ |
+ std::string active_network_path = network_state_informer_->network_path(); |
+ if (gaia_silent_load_ && |
+ (network_state_informer_->state() != NetworkStateInformer::ONLINE || |
+ gaia_silent_load_network_ != active_network_path)) { |
+ // Network has changed. Force Gaia reload. |
+ gaia_silent_load_ = false; |
+ // Gaia page will be realoded, so focus isn't stolen anymore. |
+ focus_stolen_ = false; |
+ } |
+ |
+ // Note that LoadAuthExtension clears |email_|. |
+ if (email_.empty()) |
+ delegate_->LoadSigninWallpaper(); |
+ else |
+ delegate_->LoadWallpaper(email_); |
+ |
+ // Set Least Recently Used input method for the user. |
+ if (!email_.empty()) |
+ SetUserInputMethod(email_); |
+ |
+ LoadAuthExtension(!gaia_silent_load_, false, false); |
+ UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL); |
+ |
+ if (gaia_silent_load_) { |
+ // The variable is assigned to false because silently loaded Gaia page was |
+ // used. |
+ gaia_silent_load_ = false; |
+ if (focus_stolen_) |
+ HandleLoginWebuiReady(); |
+ } |
+ |
+ UpdateState(ErrorScreenActor::ERROR_REASON_UPDATE); |
+} |
+ |
+void SigninScreenHandler::LoadAuthExtension( |
+ bool force, bool silent_load, bool offline) { |
+ GaiaContext context; |
+ context.force_reload = force; |
+ context.is_local = offline; |
+ context.password_changed = |
+ !email_.empty() && password_changed_for_.count(email_); |
+ if (delegate_) |
+ context.show_users = delegate_->IsShowUsers(); |
+ context.use_offline = offline; |
+ if (delegate_) |
+ context.has_users = !delegate_->GetUsers().empty(); |
+ context.email = email_; |
+ |
+ email_.clear(); |
+ |
+ DCHECK(gaia_screen_handler_); |
+ gaia_screen_handler_->LoadGaia(context); |
+} |
+ |
void SigninScreenHandler::UserSettingsChanged() { |
DCHECK(gaia_screen_handler_); |
GaiaContext context; |
@@ -975,6 +1084,65 @@ |
AllWhitelistedUsersPresent()); |
} |
+void SigninScreenHandler::HandleUsingSAMLAPI() { |
+ SetSAMLPrincipalsAPIUsed(true); |
+} |
+ |
+void SigninScreenHandler::HandleScrapedPasswordCount(int password_count) { |
+ SetSAMLPrincipalsAPIUsed(false); |
+ // Use a histogram that has 11 buckets, one for each of the values in [0, 9] |
+ // and an overflow bucket at the end. |
+ UMA_HISTOGRAM_ENUMERATION( |
+ "ChromeOS.SAML.Scraping.PasswordCount", std::min(password_count, 10), 11); |
+ if (password_count == 0) |
+ HandleScrapedPasswordVerificationFailed(); |
+} |
+ |
+void SigninScreenHandler::HandleScrapedPasswordVerificationFailed() { |
+ RecordSAMLScrapingVerificationResultInHistogram(false); |
+} |
+ |
+void SigninScreenHandler::HandleCompleteLogin(const std::string& typed_email, |
+ const std::string& password, |
+ bool using_saml) { |
+ if (!delegate_) |
+ return; |
+ |
+ if (using_saml && !using_saml_api_) |
+ RecordSAMLScrapingVerificationResultInHistogram(true); |
+ |
+ const std::string sanitized_email = gaia::SanitizeEmail(typed_email); |
+ delegate_->SetDisplayEmail(sanitized_email); |
+ UserContext user_context(sanitized_email); |
+ user_context.SetKey(Key(password)); |
+ user_context.SetAuthFlow(using_saml ? |
+ UserContext::AUTH_FLOW_GAIA_WITH_SAML : |
+ UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML); |
+ delegate_->CompleteLogin(user_context); |
+ |
+ if (test_expects_complete_login_) { |
+ VLOG(2) << "Complete test login for " << typed_email |
+ << ", requested=" << test_user_; |
+ |
+ test_expects_complete_login_ = false; |
+ test_user_.clear(); |
+ test_pass_.clear(); |
+ } |
+} |
+ |
+void SigninScreenHandler::HandleCompleteAuthentication( |
+ const std::string& email, |
+ const std::string& password, |
+ const std::string& auth_code) { |
+ if (!delegate_) |
+ return; |
+ delegate_->SetDisplayEmail(gaia::SanitizeEmail(email)); |
+ UserContext user_context(email); |
+ user_context.SetKey(Key(password)); |
+ user_context.SetAuthCode(auth_code); |
+ delegate_->CompleteLogin(user_context); |
+} |
+ |
void SigninScreenHandler::HandleAuthenticateUser(const std::string& username, |
const std::string& password) { |
if (!delegate_) |
@@ -1037,13 +1205,11 @@ |
NOTREACHED(); |
return; |
} |
- std::string email; |
- args->GetString(0, &email); |
- |
- gaia_screen_handler_->PopulateEmail(email); |
+ if (!args->GetString(0, &email_)) |
+ email_.clear(); |
// Load auth extension. Parameters are: force reload, do not load extension in |
// background, use offline version. |
- gaia_screen_handler_->LoadAuthExtension(true, false, true); |
+ LoadAuthExtension(true, false, true); |
UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL); |
} |
@@ -1076,8 +1242,7 @@ |
// |args| can be null if it's OOBE. |
if (args) |
args->GetString(0, &email); |
- gaia_screen_handler_->PopulateEmail(email); |
- OnShowAddUser(); |
+ OnShowAddUser(email); |
} |
void SigninScreenHandler::HandleToggleEnrollmentScreen() { |
@@ -1136,7 +1301,7 @@ |
} |
is_account_picker_showing_first_time_ = true; |
- gaia_screen_handler_->MaybePreloadAuthExtension(); |
+ MaybePreloadAuthExtension(); |
if (ScreenLocker::default_screen_locker()) { |
ScreenLocker::default_screen_locker()->delegate()->OnLockWebUIReady(); |
@@ -1154,6 +1319,40 @@ |
} |
} |
+void SigninScreenHandler::HandleLoginWebuiReady() { |
+ if (focus_stolen_) { |
+ // Set focus to the Gaia page. |
+ // TODO(altimofeev): temporary solution, until focus parameters are |
+ // implemented on the Gaia side. |
+ // Do this only once. Any subsequent call would relod GAIA frame. |
+ focus_stolen_ = false; |
+ const char code[] = |
+ "if (typeof gWindowOnLoad != 'undefined') gWindowOnLoad();"; |
+ content::RenderFrameHost* frame = |
+ LoginDisplayHostImpl::GetGaiaAuthIframe(web_ui()->GetWebContents()); |
+ frame->ExecuteJavaScript(base::ASCIIToUTF16(code)); |
+ } |
+ if (gaia_silent_load_) { |
+ focus_stolen_ = true; |
+ // Prevent focus stealing by the Gaia page. |
+ // TODO(altimofeev): temporary solution, until focus parameters are |
+ // implemented on the Gaia side. |
+ const char code[] = "var gWindowOnLoad = window.onload; " |
+ "window.onload=function() {};"; |
+ content::RenderFrameHost* frame = |
+ LoginDisplayHostImpl::GetGaiaAuthIframe(web_ui()->GetWebContents()); |
+ frame->ExecuteJavaScript(base::ASCIIToUTF16(code)); |
+ // As we could miss and window.onload could already be called, restore |
+ // focus to current pod (see crbug/175243). |
+ RefocusCurrentPod(); |
+ } |
+ DCHECK(gaia_screen_handler_); |
+ gaia_screen_handler_->HandleFrameLoadingCompleted(0); |
+ |
+ if (test_expects_complete_login_) |
+ SubmitLoginFormForTest(); |
+} |
+ |
void SigninScreenHandler::HandleSignOutUser() { |
if (delegate_) |
delegate_->Signout(); |
@@ -1187,9 +1386,9 @@ |
} |
void SigninScreenHandler::HandleCancelPasswordChangedFlow() { |
- gaia_screen_handler_->StartClearingCookies( |
- base::Bind(&SigninScreenHandler::CancelPasswordChangedFlowInternal, |
- weak_factory_.GetWeakPtr())); |
+ StartClearingCookies(base::Bind( |
+ &SigninScreenHandler::CancelPasswordChangedFlowInternal, |
+ weak_factory_.GetWeakPtr())); |
} |
void SigninScreenHandler::HandleCancelUserAdding() { |
@@ -1268,6 +1467,51 @@ |
delegate_->LoginAsKioskApp(app_id, diagnostic_mode); |
} |
+void SigninScreenHandler::StartClearingDnsCache() { |
+ if (dns_clear_task_running_ || !g_browser_process->io_thread()) |
+ return; |
+ |
+ dns_cleared_ = false; |
+ BrowserThread::PostTaskAndReply( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&ClearDnsCache, g_browser_process->io_thread()), |
+ base::Bind(&SigninScreenHandler::OnDnsCleared, |
+ weak_factory_.GetWeakPtr())); |
+ dns_clear_task_running_ = true; |
+} |
+ |
+void SigninScreenHandler::StartClearingCookies( |
+ const base::Closure& on_clear_callback) { |
+ cookies_cleared_ = false; |
+ ProfileHelper* profile_helper = |
+ g_browser_process->platform_part()->profile_helper(); |
+ LOG_ASSERT( |
+ Profile::FromWebUI(web_ui()) == profile_helper->GetSigninProfile()); |
+ profile_helper->ClearSigninProfile(base::Bind( |
+ &SigninScreenHandler::OnCookiesCleared, |
+ weak_factory_.GetWeakPtr(), on_clear_callback)); |
+} |
+ |
+void SigninScreenHandler::MaybePreloadAuthExtension() { |
+ LOG(WARNING) << "MaybePreloadAuthExtension() call."; |
+ |
+ // Fetching of the extension is not started before account picker page is |
+ // loaded because it can affect the loading speed. Also if cookies clearing |
+ // was initiated or |dns_clear_task_running_| then auth extension showing has |
+ // already been initiated and preloading is senseless. |
+ // Do not load the extension for the screen locker, see crosbug.com/25018. |
+ if (is_account_picker_showing_first_time_ && |
+ !gaia_silent_load_ && |
+ !ScreenLocker::default_screen_locker() && |
+ !cookies_cleared_ && |
+ !dns_clear_task_running_ && |
+ network_state_informer_->state() == NetworkStateInformer::ONLINE) { |
+ gaia_silent_load_ = true; |
+ gaia_silent_load_network_ = network_state_informer_->network_path(); |
+ LoadAuthExtension(true, true, false); |
+ } |
+} |
+ |
bool SigninScreenHandler::AllWhitelistedUsersPresent() { |
CrosSettings* cros_settings = CrosSettings::Get(); |
bool allow_new_user = false; |
@@ -1343,6 +1587,23 @@ |
return !show_pods; |
} |
+void SigninScreenHandler::SubmitLoginFormForTest() { |
+ VLOG(2) << "Submit login form for test, user=" << test_user_; |
+ |
+ std::string code; |
+ code += "document.getElementById('Email').value = '" + test_user_ + "';"; |
+ code += "document.getElementById('Passwd').value = '" + test_pass_ + "';"; |
+ code += "document.getElementById('signIn').click();"; |
+ |
+ content::RenderFrameHost* frame = |
+ LoginDisplayHostImpl::GetGaiaAuthIframe(web_ui()->GetWebContents()); |
+ frame->ExecuteJavaScript(base::ASCIIToUTF16(code)); |
+ |
+ // Test properties are cleared in HandleCompleteLogin because the form |
+ // submission might fail and login will not be attempted after reloading |
+ // if they are cleared here. |
+} |
+ |
void SigninScreenHandler::ContinueKioskEnableFlow( |
policy::AutoEnrollmentState state) { |
// Do not proceed with kiosk enable when auto enroll will be enforced. |
@@ -1370,12 +1631,27 @@ |
auto_enrollment_progress_subscription_.reset(); |
} |
-void SigninScreenHandler::OnShowAddUser() { |
+void SigninScreenHandler::OnShowAddUser(const std::string& email) { |
+ email_ = email; |
is_account_picker_showing_first_time_ = false; |
- DCHECK(gaia_screen_handler_); |
- gaia_screen_handler_->ShowGaia(); |
+ |
+ if (gaia_silent_load_ && email_.empty()) { |
+ dns_cleared_ = true; |
+ cookies_cleared_ = true; |
+ ShowSigninScreenIfReady(); |
+ } else { |
+ StartClearingDnsCache(); |
+ StartClearingCookies(base::Bind( |
+ &SigninScreenHandler::ShowSigninScreenIfReady, |
+ weak_factory_.GetWeakPtr())); |
+ } |
} |
+void SigninScreenHandler::SetSAMLPrincipalsAPIUsed(bool api_used) { |
+ using_saml_api_ = api_used; |
+ UMA_HISTOGRAM_BOOLEAN("ChromeOS.SAML.APIUsed", api_used); |
+} |
+ |
GaiaScreenHandler::FrameState SigninScreenHandler::FrameState() const { |
DCHECK(gaia_screen_handler_); |
return gaia_screen_handler_->frame_state(); |