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 13 matching lines...) Expand all Loading... |
24 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/success.html'; | 24 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/success.html'; |
25 var SIGN_IN_HEADER = 'google-accounts-signin'; | 25 var SIGN_IN_HEADER = 'google-accounts-signin'; |
26 var EMBEDDED_FORM_HEADER = 'google-accounts-embedded'; | 26 var EMBEDDED_FORM_HEADER = 'google-accounts-embedded'; |
27 var LOCATION_HEADER = 'location'; | 27 var LOCATION_HEADER = 'location'; |
28 var COOKIE_HEADER = 'cookie'; | 28 var COOKIE_HEADER = 'cookie'; |
29 var SET_COOKIE_HEADER = 'set-cookie'; | 29 var SET_COOKIE_HEADER = 'set-cookie'; |
30 var OAUTH_CODE_COOKIE = 'oauth_code'; | 30 var OAUTH_CODE_COOKIE = 'oauth_code'; |
31 var GAPS_COOKIE = 'GAPS'; | 31 var GAPS_COOKIE = 'GAPS'; |
32 var SERVICE_ID = 'chromeoslogin'; | 32 var SERVICE_ID = 'chromeoslogin'; |
33 var EMBEDDED_SETUP_CHROMEOS_ENDPOINT = 'embedded/setup/chromeos'; | 33 var EMBEDDED_SETUP_CHROMEOS_ENDPOINT = 'embedded/setup/chromeos'; |
| 34 var SAML_REDIRECTION_PATH = 'samlredirect'; |
34 | 35 |
35 /** | 36 /** |
36 * The source URL parameter for the constrained signin flow. | 37 * The source URL parameter for the constrained signin flow. |
37 */ | 38 */ |
38 var CONSTRAINED_FLOW_SOURCE = 'chrome'; | 39 var CONSTRAINED_FLOW_SOURCE = 'chrome'; |
39 | 40 |
40 /** | 41 /** |
41 * Enum for the authorization mode, must match AuthMode defined in | 42 * Enum for the authorization mode, must match AuthMode defined in |
42 * chrome/browser/ui/webui/inline_login_ui.cc. | 43 * chrome/browser/ui/webui/inline_login_ui.cc. |
43 * @enum {number} | 44 * @enum {number} |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 this.idpOrigin_ = null; | 132 this.idpOrigin_ = null; |
132 this.continueUrl_ = null; | 133 this.continueUrl_ = null; |
133 this.continueUrlWithoutParams_ = null; | 134 this.continueUrlWithoutParams_ = null; |
134 this.initialFrameUrl_ = null; | 135 this.initialFrameUrl_ = null; |
135 this.reloadUrl_ = null; | 136 this.reloadUrl_ = null; |
136 this.trusted_ = true; | 137 this.trusted_ = true; |
137 this.oauthCode_ = null; | 138 this.oauthCode_ = null; |
138 this.gapsCookie_ = null; | 139 this.gapsCookie_ = null; |
139 this.gapsCookieSent_ = false; | 140 this.gapsCookieSent_ = false; |
140 this.newGapsCookie_ = null; | 141 this.newGapsCookie_ = null; |
| 142 this.readyFired_ = false; |
141 | 143 |
142 this.useEafe_ = false; | 144 this.useEafe_ = false; |
143 this.clientId_ = null; | 145 this.clientId_ = null; |
144 | 146 |
145 this.samlHandler_ = new cr.login.SamlHandler(this.webview_); | 147 this.samlHandler_ = new cr.login.SamlHandler(this.webview_); |
146 this.confirmPasswordCallback = null; | 148 this.confirmPasswordCallback = null; |
147 this.noPasswordCallback = null; | 149 this.noPasswordCallback = null; |
148 this.insecureContentBlockedCallback = null; | 150 this.insecureContentBlockedCallback = null; |
149 this.samlApiUsedCallback = null; | 151 this.samlApiUsedCallback = null; |
150 this.missingGaiaInfoCallback = null; | 152 this.missingGaiaInfoCallback = null; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 window.addEventListener( | 184 window.addEventListener( |
183 'popstate', this.onPopState_.bind(this), false); | 185 'popstate', this.onPopState_.bind(this), false); |
184 } | 186 } |
185 | 187 |
186 Authenticator.prototype = Object.create(cr.EventTarget.prototype); | 188 Authenticator.prototype = Object.create(cr.EventTarget.prototype); |
187 | 189 |
188 /** | 190 /** |
189 * Reinitializes authentication parameters so that a failed login attempt | 191 * Reinitializes authentication parameters so that a failed login attempt |
190 * would not result in an infinite loop. | 192 * would not result in an infinite loop. |
191 */ | 193 */ |
192 Authenticator.prototype.clearCredentials_ = function() { | 194 Authenticator.prototype.resetStates_ = function() { |
193 this.email_ = null; | 195 this.email_ = null; |
194 this.gaiaId_ = null; | 196 this.gaiaId_ = null; |
195 this.password_ = null; | 197 this.password_ = null; |
196 this.oauthCode_ = null; | 198 this.oauthCode_ = null; |
197 this.gapsCookie_ = null; | 199 this.gapsCookie_ = null; |
198 this.gapsCookieSent_ = false; | 200 this.gapsCookieSent_ = false; |
199 this.newGapsCookie_ = null; | 201 this.newGapsCookie_ = null; |
| 202 this.readyFired_ = false; |
200 this.chooseWhatToSync_ = false; | 203 this.chooseWhatToSync_ = false; |
201 this.skipForNow_ = false; | 204 this.skipForNow_ = false; |
202 this.sessionIndex_ = null; | 205 this.sessionIndex_ = null; |
203 this.trusted_ = true; | 206 this.trusted_ = true; |
204 this.authFlow = AuthFlow.DEFAULT; | 207 this.authFlow = AuthFlow.DEFAULT; |
205 this.samlHandler_.reset(); | 208 this.samlHandler_.reset(); |
206 }; | 209 }; |
207 | 210 |
208 /** | 211 /** |
209 * Loads the authenticator component with the given parameters. | 212 * Loads the authenticator component with the given parameters. |
210 * @param {AuthMode} authMode Authorization mode. | 213 * @param {AuthMode} authMode Authorization mode. |
211 * @param {Object} data Parameters for the authorization flow. | 214 * @param {Object} data Parameters for the authorization flow. |
212 */ | 215 */ |
213 Authenticator.prototype.load = function(authMode, data) { | 216 Authenticator.prototype.load = function(authMode, data) { |
214 this.authMode = authMode; | 217 this.authMode = authMode; |
215 this.clearCredentials_(); | 218 this.resetStates_(); |
216 // gaiaUrl parameter is used for testing. Once defined, it is never changed. | 219 // gaiaUrl parameter is used for testing. Once defined, it is never changed. |
217 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; | 220 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; |
218 this.continueUrl_ = data.continueUrl || CONTINUE_URL; | 221 this.continueUrl_ = data.continueUrl || CONTINUE_URL; |
219 this.continueUrlWithoutParams_ = | 222 this.continueUrlWithoutParams_ = |
220 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || | 223 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || |
221 this.continueUrl_; | 224 this.continueUrl_; |
222 this.isConstrainedWindow_ = data.constrained == '1'; | 225 this.isConstrainedWindow_ = data.constrained == '1'; |
223 this.isNewGaiaFlow = data.isNewGaiaFlow; | 226 this.isNewGaiaFlow = data.isNewGaiaFlow; |
224 this.useEafe_ = data.useEafe || false; | 227 this.useEafe_ = data.useEafe || false; |
225 this.clientId_ = data.clientId; | 228 this.clientId_ = data.clientId; |
(...skipping 26 matching lines...) Expand all Loading... |
252 } | 255 } |
253 } | 256 } |
254 | 257 |
255 this.webview_.src = this.reloadUrl_; | 258 this.webview_.src = this.reloadUrl_; |
256 }; | 259 }; |
257 | 260 |
258 /** | 261 /** |
259 * Reloads the authenticator component. | 262 * Reloads the authenticator component. |
260 */ | 263 */ |
261 Authenticator.prototype.reload = function() { | 264 Authenticator.prototype.reload = function() { |
262 this.clearCredentials_(); | 265 this.resetStates_(); |
263 this.webview_.src = this.reloadUrl_; | 266 this.webview_.src = this.reloadUrl_; |
264 }; | 267 }; |
265 | 268 |
266 Authenticator.prototype.constructInitialFrameUrl_ = function(data) { | 269 Authenticator.prototype.constructInitialFrameUrl_ = function(data) { |
| 270 if (data.doSamlRedirect) { |
| 271 var url = this.idpOrigin_ + SAML_REDIRECTION_PATH; |
| 272 url = appendParam(url, 'domain', data.enterpriseDomain); |
| 273 url = appendParam(url, 'continue', data.gaiaUrl + |
| 274 'o/oauth2/programmatic_auth?hl=' + data.hl + |
| 275 '&scope=https%3A%2F%2Fwww.google.com%2Faccounts%2FOAuthLogin&' + |
| 276 'client_id=' + encodeURIComponent(data.clientId) + |
| 277 '&access_type=offline'); |
| 278 |
| 279 return url; |
| 280 } |
| 281 |
267 var path = data.gaiaPath; | 282 var path = data.gaiaPath; |
268 if (!path && this.isNewGaiaFlow) | 283 if (!path && this.isNewGaiaFlow) |
269 path = EMBEDDED_SETUP_CHROMEOS_ENDPOINT; | 284 path = EMBEDDED_SETUP_CHROMEOS_ENDPOINT; |
270 if (!path) | 285 if (!path) |
271 path = IDP_PATH; | 286 path = IDP_PATH; |
272 var url = this.idpOrigin_ + path; | 287 var url = this.idpOrigin_ + path; |
273 | 288 |
274 if (this.isNewGaiaFlow) { | 289 if (this.isNewGaiaFlow) { |
275 if (data.chromeType) | 290 if (data.chromeType) |
276 url = appendParam(url, 'chrometype', data.chromeType); | 291 url = appendParam(url, 'chrometype', data.chromeType); |
(...skipping 27 matching lines...) Expand all Loading... |
304 if (this.isConstrainedWindow_) | 319 if (this.isConstrainedWindow_) |
305 url = appendParam(url, 'source', CONSTRAINED_FLOW_SOURCE); | 320 url = appendParam(url, 'source', CONSTRAINED_FLOW_SOURCE); |
306 if (data.flow) | 321 if (data.flow) |
307 url = appendParam(url, 'flow', data.flow); | 322 url = appendParam(url, 'flow', data.flow); |
308 if (data.emailDomain) | 323 if (data.emailDomain) |
309 url = appendParam(url, 'emaildomain', data.emailDomain); | 324 url = appendParam(url, 'emaildomain', data.emailDomain); |
310 return url; | 325 return url; |
311 }; | 326 }; |
312 | 327 |
313 /** | 328 /** |
| 329 * Dispatches the 'ready' event if it hasn't been dispatched already for the |
| 330 * current content. |
| 331 * @private |
| 332 */ |
| 333 Authenticator.prototype.fireReadyEvent_ = function() { |
| 334 if (!this.readyFired_) { |
| 335 this.dispatchEvent(new Event('ready')); |
| 336 this.readyFired_ = true; |
| 337 } |
| 338 }; |
| 339 |
| 340 /** |
314 * Invoked when a main frame request in the webview has completed. | 341 * Invoked when a main frame request in the webview has completed. |
315 * @private | 342 * @private |
316 */ | 343 */ |
317 Authenticator.prototype.onRequestCompleted_ = function(details) { | 344 Authenticator.prototype.onRequestCompleted_ = function(details) { |
318 var currentUrl = details.url; | 345 var currentUrl = details.url; |
319 | 346 |
320 if (!this.isNewGaiaFlow && | 347 if (!this.isNewGaiaFlow && |
321 currentUrl.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) { | 348 currentUrl.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) { |
322 if (currentUrl.indexOf('ntp=1') >= 0) | 349 if (currentUrl.indexOf('ntp=1') >= 0) |
323 this.skipForNow_ = true; | 350 this.skipForNow_ = true; |
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 password: this.password_ || '', | 679 password: this.password_ || '', |
653 authCode: this.oauthCode_, | 680 authCode: this.oauthCode_, |
654 usingSAML: this.authFlow == AuthFlow.SAML, | 681 usingSAML: this.authFlow == AuthFlow.SAML, |
655 chooseWhatToSync: this.chooseWhatToSync_, | 682 chooseWhatToSync: this.chooseWhatToSync_, |
656 skipForNow: this.skipForNow_, | 683 skipForNow: this.skipForNow_, |
657 sessionIndex: this.sessionIndex_ || '', | 684 sessionIndex: this.sessionIndex_ || '', |
658 trusted: this.trusted_, | 685 trusted: this.trusted_, |
659 gapsCookie: this.newGapsCookie_ || this.gapsCookie_ || '', | 686 gapsCookie: this.newGapsCookie_ || this.gapsCookie_ || '', |
660 } | 687 } |
661 })); | 688 })); |
662 this.clearCredentials_(); | 689 this.resetStates_(); |
663 }; | 690 }; |
664 | 691 |
665 /** | 692 /** |
666 * Invoked when |samlHandler_| fires 'insecureContentBlocked' event. | 693 * Invoked when |samlHandler_| fires 'insecureContentBlocked' event. |
667 * @private | 694 * @private |
668 */ | 695 */ |
669 Authenticator.prototype.onInsecureContentBlocked_ = function(e) { | 696 Authenticator.prototype.onInsecureContentBlocked_ = function(e) { |
670 if (this.insecureContentBlockedCallback) { | 697 if (this.insecureContentBlockedCallback) { |
671 this.insecureContentBlockedCallback(e.detail.url); | 698 this.insecureContentBlockedCallback(e.detail.url); |
672 } else { | 699 } else { |
673 console.error('Authenticator: Insecure content blocked.'); | 700 console.error('Authenticator: Insecure content blocked.'); |
674 } | 701 } |
675 }; | 702 }; |
676 | 703 |
677 /** | 704 /** |
678 * Invoked when |samlHandler_| fires 'authPageLoaded' event. | 705 * Invoked when |samlHandler_| fires 'authPageLoaded' event. |
679 * @private | 706 * @private |
680 */ | 707 */ |
681 Authenticator.prototype.onAuthPageLoaded_ = function(e) { | 708 Authenticator.prototype.onAuthPageLoaded_ = function(e) { |
682 if (!e.detail.isSAMLPage) | 709 if (!e.detail.isSAMLPage) |
683 return; | 710 return; |
684 | 711 |
685 this.authDomain = this.samlHandler_.authDomain; | 712 this.authDomain = this.samlHandler_.authDomain; |
686 this.authFlow = AuthFlow.SAML; | 713 this.authFlow = AuthFlow.SAML; |
| 714 |
| 715 this.fireReadyEvent_(); |
687 }; | 716 }; |
688 | 717 |
689 /** | 718 /** |
690 * Invoked when a link is dropped on the webview. | 719 * Invoked when a link is dropped on the webview. |
691 * @private | 720 * @private |
692 */ | 721 */ |
693 Authenticator.prototype.onDropLink_ = function(e) { | 722 Authenticator.prototype.onDropLink_ = function(e) { |
694 this.dispatchEvent(new CustomEvent('dropLink', {detail: e.url})); | 723 this.dispatchEvent(new CustomEvent('dropLink', {detail: e.url})); |
695 }; | 724 }; |
696 | 725 |
(...skipping 20 matching lines...) Expand all Loading... |
717 | 746 |
718 // Posts a message to IdP pages to initiate communication. | 747 // Posts a message to IdP pages to initiate communication. |
719 var currentUrl = this.webview_.src; | 748 var currentUrl = this.webview_.src; |
720 if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) { | 749 if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) { |
721 var msg = { | 750 var msg = { |
722 'method': 'handshake', | 751 'method': 'handshake', |
723 }; | 752 }; |
724 | 753 |
725 this.webview_.contentWindow.postMessage(msg, currentUrl); | 754 this.webview_.contentWindow.postMessage(msg, currentUrl); |
726 | 755 |
727 this.dispatchEvent(new Event('ready')); | 756 this.fireReadyEvent_(); |
728 // Focus webview after dispatching event when webview is already visible. | 757 // Focus webview after dispatching event when webview is already visible. |
729 this.webview_.focus(); | 758 this.webview_.focus(); |
730 } | 759 } |
731 }; | 760 }; |
732 | 761 |
733 /** | 762 /** |
734 * Invoked when the webview fails loading a page. | 763 * Invoked when the webview fails loading a page. |
735 * @private | 764 * @private |
736 */ | 765 */ |
737 Authenticator.prototype.onLoadAbort_ = function(e) { | 766 Authenticator.prototype.onLoadAbort_ = function(e) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
798 Authenticator.AuthMode = AuthMode; | 827 Authenticator.AuthMode = AuthMode; |
799 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; | 828 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; |
800 | 829 |
801 return { | 830 return { |
802 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old | 831 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old |
803 // iframe-based flow is deprecated. | 832 // iframe-based flow is deprecated. |
804 GaiaAuthHost: Authenticator, | 833 GaiaAuthHost: Authenticator, |
805 Authenticator: Authenticator | 834 Authenticator: Authenticator |
806 }; | 835 }; |
807 }); | 836 }); |
OLD | NEW |