| 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 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 195 Authenticator.prototype.load = function(authMode, data) { | 195 Authenticator.prototype.load = function(authMode, data) { |
| 196 this.authMode = authMode; | 196 this.authMode = authMode; |
| 197 this.clearCredentials_(); | 197 this.clearCredentials_(); |
| 198 // gaiaUrl parameter is used for testing. Once defined, it is never changed. | 198 // gaiaUrl parameter is used for testing. Once defined, it is never changed. |
| 199 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; | 199 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; |
| 200 this.continueUrl_ = data.continueUrl || CONTINUE_URL; | 200 this.continueUrl_ = data.continueUrl || CONTINUE_URL; |
| 201 this.continueUrlWithoutParams_ = | 201 this.continueUrlWithoutParams_ = |
| 202 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || | 202 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || |
| 203 this.continueUrl_; | 203 this.continueUrl_; |
| 204 this.isConstrainedWindow_ = data.constrained == '1'; | 204 this.isConstrainedWindow_ = data.constrained == '1'; |
| 205 this.isNewGaiaFlowChromeOS = data.isNewGaiaFlowChromeOS; | 205 this.isNewGaiaFlow = data.isNewGaiaFlow; |
| 206 this.useEafe_ = data.useEafe || false; | 206 this.useEafe_ = data.useEafe || false; |
| 207 this.clientId_ = data.clientId; | 207 this.clientId_ = data.clientId; |
| 208 this.gapsCookie_ = data.gapsCookie; | 208 this.gapsCookie_ = data.gapsCookie; |
| 209 this.gapsCookieSent_ = false; | 209 this.gapsCookieSent_ = false; |
| 210 this.newGapsCookie_ = null; | 210 this.newGapsCookie_ = null; |
| 211 this.dontResizeNonEmbeddedPages = data.dontResizeNonEmbeddedPages; | 211 this.dontResizeNonEmbeddedPages = data.dontResizeNonEmbeddedPages; |
| 212 | 212 |
| 213 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); | 213 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); |
| 214 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; | 214 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; |
| 215 // Don't block insecure content for desktop flow because it lands on | 215 // Don't block insecure content for desktop flow because it lands on |
| 216 // http. Otherwise, block insecure content as long as gaia is https. | 216 // http. Otherwise, block insecure content as long as gaia is https. |
| 217 this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP && | 217 this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP && |
| 218 this.idpOrigin_.indexOf('https://') == 0; | 218 this.idpOrigin_.indexOf('https://') == 0; |
| 219 this.needPassword = !('needPassword' in data) || data.needPassword; | 219 this.needPassword = !('needPassword' in data) || data.needPassword; |
| 220 | 220 |
| 221 if (this.isNewGaiaFlowChromeOS) { | 221 if (this.isNewGaiaFlow) { |
| 222 this.webview_.contextMenus.onShow.addListener(function(e) { | 222 this.webview_.contextMenus.onShow.addListener(function(e) { |
| 223 e.preventDefault(); | 223 e.preventDefault(); |
| 224 }); | 224 }); |
| 225 | 225 |
| 226 if (!this.onBeforeSetHeadersSet_) { | 226 if (!this.onBeforeSetHeadersSet_) { |
| 227 this.onBeforeSetHeadersSet_ = true; | 227 this.onBeforeSetHeadersSet_ = true; |
| 228 var filterPrefix = this.idpOrigin_ + EMBEDDED_SETUP_CHROMEOS_ENDPOINT; | 228 var filterPrefix = this.idpOrigin_ + EMBEDDED_SETUP_CHROMEOS_ENDPOINT; |
| 229 // This depends on gaiaUrl parameter, that is why it is here. | 229 // This depends on gaiaUrl parameter, that is why it is here. |
| 230 this.webview_.request.onBeforeSendHeaders.addListener( | 230 this.webview_.request.onBeforeSendHeaders.addListener( |
| 231 this.onBeforeSendHeaders_.bind(this), | 231 this.onBeforeSendHeaders_.bind(this), |
| 232 {urls: [filterPrefix + '?*', filterPrefix + '/*']}, | 232 {urls: [filterPrefix + '?*', filterPrefix + '/*']}, |
| 233 ['requestHeaders', 'blocking']); | 233 ['requestHeaders', 'blocking']); |
| 234 } | 234 } |
| 235 } | 235 } |
| 236 | 236 |
| 237 this.webview_.src = this.reloadUrl_; | 237 this.webview_.src = this.reloadUrl_; |
| 238 }; | 238 }; |
| 239 | 239 |
| 240 /** | 240 /** |
| 241 * Reloads the authenticator component. | 241 * Reloads the authenticator component. |
| 242 */ | 242 */ |
| 243 Authenticator.prototype.reload = function() { | 243 Authenticator.prototype.reload = function() { |
| 244 this.clearCredentials_(); | 244 this.clearCredentials_(); |
| 245 this.webview_.src = this.reloadUrl_; | 245 this.webview_.src = this.reloadUrl_; |
| 246 }; | 246 }; |
| 247 | 247 |
| 248 Authenticator.prototype.constructInitialFrameUrl_ = function(data) { | 248 Authenticator.prototype.constructInitialFrameUrl_ = function(data) { |
| 249 var path = data.gaiaPath; | 249 var path = data.gaiaPath; |
| 250 if (!path && this.isNewGaiaFlowChromeOS) | 250 if (!path && this.isNewGaiaFlow) |
| 251 path = EMBEDDED_SETUP_CHROMEOS_ENDPOINT; | 251 path = EMBEDDED_SETUP_CHROMEOS_ENDPOINT; |
| 252 if (!path) | 252 if (!path) |
| 253 path = IDP_PATH; | 253 path = IDP_PATH; |
| 254 var url = this.idpOrigin_ + path; | 254 var url = this.idpOrigin_ + path; |
| 255 | 255 |
| 256 if (this.isNewGaiaFlowChromeOS) { | 256 if (this.isNewGaiaFlow) { |
| 257 if (data.chromeType) | 257 if (data.chromeType) |
| 258 url = appendParam(url, 'chrometype', data.chromeType); | 258 url = appendParam(url, 'chrometype', data.chromeType); |
| 259 if (data.clientId) | 259 if (data.clientId) |
| 260 url = appendParam(url, 'client_id', data.clientId); | 260 url = appendParam(url, 'client_id', data.clientId); |
| 261 if (data.enterpriseDomain) | 261 if (data.enterpriseDomain) |
| 262 url = appendParam(url, 'manageddomain', data.enterpriseDomain); | 262 url = appendParam(url, 'manageddomain', data.enterpriseDomain); |
| 263 if (data.clientVersion) | 263 if (data.clientVersion) |
| 264 url = appendParam(url, 'client_version', data.clientVersion); | 264 url = appendParam(url, 'client_version', data.clientVersion); |
| 265 if (data.platformVersion) | 265 if (data.platformVersion) |
| 266 url = appendParam(url, 'platform_version', data.platformVersion); | 266 url = appendParam(url, 'platform_version', data.platformVersion); |
| 267 if (data.releaseChannel) | 267 if (data.releaseChannel) |
| 268 url = appendParam(url, 'release_channel', data.releaseChannel); | 268 url = appendParam(url, 'release_channel', data.releaseChannel); |
| 269 if (data.endpointGen) | 269 if (data.endpointGen) |
| 270 url = appendParam(url, 'endpoint_gen', data.endpointGen); | 270 url = appendParam(url, 'endpoint_gen', data.endpointGen); |
| 271 } else { | 271 } else { |
| 272 url = appendParam(url, 'continue', this.continueUrl_); | 272 url = appendParam(url, 'continue', this.continueUrl_); |
| 273 url = appendParam(url, 'service', data.service || SERVICE_ID); | 273 url = appendParam(url, 'service', data.service || SERVICE_ID); |
| 274 } | 274 } |
| 275 if (data.hl) | 275 if (data.hl) |
| 276 url = appendParam(url, 'hl', data.hl); | 276 url = appendParam(url, 'hl', data.hl); |
| 277 if (data.gaiaId) | 277 if (data.gaiaId) |
| 278 url = appendParam(url, 'user_id', data.gaiaId); | 278 url = appendParam(url, 'user_id', data.gaiaId); |
| 279 if (data.email) | 279 if (data.email) { |
| 280 url = appendParam(url, 'Email', data.email); | 280 // The email fields allow for the following possibilities: |
| 281 // |
| 282 // 1/ If neither Email nor email_hint is supplied, then the email text |
| 283 // field is blank and the user must type an email to proceed. |
| 284 // |
| 285 // 2/ If Email is supplied, then the email is hardcoded and the user |
| 286 // cannot change it. The user is asked for password. This is useful for |
| 287 // re-auth scenarios, where chrome needs the user to authenticate for a |
| 288 // specific account and only that account. |
| 289 // |
| 290 // 3/ If email_hint is supplied, gaia will prefill the email text field |
| 291 // using the given email address, but the user can still change it and |
| 292 // then proceed. This is used on desktop when the user disconnects their |
| 293 // profile then reconnects, to encourage them to use the same account. |
| 294 if (data.readOnlyEmail) { |
| 295 url = appendParam(url, 'Email', data.email); |
| 296 } else { |
| 297 url = appendParam(url, 'email_hint', data.email); |
| 298 } |
| 299 } |
| 281 if (this.isConstrainedWindow_) | 300 if (this.isConstrainedWindow_) |
| 282 url = appendParam(url, 'source', CONSTRAINED_FLOW_SOURCE); | 301 url = appendParam(url, 'source', CONSTRAINED_FLOW_SOURCE); |
| 283 if (data.flow) | 302 if (data.flow) |
| 284 url = appendParam(url, 'flow', data.flow); | 303 url = appendParam(url, 'flow', data.flow); |
| 285 if (data.emailDomain) | 304 if (data.emailDomain) |
| 286 url = appendParam(url, 'emaildomain', data.emailDomain); | 305 url = appendParam(url, 'emaildomain', data.emailDomain); |
| 287 return url; | 306 return url; |
| 288 }; | 307 }; |
| 289 | 308 |
| 290 /** | 309 /** |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 // Removes "" around. | 409 // Removes "" around. |
| 391 this.email_ = signinDetails['email'].slice(1, -1); | 410 this.email_ = signinDetails['email'].slice(1, -1); |
| 392 this.gaiaId_ = signinDetails['obfuscatedid'].slice(1, -1); | 411 this.gaiaId_ = signinDetails['obfuscatedid'].slice(1, -1); |
| 393 this.sessionIndex_ = signinDetails['sessionindex']; | 412 this.sessionIndex_ = signinDetails['sessionindex']; |
| 394 } else if (headerName == LOCATION_HEADER) { | 413 } else if (headerName == LOCATION_HEADER) { |
| 395 // If the "choose what to sync" checkbox was clicked, then the continue | 414 // If the "choose what to sync" checkbox was clicked, then the continue |
| 396 // URL will contain a source=3 field. | 415 // URL will contain a source=3 field. |
| 397 var location = decodeURIComponent(header.value); | 416 var location = decodeURIComponent(header.value); |
| 398 this.chooseWhatToSync_ = !!location.match(/(\?|&)source=3($|&)/); | 417 this.chooseWhatToSync_ = !!location.match(/(\?|&)source=3($|&)/); |
| 399 } else if ( | 418 } else if ( |
| 400 this.isNewGaiaFlowChromeOS && headerName == SET_COOKIE_HEADER) { | 419 this.isNewGaiaFlow && headerName == SET_COOKIE_HEADER) { |
| 401 var headerValue = header.value; | 420 var headerValue = header.value; |
| 402 if (headerValue.indexOf(OAUTH_CODE_COOKIE + '=', 0) == 0) { | 421 if (headerValue.indexOf(OAUTH_CODE_COOKIE + '=', 0) == 0) { |
| 403 this.oauthCode_ = | 422 this.oauthCode_ = |
| 404 headerValue.substring(OAUTH_CODE_COOKIE.length + 1).split(';')[0]; | 423 headerValue.substring(OAUTH_CODE_COOKIE.length + 1).split(';')[0]; |
| 405 } | 424 } |
| 406 if (headerValue.indexOf(GAPS_COOKIE + '=', 0) == 0) { | 425 if (headerValue.indexOf(GAPS_COOKIE + '=', 0) == 0) { |
| 407 this.newGapsCookie_ = | 426 this.newGapsCookie_ = |
| 408 headerValue.substring(GAPS_COOKIE.length + 1).split(';')[0]; | 427 headerValue.substring(GAPS_COOKIE.length + 1).split(';')[0]; |
| 409 } | 428 } |
| 410 } | 429 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 437 }; | 456 }; |
| 438 | 457 |
| 439 /** | 458 /** |
| 440 * Handler for webView.request.onBeforeSendHeaders . | 459 * Handler for webView.request.onBeforeSendHeaders . |
| 441 * @return {!Object} Modified request headers. | 460 * @return {!Object} Modified request headers. |
| 442 * @private | 461 * @private |
| 443 */ | 462 */ |
| 444 Authenticator.prototype.onBeforeSendHeaders_ = function(details) { | 463 Authenticator.prototype.onBeforeSendHeaders_ = function(details) { |
| 445 // We should re-send cookie if first request was unsuccessful (i.e. no new | 464 // We should re-send cookie if first request was unsuccessful (i.e. no new |
| 446 // GAPS cookie was received). | 465 // GAPS cookie was received). |
| 447 if (this.isNewGaiaFlowChromeOS && this.gapsCookie_ && | 466 if (this.isNewGaiaFlow && this.gapsCookie_ && |
| 448 (!this.gapsCookieSent_ || !this.newGapsCookie_)) { | 467 (!this.gapsCookieSent_ || !this.newGapsCookie_)) { |
| 449 var headers = details.requestHeaders; | 468 var headers = details.requestHeaders; |
| 450 var found = false; | 469 var found = false; |
| 451 var gapsCookie = this.gapsCookie_; | 470 var gapsCookie = this.gapsCookie_; |
| 452 | 471 |
| 453 for (var i = 0, l = headers.length; i < l; ++i) { | 472 for (var i = 0, l = headers.length; i < l; ++i) { |
| 454 if (headers[i].name == COOKIE_HEADER) { | 473 if (headers[i].name == COOKIE_HEADER) { |
| 455 headers[i].value = this.updateCookieValue_(headers[i].value, | 474 headers[i].value = this.updateCookieValue_(headers[i].value, |
| 456 GAPS_COOKIE, gapsCookie); | 475 GAPS_COOKIE, gapsCookie); |
| 457 found = true; | 476 found = true; |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 735 this.webview_.contentWindow.postMessage(msg, this.idpOrigin_); | 754 this.webview_.contentWindow.postMessage(msg, this.idpOrigin_); |
| 736 }).bind(this), EAFE_INITIAL_MESSAGE_DELAY_IN_MS); | 755 }).bind(this), EAFE_INITIAL_MESSAGE_DELAY_IN_MS); |
| 737 } | 756 } |
| 738 }; | 757 }; |
| 739 | 758 |
| 740 /** | 759 /** |
| 741 * Invoked when the webview navigates withing the current document. | 760 * Invoked when the webview navigates withing the current document. |
| 742 * @private | 761 * @private |
| 743 */ | 762 */ |
| 744 Authenticator.prototype.onLoadCommit_ = function(e) { | 763 Authenticator.prototype.onLoadCommit_ = function(e) { |
| 745 if (this.oauthCode_) { | 764 if (this.oauthCode_) |
| 746 this.skipForNow_ = true; | |
| 747 this.maybeCompleteAuth_(); | 765 this.maybeCompleteAuth_(); |
| 748 } | |
| 749 }; | 766 }; |
| 750 | 767 |
| 751 /** | 768 /** |
| 752 * Returns |true| if event |e| was sent from the hosted webview. | 769 * Returns |true| if event |e| was sent from the hosted webview. |
| 753 * @private | 770 * @private |
| 754 */ | 771 */ |
| 755 Authenticator.prototype.isWebviewEvent_ = function(e) { | 772 Authenticator.prototype.isWebviewEvent_ = function(e) { |
| 756 // Note: <webview> prints error message to console if |contentWindow| is not | 773 // Note: <webview> prints error message to console if |contentWindow| is not |
| 757 // defined. | 774 // defined. |
| 758 // TODO(dzhioev): remove the message. http://crbug.com/469522 | 775 // TODO(dzhioev): remove the message. http://crbug.com/469522 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 776 Authenticator.AuthMode = AuthMode; | 793 Authenticator.AuthMode = AuthMode; |
| 777 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; | 794 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; |
| 778 | 795 |
| 779 return { | 796 return { |
| 780 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old | 797 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old |
| 781 // iframe-based flow is deprecated. | 798 // iframe-based flow is deprecated. |
| 782 GaiaAuthHost: Authenticator, | 799 GaiaAuthHost: Authenticator, |
| 783 Authenticator: Authenticator | 800 Authenticator: Authenticator |
| 784 }; | 801 }; |
| 785 }); | 802 }); |
| OLD | NEW |