Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * Authenticator class wraps the communications between Gaia and its host. | 6 * Authenticator class wraps the communications between Gaia and its host. |
| 7 */ | 7 */ |
| 8 function Authenticator() { | 8 function Authenticator() { |
| 9 } | 9 } |
| 10 | 10 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 56 // when support for key types other than plain text password is added. | 56 // when support for key types other than plain text password is added. |
| 57 passwordBytes_: null, | 57 passwordBytes_: null, |
| 58 | 58 |
| 59 attemptToken_: null, | 59 attemptToken_: null, |
| 60 | 60 |
| 61 // Input params from extension initialization URL. | 61 // Input params from extension initialization URL. |
| 62 inputLang_: undefined, | 62 inputLang_: undefined, |
| 63 intputEmail_: undefined, | 63 intputEmail_: undefined, |
| 64 | 64 |
| 65 isSAMLFlow_: false, | 65 isSAMLFlow_: false, |
| 66 isSAMLEnabled_: false, | 66 gaiaLoaded_: false, |
| 67 supportChannel_: null, | 67 supportChannel_: null, |
| 68 | 68 |
| 69 GAIA_URL: 'https://accounts.google.com/', | 69 GAIA_URL: 'https://accounts.google.com/', |
| 70 GAIA_PAGE_PATH: 'ServiceLogin?skipvpage=true&sarp=1&rm=hide', | 70 GAIA_PAGE_PATH: 'ServiceLogin?skipvpage=true&sarp=1&rm=hide', |
| 71 PARENT_PAGE: 'chrome://oobe/', | 71 PARENT_PAGE: 'chrome://oobe/', |
| 72 SERVICE_ID: 'chromeoslogin', | 72 SERVICE_ID: 'chromeoslogin', |
| 73 CONTINUE_URL: Authenticator.THIS_EXTENSION_ORIGIN + '/success.html', | 73 CONTINUE_URL: Authenticator.THIS_EXTENSION_ORIGIN + '/success.html', |
| 74 CONSTRAINED_FLOW_SOURCE: 'chrome', | 74 CONSTRAINED_FLOW_SOURCE: 'chrome', |
| 75 | 75 |
| 76 initialize: function() { | 76 initialize: function() { |
| 77 var params = getUrlSearchParams(location.search); | 77 var params = getUrlSearchParams(location.search); |
| 78 this.parentPage_ = params.parentPage || this.PARENT_PAGE; | 78 this.parentPage_ = params.parentPage || this.PARENT_PAGE; |
| 79 this.gaiaUrl_ = params.gaiaUrl || this.GAIA_URL; | 79 this.gaiaUrl_ = params.gaiaUrl || this.GAIA_URL; |
| 80 this.gaiaPath_ = params.gaiaPath || this.GAIA_PAGE_PATH; | 80 this.gaiaPath_ = params.gaiaPath || this.GAIA_PAGE_PATH; |
| 81 this.inputLang_ = params.hl; | 81 this.inputLang_ = params.hl; |
| 82 this.inputEmail_ = params.email; | 82 this.inputEmail_ = params.email; |
| 83 this.service_ = params.service || this.SERVICE_ID; | 83 this.service_ = params.service || this.SERVICE_ID; |
| 84 this.continueUrl_ = params.continueUrl || this.CONTINUE_URL; | 84 this.continueUrl_ = params.continueUrl || this.CONTINUE_URL; |
| 85 this.desktopMode_ = params.desktopMode == '1'; | 85 this.desktopMode_ = params.desktopMode == '1'; |
| 86 this.isConstrainedWindow_ = params.constrained == '1'; | 86 this.isConstrainedWindow_ = params.constrained == '1'; |
| 87 this.initialFrameUrl_ = params.frameUrl || this.constructInitialFrameUrl_(); | 87 this.initialFrameUrl_ = params.frameUrl || this.constructInitialFrameUrl_(); |
| 88 this.initialFrameUrlWithoutParams_ = stripParams(this.initialFrameUrl_); | 88 this.initialFrameUrlWithoutParams_ = stripParams(this.initialFrameUrl_); |
| 89 | 89 |
| 90 // For CrOS 'ServiceLogin' we assume that Gaia is loaded if we recieved | |
| 91 // 'clearOldAttempts' message. For other scenarios Gaia doesn't send this | |
| 92 // message so we have to rely on 'load' event. | |
| 93 // TODO(dzhioev): Do not rely on 'load' event after b/16313327 is fixed. | |
| 94 this.assumeLoadedOnLoadEvent_ = | |
| 95 this.gaiaPath_.indexOf('ServiceLogin') !== 0 || | |
| 96 this.service_ !== 'chromeoslogin'; | |
| 97 | |
| 90 document.addEventListener('DOMContentLoaded', this.onPageLoad_.bind(this)); | 98 document.addEventListener('DOMContentLoaded', this.onPageLoad_.bind(this)); |
| 91 if (!this.desktopMode_) { | |
| 92 // SAML is always enabled in desktop mode, thus no need to listen for | |
| 93 // enableSAML event. | |
| 94 document.addEventListener('enableSAML', this.onEnableSAML_.bind(this)); | |
| 95 } | |
| 96 }, | 99 }, |
| 97 | 100 |
| 98 isGaiaMessage_: function(msg) { | 101 isGaiaMessage_: function(msg) { |
| 99 // Not quite right, but good enough. | 102 // Not quite right, but good enough. |
| 100 return this.gaiaUrl_.indexOf(msg.origin) == 0 || | 103 return this.gaiaUrl_.indexOf(msg.origin) == 0 || |
| 101 this.GAIA_URL.indexOf(msg.origin) == 0; | 104 this.GAIA_URL.indexOf(msg.origin) == 0; |
| 102 }, | 105 }, |
| 103 | 106 |
| 104 isInternalMessage_: function(msg) { | 107 isInternalMessage_: function(msg) { |
| 105 return msg.origin == Authenticator.THIS_EXTENSION_ORIGIN; | 108 return msg.origin == Authenticator.THIS_EXTENSION_ORIGIN; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 118 url = appendParam(url, 'hl', this.inputLang_); | 121 url = appendParam(url, 'hl', this.inputLang_); |
| 119 if (this.inputEmail_) | 122 if (this.inputEmail_) |
| 120 url = appendParam(url, 'Email', this.inputEmail_); | 123 url = appendParam(url, 'Email', this.inputEmail_); |
| 121 if (this.isConstrainedWindow_) | 124 if (this.isConstrainedWindow_) |
| 122 url = appendParam(url, 'source', this.CONSTRAINED_FLOW_SOURCE); | 125 url = appendParam(url, 'source', this.CONSTRAINED_FLOW_SOURCE); |
| 123 return url; | 126 return url; |
| 124 }, | 127 }, |
| 125 | 128 |
| 126 onPageLoad_: function() { | 129 onPageLoad_: function() { |
| 127 window.addEventListener('message', this.onMessage.bind(this), false); | 130 window.addEventListener('message', this.onMessage.bind(this), false); |
| 131 this.initSupportChannel_(); | |
| 128 | 132 |
| 129 var gaiaFrame = $('gaia-frame'); | 133 var gaiaFrame = $('gaia-frame'); |
| 130 gaiaFrame.src = this.initialFrameUrl_; | 134 gaiaFrame.src = this.initialFrameUrl_; |
| 131 | 135 |
| 132 if (this.desktopMode_) { | 136 if (this.assumeLoadedOnLoadEvent_) { |
| 133 var handler = function() { | 137 var handler = function() { |
| 134 this.onLoginUILoaded_(); | |
| 135 gaiaFrame.removeEventListener('load', handler); | 138 gaiaFrame.removeEventListener('load', handler); |
| 136 | 139 if (!this.gaiaLoaded_) { |
| 137 this.initDesktopChannel_(); | 140 this.gaiaLoaded_ = true; |
| 141 this.maybeInitialized_(); | |
| 142 } | |
| 138 }.bind(this); | 143 }.bind(this); |
| 139 gaiaFrame.addEventListener('load', handler); | 144 gaiaFrame.addEventListener('load', handler); |
| 140 } | 145 } |
| 141 }, | 146 }, |
| 142 | 147 |
| 143 initDesktopChannel_: function() { | 148 initSupportChannel_: function() { |
| 144 this.supportChannel_ = new Channel(); | 149 var supportChannel = new Channel(); |
| 145 this.supportChannel_.connect('authMain'); | 150 supportChannel.connect('authMain'); |
| 146 | 151 |
| 147 var channelConnected = false; | 152 supportChannel.registerMessage('channelConnected', function() { |
| 148 this.supportChannel_.registerMessage('channelConnected', function() { | 153 if (this.supportChannel_) { |
| 149 channelConnected = true; | 154 console.error('Support channel is already initialized.'); |
| 155 return; | |
| 156 } | |
| 157 this.supportChannel_ = supportChannel; | |
| 150 | 158 |
| 151 this.supportChannel_.send({ | 159 if (this.desktopMode_) { |
| 152 name: 'initDesktopFlow', | 160 this.supportChannel_.send({ |
| 153 gaiaUrl: this.gaiaUrl_, | 161 name: 'initDesktopFlow', |
| 154 continueUrl: stripParams(this.continueUrl_), | 162 gaiaUrl: this.gaiaUrl_, |
| 155 isConstrainedWindow: this.isConstrainedWindow_ | 163 continueUrl: stripParams(this.continueUrl_), |
| 156 }); | 164 isConstrainedWindow: this.isConstrainedWindow_ |
| 157 this.supportChannel_.registerMessage( | 165 }); |
| 158 'switchToFullTab', this.switchToFullTab_.bind(this)); | 166 this.supportChannel_.registerMessage( |
| 159 this.supportChannel_.registerMessage( | 167 'switchToFullTab', this.switchToFullTab_.bind(this)); |
| 160 'completeLogin', this.completeLogin_.bind(this)); | 168 this.supportChannel_.registerMessage( |
| 161 | 169 'completeLogin', this.completeLogin_.bind(this)); |
| 162 this.onEnableSAML_(); | 170 } |
| 171 this.initSAML_(); | |
| 172 this.maybeInitialized_(); | |
| 163 }.bind(this)); | 173 }.bind(this)); |
| 164 | 174 |
| 165 window.setTimeout(function() { | 175 window.setTimeout(function() { |
| 166 if (!channelConnected) { | 176 if (!this.supportChannel_) { |
| 167 // Re-initialize the channel if it is not connected properly, e.g. | 177 // Re-initialize the channel if it is not connected properly, e.g. |
| 168 // connect may be called before background script started running. | 178 // connect may be called before background script started running. |
| 169 this.initDesktopChannel_(); | 179 this.initSupportChannel_(); |
|
bartfab (slow)
2014/07/16 11:32:13
What happens if the initialization of a support ch
dzhioev (left Google)
2014/07/16 13:25:18
Yes, it can. 'chrome.runtime.connect' is a strange
| |
| 170 } | 180 } |
| 171 }.bind(this), 200); | 181 }.bind(this), 200); |
| 172 }, | 182 }, |
| 173 | 183 |
| 174 /** | 184 /** |
| 175 * Invoked when the login UI is initialized or reset. | 185 * Called when one of the initialization stages has finished. If all the |
| 186 * needed parts are initialized, notifies parent about successfull | |
| 187 * initialization. | |
| 176 */ | 188 */ |
| 177 onLoginUILoaded_: function() { | 189 maybeInitialized_: function() { |
| 190 if (!this.gaiaLoaded_ || !this.supportChannel_) | |
| 191 return; | |
| 178 var msg = { | 192 var msg = { |
| 179 'method': 'loginUILoaded' | 193 'method': 'loginUILoaded' |
| 180 }; | 194 }; |
| 181 window.parent.postMessage(msg, this.parentPage_); | 195 window.parent.postMessage(msg, this.parentPage_); |
| 182 }, | 196 }, |
| 183 | 197 |
| 184 /** | 198 /** |
| 185 * Invoked when the background script sends a message to indicate that the | 199 * Invoked when the background script sends a message to indicate that the |
| 186 * current content does not fit in a constrained window. | 200 * current content does not fit in a constrained window. |
| 187 * @param {Object=} opt_extraMsg Optional extra info to send. | 201 * @param {Object=} opt_extraMsg Optional extra info to send. |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 203 'method': 'completeLogin', | 217 'method': 'completeLogin', |
| 204 'email': (opt_extraMsg && opt_extraMsg.email) || this.email_, | 218 'email': (opt_extraMsg && opt_extraMsg.email) || this.email_, |
| 205 'password': (opt_extraMsg && opt_extraMsg.password) || | 219 'password': (opt_extraMsg && opt_extraMsg.password) || |
| 206 this.passwordBytes_, | 220 this.passwordBytes_, |
| 207 'usingSAML': this.isSAMLFlow_, | 221 'usingSAML': this.isSAMLFlow_, |
| 208 'chooseWhatToSync': this.chooseWhatToSync_ || false, | 222 'chooseWhatToSync': this.chooseWhatToSync_ || false, |
| 209 'skipForNow': opt_extraMsg && opt_extraMsg.skipForNow, | 223 'skipForNow': opt_extraMsg && opt_extraMsg.skipForNow, |
| 210 'sessionIndex': opt_extraMsg && opt_extraMsg.sessionIndex | 224 'sessionIndex': opt_extraMsg && opt_extraMsg.sessionIndex |
| 211 }; | 225 }; |
| 212 window.parent.postMessage(msg, this.parentPage_); | 226 window.parent.postMessage(msg, this.parentPage_); |
| 213 if (this.isSAMLEnabled_) | 227 this.supportChannel_.send({name: 'resetAuth'}); |
| 214 this.supportChannel_.send({name: 'resetAuth'}); | |
| 215 }, | 228 }, |
| 216 | 229 |
| 217 /** | 230 /** |
| 218 * Invoked when 'enableSAML' event is received to initialize SAML support on | 231 * Invoked when support channel is connected. |
| 219 * Chrome OS, or when initDesktopChannel_ is called on desktop. | |
| 220 */ | 232 */ |
| 221 onEnableSAML_: function() { | 233 initSAML_: function() { |
| 222 this.isSAMLEnabled_ = true; | |
| 223 this.isSAMLFlow_ = false; | 234 this.isSAMLFlow_ = false; |
| 224 | 235 |
| 225 if (!this.supportChannel_) { | |
| 226 this.supportChannel_ = new Channel(); | |
| 227 this.supportChannel_.connect('authMain'); | |
| 228 } | |
| 229 | |
| 230 this.supportChannel_.registerMessage( | 236 this.supportChannel_.registerMessage( |
| 231 'onAuthPageLoaded', this.onAuthPageLoaded_.bind(this)); | 237 'onAuthPageLoaded', this.onAuthPageLoaded_.bind(this)); |
| 232 this.supportChannel_.registerMessage( | 238 this.supportChannel_.registerMessage( |
| 233 'onInsecureContentBlocked', this.onInsecureContentBlocked_.bind(this)); | 239 'onInsecureContentBlocked', this.onInsecureContentBlocked_.bind(this)); |
| 234 this.supportChannel_.registerMessage( | 240 this.supportChannel_.registerMessage( |
| 235 'apiCall', this.onAPICall_.bind(this)); | 241 'apiCall', this.onAPICall_.bind(this)); |
| 236 this.supportChannel_.send({ | 242 this.supportChannel_.send({ |
| 237 name: 'setGaiaUrl', | 243 name: 'setGaiaUrl', |
| 238 gaiaUrl: this.gaiaUrl_ | 244 gaiaUrl: this.gaiaUrl_ |
| 239 }); | 245 }); |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 393 }, | 399 }, |
| 394 | 400 |
| 395 onMessage: function(e) { | 401 onMessage: function(e) { |
| 396 var msg = e.data; | 402 var msg = e.data; |
| 397 if (msg.method == 'attemptLogin' && this.isGaiaMessage_(e)) { | 403 if (msg.method == 'attemptLogin' && this.isGaiaMessage_(e)) { |
| 398 this.email_ = msg.email; | 404 this.email_ = msg.email; |
| 399 this.passwordBytes_ = msg.password; | 405 this.passwordBytes_ = msg.password; |
| 400 this.attemptToken_ = msg.attemptToken; | 406 this.attemptToken_ = msg.attemptToken; |
| 401 this.chooseWhatToSync_ = msg.chooseWhatToSync; | 407 this.chooseWhatToSync_ = msg.chooseWhatToSync; |
| 402 this.isSAMLFlow_ = false; | 408 this.isSAMLFlow_ = false; |
| 403 if (this.isSAMLEnabled_) | 409 if (this.supportChannel_) |
| 404 this.supportChannel_.send({name: 'startAuth'}); | 410 this.supportChannel_.send({name: 'startAuth'}); |
| 411 else | |
| 412 console.error('Support channel is not initialized.'); | |
| 405 } else if (msg.method == 'clearOldAttempts' && this.isGaiaMessage_(e)) { | 413 } else if (msg.method == 'clearOldAttempts' && this.isGaiaMessage_(e)) { |
| 414 if (!this.gaiaLoaded_) { | |
| 415 this.gaiaLoaded_ = true; | |
| 416 this.maybeInitialized_(); | |
| 417 } | |
| 406 this.email_ = null; | 418 this.email_ = null; |
| 407 this.passwordBytes_ = null; | 419 this.passwordBytes_ = null; |
| 408 this.attemptToken_ = null; | 420 this.attemptToken_ = null; |
| 409 this.isSAMLFlow_ = false; | 421 this.isSAMLFlow_ = false; |
| 410 this.onLoginUILoaded_(); | 422 if (this.supportChannel_) |
| 411 if (this.isSAMLEnabled_) | |
| 412 this.supportChannel_.send({name: 'resetAuth'}); | 423 this.supportChannel_.send({name: 'resetAuth'}); |
| 413 } else if (msg.method == 'setAuthenticatedUserEmail' && | 424 } else if (msg.method == 'setAuthenticatedUserEmail' && |
| 414 this.isParentMessage_(e)) { | 425 this.isParentMessage_(e)) { |
| 415 if (this.attemptToken_ == msg.attemptToken) { | 426 if (this.attemptToken_ == msg.attemptToken) { |
| 416 this.email_ = msg.email; | 427 this.email_ = msg.email; |
| 417 this.maybeCompleteSAMLLogin_(); | 428 this.maybeCompleteSAMLLogin_(); |
| 418 } | 429 } |
| 419 } else if (msg.method == 'confirmLogin' && this.isInternalMessage_(e)) { | 430 } else if (msg.method == 'confirmLogin' && this.isInternalMessage_(e)) { |
| 420 if (this.attemptToken_ == msg.attemptToken) | 431 if (this.attemptToken_ == msg.attemptToken) |
| 421 this.onConfirmLogin_(); | 432 this.onConfirmLogin_(); |
| 422 else | 433 else |
| 423 console.error('Authenticator.onMessage: unexpected attemptToken!?'); | 434 console.error('Authenticator.onMessage: unexpected attemptToken!?'); |
| 424 } else if (msg.method == 'verifyConfirmedPassword' && | 435 } else if (msg.method == 'verifyConfirmedPassword' && |
| 425 this.isParentMessage_(e)) { | 436 this.isParentMessage_(e)) { |
| 426 this.onVerifyConfirmedPassword_(msg.password); | 437 this.onVerifyConfirmedPassword_(msg.password); |
| 427 } else if (msg.method == 'redirectToSignin' && | 438 } else if (msg.method == 'redirectToSignin' && |
| 428 this.isParentMessage_(e)) { | 439 this.isParentMessage_(e)) { |
| 429 $('gaia-frame').src = this.constructInitialFrameUrl_(); | 440 $('gaia-frame').src = this.constructInitialFrameUrl_(); |
| 430 } else { | 441 } else { |
| 431 console.error('Authenticator.onMessage: unknown message + origin!?'); | 442 console.error('Authenticator.onMessage: unknown message + origin!?'); |
| 432 } | 443 } |
| 433 } | 444 } |
| 434 }; | 445 }; |
| 435 | 446 |
| 436 Authenticator.getInstance().initialize(); | 447 Authenticator.getInstance().initialize(); |
| OLD | NEW |