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

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

Issue 1138143002: Pass Device ID in the oauth2/token request. Keep Device ID in local state on Chrome OS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Final version. Created 5 years, 7 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"> 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 11 matching lines...) Expand all
22 var IDP_PATH = 'ServiceLogin?skipvpage=true&sarp=1&rm=hide'; 22 var IDP_PATH = 'ServiceLogin?skipvpage=true&sarp=1&rm=hide';
23 var CONTINUE_URL = 23 var CONTINUE_URL =
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 SET_COOKIE_HEADER = 'set-cookie'; 28 var SET_COOKIE_HEADER = 'set-cookie';
29 var OAUTH_CODE_COOKIE = 'oauth_code'; 29 var OAUTH_CODE_COOKIE = 'oauth_code';
30 var SERVICE_ID = 'chromeoslogin'; 30 var SERVICE_ID = 'chromeoslogin';
31 var EMBEDDED_SETUP_CHROMEOS_ENDPOINT = 'embedded/setup/chromeos'; 31 var EMBEDDED_SETUP_CHROMEOS_ENDPOINT = 'embedded/setup/chromeos';
32 var X_DEVICE_ID_HEADER = 'X-Device-ID';
33 var EPHEMERAL_DEVICE_ID_PREFIX = 't_';
34 32
35 /** 33 /**
36 * The source URL parameter for the constrained signin flow. 34 * The source URL parameter for the constrained signin flow.
37 */ 35 */
38 var CONSTRAINED_FLOW_SOURCE = 'chrome'; 36 var CONSTRAINED_FLOW_SOURCE = 'chrome';
39 37
40 /** 38 /**
41 * Enum for the authorization mode, must match AuthMode defined in 39 * Enum for the authorization mode, must match AuthMode defined in
42 * chrome/browser/ui/webui/inline_login_ui.cc. 40 * chrome/browser/ui/webui/inline_login_ui.cc.
43 * @enum {number} 41 * @enum {number}
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
78 'clientId', // Chrome client id. 76 'clientId', // Chrome client id.
79 'useEafe', // Whether to use EAFE. 77 'useEafe', // Whether to use EAFE.
80 'needPassword', // Whether the host is interested in getting a password. 78 'needPassword', // Whether the host is interested in getting a password.
81 // If this set to |false|, |confirmPasswordCallback| is 79 // If this set to |false|, |confirmPasswordCallback| is
82 // not called before dispatching |authCopleted|. 80 // not called before dispatching |authCopleted|.
83 // Default is |true|. 81 // Default is |true|.
84 'flow', // One of 'default', 'enterprise', or 'theftprotection'. 82 'flow', // One of 'default', 'enterprise', or 'theftprotection'.
85 'enterpriseDomain', // Domain in which hosting device is (or should be) 83 'enterpriseDomain', // Domain in which hosting device is (or should be)
86 // enrolled. 84 // enrolled.
87 'emailDomain', // Value used to prefill domain for email. 85 'emailDomain', // Value used to prefill domain for email.
88 'deviceId', // User device ID (sync Id).
89 'sessionIsEphemeral', // User session would be ephemeral.
90 'clientVersion', // Version of the Chrome build. 86 'clientVersion', // Version of the Chrome build.
91 'platformVersion', // Version of the OS build. 87 'platformVersion', // Version of the OS build.
92 'releaseChannel', // Installation channel. 88 'releaseChannel', // Installation channel.
93 'endpointGen', // Current endpoint generation. 89 'endpointGen', // Current endpoint generation.
94 ]; 90 ];
95 91
96 /** 92 /**
97 * Initializes the authenticator component. 93 * Initializes the authenticator component.
98 * @param {webview|string} webview The webview element or its ID to host IdP 94 * @param {webview|string} webview The webview element or its ID to host IdP
99 * web pages. 95 * web pages.
(...skipping 12 matching lines...) Expand all
112 this.authFlow = AuthFlow.DEFAULT; 108 this.authFlow = AuthFlow.DEFAULT;
113 this.authDomain = ''; 109 this.authDomain = '';
114 this.loaded_ = false; 110 this.loaded_ = false;
115 this.idpOrigin_ = null; 111 this.idpOrigin_ = null;
116 this.continueUrl_ = null; 112 this.continueUrl_ = null;
117 this.continueUrlWithoutParams_ = null; 113 this.continueUrlWithoutParams_ = null;
118 this.initialFrameUrl_ = null; 114 this.initialFrameUrl_ = null;
119 this.reloadUrl_ = null; 115 this.reloadUrl_ = null;
120 this.trusted_ = true; 116 this.trusted_ = true;
121 this.oauth_code_ = null; 117 this.oauth_code_ = null;
122 this.deviceId_ = null;
123 this.sessionIsEphemeral_ = null;
124 this.onBeforeSetHeadersSet_ = false;
125 118
126 this.useEafe_ = false; 119 this.useEafe_ = false;
127 this.clientId_ = null; 120 this.clientId_ = null;
128 121
129 this.samlHandler_ = new cr.login.SamlHandler(this.webview_); 122 this.samlHandler_ = new cr.login.SamlHandler(this.webview_);
130 this.confirmPasswordCallback = null; 123 this.confirmPasswordCallback = null;
131 this.noPasswordCallback = null; 124 this.noPasswordCallback = null;
132 this.insecureContentBlockedCallback = null; 125 this.insecureContentBlockedCallback = null;
133 this.samlApiUsedCallback = null; 126 this.samlApiUsedCallback = null;
134 this.missingGaiaInfoCallback = null; 127 this.missingGaiaInfoCallback = null;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
209 // Don't block insecure content for desktop flow because it lands on 202 // Don't block insecure content for desktop flow because it lands on
210 // http. Otherwise, block insecure content as long as gaia is https. 203 // http. Otherwise, block insecure content as long as gaia is https.
211 this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP && 204 this.samlHandler_.blockInsecureContent = authMode != AuthMode.DESKTOP &&
212 this.idpOrigin_.indexOf('https://') == 0; 205 this.idpOrigin_.indexOf('https://') == 0;
213 this.needPassword = !('needPassword' in data) || data.needPassword; 206 this.needPassword = !('needPassword' in data) || data.needPassword;
214 207
215 if (this.isNewGaiaFlowChromeOS) { 208 if (this.isNewGaiaFlowChromeOS) {
216 this.webview_.contextMenus.onShow.addListener(function(e) { 209 this.webview_.contextMenus.onShow.addListener(function(e) {
217 e.preventDefault(); 210 e.preventDefault();
218 }); 211 });
219 if (!this.onBeforeSetHeadersSet_) {
220 this.onBeforeSetHeadersSet_ = true;
221 var filterPrefix = this.idpOrigin_ + EMBEDDED_SETUP_CHROMEOS_ENDPOINT;
222 this.webview_.request.onBeforeSendHeaders.addListener(
223 this.onBeforeSendHeaders_.bind(this),
224 {urls: [filterPrefix + '?*', filterPrefix + '/*']},
225 ['requestHeaders', 'blocking']);
226 }
227 } 212 }
228 213
229 this.webview_.src = this.reloadUrl_; 214 this.webview_.src = this.reloadUrl_;
230 }; 215 };
231 216
232 /** 217 /**
233 * Reloads the authenticator component. 218 * Reloads the authenticator component.
234 */ 219 */
235 Authenticator.prototype.reload = function() { 220 Authenticator.prototype.reload = function() {
236 this.clearCredentials_(); 221 this.clearCredentials_();
(...skipping 17 matching lines...) Expand all
254 if (data.enterpriseDomain) 239 if (data.enterpriseDomain)
255 url = appendParam(url, 'manageddomain', data.enterpriseDomain); 240 url = appendParam(url, 'manageddomain', data.enterpriseDomain);
256 if (data.clientVersion) 241 if (data.clientVersion)
257 url = appendParam(url, 'client_version', data.clientVersion); 242 url = appendParam(url, 'client_version', data.clientVersion);
258 if (data.platformVersion) 243 if (data.platformVersion)
259 url = appendParam(url, 'platform_version', data.platformVersion); 244 url = appendParam(url, 'platform_version', data.platformVersion);
260 if (data.releaseChannel) 245 if (data.releaseChannel)
261 url = appendParam(url, 'release_channel', data.releaseChannel); 246 url = appendParam(url, 'release_channel', data.releaseChannel);
262 if (data.endpointGen) 247 if (data.endpointGen)
263 url = appendParam(url, 'endpoint_gen', data.endpointGen); 248 url = appendParam(url, 'endpoint_gen', data.endpointGen);
264 this.deviceId_ = data.deviceId;
265 this.sessionIsEphemeral_ = data.sessionIsEphemeral;
266 } else { 249 } else {
267 url = appendParam(url, 'continue', this.continueUrl_); 250 url = appendParam(url, 'continue', this.continueUrl_);
268 url = appendParam(url, 'service', data.service || SERVICE_ID); 251 url = appendParam(url, 'service', data.service || SERVICE_ID);
269 } 252 }
270 if (data.hl) 253 if (data.hl)
271 url = appendParam(url, 'hl', data.hl); 254 url = appendParam(url, 'hl', data.hl);
272 if (data.gaiaId) 255 if (data.gaiaId)
273 url = appendParam(url, 'user_id', data.gaiaId); 256 url = appendParam(url, 'user_id', data.gaiaId);
274 if (data.email) 257 if (data.email)
275 url = appendParam(url, 'Email', data.email); 258 url = appendParam(url, 'Email', data.email);
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
390 var headerValue = header.value; 373 var headerValue = header.value;
391 if (headerValue.indexOf(OAUTH_CODE_COOKIE + '=', 0) == 0) { 374 if (headerValue.indexOf(OAUTH_CODE_COOKIE + '=', 0) == 0) {
392 this.oauth_code_ = 375 this.oauth_code_ =
393 headerValue.substring(OAUTH_CODE_COOKIE.length + 1).split(';')[0]; 376 headerValue.substring(OAUTH_CODE_COOKIE.length + 1).split(';')[0];
394 } 377 }
395 } 378 }
396 } 379 }
397 }; 380 };
398 381
399 /** 382 /**
400 * Handler for webView.request.onBeforeSendHeaders .
401 * @return {!Object} Modified request headers.
402 * @private
403 */
404 Authenticator.prototype.onBeforeSendHeaders_ = function(details) {
405 // deviceId_ is empty when we do not need to send it. For example,
406 // in case of device enrollment.
407 if (this.isNewGaiaFlowChromeOS && this.deviceId_) {
408 var headers = details.requestHeaders;
409 var found = false;
410 var deviceId = this.getGAIADeviceId_();
411
412 for (var i = 0, l = headers.length; i < l; ++i) {
413 if (headers[i].name == X_DEVICE_ID_HEADER) {
414 headers[i].value = deviceId;
415 found = true;
416 break;
417 }
418 }
419 if (!found) {
420 details.requestHeaders.push(
421 {name: X_DEVICE_ID_HEADER, value: deviceId});
422 }
423 }
424 return {
425 requestHeaders: details.requestHeaders
426 };
427 };
428
429 /**
430 * Returns true if given HTML5 message is received from the webview element. 383 * Returns true if given HTML5 message is received from the webview element.
431 * @param {object} e Payload of the received HTML5 message. 384 * @param {object} e Payload of the received HTML5 message.
432 */ 385 */
433 Authenticator.prototype.isGaiaMessage = function(e) { 386 Authenticator.prototype.isGaiaMessage = function(e) {
434 if (!this.isWebviewEvent_(e)) 387 if (!this.isWebviewEvent_(e))
435 return false; 388 return false;
436 389
437 // The event origin does not have a trailing slash. 390 // The event origin does not have a trailing slash.
438 if (e.origin != this.idpOrigin_.substring(0, this.idpOrigin_.length - 1)) { 391 if (e.origin != this.idpOrigin_.substring(0, this.idpOrigin_.length - 1)) {
439 return false; 392 return false;
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
575 { 528 {
576 detail: { 529 detail: {
577 email: this.email_ || '', 530 email: this.email_ || '',
578 gaiaId: this.gaiaId_ || '', 531 gaiaId: this.gaiaId_ || '',
579 password: this.password_ || '', 532 password: this.password_ || '',
580 authCode: this.oauth_code_, 533 authCode: this.oauth_code_,
581 usingSAML: this.authFlow == AuthFlow.SAML, 534 usingSAML: this.authFlow == AuthFlow.SAML,
582 chooseWhatToSync: this.chooseWhatToSync_, 535 chooseWhatToSync: this.chooseWhatToSync_,
583 skipForNow: this.skipForNow_, 536 skipForNow: this.skipForNow_,
584 sessionIndex: this.sessionIndex_ || '', 537 sessionIndex: this.sessionIndex_ || '',
585 trusted: this.trusted_, 538 trusted: this.trusted_
586 deviceId: this.deviceId_ || ''
587 } 539 }
588 })); 540 }));
589 this.clearCredentials_(); 541 this.clearCredentials_();
590 }; 542 };
591 543
592 /** 544 /**
593 * Invoked when |samlHandler_| fires 'insecureContentBlocked' event. 545 * Invoked when |samlHandler_| fires 'insecureContentBlocked' event.
594 * @private 546 * @private
595 */ 547 */
596 Authenticator.prototype.onInsecureContentBlocked_ = function(e) { 548 Authenticator.prototype.onInsecureContentBlocked_ = function(e) {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
640 // mode, and then set it to 100% zoom. 592 // mode, and then set it to 100% zoom.
641 this.webview_.setZoomMode('per-view'); 593 this.webview_.setZoomMode('per-view');
642 this.webview_.setZoom(1); 594 this.webview_.setZoom(1);
643 } 595 }
644 596
645 // Posts a message to IdP pages to initiate communication. 597 // Posts a message to IdP pages to initiate communication.
646 var currentUrl = this.webview_.src; 598 var currentUrl = this.webview_.src;
647 if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) { 599 if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) {
648 var msg = { 600 var msg = {
649 'method': 'handshake', 601 'method': 'handshake',
650 'deviceId': this.getGAIADeviceId_(),
651 }; 602 };
652 603
653 this.webview_.contentWindow.postMessage(msg, currentUrl); 604 this.webview_.contentWindow.postMessage(msg, currentUrl);
654 } 605 }
655 }; 606 };
656 607
657 /** 608 /**
658 * Invoked when the webview fails loading a page. 609 * Invoked when the webview fails loading a page.
659 * @private 610 * @private
660 */ 611 */
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
709 */ 660 */
710 Authenticator.prototype.isWebviewEvent_ = function(e) { 661 Authenticator.prototype.isWebviewEvent_ = function(e) {
711 // Note: <webview> prints error message to console if |contentWindow| is not 662 // Note: <webview> prints error message to console if |contentWindow| is not
712 // defined. 663 // defined.
713 // TODO(dzhioev): remove the message. http://crbug.com/469522 664 // TODO(dzhioev): remove the message. http://crbug.com/469522
714 var webviewWindow = this.webview_.contentWindow; 665 var webviewWindow = this.webview_.contentWindow;
715 return !!webviewWindow && webviewWindow === e.source; 666 return !!webviewWindow && webviewWindow === e.source;
716 }; 667 };
717 668
718 /** 669 /**
719 * Format deviceId for GAIA .
720 * @return {string} deviceId.
721 * @private
722 */
723 Authenticator.prototype.getGAIADeviceId_ = function() {
724 // deviceId_ is empty when we do not need to send it. For example,
725 // in case of device enrollment.
726 if (!(this.isNewGaiaFlowChromeOS && this.deviceId_))
727 return;
728
729 if (this.sessionIsEphemeral_)
730 return EPHEMERAL_DEVICE_ID_PREFIX + this.deviceId_;
731 else
732 return this.deviceId_;
733 };
734
735 /**
736 * Informs Gaia of new deviceId to be used.
737 */
738 Authenticator.prototype.updateDeviceId = function(deviceId) {
739 this.deviceId_ = deviceId;
740 var msg = {
741 'method': 'updateDeviceId',
742 'deviceId': this.getGAIADeviceId_(),
743 };
744
745 var currentUrl = this.webview_.src;
746 this.webview_.contentWindow.postMessage(msg, currentUrl);
747 };
748
749 /**
750 * The current auth flow of the hosted auth page. 670 * The current auth flow of the hosted auth page.
751 * @type {AuthFlow} 671 * @type {AuthFlow}
752 */ 672 */
753 cr.defineProperty(Authenticator, 'authFlow'); 673 cr.defineProperty(Authenticator, 'authFlow');
754 674
755 /** 675 /**
756 * The domain name of the current auth page. 676 * The domain name of the current auth page.
757 * @type {string} 677 * @type {string}
758 */ 678 */
759 cr.defineProperty(Authenticator, 'authDomain'); 679 cr.defineProperty(Authenticator, 'authDomain');
760 680
761 Authenticator.AuthFlow = AuthFlow; 681 Authenticator.AuthFlow = AuthFlow;
762 Authenticator.AuthMode = AuthMode; 682 Authenticator.AuthMode = AuthMode;
763 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS; 683 Authenticator.SUPPORTED_PARAMS = SUPPORTED_PARAMS;
764 684
765 return { 685 return {
766 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old 686 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old
767 // iframe-based flow is deprecated. 687 // iframe-based flow is deprecated.
768 GaiaAuthHost: Authenticator, 688 GaiaAuthHost: Authenticator,
769 Authenticator: Authenticator 689 Authenticator: Authenticator
770 }; 690 };
771 }); 691 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698