diff options
31 files changed, 422 insertions, 301 deletions
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 514e87d..ac7ccd6 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp @@ -1436,8 +1436,8 @@ Press any key to continue exploring. <message name="IDS_LOGIN_CONFIRM_PASSWORD_ERROR_TEXT" desc="Error text to show when the password typed by the user could not be verified."> Sorry, your password could not be verified. Please try again. </message> - <message name="IDS_LOGIN_FATAL_ERROR_NO_EMAIL" desc="Message to show when the authentication could not be completed because the user's e-mail address could not be retrieved."> - Oops, couldn't sign you in. Sign-in failed because your e-mail address could not be retrieved. + <message name="IDS_LOGIN_FATAL_ERROR_NO_ACCOUNT_DETAILS" desc="Message to show when the authentication could not be completed because the user's account details could not be retrieved."> + Oops, couldn't sign you in. Sign-in failed because your account details could not be retrieved. </message> <message name="IDS_LOGIN_FATAL_ERROR_NO_PASSWORD" desc="Message to show when the authentication could not be completed because the user's password could not be retrieved."> Something went wrong with signing in. diff --git a/chrome/browser/chromeos/login/saml/saml_browsertest.cc b/chrome/browser/chromeos/login/saml/saml_browsertest.cc index a0e34ba..44e8402 100644 --- a/chrome/browser/chromeos/login/saml/saml_browsertest.cc +++ b/chrome/browser/chromeos/login/saml/saml_browsertest.cc @@ -575,7 +575,7 @@ IN_PROC_BROWSER_TEST_F(SamlTest, FailToRetrieveAutenticatedUserEmailAddress) { SetSignFormField("Password", "fake_password"); ExecuteJsInSigninFrame("document.getElementById('Submit').click();"); - EXPECT_EQ(l10n_util::GetStringUTF8(IDS_LOGIN_FATAL_ERROR_NO_EMAIL), + EXPECT_EQ(l10n_util::GetStringUTF8(IDS_LOGIN_FATAL_ERROR_NO_ACCOUNT_DETAILS), WaitForAndGetFatalErrorMessage()); } diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc index 123b80a..374cf3f 100644 --- a/chrome/browser/chromeos/login/session/user_session_manager.cc +++ b/chrome/browser/chromeos/login/session/user_session_manager.cc @@ -56,6 +56,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/rlz/rlz.h" +#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/easy_unlock_service.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/common/chrome_switches.h" @@ -75,6 +76,7 @@ #include "components/component_updater/component_updater_service.h" #include "components/policy/core/common/cloud/cloud_policy_constants.h" #include "components/session_manager/core/session_manager.h" +#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/signin_manager_base.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" @@ -745,6 +747,17 @@ void UserSessionManager::InitProfilePreferences( profile->GetPrefs()->SetString(prefs::kSupervisedUserId, supervised_user_sync_id); } else if (user_manager::UserManager::Get()->IsLoggedInAsRegularUser()) { + // Prime the account tracker with this combination of gaia id/display email. + // Don't do this unless both email and gaia_id are valid. They may not + // be when simply unlocking the profile. + if (!user_context.GetGaiaID().empty() && + !user_context.GetUserID().empty()) { + AccountTrackerService* account_tracker = + AccountTrackerServiceFactory::GetForProfile(profile); + account_tracker->SeedAccountInfo(user_context.GetGaiaID(), + user_context.GetUserID()); + } + // Make sure that the google service username is properly set (we do this // on every sign in, not just the first login, to deal with existing // profiles that might not have it set yet). diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc index 97bff3b..8128dda 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc +++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.cc @@ -13,11 +13,13 @@ #include "base/strings/string_util.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/common/chrome_switches.h" #include "chromeos/chromeos_switches.h" +#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_client.h" #include "components/signin/core/browser/signin_manager.h" @@ -166,53 +168,67 @@ const std::string& OAuth2LoginManager::GetPrimaryAccountId() { void OAuth2LoginManager::StoreOAuth2Token() { const std::string& primary_account_id = GetPrimaryAccountId(); if (primary_account_id.empty()) { - GetAccountIdOfRefreshToken(refresh_token_); + GetAccountInfoOfRefreshToken(refresh_token_); return; } - OnGetUserEmailResponse(primary_account_id); + UpdateCredentials(primary_account_id); } -void OAuth2LoginManager::GetAccountIdOfRefreshToken( +void OAuth2LoginManager::GetAccountInfoOfRefreshToken( const std::string& refresh_token) { gaia::OAuthClientInfo client_info; GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); client_info.client_id = gaia_urls->oauth2_chrome_client_id(); client_info.client_secret = gaia_urls->oauth2_chrome_client_secret(); - account_id_fetcher_.reset(new gaia::GaiaOAuthClient( + account_info_fetcher_.reset(new gaia::GaiaOAuthClient( auth_request_context_.get())); - account_id_fetcher_->RefreshToken(client_info, refresh_token, + account_info_fetcher_->RefreshToken(client_info, refresh_token, std::vector<std::string>(1, kServiceScopeGetUserInfo), kMaxRetries, this); } +void OAuth2LoginManager::UpdateCredentials(const std::string& account_id) { + DCHECK(!account_id.empty()); + DCHECK(!refresh_token_.empty()); + // |account_id| is assumed to be already canonicalized if it's an email. + GetTokenService()->UpdateCredentials(account_id, refresh_token_); + + FOR_EACH_OBSERVER(Observer, observer_list_, + OnNewRefreshTokenAvaiable(user_profile_)); +} + void OAuth2LoginManager::OnRefreshTokenResponse( const std::string& access_token, int expires_in_seconds) { - account_id_fetcher_->GetUserEmail(access_token, kMaxRetries, this); + account_info_fetcher_->GetUserInfo(access_token, kMaxRetries, this); } -void OAuth2LoginManager::OnGetUserEmailResponse( - const std::string& user_email) { - DCHECK(!refresh_token_.empty()); - account_id_fetcher_.reset(); - std::string canonicalized = gaia::CanonicalizeEmail(user_email); - GetTokenService()->UpdateCredentials(canonicalized, refresh_token_); +void OAuth2LoginManager::OnGetUserInfoResponse( + scoped_ptr<base::DictionaryValue> user_info) { + account_info_fetcher_.reset(); - FOR_EACH_OBSERVER(Observer, observer_list_, - OnNewRefreshTokenAvaiable(user_profile_)); + std::string gaia_id; + std::string email; + user_info->GetString("id", &gaia_id); + user_info->GetString("email", &email); + + AccountTrackerService* account_tracker = + AccountTrackerServiceFactory::GetForProfile(user_profile_); + account_tracker->SeedAccountInfo(gaia_id, email); + UpdateCredentials(account_tracker->PickAccountIdForAccount(gaia_id, email)); } void OAuth2LoginManager::OnOAuthError() { - account_id_fetcher_.reset(); - LOG(ERROR) << "Account id fetch failed!"; + account_info_fetcher_.reset(); + LOG(ERROR) << "Account info fetch failed!"; SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED); } void OAuth2LoginManager::OnNetworkError(int response_code) { - account_id_fetcher_.reset(); - LOG(ERROR) << "Account id fetch failed! response_code=" << response_code; + account_info_fetcher_.reset(); + LOG(ERROR) << "Account info fetch failed! response_code=" << response_code; SetSessionRestoreState(OAuth2LoginManager::SESSION_RESTORE_FAILED); } diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h index 9543f5d..ab9ccdf 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_login_manager.h +++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager.h @@ -149,8 +149,9 @@ class OAuth2LoginManager : public KeyedService, // gaia::GaiaOAuthClient::Delegate overrides. void OnRefreshTokenResponse(const std::string& access_token, - int expires_in_seconds) override; - void OnGetUserEmailResponse(const std::string& user_email) override; + int expires_in_seconds) override; + void OnGetUserInfoResponse( + scoped_ptr<base::DictionaryValue> user_info) override; void OnOAuthError() override; void OnNetworkError(int response_code) override; @@ -180,12 +181,15 @@ class OAuth2LoginManager : public KeyedService, // Records |refresh_token_| to token service. The associated account id is // assumed to be the primary account id of the user profile. If the primary - // account id is not present, GetAccountIdOfRefreshToken will be called to - // retrieve the associated account id. + // account id is not present, GetAccountInfoOfRefreshToken will be called to + // retrieve the associated account info. void StoreOAuth2Token(); - // Get the account id corresponding to the specified refresh token. - void GetAccountIdOfRefreshToken(const std::string& refresh_token); + // Get the account info corresponding to the specified refresh token. + void GetAccountInfoOfRefreshToken(const std::string& refresh_token); + + // Update the token service and inform listeners of a new refresh token. + void UpdateCredentials(const std::string& account_id); // Attempts to fetch OAuth2 tokens by using pre-authenticated cookie jar from // provided |auth_profile|. @@ -230,7 +234,7 @@ class OAuth2LoginManager : public KeyedService, scoped_ptr<OAuth2TokenFetcher> oauth2_token_fetcher_; scoped_ptr<OAuth2LoginVerifier> login_verifier_; - scoped_ptr<gaia::GaiaOAuthClient> account_id_fetcher_; + scoped_ptr<gaia::GaiaOAuthClient> account_info_fetcher_; // OAuth2 refresh token. std::string refresh_token_; diff --git a/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc b/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc index 1d429a0..da71de9 100644 --- a/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc +++ b/chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.cc @@ -6,6 +6,7 @@ #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/ui/global_error/global_error_service_factory.h" @@ -17,6 +18,7 @@ OAuth2LoginManagerFactory::OAuth2LoginManagerFactory() : BrowserContextKeyedServiceFactory( "OAuth2LoginManager", BrowserContextDependencyManager::GetInstance()) { + DependsOn(AccountTrackerServiceFactory::GetInstance()); DependsOn(GlobalErrorServiceFactory::GetInstance()); DependsOn(SigninManagerFactory::GetInstance()); DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance()); diff --git a/chrome/browser/resources/chromeos/login/login_common.js b/chrome/browser/resources/chromeos/login/login_common.js index 0366f8c..c25f59b 100644 --- a/chrome/browser/resources/chromeos/login/login_common.js +++ b/chrome/browser/resources/chromeos/login/login_common.js @@ -263,7 +263,7 @@ cr.define('cr.ui', function() { Oobe.loginForTesting = function(username, password) { Oobe.disableSigninUI(); chrome.send('skipToLoginForTesting', [username]); - chrome.send('completeLogin', [username, password, false]); + chrome.send('completeLogin', ['12345', username, password, false]); }; /** diff --git a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js index 0947594..67e163d 100644 --- a/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js +++ b/chrome/browser/resources/chromeos/login/oobe_screen_oauth_enrollment.js @@ -16,7 +16,6 @@ login.createScreen('OAuthEnrollmentScreen', 'oauth-enrollment', function() { 'showStep', 'showError', 'showWorking', - 'setAuthenticatedUserEmail', 'doReload', ], @@ -206,24 +205,6 @@ login.createScreen('OAuthEnrollmentScreen', 'oauth-enrollment', function() { this.showStep(STEP_WORKING); }, - /** - * Invoked when the authenticated user's e-mail address has been retrieved. - * This completes SAML authentication. - * @param {number} attemptToken An opaque token used to correlate this - * method invocation with the corresponding request to retrieve the - * user's e-mail address. - * @param {string} email The authenticated user's e-mail address. - */ - setAuthenticatedUserEmail: function(attemptToken, email) { - if (this.attemptToken_ != attemptToken) - return; - - if (!email) - this.showError(loadTimeData.getString('fatalEnrollmentError'), false); - else - chrome.send('oauthEnrollCompleteLogin', [email]); - }, - doReload: function() { $('oauth-enroll-signin-frame').contentWindow.location.href = this.signInUrl_; @@ -289,20 +270,10 @@ login.createScreen('OAuthEnrollmentScreen', 'oauth-enrollment', function() { var msg = m.data; if (msg.method == 'completeLogin') { - // A user has successfully authenticated via regular GAIA. + // A user has successfully authenticated via regular GAIA or SAML. chrome.send('oauthEnrollCompleteLogin', [msg.email]); } - if (msg.method == 'retrieveAuthenticatedUserEmail') { - // A user has successfully authenticated via SAML. However, the user's - // identity is not known. Instead of reporting success immediately, - // retrieve the user's e-mail address first. - this.attemptToken_ = msg.attemptToken; - this.showWorking(null); - chrome.send('oauthEnrollRetrieveAuthenticatedUserEmail', - [msg.attemptToken]); - } - if (msg.method == 'authPageLoaded' && this.currentStep_ == STEP_SIGNIN) { if (msg.isSAML) { $('oauth-saml-notice-message').textContent = loadTimeData.getStringF( @@ -318,6 +289,12 @@ login.createScreen('OAuthEnrollmentScreen', 'oauth-enrollment', function() { loadTimeData.getStringF('insecureURLEnrollmentError', msg.url), false); } + + if (msg.method == 'missingGaiaInfo') { + this.showError( + loadTimeData.getString('fatalEnrollmentError'), + false); + } } }; }); diff --git a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js index 153663d..ff04403 100644 --- a/chrome/browser/resources/chromeos/login/screen_gaia_signin.js +++ b/chrome/browser/resources/chromeos/login/screen_gaia_signin.js @@ -22,7 +22,6 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { EXTERNAL_API: [ 'loadAuthExtension', 'updateAuthExtension', - 'setAuthenticatedUserEmail', 'doReload', 'onFrameError', 'updateCancelButtonState' @@ -94,14 +93,16 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { this.gaiaAuthHost_ = new cr.login.GaiaAuthHost($('signin-frame')); this.gaiaAuthHost_.addEventListener( 'ready', this.onAuthReady_.bind(this)); - this.gaiaAuthHost_.retrieveAuthenticatedUserEmailCallback = - this.onRetrieveAuthenticatedUserEmail_.bind(this); this.gaiaAuthHost_.confirmPasswordCallback = this.onAuthConfirmPassword_.bind(this); this.gaiaAuthHost_.noPasswordCallback = this.onAuthNoPassword_.bind(this); this.gaiaAuthHost_.insecureContentBlockedCallback = this.onInsecureContentBlocked_.bind(this); + this.gaiaAuthHost_.missingGaiaInfoCallback = + this.missingGaiaInfo_.bind(this); + this.gaiaAuthHost_.samlApiUsedCallback = + this.samlApiUsed_.bind(this); this.gaiaAuthHost_.addEventListener('authFlowChange', this.onAuthFlowChange_.bind(this)); @@ -338,21 +339,6 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { }, /** - * Sends the authenticated user's e-mail address to the auth extension. - * @param {number} attemptToken The opaque token provided to - * onRetrieveAuthenticatedUserEmail_. - * @param {string} email The authenticated user's e-mail address. - */ - setAuthenticatedUserEmail: function(attemptToken, email) { - if (!email) { - this.showFatalAuthError( - loadTimeData.getString('fatalErrorMessageNoEmail')); - } else { - this.gaiaAuthHost_.setAuthenticatedUserEmail(attemptToken, email); - } - }, - - /** * Updates [Cancel] button state. Allow cancellation of screen only when * user pods can be displayed. */ @@ -413,27 +399,6 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { }, /** - * Invoked when the user has successfully authenticated via SAML and the - * auth host needs to retrieve the user's e-mail. - * @param {number} attemptToken Opaque token to be passed to - * setAuthenticatedUserEmail along with the e-mail address. - * @param {boolean} apiUsed Whether the principals API was used during - * authentication. - * @private - */ - onRetrieveAuthenticatedUserEmail_: function(attemptToken, apiUsed) { - if (apiUsed) { - // If the principals API was used, report this to the C++ backend so - // that statistics can be kept. If password scraping was used instead, - // there is no need to inform the C++ backend at this point: Either - // onAuthNoPassword_ or onAuthConfirmPassword_ will be called in a - // moment, both of which imply to the backend that the API was not used. - chrome.send('usingSAMLAPI'); - } - chrome.send('retrieveAuthenticatedUserEmail', [attemptToken]); - }, - - /** * Invoked when the user has successfully authenticated via SAML, the * principals API was not used and the auth host needs the user to confirm * the scraped password. @@ -503,6 +468,21 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { }, /** + * Show fatal auth error when information is missing from GAIA. + */ + missingGaiaInfo_: function() { + this.showFatalAuthError( + loadTimeData.getString('fatalErrorMessageNoAccountDetails')); + }, + + /** + * Record that SAML API was used during sign-in. + */ + samlApiUsed_: function() { + chrome.send('usingSAMLAPI'); + }, + + /** * Invoked when auth is completed successfully. * @param {!Object} credentials Credentials of the completed authentication. * @private @@ -511,15 +491,19 @@ login.createScreen('GaiaSigninScreen', 'gaia-signin', function() { if (credentials.useOffline) { this.email = credentials.email; chrome.send('authenticateUser', - [credentials.email, credentials.password]); + [credentials.gaiaId, + credentials.email, + credentials.password]); } else if (credentials.authCode) { chrome.send('completeAuthentication', - [credentials.email, + [credentials.gaiaId, + credentials.email, credentials.password, credentials.authCode]); } else { chrome.send('completeLogin', - [credentials.email, + [credentials.gaiaId, + credentials.email, credentials.password, credentials.usingSAML]); } diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd index 914afdf..44c409d 100644 --- a/chrome/browser/resources/component_extension_resources.grd +++ b/chrome/browser/resources/component_extension_resources.grd @@ -49,7 +49,6 @@ <include name="IDR_GAIA_AUTH_OFFLINE_JS" file="gaia_auth/offline.js" type="BINDATA" /> <include name="IDR_GAIA_AUTH_OFFLINE_CSS" file="gaia_auth/offline.css" type="BINDATA" /> <include name="IDR_GAIA_AUTH_SUCCESS" file="gaia_auth/success.html" allowexternalscript="true" type="BINDATA" /> - <include name="IDR_GAIA_AUTH_SUCCESS_JS" file="gaia_auth/success.js" type="BINDATA" /> <include name="IDR_GAIA_AUTH_UTIL_JS" file="gaia_auth/util.js" type="BINDATA" /> <include name="IDR_GAIA_AUTH_BACKGROUND_JS" file="gaia_auth/background.js" type="BINDATA" /> <include name="IDR_GAIA_AUTH_SAML_INJECTED_JS" file="gaia_auth/saml_injected.js" type="BINDATA" /> diff --git a/chrome/browser/resources/gaia_auth/background.js b/chrome/browser/resources/gaia_auth/background.js index ffe0b078..db94085 100644 --- a/chrome/browser/resources/gaia_auth/background.js +++ b/chrome/browser/resources/gaia_auth/background.js @@ -119,6 +119,10 @@ BackgroundBridge.prototype = { // 'google-accounts-signin'. email_: null, + // Gaia Id of the newly authenticated user based on the gaia response + // header 'google-accounts-signin'. + gaiaId_: null, + // Session index of the newly authenticated user based on the gaia response // header 'google-accounts-signin'. sessionIndex_: null, @@ -204,7 +208,7 @@ BackgroundBridge.prototype = { onCompleted: function(details) { // Only monitors requests in the gaia frame whose parent frame ID must be // positive. - if (!this.isDesktopFlow_ || details.parentFrameId <= 0) + if (details.parentFrameId <= 0) return; if (details.url.lastIndexOf(backgroundBridgeManager.CONTINUE_URL_BASE, 0) == @@ -213,11 +217,12 @@ BackgroundBridge.prototype = { if (details.url.indexOf('ntp=1') >= 0) skipForNow = true; - // TOOD(guohui): Show password confirmation UI. + // TOOD(guohui): For desktop SAML flow, show password confirmation UI. var passwords = this.onGetScrapedPasswords_(); var msg = { 'name': 'completeLogin', 'email': this.email_, + 'gaiaId': this.gaiaId_, 'password': passwords[0], 'sessionIndex': this.sessionIndex_, 'skipForNow': skipForNow @@ -262,11 +267,7 @@ BackgroundBridge.prototype = { onHeadersReceived: function(details) { var headers = details.responseHeaders; - if (this.isDesktopFlow_ && - this.gaiaUrl_ && - details.url.lastIndexOf(this.gaiaUrl_) == 0) { - // TODO(xiyuan, guohui): CrOS should reuse the logic below for reading the - // email for SAML users and cut off the /ListAccount call. + if (this.gaiaUrl_ && details.url.lastIndexOf(this.gaiaUrl_) == 0) { for (var i = 0; headers && i < headers.length; ++i) { if (headers[i].name.toLowerCase() == 'google-accounts-signin') { var headerValues = headers[i].value.toLowerCase().split(','); @@ -277,6 +278,7 @@ BackgroundBridge.prototype = { }); // Remove "" around. this.email_ = signinDetails['email'].slice(1, -1); + this.gaiaId_ = signinDetails['obfuscatedid'].slice(1, -1); this.sessionIndex_ = signinDetails['sessionindex']; break; } diff --git a/chrome/browser/resources/gaia_auth/main.js b/chrome/browser/resources/gaia_auth/main.js index ba48c65..b9a57d8 100644 --- a/chrome/browser/resources/gaia_auth/main.js +++ b/chrome/browser/resources/gaia_auth/main.js @@ -48,6 +48,7 @@ Authenticator.getInstance = function() { Authenticator.prototype = { email_: null, + gaiaId_: null, // Depending on the key type chosen, this will contain the plain text password // or a credential derived from it along with the information required to @@ -56,6 +57,9 @@ Authenticator.prototype = { // when support for key types other than plain text password is added. passwordBytes_: null, + chooseWhatToSync_: false, + skipForNow_: false, + sessionIndex_: null, attemptToken_: null, // Input params from extension initialization URL. @@ -104,10 +108,6 @@ Authenticator.prototype = { this.GAIA_URL.indexOf(msg.origin) == 0; }, - isInternalMessage_: function(msg) { - return msg.origin == Authenticator.THIS_EXTENSION_ORIGIN; - }, - isParentMessage_: function(msg) { return msg.origin == this.parentPage_; }, @@ -165,9 +165,9 @@ Authenticator.prototype = { }); this.supportChannel_.registerMessage( 'switchToFullTab', this.switchToFullTab_.bind(this)); - this.supportChannel_.registerMessage( - 'completeLogin', this.completeLogin_.bind(this)); } + this.supportChannel_.registerMessage( + 'completeLogin', this.onCompleteLogin_.bind(this)); this.initSAML_(); this.maybeInitialized_(); }.bind(this)); @@ -198,7 +198,7 @@ Authenticator.prototype = { /** * Invoked when the background script sends a message to indicate that the * current content does not fit in a constrained window. - * @param {Object=} opt_extraMsg Optional extra info to send. + * @param {Object=} msg Extra info to send. */ switchToFullTab_: function(msg) { var parentMsg = { @@ -220,8 +220,11 @@ Authenticator.prototype = { this.passwordBytes_, 'usingSAML': this.isSAMLFlow_, 'chooseWhatToSync': this.chooseWhatToSync_ || false, - 'skipForNow': opt_extraMsg && opt_extraMsg.skipForNow, - 'sessionIndex': opt_extraMsg && opt_extraMsg.sessionIndex + 'skipForNow': (opt_extraMsg && opt_extraMsg.skipForNow) || + this.skipForNow_, + 'sessionIndex': (opt_extraMsg && opt_extraMsg.sessionIndex) || + this.sessionIndex_, + 'gaiaId': (opt_extraMsg && opt_extraMsg.gaiaId) || this.gaiaId_ }; window.parent.postMessage(msg, this.parentPage_); this.supportChannel_.send({name: 'resetAuth'}); @@ -268,6 +271,7 @@ Authenticator.prototype = { // from the GAIA login form are no longer relevant and can be discarded. this.isSAMLFlow_ = true; this.email_ = null; + this.gaiaId_ = null; this.passwordBytes_ = null; } @@ -316,8 +320,9 @@ Authenticator.prototype = { console.error('Authenticator.onAPICall_: unsupported key type'); return; } + // Not setting |email_| and |gaiaId_| because this API call will + // eventually be followed by onCompleteLogin_() which does set it. this.apiToken_ = call.token; - this.email_ = call.user; this.passwordBytes_ = call.passwordBytes; } else if (call.method == 'confirm') { if (call.token != this.apiToken_) @@ -342,21 +347,34 @@ Authenticator.prototype = { }); }, - onConfirmLogin_: function() { - if (!this.isSAMLFlow_) { - this.completeLogin_(); + /** + * Callback invoked for 'completeLogin' message. + * @param {Object=} msg Message sent from background page. + */ + onCompleteLogin_: function(msg) { + if (!msg.email || !msg.gaiaId || !msg.sessionIndex) { + console.error('Missing fields to complete login.'); + window.parent.postMessage({method: 'missingGaiaInfo'}, this.parentPage_); return; } - var apiUsed = !!this.passwordBytes_; + // Skip SAML extra steps for desktop flow and non-SAML flow. + if (!this.isSAMLFlow_ || this.desktopMode_) { + this.completeLogin_(msg); + return; + } - // Retrieve the e-mail address of the user who just authenticated from GAIA. - window.parent.postMessage({method: 'retrieveAuthenticatedUserEmail', - attemptToken: this.attemptToken_, - apiUsed: apiUsed}, - this.parentPage_); + this.email_ = msg.email; + this.gaiaId_ = msg.gaiaId; + // Password from |msg| is not used because ChromeOS SAML flow + // gets password by asking user to confirm. + this.skipForNow_ = msg.skipForNow; + this.sessionIndex_ = msg.sessionIndex; - if (!apiUsed) { + if (this.passwordBytes_) { + window.parent.postMessage({method: 'samlApiUsed'}, this.parentPage_); + this.completeLogin_(msg); + } else { this.supportChannel_.sendWithCallback( {name: 'getScrapedPasswords'}, function(passwords) { @@ -374,13 +392,6 @@ Authenticator.prototype = { } }, - maybeCompleteSAMLLogin_: function() { - // SAML login is complete when the user's e-mail address has been retrieved - // from GAIA and the user has successfully confirmed the password. - if (this.email_ !== null && this.passwordBytes_ !== null) - this.completeLogin_(); - }, - onVerifyConfirmedPassword_: function(password) { this.supportChannel_.sendWithCallback( {name: 'getScrapedPasswords'}, @@ -388,7 +399,10 @@ Authenticator.prototype = { for (var i = 0; i < passwords.length; ++i) { if (passwords[i] == password) { this.passwordBytes_ = passwords[i]; - this.maybeCompleteSAMLLogin_(); + // SAML login is complete when the user has successfully + // confirmed the password. + if (this.passwordBytes_ !== null) + this.completeLogin_(); return; } } @@ -401,6 +415,7 @@ Authenticator.prototype = { onMessage: function(e) { var msg = e.data; if (msg.method == 'attemptLogin' && this.isGaiaMessage_(e)) { + // At this point GAIA does not yet know the gaiaId, so its not set here. this.email_ = msg.email; this.passwordBytes_ = msg.password; this.attemptToken_ = msg.attemptToken; @@ -416,27 +431,15 @@ Authenticator.prototype = { this.maybeInitialized_(); } this.email_ = null; + this.gaiaId_ = null; + this.sessionIndex_ = false; this.passwordBytes_ = null; this.attemptToken_ = null; this.isSAMLFlow_ = false; + this.skipForNow_ = false; + this.chooseWhatToSync_ = false; if (this.supportChannel_) this.supportChannel_.send({name: 'resetAuth'}); - } else if (msg.method == 'setAuthenticatedUserEmail' && - this.isParentMessage_(e)) { - if (this.attemptToken_ == msg.attemptToken) { - this.email_ = msg.email; - this.maybeCompleteSAMLLogin_(); - } - } else if (msg.method == 'confirmLogin' && this.isInternalMessage_(e)) { - // In the desktop mode, Chrome needs to wait for extra info such as - // session index from the background JS. - if (this.desktopMode_) - return; - - if (this.attemptToken_ == msg.attemptToken) - this.onConfirmLogin_(); - else - console.error('Authenticator.onMessage: unexpected attemptToken!?'); } else if (msg.method == 'verifyConfirmedPassword' && this.isParentMessage_(e)) { this.onVerifyConfirmedPassword_(msg.password); diff --git a/chrome/browser/resources/gaia_auth/success.html b/chrome/browser/resources/gaia_auth/success.html index d9c5712..fa5b1e6 100644 --- a/chrome/browser/resources/gaia_auth/success.html +++ b/chrome/browser/resources/gaia_auth/success.html @@ -1,8 +1,6 @@ <!DOCTYPE html> <head> <meta charset="utf-8"> -<script src="util.js"></script> -<script src="success.js"></script> </head> <html> <body></body> diff --git a/chrome/browser/resources/gaia_auth/success.js b/chrome/browser/resources/gaia_auth/success.js deleted file mode 100644 index 54ed7fa..0000000 --- a/chrome/browser/resources/gaia_auth/success.js +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -function load() { - var params = getUrlSearchParams(location.search); - var msg = { - 'method': 'confirmLogin', - 'attemptToken': params['attemptToken'] - }; - window.parent.postMessage(msg, - 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/main.html'); -} - -document.addEventListener('DOMContentLoaded', load); - diff --git a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js index e835e20..cf870cb 100644 --- a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js +++ b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js @@ -141,18 +141,6 @@ cr.define('cr.login', function() { successCallback_: null, /** - * Invoked when GAIA indicates login success and SAML was used. At this - * point, GAIA cookies are present but the identity of the authenticated - * user is not known. The embedder of GaiaAuthHost should extract the GAIA - * cookies from the cookie jar, query GAIA for the authenticated user's - * e-mail address and invoke GaiaAuthHost.setAuthenticatedUserEmail with the - * result. The argument is an opaque token that should be passed back to - * GaiaAuthHost.setAuthenticatedUserEmail. - * @type {function(number)} - */ - retrieveAuthenticatedUserEmailCallback_: null, - - /** * Invoked when the auth flow needs a user to confirm his/her passwords. * This could happen when there are more than one passwords scraped during * SAML flow. The embedder of GaiaAuthHost should show an UI to collect a @@ -175,22 +163,28 @@ cr.define('cr.login', function() { /** * Invoked when the authentication flow had to be aborted because content * served over an unencrypted connection was detected. + */ insecureContentBlockedCallback_: null, /** - * The iframe container. - * @type {HTMLIFrameElement} + * Invoked to display an error message to the user when a GAIA error occurs + * during authentication. + * @type {function()} */ - get frame() { - return this.frame_; - }, + missingGaiaInfoCallback_: null, /** - * Sets retrieveAuthenticatedUserEmailCallback_. + * Invoked to record that the credentials passing API was used. * @type {function()} */ - set retrieveAuthenticatedUserEmailCallback(callback) { - this.retrieveAuthenticatedUserEmailCallback_ = callback; + samlApiUsedCallback_: null, + + /** + * The iframe container. + * @type {HTMLIFrameElement} + */ + get frame() { + return this.frame_; }, /** @@ -218,6 +212,22 @@ cr.define('cr.login', function() { }, /** + * Sets missingGaiaInfoCallback_. + * @type {function()} + */ + set missingGaiaInfoCallback(callback) { + this.missingGaiaInfoCallback_ = callback; + }, + + /** + * Sets samlApiUsedCallback_. + * @type {function()} + */ + set samlApiUsedCallback(callback) { + this.samlApiUsedCallback_ = callback; + }, + + /** * Loads the auth extension. * @param {AuthMode} authMode Authorization mode. * @param {Object} data Parameters for the auth extension. See the auth @@ -286,21 +296,6 @@ cr.define('cr.login', function() { }, /** - * Sends the authenticated user's e-mail address to the auth extension. - * @param {number} attemptToken The opaque token provided to the - * retrieveAuthenticatedUserEmailCallback_. - * @param {string} email The authenticated user's e-mail address. - */ - setAuthenticatedUserEmail: function(attemptToken, email) { - var msg = { - method: 'setAuthenticatedUserEmail', - attemptToken: attemptToken, - email: email - }; - this.frame_.contentWindow.postMessage(msg, AUTH_URL_BASE); - }, - - /** * Invoked to process authentication success. * @param {Object} credentials Credential object to pass to success * callback. @@ -346,6 +341,7 @@ cr.define('cr.login', function() { } this.onAuthSuccess_({email: msg.email, password: msg.password, + gaiaId: msg.gaiaId, useOffline: msg.method == 'offlineLogin', usingSAML: msg.usingSAML || false, chooseWhatToSync: msg.chooseWhatToSync, @@ -354,17 +350,6 @@ cr.define('cr.login', function() { return; } - if (msg.method == 'retrieveAuthenticatedUserEmail') { - if (this.retrieveAuthenticatedUserEmailCallback_) { - this.retrieveAuthenticatedUserEmailCallback_(msg.attemptToken, - msg.apiUsed); - } else { - console.error( - 'GaiaAuthHost: Invalid retrieveAuthenticatedUserEmailCallback_.'); - } - return; - } - if (msg.method == 'confirmPassword') { if (this.confirmPasswordCallback_) this.confirmPasswordCallback_(msg.passwordCount); @@ -402,6 +387,24 @@ cr.define('cr.login', function() { return; } + if (msg.method == 'missingGaiaInfo') { + if (this.missingGaiaInfoCallback_) { + this.missingGaiaInfoCallback_(); + } else { + console.error('GaiaAuthHost: Invalid missingGaiaInfoCallback_.'); + } + return; + } + + if (msg.method == 'samlApiUsed') { + if (this.samlApiUsedCallback_) { + this.samlApiUsedCallback_(); + } else { + console.error('GaiaAuthHost: Invalid samlApiUsedCallback_.'); + } + return; + } + console.error('Unknown message method=' + msg.method); } }; diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc index 00e9841..1d78088 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.cc @@ -22,7 +22,6 @@ #include "chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h" #include "chrome/browser/extensions/signin/gaia_auth_extension_loader.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/grit/generated_resources.h" #include "chromeos/network/network_state.h" @@ -148,8 +147,6 @@ EnrollmentScreenHandler::~EnrollmentScreenHandler() { // EnrollmentScreenHandler, WebUIMessageHandler implementation -- void EnrollmentScreenHandler::RegisterMessages() { - AddCallback("oauthEnrollRetrieveAuthenticatedUserEmail", - &EnrollmentScreenHandler::HandleRetrieveAuthenticatedUserEmail); AddCallback("oauthEnrollClose", &EnrollmentScreenHandler::HandleClose); AddCallback("oauthEnrollCompleteLogin", @@ -519,16 +516,6 @@ void EnrollmentScreenHandler::OnFrameError( } // EnrollmentScreenHandler, private ----------------------------- -void EnrollmentScreenHandler::HandleRetrieveAuthenticatedUserEmail( - double attempt_token) { - email_retriever_.reset(new AuthenticatedUserEmailRetriever( - base::Bind(&EnrollmentScreenHandler::CallJS<double, std::string>, - base::Unretained(this), - "setAuthenticatedUserEmail", - attempt_token), - Profile::FromWebUI(web_ui())->GetRequestContext())); -} - void EnrollmentScreenHandler::HandleClose(const std::string& reason) { DCHECK(controller_); diff --git a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h index b8ab5c3..004ddb1 100644 --- a/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h @@ -24,7 +24,6 @@ class PolicyOAuth2TokenFetcher; namespace chromeos { -class AuthenticatedUserEmailRetriever; class ErrorScreensHistogramHelper; // WebUIMessageHandler implementation which handles events occurring on the @@ -75,7 +74,6 @@ class EnrollmentScreenHandler private: // Handlers for WebUI messages. - void HandleRetrieveAuthenticatedUserEmail(double attempt_token); void HandleClose(const std::string& reason); void HandleCompleteLogin(const std::string& user); void HandleRetry(); @@ -140,9 +138,6 @@ class EnrollmentScreenHandler // The callbacks to invoke after browsing data has been cleared. std::vector<base::Closure> auth_reset_callbacks_; - // Helper that retrieves the authenticated user's e-mail address. - scoped_ptr<AuthenticatedUserEmailRetriever> email_retriever_; - // Latest enrollment frame error. net::Error frame_error_; diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc index 4325274..4e4f710 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.cc @@ -267,7 +267,8 @@ void GaiaScreenHandler::DeclareLocalizedValues( IDS_LOGIN_CONSUMER_MANAGEMENT_ENROLLMENT); // Strings used by the SAML fatal error dialog. - builder->Add("fatalErrorMessageNoEmail", IDS_LOGIN_FATAL_ERROR_NO_EMAIL); + builder->Add("fatalErrorMessageNoAccountDetails", + IDS_LOGIN_FATAL_ERROR_NO_ACCOUNT_DETAILS); builder->Add("fatalErrorMessageNoPassword", IDS_LOGIN_FATAL_ERROR_NO_PASSWORD); builder->Add("fatalErrorMessageVerificationFailed", @@ -319,23 +320,29 @@ void GaiaScreenHandler::HandleFrameLoadingCompleted(int status) { } void GaiaScreenHandler::HandleCompleteAuthentication( + const std::string& gaia_id, const std::string& email, const std::string& password, const std::string& auth_code) { if (!Delegate()) return; + + DCHECK(!email.empty()); + DCHECK(!gaia_id.empty()); Delegate()->SetDisplayEmail(gaia::SanitizeEmail(email)); UserContext user_context(email); + user_context.SetGaiaID(gaia_id); user_context.SetKey(Key(password)); user_context.SetAuthCode(auth_code); Delegate()->CompleteLogin(user_context); } -void GaiaScreenHandler::HandleCompleteLogin(const std::string& typed_email, +void GaiaScreenHandler::HandleCompleteLogin(const std::string& gaia_id, + const std::string& typed_email, const std::string& password, bool using_saml) { if (!is_enrolling_consumer_management_) { - DoCompleteLogin(typed_email, password, using_saml); + DoCompleteLogin(gaia_id, typed_email, password, using_saml); return; } @@ -354,6 +361,7 @@ void GaiaScreenHandler::HandleCompleteLogin(const std::string& typed_email, consumer_management_->SetOwner(owner_email, base::Bind(&GaiaScreenHandler::OnSetOwnerDone, weak_factory_.GetWeakPtr(), + gaia_id, typed_email, password, using_saml)); @@ -417,7 +425,8 @@ void GaiaScreenHandler::HandleGaiaUIReady() { SubmitLoginFormForTest(); } -void GaiaScreenHandler::OnSetOwnerDone(const std::string& typed_email, +void GaiaScreenHandler::OnSetOwnerDone(const std::string& gaia_id, + const std::string& typed_email, const std::string& password, bool using_saml, bool success) { @@ -433,10 +442,11 @@ void GaiaScreenHandler::OnSetOwnerDone(const std::string& typed_email, // We should continue logging in the user, as there's not much we can do // here. } - DoCompleteLogin(typed_email, password, using_saml); + DoCompleteLogin(gaia_id, typed_email, password, using_saml); } -void GaiaScreenHandler::DoCompleteLogin(const std::string& typed_email, +void GaiaScreenHandler::DoCompleteLogin(const std::string& gaia_id, + const std::string& typed_email, const std::string& password, bool using_saml) { if (!Delegate()) @@ -445,9 +455,12 @@ void GaiaScreenHandler::DoCompleteLogin(const std::string& typed_email, if (using_saml && !using_saml_api_) RecordSAMLScrapingVerificationResultInHistogram(true); + DCHECK(!typed_email.empty()); + DCHECK(!gaia_id.empty()); const std::string sanitized_email = gaia::SanitizeEmail(typed_email); Delegate()->SetDisplayEmail(sanitized_email); UserContext user_context(sanitized_email); + user_context.SetGaiaID(gaia_id); user_context.SetKey(Key(password)); user_context.SetAuthFlow(using_saml ? UserContext::AUTH_FLOW_GAIA_WITH_SAML diff --git a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h index 4d5c411..c90428d 100644 --- a/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h @@ -100,10 +100,12 @@ class GaiaScreenHandler : public BaseScreenHandler { // WebUI message handlers. void HandleFrameLoadingCompleted(int status); - void HandleCompleteAuthentication(const std::string& email, + void HandleCompleteAuthentication(const std::string& gaia_id, + const std::string& email, const std::string& password, const std::string& auth_code); - void HandleCompleteLogin(const std::string& typed_email, + void HandleCompleteLogin(const std::string& gaia_id, + const std::string& typed_email, const std::string& password, bool using_saml); @@ -114,13 +116,15 @@ class GaiaScreenHandler : public BaseScreenHandler { void HandleGaiaUIReady(); // This is called when ConsumerManagementService::SetOwner() returns. - void OnSetOwnerDone(const std::string& typed_email, + void OnSetOwnerDone(const std::string& gaia_id, + const std::string& typed_email, const std::string& password, bool using_saml, bool success); // Really handles the complete login message. - void DoCompleteLogin(const std::string& typed_email, + void DoCompleteLogin(const std::string& gaia_id, + const std::string& typed_email, const std::string& password, bool using_saml); diff --git a/chrome/browser/ui/webui/chromeos/login/inline_login_handler_chromeos.cc b/chrome/browser/ui/webui/chromeos/login/inline_login_handler_chromeos.cc index a3a722e..12e5ae2 100644 --- a/chrome/browser/ui/webui/chromeos/login/inline_login_handler_chromeos.cc +++ b/chrome/browser/ui/webui/chromeos/login/inline_login_handler_chromeos.cc @@ -4,13 +4,17 @@ #include "chrome/browser/ui/webui/chromeos/login/inline_login_handler_chromeos.h" +#include <string> + #include "chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/signin/account_tracker_service_factory.h" #include "chrome/browser/signin/chrome_signin_client_factory.h" #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" #include "chrome/browser/signin/signin_manager_factory.h" #include "chrome/browser/signin/signin_promo.h" #include "chrome/common/url_constants.h" +#include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_client.h" #include "components/signin/core/browser/signin_manager.h" @@ -72,10 +76,20 @@ void InlineLoginHandlerChromeOS::CompleteLogin(const base::ListValue* args) { dict->GetString("sessionIndex", &session_index); CHECK(!session_index.empty()) << "Session index is empty."; - std::string account_id; - dict->GetString("email", &account_id); - CHECK(!account_id.empty()) << "Account ID is empty."; + std::string email; + dict->GetString("email", &email); + CHECK(!email.empty()) << "Email is empty."; + + std::string gaia_id; + dict->GetString("gaiaId", &gaia_id); + CHECK(!gaia_id.empty()) << "Gaia ID is empty."; + + AccountTrackerService* account_tracker = + AccountTrackerServiceFactory::GetForProfile(profile); + account_tracker->SeedAccountInfo(gaia_id, email); + const std::string account_id = + account_tracker->PickAccountIdForAccount(gaia_id, email); oauth2_delegate_.reset(new InlineLoginUIOAuth2Delegate(web_ui(), account_id)); net::URLRequestContextGetter* request_context = content::BrowserContext::GetStoragePartitionForSite( diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index ddc2215..d1ccfa6 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc @@ -8,7 +8,6 @@ #include <vector> #include "base/bind.h" -#include "base/bind_helpers.h" #include "base/debug/trace_event.h" #include "base/location.h" #include "base/logging.h" @@ -47,7 +46,6 @@ #include "chrome/browser/io_thread.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/signin/easy_unlock_service.h" -#include "chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.h" #include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h" #include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h" @@ -73,7 +71,6 @@ #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "google_apis/gaia/gaia_auth_util.h" -#include "net/url_request/url_request_context_getter.h" #include "third_party/cros_system_api/dbus/service_constants.h" #include "ui/base/webui/web_ui_util.h" @@ -777,8 +774,6 @@ void SigninScreenHandler::RegisterMessages() { &SigninScreenHandler::HandleUpdateOfflineLogin); AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod); AddCallback("hardlockPod", &SigninScreenHandler::HandleHardlockPod); - AddCallback("retrieveAuthenticatedUserEmail", - &SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail); AddCallback("getPublicSessionKeyboardLayouts", &SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts); AddCallback("cancelConsumerManagementEnrollment", @@ -1385,17 +1380,6 @@ void SigninScreenHandler::HandleHardlockPod(const std::string& user_id) { service->SetHardlockState(EasyUnlockScreenlockStateHandler::USER_HARDLOCK); } -void SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail( - double attempt_token) { - // TODO(antrim) : move GaiaSigninScreen dependency to GaiaSigninScreen. - email_retriever_.reset(new AuthenticatedUserEmailRetriever( - base::Bind(&SigninScreenHandler::CallJS<double, std::string>, - base::Unretained(this), - "login.GaiaSigninScreen.setAuthenticatedUserEmail", - attempt_token), - Profile::FromWebUI(web_ui())->GetRequestContext())); -} - void SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts( const std::string& user_id, const std::string& locale) { diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index 74dda85..22277e3 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h @@ -46,7 +46,6 @@ class ListValue; namespace chromeos { -class AuthenticatedUserEmailRetriever; class CaptivePortalWindowProxy; class CoreOobeActor; class ErrorScreensHistogramHelper; @@ -395,7 +394,6 @@ class SigninScreenHandler void HandleFocusPod(const std::string& user_id); void HandleHardlockPod(const std::string& user_id); void HandleLaunchKioskApp(const std::string& app_id, bool diagnostic_mode); - void HandleRetrieveAuthenticatedUserEmail(double attempt_token); void HandleGetPublicSessionKeyboardLayouts(const std::string& user_id, const std::string& locale); void HandleCancelConsumerManagementEnrollment(); @@ -520,9 +518,6 @@ class SigninScreenHandler // TODO(ygorshenin@): remove this dependency. GaiaScreenHandler* gaia_screen_handler_; - // Helper that retrieves the authenticated user's e-mail address. - scoped_ptr<AuthenticatedUserEmailRetriever> email_retriever_; - // Maximized mode controller delegate. scoped_ptr<TouchViewControllerDelegate> max_mode_delegate_; diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc index a3d56d6..13c59ca 100644 --- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc +++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc @@ -33,10 +33,10 @@ #include "components/signin/core/browser/account_tracker_service.h" #include "components/signin/core/browser/profile_oauth2_token_service.h" #include "components/signin/core/browser/signin_error_controller.h" -#include "components/signin/core/browser/signin_oauth_helper.h" #include "components/signin/core/common/profile_management_switches.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_ui.h" +#include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/gaia_auth_fetcher.h" #include "google_apis/gaia/gaia_auth_util.h" #include "google_apis/gaia/gaia_constants.h" @@ -45,7 +45,7 @@ namespace { -class InlineSigninHelper : public SigninOAuthHelper::Consumer { +class InlineSigninHelper : public GaiaAuthConsumer { public: InlineSigninHelper( base::WeakPtr<InlineLoginHandlerImpl> handler, @@ -53,6 +53,7 @@ class InlineSigninHelper : public SigninOAuthHelper::Consumer { Profile* profile, const GURL& current_url, const std::string& email, + const std::string& gaia_id, const std::string& password, const std::string& session_index, const std::string& signin_scoped_device_id, @@ -60,19 +61,17 @@ class InlineSigninHelper : public SigninOAuthHelper::Consumer { bool confirm_untrusted_signin); private: - // Overriden from SigninOAuthHelper::Consumer. - void OnSigninOAuthInformationAvailable( - const std::string& email, - const std::string& display_email, - const std::string& refresh_token) override; - void OnSigninOAuthInformationFailure( - const GoogleServiceAuthError& error) override; + // Overridden from GaiaAuthConsumer. + void OnClientOAuthSuccess(const ClientOAuthResult& result) override; + void OnClientOAuthFailure(const GoogleServiceAuthError& error) + override; - SigninOAuthHelper signin_oauth_helper_; + GaiaAuthFetcher gaia_auth_fetcher_; base::WeakPtr<InlineLoginHandlerImpl> handler_; Profile* profile_; GURL current_url_; std::string email_; + std::string gaia_id_; std::string password_; std::string session_index_; bool choose_what_to_sync_; @@ -87,29 +86,29 @@ InlineSigninHelper::InlineSigninHelper( Profile* profile, const GURL& current_url, const std::string& email, + const std::string& gaia_id, const std::string& password, const std::string& session_index, const std::string& signin_scoped_device_id, bool choose_what_to_sync, bool confirm_untrusted_signin) - : signin_oauth_helper_(getter, session_index, signin_scoped_device_id, - this), + : gaia_auth_fetcher_(this, GaiaConstants::kChromeSource, getter), handler_(handler), profile_(profile), current_url_(current_url), email_(email), + gaia_id_(gaia_id), password_(password), session_index_(session_index), choose_what_to_sync_(choose_what_to_sync), confirm_untrusted_signin_(confirm_untrusted_signin) { DCHECK(profile_); DCHECK(!email_.empty()); + gaia_auth_fetcher_.StartCookieForOAuthLoginTokenExchangeWithDeviceId( + session_index, signin_scoped_device_id); } -void InlineSigninHelper::OnSigninOAuthInformationAvailable( - const std::string& email, - const std::string& display_email, - const std::string& refresh_token) { +void InlineSigninHelper::OnClientOAuthSuccess(const ClientOAuthResult& result) { content::WebContents* contents = NULL; Browser* browser = NULL; if (handler_) { @@ -121,11 +120,19 @@ void InlineSigninHelper::OnSigninOAuthInformationAvailable( AboutSigninInternalsFactory::GetForProfile(profile_); about_signin_internals->OnRefreshTokenReceived("Successful"); + AccountTrackerService* account_tracker = + AccountTrackerServiceFactory::GetForProfile(profile_); + std::string account_id = + account_tracker->PickAccountIdForAccount(gaia_id_, email_); + + // Prime the account tracker with this combination of gaia id/display email. + account_tracker->SeedAccountInfo(gaia_id_, email_); + signin::Source source = signin::GetSourceForPromoURL(current_url_); std::string primary_email = SigninManagerFactory::GetForProfile(profile_)->GetAuthenticatedUsername(); - if (gaia::AreEmailsSame(email, primary_email) && + if (gaia::AreEmailsSame(email_, primary_email) && source == signin::SOURCE_REAUTH && switches::IsNewProfileManagement()) { chrome::SetLocalAuthCredentials(profile_, password_); @@ -133,14 +140,8 @@ void InlineSigninHelper::OnSigninOAuthInformationAvailable( if (source == signin::SOURCE_AVATAR_BUBBLE_ADD_ACCOUNT || source == signin::SOURCE_REAUTH) { - // TODO(rogerta): the javascript code will need to pass in the gaia-id - // of the account instead of the email when chrome uses gaia-id as key. - DCHECK_EQ(AccountTrackerService::MIGRATION_NOT_STARTED, - AccountTrackerServiceFactory::GetForProfile(profile_)-> - GetMigrationState()); - const std::string account_id = gaia::CanonicalizeEmail(email); ProfileOAuth2TokenServiceFactory::GetForProfile(profile_)-> - UpdateCredentials(account_id, refresh_token); + UpdateCredentials(account_id, result.refresh_token); if (signin::IsAutoCloseEnabledInURL(current_url_)) { // Close the gaia sign in tab via a task to make sure we aren't in the @@ -192,7 +193,7 @@ void InlineSigninHelper::OnSigninOAuthInformationAvailable( bool start_signin = !OneClickSigninHelper::HandleCrossAccountError( profile_, "", - email, password_, refresh_token, + email_, password_, result.refresh_token, OneClickSigninHelper::AUTO_ACCEPT_EXPLICIT, source, start_mode, base::Bind(&InlineLoginHandlerImpl::SyncStarterCallback, @@ -202,7 +203,7 @@ void InlineSigninHelper::OnSigninOAuthInformationAvailable( // OneClickSigninSyncStarter will delete itself once the job is done. new OneClickSigninSyncStarter( profile_, browser, - email, password_, refresh_token, + account_id, password_, result.refresh_token, start_mode, contents, confirmation_required, @@ -214,7 +215,7 @@ void InlineSigninHelper::OnSigninOAuthInformationAvailable( base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); } -void InlineSigninHelper::OnSigninOAuthInformationFailure( +void InlineSigninHelper::OnClientOAuthFailure( const GoogleServiceAuthError& error) { if (handler_) handler_->HandleLoginError(error.ToString()); @@ -312,6 +313,11 @@ void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) { dict->GetString("password", &password_string16); std::string password(base::UTF16ToASCII(password_string16)); + base::string16 gaia_id_string16; + dict->GetString("gaiaId", &gaia_id_string16); + DCHECK(!gaia_id_string16.empty()); + std::string gaia_id = base::UTF16ToASCII(gaia_id_string16); + // When doing a SAML sign in, this email check may result in a false // positive. This happens when the user types one email address in the // gaia sign in page, but signs in to a different account in the SAML sign in @@ -390,7 +396,7 @@ void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) { // InlineSigninHelper will delete itself. new InlineSigninHelper(GetWeakPtr(), partition->GetURLRequestContext(), Profile::FromWebUI(web_ui()), current_url, - email, password, session_index, + email, gaia_id, password, session_index, signin_scoped_device_id, choose_what_to_sync, confirm_untrusted_signin_); diff --git a/chromeos/login/auth/user_context.cc b/chromeos/login/auth/user_context.cc index 31113f1..edeb24e 100644 --- a/chromeos/login/auth/user_context.cc +++ b/chromeos/login/auth/user_context.cc @@ -15,6 +15,7 @@ UserContext::UserContext() UserContext::UserContext(const UserContext& other) : user_id_(other.user_id_), + gaia_id_(other.gaia_id_), key_(other.key_), auth_code_(other.auth_code_), user_id_hash_(other.user_id_hash_), @@ -48,6 +49,7 @@ UserContext::~UserContext() { bool UserContext::operator==(const UserContext& context) const { return context.user_id_ == user_id_ && + context.gaia_id_ == gaia_id_ && context.key_ == key_ && context.auth_code_ == auth_code_ && context.user_id_hash_ == user_id_hash_ && @@ -66,6 +68,10 @@ const std::string& UserContext::GetUserID() const { return user_id_; } +const std::string& UserContext::GetGaiaID() const { + return gaia_id_; +} + const Key* UserContext::GetKey() const { return &key_; } @@ -111,6 +117,10 @@ void UserContext::SetUserID(const std::string& user_id) { user_id_ = login::CanonicalizeUserID(user_id); } +void UserContext::SetGaiaID(const std::string& gaia_id) { + gaia_id_ = gaia_id; +} + void UserContext::SetKey(const Key& key) { key_ = key; } diff --git a/chromeos/login/auth/user_context.h b/chromeos/login/auth/user_context.h index ff28c96..879e59a 100644 --- a/chromeos/login/auth/user_context.h +++ b/chromeos/login/auth/user_context.h @@ -41,6 +41,7 @@ class CHROMEOS_EXPORT UserContext { bool operator!=(const UserContext& context) const; const std::string& GetUserID() const; + const std::string& GetGaiaID() const; const Key* GetKey() const; Key* GetKey(); const std::string& GetAuthCode() const; @@ -54,6 +55,7 @@ class CHROMEOS_EXPORT UserContext { bool HasCredentials() const; void SetUserID(const std::string& user_id); + void SetGaiaID(const std::string& gaia_id); void SetKey(const Key& key); void SetAuthCode(const std::string& auth_code); void SetUserIDHash(const std::string& user_id_hash); @@ -67,6 +69,7 @@ class CHROMEOS_EXPORT UserContext { private: std::string user_id_; + std::string gaia_id_; Key key_; std::string auth_code_; std::string user_id_hash_; diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc index 714c452..0b13386 100644 --- a/components/signin/core/browser/account_tracker_service.cc +++ b/components/signin/core/browser/account_tracker_service.cc @@ -5,6 +5,7 @@ #include "components/signin/core/browser/account_tracker_service.h" #include "base/debug/trace_event.h" +#include "base/logging.h" #include "base/prefs/pref_service.h" #include "base/prefs/scoped_user_pref_update.h" #include "base/profiler/scoped_profile.h" @@ -448,3 +449,42 @@ void AccountTrackerService::LoadFromTokenService() { OnRefreshTokenAvailable(*it); } } + +std::string AccountTrackerService::PickAccountIdForAccount( + const std::string& gaia, + const std::string& email) { + return PickAccountIdForAccount(pref_service_, gaia, email); +} + +// static +std::string AccountTrackerService::PickAccountIdForAccount( + PrefService* pref_service, + const std::string& gaia, + const std::string& email) { + DCHECK(!gaia.empty()); + DCHECK(!email.empty()); + switch(GetMigrationState(pref_service)) { + case MIGRATION_NOT_STARTED: + case MIGRATION_IN_PROGRESS: + return gaia::CanonicalizeEmail(gaia::SanitizeEmail(email)); + case MIGRATION_DONE: + return gaia; + default: + NOTREACHED(); + return email; + } +} + +void AccountTrackerService::SeedAccountInfo(const std::string& gaia, + const std::string& email) { + DCHECK(!gaia.empty()); + DCHECK(!email.empty()); + const std::string account_id = PickAccountIdForAccount(gaia, email); + const bool already_exists = ContainsKey(accounts_, account_id); + StartTrackingAccount(account_id); + AccountState& state = accounts_[account_id]; + DCHECK(!already_exists || state.info.gaia == gaia); + state.info.gaia = gaia; + state.info.email = email; + SaveToPrefs(state); +} diff --git a/components/signin/core/browser/account_tracker_service.h b/components/signin/core/browser/account_tracker_service.h index a6f403e..c65ed01 100644 --- a/components/signin/core/browser/account_tracker_service.h +++ b/components/signin/core/browser/account_tracker_service.h @@ -79,6 +79,18 @@ class AccountTrackerService : public KeyedService, // there are still unfininshed fetchers. virtual bool IsAllUserInfoFetched() const; + // Picks the correct account_id for the specified account depending on the + // migration state. + std::string PickAccountIdForAccount(const std::string& gaia, + const std::string& email); + static std::string PickAccountIdForAccount(PrefService* pref_service, + const std::string& gaia, + const std::string& email); + + // Seeds the account whose account_id is given by PickAccountIdForAccount() + // with its corresponding gaia id and email address. + void SeedAccountInfo(const std::string& gaia, const std::string& email); + AccountIdMigrationState GetMigrationState(); static AccountIdMigrationState GetMigrationState(PrefService* pref_service); diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc index 64b83b0..7a4d327 100644 --- a/components/signin/core/browser/account_tracker_service_unittest.cc +++ b/components/signin/core/browser/account_tracker_service_unittest.cc @@ -10,6 +10,7 @@ #include "base/prefs/testing_pref_service.h" #include "base/strings/stringprintf.h" #include "components/signin/core/browser/account_tracker_service.h" +#include "components/signin/core/common/signin_pref_names.h" #include "google_apis/gaia/fake_oauth2_token_service.h" #include "google_apis/gaia/gaia_oauth_client.h" #include "net/http/http_status_code.h" @@ -198,6 +199,9 @@ class AccountTrackerServiceTest : public testing::Test { pref_service_.registry()->RegisterListPref( AccountTrackerService::kAccountInfoPref); + pref_service_.registry()->RegisterIntegerPref( + prefs::kAccountIdMigrationState, + AccountTrackerService::MIGRATION_NOT_STARTED); account_tracker_.reset(new AccountTrackerService()); account_tracker_->Initialize(fake_oauth2_token_service_.get(), @@ -505,3 +509,21 @@ TEST_F(AccountTrackerServiceTest, Persistence) { tracker.Shutdown(); } } + +TEST_F(AccountTrackerServiceTest, SeedAccountInfo) { + std::vector<AccountTrackerService::AccountInfo> infos = + account_tracker()->GetAccounts(); + EXPECT_EQ(0u, infos.size()); + + const std::string gaia_id = AccountIdToGaiaId("alpha"); + const std::string email = AccountIdToEmail("alpha"); + const std::string account_id = + account_tracker()->PickAccountIdForAccount(gaia_id, email); + account_tracker()->SeedAccountInfo(gaia_id, email); + + infos = account_tracker()->GetAccounts(); + EXPECT_EQ(1u, infos.size()); + EXPECT_EQ(account_id, infos[0].account_id); + EXPECT_EQ(gaia_id, infos[0].gaia); + EXPECT_EQ(email, infos[0].email); +} diff --git a/google_apis/gaia/fake_gaia.cc b/google_apis/gaia/fake_gaia.cc index 9c4836f..b1a3942 100644 --- a/google_apis/gaia/fake_gaia.cc +++ b/google_apis/gaia/fake_gaia.cc @@ -51,6 +51,8 @@ const char kTestOAuthLoginSID[] = "fake-oauth-SID-cookie"; const char kTestOAuthLoginLSID[] = "fake-oauth-LSID-cookie"; const char kTestOAuthLoginAuthCode[] = "fake-oauth-auth-code"; +const char kDefaultGaiaId[] ="12345"; + const base::FilePath::CharType kServiceLogin[] = FILE_PATH_LITERAL("google_apis/test/service_login.html"); @@ -163,6 +165,30 @@ void FakeGaia::SetMergeSessionParams( merge_session_params_ = params; } +void FakeGaia::MapEmailToGaiaId(const std::string& email, + const std::string& gaia_id) { + DCHECK(!email.empty()); + DCHECK(!gaia_id.empty()); + email_to_gaia_id_map_[email] = gaia_id; +} + +std::string FakeGaia::GetGaiaIdOfEmail(const std::string& email) const { + DCHECK(!email.empty()); + auto it = email_to_gaia_id_map_.find(email); + return it == email_to_gaia_id_map_.end() ? std::string(kDefaultGaiaId) : + it->second; +} + +void FakeGaia::AddGoogleAccountsSigninHeader( + net::test_server::BasicHttpResponse* http_response, + const std::string& email) const { + DCHECK(!email.empty()); + http_response->AddCustomHeader("google-accounts-signin", + base::StringPrintf( + "email=\"%s\", obfuscatedid=\"%s\", sessionindex=0", + email.c_str(), GetGaiaIdOfEmail(email).c_str())); +} + void FakeGaia::Initialize() { GaiaUrls* gaia_urls = GaiaUrls::GetInstance(); // Handles /MergeSession GAIA call. @@ -415,8 +441,11 @@ void FakeGaia::HandleServiceLoginAuth(const HttpRequest& request, std::string redirect_url = continue_url; std::string email; - if (GetQueryParameter(request.content, "Email", &email) && - saml_account_idp_map_.find(email) != saml_account_idp_map_.end()) { + const bool is_saml = + GetQueryParameter(request.content, "Email", &email) && + saml_account_idp_map_.find(email) != saml_account_idp_map_.end(); + + if (is_saml) { GURL url(saml_account_idp_map_[email]); url = net::AppendQueryParameter(url, "SAMLRequest", "fake_request"); url = net::AppendQueryParameter(url, "RelayState", continue_url); @@ -431,8 +460,12 @@ void FakeGaia::HandleServiceLoginAuth(const HttpRequest& request, http_response->set_code(net::HTTP_TEMPORARY_REDIRECT); http_response->AddCustomHeader("Location", redirect_url); - http_response->AddCustomHeader("google-accounts-signin", - base::StringPrintf("email=\"%s\", sessionindex=0", email.c_str())); + + // SAML sign-ins complete in HandleSSO(). + if (is_saml) + return; + + AddGoogleAccountsSigninHeader(http_response, email); } void FakeGaia::HandleSSO(const HttpRequest& request, @@ -449,6 +482,9 @@ void FakeGaia::HandleSSO(const HttpRequest& request, http_response->set_code(net::HTTP_TEMPORARY_REDIRECT); http_response->AddCustomHeader("Location", redirect_url); http_response->AddCustomHeader("Google-Accounts-SAML", "End"); + + if (!merge_session_params_.email.empty()) + AddGoogleAccountsSigninHeader(http_response, merge_session_params_.email); } void FakeGaia::HandleAuthToken(const HttpRequest& request, @@ -580,3 +616,4 @@ void FakeGaia::HandleGetUserInfo(const HttpRequest& request, merge_session_params_.email.c_str())); http_response->set_code(net::HTTP_OK); } + diff --git a/google_apis/gaia/fake_gaia.h b/google_apis/gaia/fake_gaia.h index 4db3b84..e00a80a 100644 --- a/google_apis/gaia/fake_gaia.h +++ b/google_apis/gaia/fake_gaia.h @@ -86,6 +86,11 @@ class FakeGaia { // Sets the initial value of tokens and cookies. void SetMergeSessionParams(const MergeSessionParams& params); + // Sets the specified |gaia_id| as corresponding to the given |email| + // address when setting GAIA response headers. If no mapping is given for + // an email address, a default GAIA Id is used. + void MapEmailToGaiaId(const std::string& email, const std::string& gaia_id); + // Initializes HTTP request handlers. Should be called after switches // for tweaking GaiaUrls are in place. void Initialize(); @@ -121,8 +126,15 @@ class FakeGaia { private: typedef std::multimap<std::string, AccessTokenInfo> AccessTokenInfoMap; + typedef std::map<std::string, std::string> EmailToGaiaIdMap; typedef std::map<std::string, GURL> SamlAccountIdpMap; + std::string GetGaiaIdOfEmail(const std::string& email) const; + + void AddGoogleAccountsSigninHeader( + net::test_server::BasicHttpResponse* http_response, + const std::string& email) const; + // Formats a JSON response with the data in |response_dict|. void FormatJSONResponse(const base::DictionaryValue& response_dict, net::test_server::BasicHttpResponse* http_response); @@ -169,6 +181,7 @@ class FakeGaia { const; MergeSessionParams merge_session_params_; + EmailToGaiaIdMap email_to_gaia_id_map_; AccessTokenInfoMap access_token_info_map_; RequestHandlerMap request_handlers_; std::string service_login_response_; diff --git a/tools/telemetry/telemetry/core/backends/chrome/chromeos_login_ext/main.js b/tools/telemetry/telemetry/core/backends/chrome/chromeos_login_ext/main.js index 7ec6a6c..7d21eb3 100644 --- a/tools/telemetry/telemetry/core/backends/chrome/chromeos_login_ext/main.js +++ b/tools/telemetry/telemetry/core/backends/chrome/chromeos_login_ext/main.js @@ -12,6 +12,7 @@ window.parent.postMessage(msg, PARENT_PAGE); var msg = { 'method': 'completeLogin', 'email': 'test@test.test', + 'gaiaId': '12345', 'password': '' }; window.parent.postMessage(msg, PARENT_PAGE); |