OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 <include src="saml_handler.js"> | 5 <include src="saml_handler.js"> |
6 | 6 |
7 /** | 7 /** |
8 * @fileoverview An UI component to authenciate to Chrome. The component hosts | 8 * @fileoverview An UI component to authenciate to Chrome. The component hosts |
9 * IdP web pages in a webview. A client who is interested in monitoring | 9 * IdP web pages in a webview. A client who is interested in monitoring |
10 * authentication events should pass a listener object of type | 10 * authentication events should pass a listener object of type |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 'gaiaPath', // Gaia path to use without a leading slash. | 69 'gaiaPath', // Gaia path to use without a leading slash. |
70 'hl', // Language code for the user interface. | 70 'hl', // Language code for the user interface. |
71 'email', // Pre-fill the email field in Gaia UI. | 71 'email', // Pre-fill the email field in Gaia UI. |
72 'service', // Name of Gaia service. | 72 'service', // Name of Gaia service. |
73 'continueUrl', // Continue url to use. | 73 'continueUrl', // Continue url to use. |
74 'frameUrl', // Initial frame URL to use. If empty defaults to | 74 'frameUrl', // Initial frame URL to use. If empty defaults to |
75 // gaiaUrl. | 75 // gaiaUrl. |
76 'constrained', // Whether the extension is loaded in a constrained | 76 'constrained', // Whether the extension is loaded in a constrained |
77 // window. | 77 // window. |
78 'clientId', // Chrome client id. | 78 'clientId', // Chrome client id. |
| 79 'useEafe', // Whether to use EAFE. |
79 'needPassword', // Whether the host is interested in getting a password. | 80 'needPassword', // Whether the host is interested in getting a password. |
80 // If this set to |false|, |confirmPasswordCallback| is | 81 // If this set to |false|, |confirmPasswordCallback| is |
81 // not called before dispatching |authCopleted|. | 82 // not called before dispatching |authCopleted|. |
82 // Default is |true|. | 83 // Default is |true|. |
83 'flow', // One of 'default', 'enterprise', or 'theftprotection'. | 84 'flow', // One of 'default', 'enterprise', or 'theftprotection'. |
84 'enterpriseDomain', // Domain in which hosting device is (or should be) | 85 'enterpriseDomain', // Domain in which hosting device is (or should be) |
85 // enrolled. | 86 // enrolled. |
86 'emailDomain', // Value used to prefill domain for email. | 87 'emailDomain', // Value used to prefill domain for email. |
87 'deviceId', // User device ID (sync Id). | 88 'deviceId', // User device ID (sync Id). |
88 'sessionIsEphemeral', // User session would be ephemeral. | 89 'sessionIsEphemeral', // User session would be ephemeral. |
(...skipping 22 matching lines...) Expand all Loading... |
111 this.continueUrl_ = null; | 112 this.continueUrl_ = null; |
112 this.continueUrlWithoutParams_ = null; | 113 this.continueUrlWithoutParams_ = null; |
113 this.initialFrameUrl_ = null; | 114 this.initialFrameUrl_ = null; |
114 this.reloadUrl_ = null; | 115 this.reloadUrl_ = null; |
115 this.trusted_ = true; | 116 this.trusted_ = true; |
116 this.oauth_code_ = null; | 117 this.oauth_code_ = null; |
117 this.deviceId_ = null; | 118 this.deviceId_ = null; |
118 this.sessionIsEphemeral_ = null; | 119 this.sessionIsEphemeral_ = null; |
119 this.onBeforeSetHeadersSet_ = false; | 120 this.onBeforeSetHeadersSet_ = false; |
120 | 121 |
| 122 this.useEafe_ = false; |
| 123 this.clientId_ = null; |
| 124 |
121 this.samlHandler_ = new cr.login.SamlHandler(this.webview_); | 125 this.samlHandler_ = new cr.login.SamlHandler(this.webview_); |
122 this.confirmPasswordCallback = null; | 126 this.confirmPasswordCallback = null; |
123 this.noPasswordCallback = null; | 127 this.noPasswordCallback = null; |
124 this.insecureContentBlockedCallback = null; | 128 this.insecureContentBlockedCallback = null; |
125 this.samlApiUsedCallback = null; | 129 this.samlApiUsedCallback = null; |
126 this.missingGaiaInfoCallback = null; | 130 this.missingGaiaInfoCallback = null; |
127 this.needPassword = true; | 131 this.needPassword = true; |
128 this.samlHandler_.addEventListener( | 132 this.samlHandler_.addEventListener( |
129 'insecureContentBlocked', | 133 'insecureContentBlocked', |
130 this.onInsecureContentBlocked_.bind(this)); | 134 this.onInsecureContentBlocked_.bind(this)); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 */ | 190 */ |
187 Authenticator.prototype.load = function(authMode, data) { | 191 Authenticator.prototype.load = function(authMode, data) { |
188 this.clearCredentials_(); | 192 this.clearCredentials_(); |
189 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; | 193 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; |
190 this.continueUrl_ = data.continueUrl || CONTINUE_URL; | 194 this.continueUrl_ = data.continueUrl || CONTINUE_URL; |
191 this.continueUrlWithoutParams_ = | 195 this.continueUrlWithoutParams_ = |
192 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || | 196 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || |
193 this.continueUrl_; | 197 this.continueUrl_; |
194 this.isConstrainedWindow_ = data.constrained == '1'; | 198 this.isConstrainedWindow_ = data.constrained == '1'; |
195 this.isNewGaiaFlowChromeOS = data.isNewGaiaFlowChromeOS; | 199 this.isNewGaiaFlowChromeOS = data.isNewGaiaFlowChromeOS; |
| 200 this.useEafe_ = data.useEafe || false; |
| 201 this.clientId_ = data.clientId; |
196 | 202 |
197 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); | 203 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); |
198 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; | 204 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; |
199 // Don't block insecure content for desktop flow because it lands on | 205 // Don't block insecure content for desktop flow because it lands on |
200 // http. Otherwise, block insecure content as long as gaia is https. | 206 // http. Otherwise, block insecure content as long as gaia is https. |
201 this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP && | 207 this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP && |
202 this.idpOrigin_.indexOf('https://') == 0; | 208 this.idpOrigin_.indexOf('https://') == 0; |
203 this.needPassword = !('needPassword' in data) || data.needPassword; | 209 this.needPassword = !('needPassword' in data) || data.needPassword; |
204 | 210 |
205 if (this.isNewGaiaFlowChromeOS) { | 211 if (this.isNewGaiaFlowChromeOS) { |
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 */ | 431 */ |
426 Authenticator.prototype.onMessageFromWebview_ = function(e) { | 432 Authenticator.prototype.onMessageFromWebview_ = function(e) { |
427 if (!this.isWebviewEvent_(e)) | 433 if (!this.isWebviewEvent_(e)) |
428 return; | 434 return; |
429 | 435 |
430 // The event origin does not have a trailing slash. | 436 // The event origin does not have a trailing slash. |
431 if (e.origin != this.idpOrigin_.substring(0, this.idpOrigin_.length - 1)) { | 437 if (e.origin != this.idpOrigin_.substring(0, this.idpOrigin_.length - 1)) { |
432 return; | 438 return; |
433 } | 439 } |
434 | 440 |
| 441 // EAFE passes back auth code via message. |
| 442 if (this.useEafe_ && |
| 443 typeof e.data == 'object' && |
| 444 e.data.hasOwnProperty('authorizationCode')) { |
| 445 assert(!this.oauth_code_); |
| 446 this.oauth_code_ = e.data.authorizationCode; |
| 447 this.dispatchEvent( |
| 448 new CustomEvent('authCompleted', |
| 449 { |
| 450 detail: { |
| 451 authCodeOnly: true, |
| 452 authCode: this.oauth_code_ |
| 453 } |
| 454 })); |
| 455 return; |
| 456 } |
| 457 |
435 // Gaia messages must be an object with 'method' property. | 458 // Gaia messages must be an object with 'method' property. |
436 if (typeof e.data != 'object' || !e.data.hasOwnProperty('method')) { | 459 if (typeof e.data != 'object' || !e.data.hasOwnProperty('method')) { |
437 return; | 460 return; |
438 } | 461 } |
439 | 462 |
440 var msg = e.data; | 463 var msg = e.data; |
441 if (msg.method == 'attemptLogin') { | 464 if (msg.method == 'attemptLogin') { |
442 this.email_ = msg.email; | 465 this.email_ = msg.email; |
443 this.password_ = msg.password; | 466 this.password_ = msg.password; |
444 this.chooseWhatToSync_ = msg.chooseWhatToSync; | 467 this.chooseWhatToSync_ = msg.chooseWhatToSync; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 * Invoked when the webview finishes loading a page. | 646 * Invoked when the webview finishes loading a page. |
624 * @private | 647 * @private |
625 */ | 648 */ |
626 Authenticator.prototype.onLoadStop_ = function(e) { | 649 Authenticator.prototype.onLoadStop_ = function(e) { |
627 if (!this.loaded_) { | 650 if (!this.loaded_) { |
628 this.loaded_ = true; | 651 this.loaded_ = true; |
629 this.dispatchEvent(new Event('ready')); | 652 this.dispatchEvent(new Event('ready')); |
630 // Focus webview after dispatching event when webview is already visible. | 653 // Focus webview after dispatching event when webview is already visible. |
631 this.webview_.focus(); | 654 this.webview_.focus(); |
632 } | 655 } |
| 656 |
| 657 // Sends client id to EAFE on every loadstop after a small timeout. This is |
| 658 // needed because EAFE sits behind SSO and initialize asynchrounouly |
| 659 // and we don't know for sure when it is loaded and ready to listen |
| 660 // for message. The postMessage is guarded by EAFE's origin. |
| 661 if (this.useEafe_) { |
| 662 // An arbitrary small timeout for delivering the initial message. |
| 663 var EAFE_INITIAL_MESSAGE_DELAY_IN_MS = 500; |
| 664 window.setTimeout((function() { |
| 665 var msg = { |
| 666 'clientId': this.clientId_ |
| 667 }; |
| 668 this.webview_.contentWindow.postMessage(msg, this.idpOrigin_); |
| 669 }).bind(this), EAFE_INITIAL_MESSAGE_DELAY_IN_MS); |
| 670 } |
633 }; | 671 }; |
634 | 672 |
635 /** | 673 /** |
636 * Invoked when the webview navigates withing the current document. | 674 * Invoked when the webview navigates withing the current document. |
637 * @private | 675 * @private |
638 */ | 676 */ |
639 Authenticator.prototype.onLoadCommit_ = function(e) { | 677 Authenticator.prototype.onLoadCommit_ = function(e) { |
640 if (this.oauth_code_) { | 678 if (this.oauth_code_) { |
641 this.skipForNow_ = true; | 679 this.skipForNow_ = true; |
642 this.maybeCompleteAuth_(); | 680 this.maybeCompleteAuth_(); |
(...skipping 28 matching lines...) Expand all Loading... |
671 Authenticator.AuthMode = AuthMode; | 709 Authenticator.AuthMode = AuthMode; |
672 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; | 710 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; |
673 | 711 |
674 return { | 712 return { |
675 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old | 713 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old |
676 // iframe-based flow is deprecated. | 714 // iframe-based flow is deprecated. |
677 GaiaAuthHost: Authenticator, | 715 GaiaAuthHost: Authenticator, |
678 Authenticator: Authenticator | 716 Authenticator: Authenticator |
679 }; | 717 }; |
680 }); | 718 }); |
OLD | NEW |