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 30 matching lines...) Expand all Loading... | |
41 */ | 41 */ |
42 Authenticator.getInstance = function() { | 42 Authenticator.getInstance = function() { |
43 if (!Authenticator.instance_) { | 43 if (!Authenticator.instance_) { |
44 Authenticator.instance_ = new Authenticator(); | 44 Authenticator.instance_ = new Authenticator(); |
45 } | 45 } |
46 return Authenticator.instance_; | 46 return Authenticator.instance_; |
47 }; | 47 }; |
48 | 48 |
49 Authenticator.prototype = { | 49 Authenticator.prototype = { |
50 email_: null, | 50 email_: null, |
51 gaiaId_: null, | |
51 | 52 |
52 // Depending on the key type chosen, this will contain the plain text password | 53 // Depending on the key type chosen, this will contain the plain text password |
53 // or a credential derived from it along with the information required to | 54 // or a credential derived from it along with the information required to |
54 // repeat the derivation, such as a salt. The information will be encoded so | 55 // repeat the derivation, such as a salt. The information will be encoded so |
55 // that it contains printable ASCII characters only. The exact encoding is TBD | 56 // that it contains printable ASCII characters only. The exact encoding is TBD |
56 // when support for key types other than plain text password is added. | 57 // when support for key types other than plain text password is added. |
57 passwordBytes_: null, | 58 passwordBytes_: null, |
58 | 59 |
60 chooseWhatToSync_: false, | |
61 skipForNow_: false, | |
62 sessionIndex_: null, | |
59 attemptToken_: null, | 63 attemptToken_: null, |
60 | 64 |
61 // Input params from extension initialization URL. | 65 // Input params from extension initialization URL. |
62 inputLang_: undefined, | 66 inputLang_: undefined, |
63 intputEmail_: undefined, | 67 intputEmail_: undefined, |
64 | 68 |
65 isSAMLFlow_: false, | 69 isSAMLFlow_: false, |
66 gaiaLoaded_: false, | 70 gaiaLoaded_: false, |
67 supportChannel_: null, | 71 supportChannel_: null, |
68 | 72 |
(...skipping 28 matching lines...) Expand all Loading... | |
97 | 101 |
98 document.addEventListener('DOMContentLoaded', this.onPageLoad_.bind(this)); | 102 document.addEventListener('DOMContentLoaded', this.onPageLoad_.bind(this)); |
99 }, | 103 }, |
100 | 104 |
101 isGaiaMessage_: function(msg) { | 105 isGaiaMessage_: function(msg) { |
102 // Not quite right, but good enough. | 106 // Not quite right, but good enough. |
103 return this.gaiaUrl_.indexOf(msg.origin) == 0 || | 107 return this.gaiaUrl_.indexOf(msg.origin) == 0 || |
104 this.GAIA_URL.indexOf(msg.origin) == 0; | 108 this.GAIA_URL.indexOf(msg.origin) == 0; |
105 }, | 109 }, |
106 | 110 |
107 isInternalMessage_: function(msg) { | 111 isInternalMessage_: function(msg) { |
bartfab (slow)
2014/10/14 17:12:38
Nit: No longer used.
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:31
Done.
| |
108 return msg.origin == Authenticator.THIS_EXTENSION_ORIGIN; | 112 return msg.origin == Authenticator.THIS_EXTENSION_ORIGIN; |
109 }, | 113 }, |
110 | 114 |
111 isParentMessage_: function(msg) { | 115 isParentMessage_: function(msg) { |
112 return msg.origin == this.parentPage_; | 116 return msg.origin == this.parentPage_; |
113 }, | 117 }, |
114 | 118 |
115 constructInitialFrameUrl_: function() { | 119 constructInitialFrameUrl_: function() { |
116 var url = this.gaiaUrl_ + this.gaiaPath_; | 120 var url = this.gaiaUrl_ + this.gaiaPath_; |
117 | 121 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
158 | 162 |
159 if (this.desktopMode_) { | 163 if (this.desktopMode_) { |
160 this.supportChannel_.send({ | 164 this.supportChannel_.send({ |
161 name: 'initDesktopFlow', | 165 name: 'initDesktopFlow', |
162 gaiaUrl: this.gaiaUrl_, | 166 gaiaUrl: this.gaiaUrl_, |
163 continueUrl: stripParams(this.continueUrl_), | 167 continueUrl: stripParams(this.continueUrl_), |
164 isConstrainedWindow: this.isConstrainedWindow_ | 168 isConstrainedWindow: this.isConstrainedWindow_ |
165 }); | 169 }); |
166 this.supportChannel_.registerMessage( | 170 this.supportChannel_.registerMessage( |
167 'switchToFullTab', this.switchToFullTab_.bind(this)); | 171 'switchToFullTab', this.switchToFullTab_.bind(this)); |
168 this.supportChannel_.registerMessage( | |
169 'completeLogin', this.completeLogin_.bind(this)); | |
170 } | 172 } |
173 this.supportChannel_.registerMessage( | |
174 'completeLogin', this.onCompleteLogin_.bind(this)); | |
171 this.initSAML_(); | 175 this.initSAML_(); |
172 this.maybeInitialized_(); | 176 this.maybeInitialized_(); |
173 }.bind(this)); | 177 }.bind(this)); |
174 | 178 |
175 window.setTimeout(function() { | 179 window.setTimeout(function() { |
176 if (!this.supportChannel_) { | 180 if (!this.supportChannel_) { |
177 // Re-initialize the channel if it is not connected properly, e.g. | 181 // Re-initialize the channel if it is not connected properly, e.g. |
178 // connect may be called before background script started running. | 182 // connect may be called before background script started running. |
179 this.initSupportChannel_(); | 183 this.initSupportChannel_(); |
180 } | 184 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
213 * @param {Object=} opt_extraMsg Optional extra info to send. | 217 * @param {Object=} opt_extraMsg Optional extra info to send. |
214 */ | 218 */ |
215 completeLogin_: function(opt_extraMsg) { | 219 completeLogin_: function(opt_extraMsg) { |
216 var msg = { | 220 var msg = { |
217 'method': 'completeLogin', | 221 'method': 'completeLogin', |
218 'email': (opt_extraMsg && opt_extraMsg.email) || this.email_, | 222 'email': (opt_extraMsg && opt_extraMsg.email) || this.email_, |
219 'password': (opt_extraMsg && opt_extraMsg.password) || | 223 'password': (opt_extraMsg && opt_extraMsg.password) || |
220 this.passwordBytes_, | 224 this.passwordBytes_, |
221 'usingSAML': this.isSAMLFlow_, | 225 'usingSAML': this.isSAMLFlow_, |
222 'chooseWhatToSync': this.chooseWhatToSync_ || false, | 226 'chooseWhatToSync': this.chooseWhatToSync_ || false, |
223 'skipForNow': opt_extraMsg && opt_extraMsg.skipForNow, | 227 'skipForNow': (opt_extraMsg && opt_extraMsg.skipForNow) || |
224 'sessionIndex': opt_extraMsg && opt_extraMsg.sessionIndex | 228 this.skipForNow_, |
229 'sessionIndex': (opt_extraMsg && opt_extraMsg.sessionIndex) || | |
230 this.sessionIndex_, | |
231 'gaiaId': (opt_extraMsg && opt_extraMsg.gaiaId) || this.gaiaId_ | |
225 }; | 232 }; |
226 window.parent.postMessage(msg, this.parentPage_); | 233 window.parent.postMessage(msg, this.parentPage_); |
227 this.supportChannel_.send({name: 'resetAuth'}); | 234 this.supportChannel_.send({name: 'resetAuth'}); |
228 }, | 235 }, |
229 | 236 |
230 /** | 237 /** |
231 * Invoked when support channel is connected. | 238 * Invoked when support channel is connected. |
232 */ | 239 */ |
233 initSAML_: function() { | 240 initSAML_: function() { |
234 this.isSAMLFlow_ = false; | 241 this.isSAMLFlow_ = false; |
(...skipping 26 matching lines...) Expand all Loading... | |
261 */ | 268 */ |
262 onAuthPageLoaded_: function(msg) { | 269 onAuthPageLoaded_: function(msg) { |
263 var isSAMLPage = msg.url.indexOf(this.gaiaUrl_) != 0; | 270 var isSAMLPage = msg.url.indexOf(this.gaiaUrl_) != 0; |
264 | 271 |
265 if (isSAMLPage && !this.isSAMLFlow_) { | 272 if (isSAMLPage && !this.isSAMLFlow_) { |
266 // GAIA redirected to a SAML login page. The credentials provided to this | 273 // GAIA redirected to a SAML login page. The credentials provided to this |
267 // page will determine what user gets logged in. The credentials obtained | 274 // page will determine what user gets logged in. The credentials obtained |
268 // from the GAIA login form are no longer relevant and can be discarded. | 275 // from the GAIA login form are no longer relevant and can be discarded. |
269 this.isSAMLFlow_ = true; | 276 this.isSAMLFlow_ = true; |
270 this.email_ = null; | 277 this.email_ = null; |
278 this.gaiaId_ = null; | |
271 this.passwordBytes_ = null; | 279 this.passwordBytes_ = null; |
272 } | 280 } |
273 | 281 |
274 window.parent.postMessage({ | 282 window.parent.postMessage({ |
275 'method': 'authPageLoaded', | 283 'method': 'authPageLoaded', |
276 'isSAML': this.isSAMLFlow_, | 284 'isSAML': this.isSAMLFlow_, |
277 'domain': extractDomain(msg.url) | 285 'domain': extractDomain(msg.url) |
278 }, this.parentPage_); | 286 }, this.parentPage_); |
279 }, | 287 }, |
280 | 288 |
(...skipping 30 matching lines...) Expand all Loading... | |
311 return; | 319 return; |
312 } | 320 } |
313 | 321 |
314 if (call.method == 'add') { | 322 if (call.method == 'add') { |
315 if (Authenticator.API_KEY_TYPES.indexOf(call.keyType) == -1) { | 323 if (Authenticator.API_KEY_TYPES.indexOf(call.keyType) == -1) { |
316 console.error('Authenticator.onAPICall_: unsupported key type'); | 324 console.error('Authenticator.onAPICall_: unsupported key type'); |
317 return; | 325 return; |
318 } | 326 } |
319 this.apiToken_ = call.token; | 327 this.apiToken_ = call.token; |
320 this.email_ = call.user; | 328 this.email_ = call.user; |
329 this.gaiaId_ = null; // TODO(rogerta): no idea what to do here. | |
guohui
2014/10/14 18:50:02
we should update the saml api to send the gaia id
bartfab (slow)
2014/10/15 08:39:07
Ah, I missed that one.
The API is called by a thi
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:31
Done.
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:32
Removed, since it cannot be set here and will be s
| |
321 this.passwordBytes_ = call.passwordBytes; | 330 this.passwordBytes_ = call.passwordBytes; |
322 } else if (call.method == 'confirm') { | 331 } else if (call.method == 'confirm') { |
323 if (call.token != this.apiToken_) | 332 if (call.token != this.apiToken_) |
324 console.error('Authenticator.onAPICall_: token mismatch'); | 333 console.error('Authenticator.onAPICall_: token mismatch'); |
325 } else { | 334 } else { |
326 console.error('Authenticator.onAPICall_: unknown message'); | 335 console.error('Authenticator.onAPICall_: unknown message'); |
327 } | 336 } |
328 }, | 337 }, |
329 | 338 |
330 sendInitializationSuccess_: function() { | 339 sendInitializationSuccess_: function() { |
331 this.supportChannel_.send({name: 'apiResponse', response: { | 340 this.supportChannel_.send({name: 'apiResponse', response: { |
332 result: 'initialized', | 341 result: 'initialized', |
333 version: this.apiVersion_, | 342 version: this.apiVersion_, |
334 keyTypes: Authenticator.API_KEY_TYPES | 343 keyTypes: Authenticator.API_KEY_TYPES |
335 }}); | 344 }}); |
336 }, | 345 }, |
337 | 346 |
338 sendInitializationFailure_: function() { | 347 sendInitializationFailure_: function() { |
339 this.supportChannel_.send({ | 348 this.supportChannel_.send({ |
340 name: 'apiResponse', | 349 name: 'apiResponse', |
341 response: {result: 'initialization_failed'} | 350 response: {result: 'initialization_failed'} |
342 }); | 351 }); |
343 }, | 352 }, |
344 | 353 |
345 onConfirmLogin_: function() { | 354 /** |
346 if (!this.isSAMLFlow_) { | 355 * Callback invoked for 'completeLogin' message. |
347 this.completeLogin_(); | 356 */ |
357 onCompleteLogin_: function(opt_extraMsg) { | |
358 // Skip SAML extra steps for desktop flow and non-SAML flow. | |
359 if (!this.isSAMLFlow_ || this.desktopMode_) { | |
360 this.completeLogin_(opt_extraMsg); | |
348 return; | 361 return; |
349 } | 362 } |
350 | 363 |
364 if (opt_extraMsg) { | |
bartfab (slow)
2014/10/14 17:12:38
How can |opt_extraMsg| ever not exist? With the ch
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:31
It can't anymore. Fixed.
| |
365 this.email_ = opt_extraMsg.email; | |
366 this.gaiaId_ = opt_extraMsg.gaiaId; | |
367 // Password from |opt_extraMsg| is not used because ChromeOS SAML flow | |
368 // gets password by asking user for confirm. | |
bartfab (slow)
2014/10/14 17:12:38
Nit: s/for/to/
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:32
Done.
| |
369 this.skipForNow_ = opt_extraMsg.skipForNow; | |
370 this.sessionIndex_ = opt_extraMsg.sessionIndex; | |
371 } | |
372 | |
351 var apiUsed = !!this.passwordBytes_; | 373 var apiUsed = !!this.passwordBytes_; |
352 | 374 |
353 // Retrieve the e-mail address of the user who just authenticated from GAIA. | 375 // Retrieve the e-mail address of the user who just authenticated from GAIA. |
bartfab (slow)
2014/10/14 17:12:38
This is no longer necessary now that we get the us
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:31
Done.
| |
354 window.parent.postMessage({method: 'retrieveAuthenticatedUserEmail', | 376 window.parent.postMessage({method: 'retrieveAuthenticatedUserEmail', |
355 attemptToken: this.attemptToken_, | 377 attemptToken: this.attemptToken_, |
356 apiUsed: apiUsed}, | 378 apiUsed: apiUsed}, |
357 this.parentPage_); | 379 this.parentPage_); |
358 | 380 |
359 if (!apiUsed) { | 381 if (!apiUsed) { |
360 this.supportChannel_.sendWithCallback( | 382 this.supportChannel_.sendWithCallback( |
361 {name: 'getScrapedPasswords'}, | 383 {name: 'getScrapedPasswords'}, |
362 function(passwords) { | 384 function(passwords) { |
363 if (passwords.length == 0) { | 385 if (passwords.length == 0) { |
364 window.parent.postMessage( | 386 window.parent.postMessage( |
365 {method: 'noPassword', email: this.email_}, | 387 {method: 'noPassword', email: this.email_}, |
366 this.parentPage_); | 388 this.parentPage_); |
367 } else { | 389 } else { |
368 window.parent.postMessage({method: 'confirmPassword', | 390 window.parent.postMessage({method: 'confirmPassword', |
369 email: this.email_, | 391 email: this.email_, |
370 passwordCount: passwords.length}, | 392 passwordCount: passwords.length}, |
371 this.parentPage_); | 393 this.parentPage_); |
372 } | 394 } |
373 }.bind(this)); | 395 }.bind(this)); |
374 } | 396 } |
375 }, | 397 }, |
376 | 398 |
377 maybeCompleteSAMLLogin_: function() { | 399 maybeCompleteSAMLLogin_: function() { |
bartfab (slow)
2014/10/14 17:12:38
This can be folded into onVerifyConfirmedPassword_
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:31
Done.
| |
378 // SAML login is complete when the user's e-mail address has been retrieved | 400 // SAML login is complete when the user's e-mail address has been retrieved |
379 // from GAIA and the user has successfully confirmed the password. | 401 // from GAIA and the user has successfully confirmed the password. |
380 if (this.email_ !== null && this.passwordBytes_ !== null) | 402 if (this.email_ !== null && this.passwordBytes_ !== null) |
381 this.completeLogin_(); | 403 this.completeLogin_(); |
382 }, | 404 }, |
383 | 405 |
384 onVerifyConfirmedPassword_: function(password) { | 406 onVerifyConfirmedPassword_: function(password) { |
385 this.supportChannel_.sendWithCallback( | 407 this.supportChannel_.sendWithCallback( |
386 {name: 'getScrapedPasswords'}, | 408 {name: 'getScrapedPasswords'}, |
387 function(passwords) { | 409 function(passwords) { |
388 for (var i = 0; i < passwords.length; ++i) { | 410 for (var i = 0; i < passwords.length; ++i) { |
389 if (passwords[i] == password) { | 411 if (passwords[i] == password) { |
390 this.passwordBytes_ = passwords[i]; | 412 this.passwordBytes_ = passwords[i]; |
391 this.maybeCompleteSAMLLogin_(); | 413 this.maybeCompleteSAMLLogin_(); |
392 return; | 414 return; |
393 } | 415 } |
394 } | 416 } |
395 window.parent.postMessage( | 417 window.parent.postMessage( |
396 {method: 'confirmPassword', email: this.email_}, | 418 {method: 'confirmPassword', email: this.email_}, |
397 this.parentPage_); | 419 this.parentPage_); |
398 }.bind(this)); | 420 }.bind(this)); |
399 }, | 421 }, |
400 | 422 |
401 onMessage: function(e) { | 423 onMessage: function(e) { |
402 var msg = e.data; | 424 var msg = e.data; |
403 if (msg.method == 'attemptLogin' && this.isGaiaMessage_(e)) { | 425 if (msg.method == 'attemptLogin' && this.isGaiaMessage_(e)) { |
426 // At this point GAIA does not yet know the gaiaId, so its not set here. | |
404 this.email_ = msg.email; | 427 this.email_ = msg.email; |
405 this.passwordBytes_ = msg.password; | 428 this.passwordBytes_ = msg.password; |
406 this.attemptToken_ = msg.attemptToken; | 429 this.attemptToken_ = msg.attemptToken; |
407 this.chooseWhatToSync_ = msg.chooseWhatToSync; | 430 this.chooseWhatToSync_ = msg.chooseWhatToSync; |
408 this.isSAMLFlow_ = false; | 431 this.isSAMLFlow_ = false; |
409 if (this.supportChannel_) | 432 if (this.supportChannel_) |
410 this.supportChannel_.send({name: 'startAuth'}); | 433 this.supportChannel_.send({name: 'startAuth'}); |
411 else | 434 else |
412 console.error('Support channel is not initialized.'); | 435 console.error('Support channel is not initialized.'); |
413 } else if (msg.method == 'clearOldAttempts' && this.isGaiaMessage_(e)) { | 436 } else if (msg.method == 'clearOldAttempts' && this.isGaiaMessage_(e)) { |
414 if (!this.gaiaLoaded_) { | 437 if (!this.gaiaLoaded_) { |
415 this.gaiaLoaded_ = true; | 438 this.gaiaLoaded_ = true; |
416 this.maybeInitialized_(); | 439 this.maybeInitialized_(); |
417 } | 440 } |
418 this.email_ = null; | 441 this.email_ = null; |
442 this.gaiaId_ = null; | |
bartfab (slow)
2014/10/14 17:12:38
Should |chooseWhatToSync_|, |skipForNow_| and |ses
Roger Tawa OOO till Jul 10th
2014/10/20 16:04:00
Done.
| |
419 this.passwordBytes_ = null; | 443 this.passwordBytes_ = null; |
420 this.attemptToken_ = null; | 444 this.attemptToken_ = null; |
421 this.isSAMLFlow_ = false; | 445 this.isSAMLFlow_ = false; |
422 if (this.supportChannel_) | 446 if (this.supportChannel_) |
423 this.supportChannel_.send({name: 'resetAuth'}); | 447 this.supportChannel_.send({name: 'resetAuth'}); |
424 } else if (msg.method == 'setAuthenticatedUserEmail' && | 448 } else if (msg.method == 'setAuthenticatedUserEmail' && |
bartfab (slow)
2014/10/14 17:12:38
This is no longer necessary now that we get the us
Roger Tawa OOO till Jul 10th
2014/10/16 02:39:31
Done.
| |
425 this.isParentMessage_(e)) { | 449 this.isParentMessage_(e)) { |
426 if (this.attemptToken_ == msg.attemptToken) { | 450 if (this.attemptToken_ == msg.attemptToken) { |
427 this.email_ = msg.email; | 451 this.email_ = msg.email; |
428 this.maybeCompleteSAMLLogin_(); | 452 this.maybeCompleteSAMLLogin_(); |
429 } | 453 } |
430 } else if (msg.method == 'confirmLogin' && this.isInternalMessage_(e)) { | |
431 // In the desktop mode, Chrome needs to wait for extra info such as | |
432 // session index from the background JS. | |
433 if (this.desktopMode_) | |
434 return; | |
435 | |
436 if (this.attemptToken_ == msg.attemptToken) | |
437 this.onConfirmLogin_(); | |
438 else | |
439 console.error('Authenticator.onMessage: unexpected attemptToken!?'); | |
440 } else if (msg.method == 'verifyConfirmedPassword' && | 454 } else if (msg.method == 'verifyConfirmedPassword' && |
441 this.isParentMessage_(e)) { | 455 this.isParentMessage_(e)) { |
442 this.onVerifyConfirmedPassword_(msg.password); | 456 this.onVerifyConfirmedPassword_(msg.password); |
443 } else if (msg.method == 'redirectToSignin' && | 457 } else if (msg.method == 'redirectToSignin' && |
444 this.isParentMessage_(e)) { | 458 this.isParentMessage_(e)) { |
445 $('gaia-frame').src = this.constructInitialFrameUrl_(); | 459 $('gaia-frame').src = this.constructInitialFrameUrl_(); |
446 } else { | 460 } else { |
447 console.error('Authenticator.onMessage: unknown message + origin!?'); | 461 console.error('Authenticator.onMessage: unknown message + origin!?'); |
448 } | 462 } |
449 } | 463 } |
450 }; | 464 }; |
451 | 465 |
452 Authenticator.getInstance().initialize(); | 466 Authenticator.getInstance().initialize(); |
OLD | NEW |