| 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"> |
| 6 |
| 5 /** | 7 /** |
| 6 * @fileoverview An UI component to authenciate to Chrome. The component hosts | 8 * @fileoverview An UI component to authenciate to Chrome. The component hosts |
| 7 * 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 |
| 8 * authentication events should pass a listener object of type | 10 * authentication events should pass a listener object of type |
| 9 * cr.login.GaiaAuthHost.Listener as defined in this file. After initialization, | 11 * cr.login.GaiaAuthHost.Listener as defined in this file. After initialization, |
| 10 * call {@code load} to start the authentication flow. | 12 * call {@code load} to start the authentication flow. |
| 11 */ | 13 */ |
| 14 |
| 12 cr.define('cr.login', function() { | 15 cr.define('cr.login', function() { |
| 13 'use strict'; | 16 'use strict'; |
| 14 | 17 |
| 15 // TODO(rogerta): should use gaia URL from GaiaUrls::gaia_url() instead | 18 // TODO(rogerta): should use gaia URL from GaiaUrls::gaia_url() instead |
| 16 // of hardcoding the prod URL here. As is, this does not work with staging | 19 // of hardcoding the prod URL here. As is, this does not work with staging |
| 17 // environments. | 20 // environments. |
| 18 var IDP_ORIGIN = 'https://accounts.google.com/'; | 21 var IDP_ORIGIN = 'https://accounts.google.com/'; |
| 19 var IDP_PATH = 'ServiceLogin?skipvpage=true&sarp=1&rm=hide'; | 22 var IDP_PATH = 'ServiceLogin?skipvpage=true&sarp=1&rm=hide'; |
| 20 var CONTINUE_URL = | 23 var CONTINUE_URL = |
| 21 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/success.html'; | 24 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik/success.html'; |
| 22 var SIGN_IN_HEADER = 'google-accounts-signin'; | 25 var SIGN_IN_HEADER = 'google-accounts-signin'; |
| 23 var EMBEDDED_FORM_HEADER = 'google-accounts-embedded'; | 26 var EMBEDDED_FORM_HEADER = 'google-accounts-embedded'; |
| 24 var SAML_HEADER = 'google-accounts-saml'; | |
| 25 var LOCATION_HEADER = 'location'; | 27 var LOCATION_HEADER = 'location'; |
| 26 var SET_COOKIE_HEADER = 'set-cookie'; | 28 var SET_COOKIE_HEADER = 'set-cookie'; |
| 27 var OAUTH_CODE_COOKIE = 'oauth_code'; | 29 var OAUTH_CODE_COOKIE = 'oauth_code'; |
| 28 var SERVICE_ID = 'chromeoslogin'; | 30 var SERVICE_ID = 'chromeoslogin'; |
| 29 | 31 |
| 30 /** | 32 /** |
| 31 * The source URL parameter for the constrained signin flow. | 33 * The source URL parameter for the constrained signin flow. |
| 32 */ | 34 */ |
| 33 var CONSTRAINED_FLOW_SOURCE = 'chrome'; | 35 var CONSTRAINED_FLOW_SOURCE = 'chrome'; |
| 34 | 36 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 78 function Authenticator(webview) { | 80 function Authenticator(webview) { |
| 79 this.webview_ = typeof webview == 'string' ? $(webview) : webview; | 81 this.webview_ = typeof webview == 'string' ? $(webview) : webview; |
| 80 assert(this.webview_); | 82 assert(this.webview_); |
| 81 | 83 |
| 82 this.email_ = null; | 84 this.email_ = null; |
| 83 this.password_ = null; | 85 this.password_ = null; |
| 84 this.gaiaId_ = null, | 86 this.gaiaId_ = null, |
| 85 this.sessionIndex_ = null; | 87 this.sessionIndex_ = null; |
| 86 this.chooseWhatToSync_ = false; | 88 this.chooseWhatToSync_ = false; |
| 87 this.skipForNow_ = false; | 89 this.skipForNow_ = false; |
| 88 this.authFlow_ = AuthFlow.DEFAULT; | 90 this.authFlow = AuthFlow.DEFAULT; |
| 89 this.loaded_ = false; | 91 this.loaded_ = false; |
| 90 this.idpOrigin_ = null; | 92 this.idpOrigin_ = null; |
| 91 this.continueUrl_ = null; | 93 this.continueUrl_ = null; |
| 92 this.continueUrlWithoutParams_ = null; | 94 this.continueUrlWithoutParams_ = null; |
| 93 this.initialFrameUrl_ = null; | 95 this.initialFrameUrl_ = null; |
| 94 this.reloadUrl_ = null; | 96 this.reloadUrl_ = null; |
| 95 this.trusted_ = true; | 97 this.trusted_ = true; |
| 96 this.oauth_code_ = null; | 98 this.oauth_code_ = null; |
| 97 | 99 |
| 100 this.samlHandler_ = new cr.login.SamlHandler(this.webview_); |
| 101 this.confirmPasswordCallback = null; |
| 102 this.noPasswordCallback = null; |
| 103 this.insecureContentBlockedCallback = null; |
| 104 this.samlApiUsedCallback = null; |
| 105 this.missingGaiaInfoCallback = null; |
| 106 this.needPassword = true; |
| 107 this.samlHandler_.addEventListener( |
| 108 'insecureContentBlocked', |
| 109 this.onInsecureContentBlocked_.bind(this)); |
| 110 this.samlHandler_.addEventListener( |
| 111 'authPageLoaded', |
| 112 this.onAuthPageLoaded_.bind(this)); |
| 113 Object.defineProperty(this, 'authDomain', { |
| 114 get: (function() { |
| 115 return this.samlHandler_.authDomain; |
| 116 }).bind(this), |
| 117 enumerable: true |
| 118 }); |
| 119 |
| 98 this.webview_.addEventListener('droplink', this.onDropLink_.bind(this)); | 120 this.webview_.addEventListener('droplink', this.onDropLink_.bind(this)); |
| 99 this.webview_.addEventListener( | 121 this.webview_.addEventListener( |
| 100 'newwindow', this.onNewWindow_.bind(this)); | 122 'newwindow', this.onNewWindow_.bind(this)); |
| 101 this.webview_.addEventListener( | 123 this.webview_.addEventListener( |
| 102 'contentload', this.onContentLoad_.bind(this)); | 124 'contentload', this.onContentLoad_.bind(this)); |
| 103 this.webview_.addEventListener( | 125 this.webview_.addEventListener( |
| 104 'loadstop', this.onLoadStop_.bind(this)); | 126 'loadstop', this.onLoadStop_.bind(this)); |
| 105 this.webview_.addEventListener( | 127 this.webview_.addEventListener( |
| 106 'loadcommit', this.onLoadCommit_.bind(this)); | 128 'loadcommit', this.onLoadCommit_.bind(this)); |
| 107 this.webview_.request.onCompleted.addListener( | 129 this.webview_.request.onCompleted.addListener( |
| 108 this.onRequestCompleted_.bind(this), | 130 this.onRequestCompleted_.bind(this), |
| 109 {urls: ['<all_urls>'], types: ['main_frame']}, | 131 {urls: ['<all_urls>'], types: ['main_frame']}, |
| 110 ['responseHeaders']); | 132 ['responseHeaders']); |
| 111 this.webview_.request.onHeadersReceived.addListener( | 133 this.webview_.request.onHeadersReceived.addListener( |
| 112 this.onHeadersReceived_.bind(this), | 134 this.onHeadersReceived_.bind(this), |
| 113 {urls: ['<all_urls>'], types: ['main_frame', 'xmlhttprequest']}, | 135 {urls: ['<all_urls>'], types: ['main_frame', 'xmlhttprequest']}, |
| 114 ['responseHeaders']); | 136 ['responseHeaders']); |
| 115 window.addEventListener( | 137 window.addEventListener( |
| 116 'message', this.onMessageFromWebview_.bind(this), false); | 138 'message', this.onMessageFromWebview_.bind(this), false); |
| 117 window.addEventListener( | 139 window.addEventListener( |
| 118 'focus', this.onFocus_.bind(this), false); | 140 'focus', this.onFocus_.bind(this), false); |
| 119 window.addEventListener( | 141 window.addEventListener( |
| 120 'popstate', this.onPopState_.bind(this), false); | 142 'popstate', this.onPopState_.bind(this), false); |
| 121 } | 143 } |
| 122 | 144 |
| 123 // TODO(guohui,xiyuan): no need to inherit EventTarget once we deprecate the | |
| 124 // old event-based signin flow. | |
| 125 Authenticator.prototype = Object.create(cr.EventTarget.prototype); | 145 Authenticator.prototype = Object.create(cr.EventTarget.prototype); |
| 126 | 146 |
| 127 /** | 147 /** |
| 128 * Loads the authenticator component with the given parameters. | 148 * Loads the authenticator component with the given parameters. |
| 129 * @param {AuthMode} authMode Authorization mode. | 149 * @param {AuthMode} authMode Authorization mode. |
| 130 * @param {Object} data Parameters for the authorization flow. | 150 * @param {Object} data Parameters for the authorization flow. |
| 131 */ | 151 */ |
| 132 Authenticator.prototype.load = function(authMode, data) { | 152 Authenticator.prototype.load = function(authMode, data) { |
| 133 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; | 153 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; |
| 134 this.continueUrl_ = data.continueUrl || CONTINUE_URL; | 154 this.continueUrl_ = data.continueUrl || CONTINUE_URL; |
| 135 this.continueUrlWithoutParams_ = | 155 this.continueUrlWithoutParams_ = |
| 136 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || | 156 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || |
| 137 this.continueUrl_; | 157 this.continueUrl_; |
| 138 this.isConstrainedWindow_ = data.constrained == '1'; | 158 this.isConstrainedWindow_ = data.constrained == '1'; |
| 139 this.isMinuteMaidChromeOS = data.isMinuteMaidChromeOS; | 159 this.isMinuteMaidChromeOS = data.isMinuteMaidChromeOS; |
| 140 | 160 |
| 141 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); | 161 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); |
| 142 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; | 162 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; |
| 143 this.authFlow_ = AuthFlow.DEFAULT; | 163 this.authFlow = AuthFlow.DEFAULT; |
| 164 this.samlHandler_.reset(); |
| 165 // Don't block insecure content for desktop flow because it lands on |
| 166 // http. Otherwise, block insecure content as long as gaia is https. |
| 167 this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP && |
| 168 this.idpOrigin_.indexOf('https://') == 0; |
| 144 | 169 |
| 145 this.webview_.src = this.reloadUrl_; | 170 this.webview_.src = this.reloadUrl_; |
| 146 | 171 |
| 147 this.loaded_ = false; | 172 this.loaded_ = false; |
| 148 }; | 173 }; |
| 149 | 174 |
| 150 /** | 175 /** |
| 151 * Reloads the authenticator component. | 176 * Reloads the authenticator component. |
| 152 */ | 177 */ |
| 153 Authenticator.prototype.reload = function() { | 178 Authenticator.prototype.reload = function() { |
| 154 this.webview_.src = this.reloadUrl_; | 179 this.webview_.src = this.reloadUrl_; |
| 155 this.authFlow_ = AuthFlow.DEFAULT; | 180 this.authFlow = AuthFlow.DEFAULT; |
| 181 this.samlHandler_.reset(); |
| 156 this.loaded_ = false; | 182 this.loaded_ = false; |
| 157 }; | 183 }; |
| 158 | 184 |
| 159 Authenticator.prototype.constructInitialFrameUrl_ = function(data) { | 185 Authenticator.prototype.constructInitialFrameUrl_ = function(data) { |
| 160 var url = this.idpOrigin_ + (data.gaiaPath || IDP_PATH); | 186 var url = this.idpOrigin_ + (data.gaiaPath || IDP_PATH); |
| 161 | 187 |
| 162 if (this.isMinuteMaidChromeOS) { | 188 if (this.isMinuteMaidChromeOS) { |
| 163 if (data.chromeType) | 189 if (data.chromeType) |
| 164 url = appendParam(url, 'chrometype', data.chromeType); | 190 url = appendParam(url, 'chrometype', data.chromeType); |
| 165 if (data.clientId) | 191 if (data.clientId) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 183 * Invoked when a main frame request in the webview has completed. | 209 * Invoked when a main frame request in the webview has completed. |
| 184 * @private | 210 * @private |
| 185 */ | 211 */ |
| 186 Authenticator.prototype.onRequestCompleted_ = function(details) { | 212 Authenticator.prototype.onRequestCompleted_ = function(details) { |
| 187 var currentUrl = details.url; | 213 var currentUrl = details.url; |
| 188 | 214 |
| 189 if (currentUrl.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) { | 215 if (currentUrl.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) { |
| 190 if (currentUrl.indexOf('ntp=1') >= 0) | 216 if (currentUrl.indexOf('ntp=1') >= 0) |
| 191 this.skipForNow_ = true; | 217 this.skipForNow_ = true; |
| 192 | 218 |
| 193 this.onAuthCompleted_(); | 219 this.maybeCompleteAuth_(); |
| 194 return; | 220 return; |
| 195 } | 221 } |
| 196 | 222 |
| 197 if (currentUrl.indexOf('https') != 0) | 223 if (currentUrl.indexOf('https') != 0) |
| 198 this.trusted_ = false; | 224 this.trusted_ = false; |
| 199 | 225 |
| 200 if (this.isConstrainedWindow_) { | 226 if (this.isConstrainedWindow_) { |
| 201 var isEmbeddedPage = false; | 227 var isEmbeddedPage = false; |
| 202 if (this.idpOrigin_ && currentUrl.lastIndexOf(this.idpOrigin_) == 0) { | 228 if (this.idpOrigin_ && currentUrl.lastIndexOf(this.idpOrigin_) == 0) { |
| 203 var headers = details.responseHeaders; | 229 var headers = details.responseHeaders; |
| 204 for (var i = 0; headers && i < headers.length; ++i) { | 230 for (var i = 0; headers && i < headers.length; ++i) { |
| 205 if (headers[i].name.toLowerCase() == EMBEDDED_FORM_HEADER) { | 231 if (headers[i].name.toLowerCase() == EMBEDDED_FORM_HEADER) { |
| 206 isEmbeddedPage = true; | 232 isEmbeddedPage = true; |
| 207 break; | 233 break; |
| 208 } | 234 } |
| 209 } | 235 } |
| 210 } | 236 } |
| 211 if (!isEmbeddedPage) { | 237 if (!isEmbeddedPage) { |
| 212 this.dispatchEvent(new CustomEvent('resize', {detail: currentUrl})); | 238 this.dispatchEvent(new CustomEvent('resize', {detail: currentUrl})); |
| 213 return; | 239 return; |
| 214 } | 240 } |
| 215 } | 241 } |
| 216 | 242 |
| 217 this.updateHistoryState_(currentUrl); | 243 this.updateHistoryState_(currentUrl); |
| 218 | |
| 219 }; | 244 }; |
| 220 | 245 |
| 221 /** | 246 /** |
| 222 * Manually updates the history. Invoked upon completion of a webview | 247 * Manually updates the history. Invoked upon completion of a webview |
| 223 * navigation. | 248 * navigation. |
| 224 * @param {string} url Request URL. | 249 * @param {string} url Request URL. |
| 225 * @private | 250 * @private |
| 226 */ | 251 */ |
| 227 Authenticator.prototype.updateHistoryState_ = function(url) { | 252 Authenticator.prototype.updateHistoryState_ = function(url) { |
| 228 if (history.state && history.state.url != url) | 253 if (history.state && history.state.url != url) |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 271 var headerValues = header.value.toLowerCase().split(','); | 296 var headerValues = header.value.toLowerCase().split(','); |
| 272 var signinDetails = {}; | 297 var signinDetails = {}; |
| 273 headerValues.forEach(function(e) { | 298 headerValues.forEach(function(e) { |
| 274 var pair = e.split('='); | 299 var pair = e.split('='); |
| 275 signinDetails[pair[0].trim()] = pair[1].trim(); | 300 signinDetails[pair[0].trim()] = pair[1].trim(); |
| 276 }); | 301 }); |
| 277 // Removes "" around. | 302 // Removes "" around. |
| 278 this.email_ = signinDetails['email'].slice(1, -1); | 303 this.email_ = signinDetails['email'].slice(1, -1); |
| 279 this.gaiaId_ = signinDetails['obfuscatedid'].slice(1, -1); | 304 this.gaiaId_ = signinDetails['obfuscatedid'].slice(1, -1); |
| 280 this.sessionIndex_ = signinDetails['sessionindex']; | 305 this.sessionIndex_ = signinDetails['sessionindex']; |
| 281 } else if (headerName == SAML_HEADER) { | |
| 282 this.authFlow_ = AuthFlow.SAML; | |
| 283 } else if (headerName == LOCATION_HEADER) { | 306 } else if (headerName == LOCATION_HEADER) { |
| 284 // If the "choose what to sync" checkbox was clicked, then the continue | 307 // If the "choose what to sync" checkbox was clicked, then the continue |
| 285 // URL will contain a source=3 field. | 308 // URL will contain a source=3 field. |
| 286 var location = decodeURIComponent(header.value); | 309 var location = decodeURIComponent(header.value); |
| 287 this.chooseWhatToSync_ = !!location.match(/(\?|&)source=3($|&)/); | 310 this.chooseWhatToSync_ = !!location.match(/(\?|&)source=3($|&)/); |
| 288 } else if (this.isMinuteMaidChromeOS && headerName == SET_COOKIE_HEADER) { | 311 } else if (this.isMinuteMaidChromeOS && headerName == SET_COOKIE_HEADER) { |
| 289 var headerValue = header.value; | 312 var headerValue = header.value; |
| 290 if (headerValue.indexOf(OAUTH_CODE_COOKIE + '=', 0) == 0) { | 313 if (headerValue.indexOf(OAUTH_CODE_COOKIE + '=', 0) == 0) { |
| 291 this.oauth_code_ = | 314 this.oauth_code_ = |
| 292 headerValue.substring(OAUTH_CODE_COOKIE.length + 1).split(';')[0]; | 315 headerValue.substring(OAUTH_CODE_COOKIE.length + 1).split(';')[0]; |
| 293 } | 316 } |
| 294 } | 317 } |
| 295 } | 318 } |
| 296 }; | 319 }; |
| 297 | 320 |
| 298 /** | 321 /** |
| 299 * Invoked when an HTML5 message is received from the webview element. | 322 * Invoked when an HTML5 message is received from the webview element. |
| 300 * @param {object} e Payload of the received HTML5 message. | 323 * @param {object} e Payload of the received HTML5 message. |
| 301 * @private | 324 * @private |
| 302 */ | 325 */ |
| 303 Authenticator.prototype.onMessageFromWebview_ = function(e) { | 326 Authenticator.prototype.onMessageFromWebview_ = function(e) { |
| 304 // The event origin does not have a trailing slash. | 327 // The event origin does not have a trailing slash. |
| 305 if (e.origin != this.idpOrigin_.substring(0, this.idpOrigin_.length - 1)) { | 328 if (e.origin != this.idpOrigin_.substring(0, this.idpOrigin_.length - 1)) { |
| 306 return; | 329 return; |
| 307 } | 330 } |
| 308 | 331 |
| 332 // Gaia messages must be an object with 'method' property. |
| 333 if (typeof e.data != 'object' || !e.data.hasOwnProperty('method')) { |
| 334 return; |
| 335 } |
| 336 |
| 309 var msg = e.data; | 337 var msg = e.data; |
| 310 if (msg.method == 'attemptLogin') { | 338 if (msg.method == 'attemptLogin') { |
| 311 this.email_ = msg.email; | 339 this.email_ = msg.email; |
| 312 this.password_ = msg.password; | 340 this.password_ = msg.password; |
| 313 this.chooseWhatToSync_ = msg.chooseWhatToSync; | 341 this.chooseWhatToSync_ = msg.chooseWhatToSync; |
| 314 } else if (msg.method == 'dialogShown') { | 342 } else if (msg.method == 'dialogShown') { |
| 315 this.dispatchEvent(new Event('dialogShown')); | 343 this.dispatchEvent(new Event('dialogShown')); |
| 316 } else if (msg.method == 'dialogHidden') { | 344 } else if (msg.method == 'dialogHidden') { |
| 317 this.dispatchEvent(new Event('dialogHidden')); | 345 this.dispatchEvent(new Event('dialogHidden')); |
| 318 } else { | 346 } else { |
| 319 console.warning('Unrecognized message from GAIA: ' + msg.method); | 347 console.warning('Unrecognized message from GAIA: ' + msg.method); |
| 320 } | 348 } |
| 321 }; | 349 }; |
| 322 | 350 |
| 323 /** | 351 /** |
| 352 * Invoked by the hosting page to verify the Saml password. |
| 353 */ |
| 354 Authenticator.prototype.verifyConfirmedPassword = function(password) { |
| 355 if (!this.samlHandler_.verifyConfirmedPassword(password)) { |
| 356 // Invoke confirm password callback asynchronously because the |
| 357 // verification was based on messages and caller (GaiaSigninScreen) |
| 358 // does not expect it to be called immediately. |
| 359 // TODO(xiyuan): Change to synchronous call when iframe based code |
| 360 // is removed. |
| 361 var invokeConfirmPassword = (function() { |
| 362 this.confirmPasswordCallback(this.samlHandler_.scrapedPasswordCount); |
| 363 }).bind(this); |
| 364 window.setTimeout(invokeConfirmPassword, 0); |
| 365 return; |
| 366 } |
| 367 |
| 368 this.password_ = password; |
| 369 this.onAuthCompleted_(); |
| 370 }; |
| 371 |
| 372 /** |
| 373 * Check Saml flow and start password confirmation flow if needed. Otherwise, |
| 374 * continue with auto completion. |
| 375 * @private |
| 376 */ |
| 377 Authenticator.prototype.maybeCompleteAuth_ = function() { |
| 378 var missingGaiaInfo = !this.email_ || !this.gaiaId_ || !this.sessionIndex_; |
| 379 if (missingGaiaInfo && !this.skipForNow_) { |
| 380 if (this.missingGaiaInfoCallback) |
| 381 this.missingGaiaInfoCallback(); |
| 382 |
| 383 this.webview_.src = this.initialFrameUrl_; |
| 384 return; |
| 385 } |
| 386 |
| 387 if (this.authFlow != AuthFlow.SAML) { |
| 388 this.onAuthCompleted_(); |
| 389 return; |
| 390 } |
| 391 |
| 392 if (this.samlHandler_.samlApiUsed) { |
| 393 if (this.samlApiUsedCallback) { |
| 394 this.samlApiUsedCallback(); |
| 395 } |
| 396 this.password_ = this.samlHandler_.apiPasswordBytes; |
| 397 } else if (this.samlHandler_.scrapedPasswordCount == 0) { |
| 398 if (this.noPasswordCallback) { |
| 399 this.noPasswordCallback(this.email_); |
| 400 } else { |
| 401 console.error('Authenticator: No password scraped for SAML.'); |
| 402 } |
| 403 return; |
| 404 } else if (this.needPassword) { |
| 405 if (this.confirmPasswordCallback) { |
| 406 // Confirm scraped password. The flow follows in |
| 407 // verifyConfirmedPassword. |
| 408 this.confirmPasswordCallback(this.samlHandler_.scrapedPasswordCount); |
| 409 return; |
| 410 } |
| 411 } |
| 412 |
| 413 this.onAuthCompleted_(); |
| 414 }; |
| 415 |
| 416 /** |
| 324 * Invoked to process authentication completion. | 417 * Invoked to process authentication completion. |
| 325 * @private | 418 * @private |
| 326 */ | 419 */ |
| 327 Authenticator.prototype.onAuthCompleted_ = function() { | 420 Authenticator.prototype.onAuthCompleted_ = function() { |
| 328 if (!this.email_ && !this.skipForNow_) { | 421 assert(this.skipForNow_ || |
| 329 this.webview_.src = this.initialFrameUrl_; | 422 (this.email_ && this.gaiaId_ && this.sessionIndex_)); |
| 330 return; | |
| 331 } | |
| 332 | |
| 333 this.dispatchEvent( | 423 this.dispatchEvent( |
| 334 new CustomEvent('authCompleted', | 424 new CustomEvent('authCompleted', |
| 335 // TODO(rsorokin): get rid of the stub values. | 425 // TODO(rsorokin): get rid of the stub values. |
| 336 {detail: {email: this.email_ || '', | 426 {detail: {email: this.email_ || '', |
| 337 gaiaId: this.gaiaId_ || '', | 427 gaiaId: this.gaiaId_ || '', |
| 338 password: this.password_ || '', | 428 password: this.password_ || '', |
| 339 authCode: this.oauth_code_, | 429 authCode: this.oauth_code_, |
| 340 usingSAML: this.authFlow_ == AuthFlow.SAML, | 430 usingSAML: this.authFlow == AuthFlow.SAML, |
| 341 chooseWhatToSync: this.chooseWhatToSync_, | 431 chooseWhatToSync: this.chooseWhatToSync_, |
| 342 skipForNow: this.skipForNow_, | 432 skipForNow: this.skipForNow_, |
| 343 sessionIndex: this.sessionIndex_ || '', | 433 sessionIndex: this.sessionIndex_ || '', |
| 344 trusted: this.trusted_}})); | 434 trusted: this.trusted_}})); |
| 345 }; | 435 }; |
| 346 | 436 |
| 347 /** | 437 /** |
| 438 * Invoked when |samlHandler_| fires 'insecureContentBlocked' event. |
| 439 * @private |
| 440 */ |
| 441 Authenticator.prototype.onInsecureContentBlocked_ = function(e) { |
| 442 if (this.insecureContentBlockedCallback) { |
| 443 this.insecureContentBlockedCallback(e.detail.url); |
| 444 } else { |
| 445 console.error('Authenticator: Insecure content blocked.'); |
| 446 } |
| 447 }; |
| 448 |
| 449 /** |
| 450 * Invoked when |samlHandler_| fires 'authPageLoaded' event. |
| 451 * @private |
| 452 */ |
| 453 Authenticator.prototype.onAuthPageLoaded_ = function(e) { |
| 454 if (!e.detail.isSAMLPage) |
| 455 return; |
| 456 |
| 457 if (this.authFlow != AuthFlow.SAML) { |
| 458 this.authFlow = AuthFlow.SAML; |
| 459 } else { |
| 460 // Force an authFlowChanged event to update UI with updated auth doamin. |
| 461 cr.dispatchPropertyChange(this, 'authFlow'); |
| 462 } |
| 463 }; |
| 464 |
| 465 /** |
| 348 * Invoked when a link is dropped on the webview. | 466 * Invoked when a link is dropped on the webview. |
| 349 * @private | 467 * @private |
| 350 */ | 468 */ |
| 351 Authenticator.prototype.onDropLink_ = function(e) { | 469 Authenticator.prototype.onDropLink_ = function(e) { |
| 352 this.dispatchEvent(new CustomEvent('dropLink', {detail: e.url})); | 470 this.dispatchEvent(new CustomEvent('dropLink', {detail: e.url})); |
| 353 }; | 471 }; |
| 354 | 472 |
| 355 /** | 473 /** |
| 356 * Invoked when the webview attempts to open a new window. | 474 * Invoked when the webview attempts to open a new window. |
| 357 * @private | 475 * @private |
| (...skipping 28 matching lines...) Expand all Loading... |
| 386 // Focus webview after dispatching event when webview is already visible. | 504 // Focus webview after dispatching event when webview is already visible. |
| 387 this.webview_.focus(); | 505 this.webview_.focus(); |
| 388 } | 506 } |
| 389 }; | 507 }; |
| 390 | 508 |
| 391 /** | 509 /** |
| 392 * Invoked when the webview navigates withing the current document. | 510 * Invoked when the webview navigates withing the current document. |
| 393 * @private | 511 * @private |
| 394 */ | 512 */ |
| 395 Authenticator.prototype.onLoadCommit_ = function(e) { | 513 Authenticator.prototype.onLoadCommit_ = function(e) { |
| 396 // TODO(rsorokin): Investigate whether this breaks SAML. | |
| 397 if (this.oauth_code_) { | 514 if (this.oauth_code_) { |
| 398 this.skipForNow_ = true; | 515 this.skipForNow_ = true; |
| 399 this.onAuthCompleted_(); | 516 this.maybeCompleteAuth_(); |
| 400 } | 517 } |
| 401 }; | 518 }; |
| 402 | 519 |
| 520 /** |
| 521 * The current auth flow of the hosted auth page. |
| 522 * @type {AuthFlow} |
| 523 */ |
| 524 cr.defineProperty(Authenticator, 'authFlow'); |
| 525 |
| 403 Authenticator.AuthFlow = AuthFlow; | 526 Authenticator.AuthFlow = AuthFlow; |
| 404 Authenticator.AuthMode = AuthMode; | 527 Authenticator.AuthMode = AuthMode; |
| 405 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; | 528 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; |
| 406 | 529 |
| 407 return { | 530 return { |
| 408 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old | 531 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old |
| 409 // iframe-based flow is deprecated. | 532 // iframe-based flow is deprecated. |
| 410 GaiaAuthHost: Authenticator | 533 GaiaAuthHost: Authenticator |
| 411 }; | 534 }; |
| 412 }); | 535 }); |
| OLD | NEW |