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 |