Index: chrome/browser/resources/gaia_auth/main.js |
diff --git a/chrome/browser/resources/gaia_auth/main.js b/chrome/browser/resources/gaia_auth/main.js |
deleted file mode 100644 |
index 1fb9c033530e9118638fd3ee2ad61a98cfe48baf..0000000000000000000000000000000000000000 |
--- a/chrome/browser/resources/gaia_auth/main.js |
+++ /dev/null |
@@ -1,553 +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. |
- |
-/** |
- * Authenticator class wraps the communications between Gaia and its host. |
- */ |
-function Authenticator() { |
-} |
- |
-/** |
- * Gaia auth extension url origin. |
- * @type {string} |
- */ |
-Authenticator.THIS_EXTENSION_ORIGIN = |
- 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik'; |
- |
-/** |
- * The lowest version of the credentials passing API supported. |
- * @type {number} |
- */ |
-Authenticator.MIN_API_VERSION_VERSION = 1; |
- |
-/** |
- * The highest version of the credentials passing API supported. |
- * @type {number} |
- */ |
-Authenticator.MAX_API_VERSION_VERSION = 1; |
- |
-/** |
- * The key types supported by the credentials passing API. |
- * @type {Array} Array of strings. |
- */ |
-Authenticator.API_KEY_TYPES = [ |
- 'KEY_TYPE_PASSWORD_PLAIN', |
-]; |
- |
-/** |
- * Allowed origins of the hosting page. |
- * @type {Array<string>} |
- */ |
-Authenticator.ALLOWED_PARENT_ORIGINS = [ |
- 'chrome://oobe', |
- 'chrome://chrome-signin' |
-]; |
- |
-/** |
- * Singleton getter of Authenticator. |
- * @return {Object} The singleton instance of Authenticator. |
- */ |
-Authenticator.getInstance = function() { |
- if (!Authenticator.instance_) { |
- Authenticator.instance_ = new Authenticator(); |
- } |
- return Authenticator.instance_; |
-}; |
- |
-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 |
- // repeat the derivation, such as a salt. The information will be encoded so |
- // that it contains printable ASCII characters only. The exact encoding is TBD |
- // when support for key types other than plain text password is added. |
- passwordBytes_: null, |
- |
- needPassword_: false, |
- chooseWhatToSync_: false, |
- skipForNow_: false, |
- sessionIndex_: null, |
- attemptToken_: null, |
- |
- // Input params from extension initialization URL. |
- inputLang_: undefined, |
- intputEmail_: undefined, |
- |
- isSAMLFlow_: false, |
- gaiaLoaded_: false, |
- supportChannel_: null, |
- |
- useEafe_: false, |
- clientId_: '', |
- |
- GAIA_URL: 'https://accounts.google.com/', |
- GAIA_PAGE_PATH: 'ServiceLogin?skipvpage=true&sarp=1&rm=hide', |
- SERVICE_ID: 'chromeoslogin', |
- CONTINUE_URL: Authenticator.THIS_EXTENSION_ORIGIN + '/success.html', |
- CONSTRAINED_FLOW_SOURCE: 'chrome', |
- |
- initialize: function() { |
- var handleInitializeMessage = function(e) { |
- if (Authenticator.ALLOWED_PARENT_ORIGINS.indexOf(e.origin) == -1) { |
- console.error('Unexpected parent message, origin=' + e.origin); |
- return; |
- } |
- window.removeEventListener('message', handleInitializeMessage); |
- |
- var params = e.data; |
- params.parentPage = e.origin; |
- this.initializeFromParent_(params); |
- this.onPageLoad_(); |
- }.bind(this); |
- |
- document.addEventListener('DOMContentLoaded', function() { |
- window.addEventListener('message', handleInitializeMessage); |
- window.parent.postMessage({'method': 'loginUIDOMContentLoaded'}, '*'); |
- }); |
- }, |
- |
- initializeFromParent_: function(params) { |
- this.parentPage_ = params.parentPage; |
- this.gaiaUrl_ = params.gaiaUrl || this.GAIA_URL; |
- this.gaiaPath_ = params.gaiaPath || this.GAIA_PAGE_PATH; |
- this.inputLang_ = params.hl; |
- this.inputEmail_ = params.email; |
- this.service_ = params.service || this.SERVICE_ID; |
- this.continueUrl_ = params.continueUrl || this.CONTINUE_URL; |
- this.desktopMode_ = params.desktopMode == '1'; |
- this.isConstrainedWindow_ = params.constrained == '1'; |
- this.useEafe_ = params.useEafe || false; |
- this.clientId_ = params.clientId || ''; |
- this.initialFrameUrl_ = params.frameUrl || this.constructInitialFrameUrl_(); |
- this.initialFrameUrlWithoutParams_ = stripParams(this.initialFrameUrl_); |
- this.needPassword_ = params.needPassword == '1'; |
- |
- // For CrOS 'ServiceLogin' we assume that Gaia is loaded if we recieved |
- // 'clearOldAttempts' message. For other scenarios Gaia doesn't send this |
- // message so we have to rely on 'load' event. |
- // TODO(dzhioev): Do not rely on 'load' event after b/16313327 is fixed. |
- this.assumeLoadedOnLoadEvent_ = |
- !this.gaiaPath_.startsWith('ServiceLogin') || |
- this.service_ !== 'chromeoslogin' || |
- this.useEafe_; |
- }, |
- |
- isGaiaMessage_: function(msg) { |
- // Not quite right, but good enough. |
- return this.gaiaUrl_.startsWith(msg.origin) || |
- this.GAIA_URL.startsWith(msg.origin); |
- }, |
- |
- isParentMessage_: function(msg) { |
- return msg.origin == this.parentPage_; |
- }, |
- |
- constructInitialFrameUrl_: function() { |
- var url = this.gaiaUrl_ + this.gaiaPath_; |
- |
- url = appendParam(url, 'service', this.service_); |
- // Easy bootstrap use auth_code message as success signal instead of |
- // continue URL. |
- if (!this.useEafe_) |
- url = appendParam(url, 'continue', this.continueUrl_); |
- if (this.inputLang_) |
- url = appendParam(url, 'hl', this.inputLang_); |
- if (this.inputEmail_) |
- url = appendParam(url, 'Email', this.inputEmail_); |
- if (this.isConstrainedWindow_) |
- url = appendParam(url, 'source', this.CONSTRAINED_FLOW_SOURCE); |
- return url; |
- }, |
- |
- onPageLoad_: function() { |
- window.addEventListener('message', this.onMessage.bind(this), false); |
- this.initSupportChannel_(); |
- |
- if (this.assumeLoadedOnLoadEvent_) { |
- var gaiaFrame = $('gaia-frame'); |
- var handler = function() { |
- gaiaFrame.removeEventListener('load', handler); |
- if (!this.gaiaLoaded_) { |
- this.gaiaLoaded_ = true; |
- this.maybeInitialized_(); |
- |
- if (this.useEafe_ && this.clientId_) { |
- // Sends initial handshake message to EAFE. Note this fails with |
- // SSO redirect because |gaiaFrame| sits on a different origin. |
- gaiaFrame.contentWindow.postMessage({ |
- clientId: this.clientId_ |
- }, this.gaiaUrl_); |
- } |
- } |
- }.bind(this); |
- gaiaFrame.addEventListener('load', handler); |
- } |
- }, |
- |
- initSupportChannel_: function() { |
- var supportChannel = new Channel(); |
- supportChannel.connect('authMain'); |
- |
- supportChannel.registerMessage('channelConnected', function() { |
- // Load the gaia frame after the background page indicates that it is |
- // ready, so that the webRequest handlers are all setup first. |
- var gaiaFrame = $('gaia-frame'); |
- gaiaFrame.src = this.initialFrameUrl_; |
- |
- if (this.supportChannel_) { |
- console.error('Support channel is already initialized.'); |
- return; |
- } |
- this.supportChannel_ = supportChannel; |
- |
- if (this.desktopMode_) { |
- this.supportChannel_.send({ |
- name: 'initDesktopFlow', |
- gaiaUrl: this.gaiaUrl_, |
- continueUrl: stripParams(this.continueUrl_), |
- isConstrainedWindow: this.isConstrainedWindow_, |
- initialFrameUrlWithoutParams: this.initialFrameUrlWithoutParams_ |
- }); |
- |
- this.supportChannel_.registerMessage( |
- 'switchToFullTab', this.switchToFullTab_.bind(this)); |
- } |
- this.supportChannel_.registerMessage( |
- 'completeLogin', this.onCompleteLogin_.bind(this)); |
- this.initSAML_(); |
- this.supportChannel_.send({name: 'resetAuth'}); |
- this.maybeInitialized_(); |
- }.bind(this)); |
- |
- window.setTimeout(function() { |
- if (!this.supportChannel_) { |
- // Give up previous channel and bind its 'channelConnected' to a no-op. |
- supportChannel.registerMessage('channelConnected', function() {}); |
- |
- // Re-initialize the channel if it is not connected properly, e.g. |
- // connect may be called before background script started running. |
- this.initSupportChannel_(); |
- } |
- }.bind(this), 200); |
- }, |
- |
- /** |
- * Called when one of the initialization stages has finished. If all the |
- * needed parts are initialized, notifies parent about successfull |
- * initialization. |
- */ |
- maybeInitialized_: function() { |
- if (!this.gaiaLoaded_ || !this.supportChannel_) |
- return; |
- var msg = { |
- 'method': 'loginUILoaded' |
- }; |
- window.parent.postMessage(msg, this.parentPage_); |
- }, |
- |
- /** |
- * Invoked when the background script sends a message to indicate that the |
- * current content does not fit in a constrained window. |
- * @param {Object=} msg Extra info to send. |
- */ |
- switchToFullTab_: function(msg) { |
- var parentMsg = { |
- 'method': 'switchToFullTab', |
- 'url': msg.url |
- }; |
- window.parent.postMessage(parentMsg, this.parentPage_); |
- }, |
- |
- /** |
- * Invoked when the signin flow is complete. |
- * @param {Object=} opt_extraMsg Optional extra info to send. |
- */ |
- completeLogin_: function(opt_extraMsg) { |
- var msg = { |
- 'method': 'completeLogin', |
- 'email': (opt_extraMsg && opt_extraMsg.email) || this.email_, |
- 'password': this.passwordBytes_ || |
- (opt_extraMsg && opt_extraMsg.password), |
- 'usingSAML': this.isSAMLFlow_, |
- 'chooseWhatToSync': this.chooseWhatToSync_ || false, |
- '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'}); |
- }, |
- |
- /** |
- * Invoked when support channel is connected. |
- */ |
- initSAML_: function() { |
- this.isSAMLFlow_ = false; |
- |
- this.supportChannel_.registerMessage( |
- 'onAuthPageLoaded', this.onAuthPageLoaded_.bind(this)); |
- this.supportChannel_.registerMessage( |
- 'onInsecureContentBlocked', this.onInsecureContentBlocked_.bind(this)); |
- this.supportChannel_.registerMessage( |
- 'apiCall', this.onAPICall_.bind(this)); |
- this.supportChannel_.send({ |
- name: 'setGaiaUrl', |
- gaiaUrl: this.gaiaUrl_ |
- }); |
- if (!this.desktopMode_ && this.gaiaUrl_.startsWith('https://')) { |
- // Abort the login flow when content served over an unencrypted connection |
- // is detected on Chrome OS. This does not apply to tests that explicitly |
- // set a non-https GAIA URL and want to perform all authentication over |
- // http. |
- this.supportChannel_.send({ |
- name: 'setBlockInsecureContent', |
- blockInsecureContent: true |
- }); |
- } |
- }, |
- |
- /** |
- * Invoked when the background page sends 'onHostedPageLoaded' message. |
- * @param {!Object} msg Details sent with the message. |
- */ |
- onAuthPageLoaded_: function(msg) { |
- if (msg.isSAMLPage && !this.isSAMLFlow_) { |
- // GAIA redirected to a SAML login page. The credentials provided to this |
- // page will determine what user gets logged in. The credentials obtained |
- // 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; |
- } |
- |
- window.parent.postMessage({ |
- 'method': 'authPageLoaded', |
- 'isSAML': this.isSAMLFlow_, |
- 'domain': extractDomain(msg.url) |
- }, this.parentPage_); |
- }, |
- |
- /** |
- * Invoked when the background page sends an 'onInsecureContentBlocked' |
- * message. |
- * @param {!Object} msg Details sent with the message. |
- */ |
- onInsecureContentBlocked_: function(msg) { |
- window.parent.postMessage({ |
- 'method': 'insecureContentBlocked', |
- 'url': stripParams(msg.url) |
- }, this.parentPage_); |
- }, |
- |
- /** |
- * Invoked when one of the credential passing API methods is called by a SAML |
- * provider. |
- * @param {!Object} msg Details of the API call. |
- */ |
- onAPICall_: function(msg) { |
- var call = msg.call; |
- if (call.method == 'initialize') { |
- if (!Number.isInteger(call.requestedVersion) || |
- call.requestedVersion < Authenticator.MIN_API_VERSION_VERSION) { |
- this.sendInitializationFailure_(); |
- return; |
- } |
- |
- this.apiVersion_ = Math.min(call.requestedVersion, |
- Authenticator.MAX_API_VERSION_VERSION); |
- this.initialized_ = true; |
- this.sendInitializationSuccess_(); |
- return; |
- } |
- |
- if (call.method == 'add') { |
- if (Authenticator.API_KEY_TYPES.indexOf(call.keyType) == -1) { |
- 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.passwordBytes_ = call.passwordBytes; |
- } else if (call.method == 'confirm') { |
- if (call.token != this.apiToken_) |
- console.error('Authenticator.onAPICall_: token mismatch'); |
- } else { |
- console.error('Authenticator.onAPICall_: unknown message'); |
- } |
- }, |
- |
- onGotAuthCode_: function(authCode) { |
- window.parent.postMessage({ |
- 'method': 'completeAuthenticationAuthCodeOnly', |
- 'authCode': authCode |
- }, this.parentPage_); |
- }, |
- |
- sendInitializationSuccess_: function() { |
- this.supportChannel_.send({name: 'apiResponse', response: { |
- result: 'initialized', |
- version: this.apiVersion_, |
- keyTypes: Authenticator.API_KEY_TYPES |
- }}); |
- }, |
- |
- sendInitializationFailure_: function() { |
- this.supportChannel_.send({ |
- name: 'apiResponse', |
- response: {result: 'initialization_failed'} |
- }); |
- }, |
- |
- /** |
- * Callback invoked for 'completeLogin' message. |
- * @param {Object=} msg Message sent from background page. |
- */ |
- onCompleteLogin_: function(msg) { |
- if (!msg.email || !msg.gaiaId || !msg.sessionIndex) { |
- // On desktop, if the skipForNow message field is set, send it to handler. |
- // This does not require the email, gaiaid or session to be valid. |
- if (this.desktopMode_ && msg.skipForNow) { |
- this.completeLogin_(msg); |
- } else { |
- console.error('Missing fields to complete login.'); |
- window.parent.postMessage({method: 'missingGaiaInfo'}, |
- this.parentPage_); |
- return; |
- } |
- } |
- |
- // Skip SAML extra steps for desktop flow and non-SAML flow. |
- if (!this.isSAMLFlow_ || this.desktopMode_) { |
- this.completeLogin_(msg); |
- return; |
- } |
- |
- 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 (this.passwordBytes_) { |
- // If the credentials passing API was used, login is complete. |
- window.parent.postMessage({method: 'samlApiUsed'}, this.parentPage_); |
- this.completeLogin_(msg); |
- } else if (!this.needPassword_) { |
- // If the credentials passing API was not used, the password was obtained |
- // by scraping. It must be verified before use. However, the host may not |
- // be interested in the password at all. In that case, verification is |
- // unnecessary and login is complete. |
- this.completeLogin_(msg); |
- } else { |
- this.supportChannel_.sendWithCallback( |
- {name: 'getScrapedPasswords'}, |
- function(passwords) { |
- if (passwords.length == 0) { |
- window.parent.postMessage( |
- {method: 'noPassword', email: this.email_}, |
- this.parentPage_); |
- } else { |
- window.parent.postMessage({method: 'confirmPassword', |
- email: this.email_, |
- passwordCount: passwords.length}, |
- this.parentPage_); |
- } |
- }.bind(this)); |
- } |
- }, |
- |
- onVerifyConfirmedPassword_: function(password) { |
- this.supportChannel_.sendWithCallback( |
- {name: 'getScrapedPasswords'}, |
- function(passwords) { |
- for (var i = 0; i < passwords.length; ++i) { |
- if (passwords[i] == password) { |
- this.passwordBytes_ = passwords[i]; |
- // SAML login is complete when the user has successfully |
- // confirmed the password. |
- if (this.passwordBytes_ !== null) |
- this.completeLogin_(); |
- return; |
- } |
- } |
- window.parent.postMessage( |
- {method: 'confirmPassword', email: this.email_}, |
- this.parentPage_); |
- }.bind(this)); |
- }, |
- |
- onMessage: function(e) { |
- var msg = e.data; |
- |
- if (this.useEafe_) { |
- if (msg == '!_{h:\'gaia-frame\'}' && this.isGaiaMessage_(e)) { |
- // Sends client ID again on the hello message to work around the SSO |
- // signin issue. |
- // TODO(xiyuan): Revisit this when EAFE is integrated or for webview. |
- $('gaia-frame').contentWindow.postMessage({ |
- clientId: this.clientId_ |
- }, this.gaiaUrl_); |
- } else if (typeof msg == 'object' && |
- msg.type == 'authorizationCode' && this.isGaiaMessage_(e)) { |
- this.onGotAuthCode_(msg.authorizationCode); |
- } else { |
- console.error('Authenticator.onMessage: unknown message' + |
- ', msg=' + JSON.stringify(msg)); |
- } |
- |
- return; |
- } |
- |
- 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; |
- this.chooseWhatToSync_ = msg.chooseWhatToSync; |
- this.isSAMLFlow_ = false; |
- if (this.supportChannel_) |
- this.supportChannel_.send({name: 'startAuth'}); |
- else |
- console.error('Support channel is not initialized.'); |
- } else if (msg.method == 'clearOldAttempts' && this.isGaiaMessage_(e)) { |
- if (!this.gaiaLoaded_) { |
- this.gaiaLoaded_ = true; |
- 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'}); |
- // This message is for clearing saml properties in gaia_auth_host and |
- // oobe_screen_oauth_enrollment. |
- window.parent.postMessage({ |
- 'method': 'resetAuthFlow', |
- }, this.parentPage_); |
- } |
- } else if (msg.method == 'verifyConfirmedPassword' && |
- this.isParentMessage_(e)) { |
- this.onVerifyConfirmedPassword_(msg.password); |
- } else if (msg.method == 'redirectToSignin' && |
- this.isParentMessage_(e)) { |
- $('gaia-frame').src = this.constructInitialFrameUrl_(); |
- } else { |
- console.error('Authenticator.onMessage: unknown message + origin!?'); |
- } |
- } |
-}; |
- |
-Authenticator.getInstance().initialize(); |