Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Side by Side Diff: chrome/browser/resources/gaia_auth_host/authenticator.js

Issue 1004753004: cros: Port SAML support to webview sign-in. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: handle loadabort to fix test Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/gaia_auth/saml_injected.js ('k') | chrome/browser/resources/gaia_auth_host/post_message_channel.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698