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

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

Issue 807503004: While trying to enable webview sign-in by default, I found a bunch of issues (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebased Created 6 years 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 /** 5 /**
6 * @fileoverview An UI component to authenciate to Chrome. The component hosts 6 * @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 7 * IdP web pages in a webview. A client who is interested in monitoring
8 * authentication events should pass a listener object of type 8 * authentication events should pass a listener object of type
9 * cr.login.GaiaAuthHost.Listener as defined in this file. After initialization, 9 * cr.login.GaiaAuthHost.Listener as defined in this file. After initialization,
10 * call {@code load} to start the authentication flow. 10 * call {@code load} to start the authentication flow.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 */ 42 */
43 var AuthFlow = { 43 var AuthFlow = {
44 DEFAULT: 0, 44 DEFAULT: 0,
45 SAML: 1 45 SAML: 1
46 }; 46 };
47 47
48 /** 48 /**
49 * Initializes the authenticator component. 49 * Initializes the authenticator component.
50 * @param {webview|string} webview The webview element or its ID to host IdP 50 * @param {webview|string} webview The webview element or its ID to host IdP
51 * web pages. 51 * web pages.
52 * @param {Authenticator.Listener=} opt_listener An optional listener for
53 * authentication events.
54 * @constructor 52 * @constructor
55 * @extends {cr.EventTarget}
56 */ 53 */
57 function Authenticator(webview, opt_listener) { 54 function Authenticator(webview) {
58 this.webview_ = typeof webview == 'string' ? $(webview) : webview; 55 this.webview_ = typeof webview == 'string' ? $(webview) : webview;
59 assert(this.webview_); 56 assert(this.webview_);
60 57
61 this.listener_ = opt_listener || null;
62
63 this.email_ = null; 58 this.email_ = null;
64 this.password_ = null; 59 this.password_ = null;
65 this.gaiaId_ = null, 60 this.gaiaId_ = null,
66 this.sessionIndex_ = null; 61 this.sessionIndex_ = null;
67 this.chooseWhatToSync_ = false; 62 this.chooseWhatToSync_ = false;
68 this.skipForNow_ = false; 63 this.skipForNow_ = false;
69 this.authFlow_ = AuthFlow.DEFAULT; 64 this.authFlow_ = AuthFlow.DEFAULT;
70 this.loaded_ = false; 65 this.loaded_ = false;
71 this.idpOrigin_ = null; 66 this.idpOrigin_ = null;
72 this.continueUrl_ = null; 67 this.continueUrl_ = null;
73 this.continueUrlWithoutParams_ = null; 68 this.continueUrlWithoutParams_ = null;
74 this.initialFrameUrl_ = null; 69 this.initialFrameUrl_ = null;
75 this.reloadUrl_ = null; 70 this.reloadUrl_ = null;
71 this.trusted_ = true;
76 } 72 }
77 73
78 // TODO(guohui,xiyuan): no need to inherit EventTarget once we deprecate the 74 // TODO(guohui,xiyuan): no need to inherit EventTarget once we deprecate the
79 // old event-based signin flow. 75 // old event-based signin flow.
80 Authenticator.prototype = Object.create(cr.EventTarget.prototype); 76 Authenticator.prototype = Object.create(cr.EventTarget.prototype);
81 77
82 /** 78 /**
83 * An interface for receiving notifications upon authentication events.
84 * @interface
85 */
86 Authenticator.Listener = function() {};
87
88 /**
89 * Invoked when authentication UI is ready.
90 */
91 Authenticator.Listener.prototype.onReady = function(e) {};
92
93 /**
94 * Invoked when authentication is completed successfully with credential data.
95 * A credential data object looks like this:
96 * <pre>
97 * {@code
98 * {
99 * email: 'xx@gmail.com',
100 * password: 'xxxx', // May be null or empty.
101 * usingSAML: false,
102 * chooseWhatToSync: false,
103 * skipForNow: false,
104 * sessionIndex: '0'
105 * }
106 * }
107 * </pre>
108 * @param {Object} credentials A credential data object.
109 */
110 Authenticator.Listener.prototype.onSuccess = function(credentials) {};
111
112 /**
113 * Invoked when the requested URL does not fit the container.
114 * @param {string} url Request URL.
115 */
116 Authenticator.Listener.prototype.onResize = function(url) {};
117
118 /**
119 * Invoked when a new window event is fired.
120 * @param {Event} e Event object.
121 */
122 Authenticator.Listener.prototype.onNewWindow = function(e) {};
123
124 /**
125 * Loads the authenticator component with the given parameters. 79 * Loads the authenticator component with the given parameters.
126 * @param {AuthMode} authMode Authorization mode. 80 * @param {AuthMode} authMode Authorization mode.
127 * @param {Object} data Parameters for the authorization flow. 81 * @param {Object} data Parameters for the authorization flow.
128 */ 82 */
129 Authenticator.prototype.load = function(authMode, data) { 83 Authenticator.prototype.load = function(authMode, data) {
130 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN; 84 this.idpOrigin_ = data.gaiaUrl || IDP_ORIGIN;
131 this.continueUrl_ = data.continueUrl || CONTINUE_URL; 85 this.continueUrl_ = data.continueUrl || CONTINUE_URL;
132 this.continueUrlWithoutParams_ = 86 this.continueUrlWithoutParams_ =
133 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) || 87 this.continueUrl_.substring(0, this.continueUrl_.indexOf('?')) ||
134 this.continueUrl_; 88 this.continueUrl_;
135 this.isConstrainedWindow_ = data.constrained == '1'; 89 this.isConstrainedWindow_ = data.constrained == '1';
136 90
137 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data); 91 this.initialFrameUrl_ = this.constructInitialFrameUrl_(data);
138 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_; 92 this.reloadUrl_ = data.frameUrl || this.initialFrameUrl_;
139 this.authFlow_ = AuthFlow.DEFAULT; 93 this.authFlow_ = AuthFlow.DEFAULT;
140 94
141 this.webview_.src = this.reloadUrl_; 95 this.webview_.src = this.reloadUrl_;
142 this.webview_.addEventListener( 96 this.webview_.addEventListener(
143 'newwindow', this.onNewWindow_.bind(this)); 97 'newwindow', this.onNewWindow_.bind(this));
98 this.webview_.addEventListener(
99 'loadstop', this.onLoadStop_.bind(this));
144 this.webview_.request.onCompleted.addListener( 100 this.webview_.request.onCompleted.addListener(
145 this.onRequestCompleted_.bind(this), 101 this.onRequestCompleted_.bind(this),
146 {urls: ['*://*/*', this.continueUrlWithoutParams_ + '*'], 102 {urls: ['*://*/*', this.continueUrlWithoutParams_ + '*'],
147 types: ['main_frame']}, 103 types: ['main_frame']},
148 ['responseHeaders']); 104 ['responseHeaders']);
149 this.webview_.request.onHeadersReceived.addListener( 105 this.webview_.request.onHeadersReceived.addListener(
150 this.onHeadersReceived_.bind(this), 106 this.onHeadersReceived_.bind(this),
151 {urls: [this.idpOrigin_ + '*'], types: ['main_frame']}, 107 {urls: [this.idpOrigin_ + '*'], types: ['main_frame']},
152 ['responseHeaders']); 108 ['responseHeaders']);
153 window.addEventListener( 109 window.addEventListener(
(...skipping 21 matching lines...) Expand all
175 url = appendParam(url, 'source', CONSTRAINED_FLOW_SOURCE); 131 url = appendParam(url, 'source', CONSTRAINED_FLOW_SOURCE);
176 return url; 132 return url;
177 }; 133 };
178 134
179 /** 135 /**
180 * Invoked when a main frame request in the webview has completed. 136 * Invoked when a main frame request in the webview has completed.
181 * @private 137 * @private
182 */ 138 */
183 Authenticator.prototype.onRequestCompleted_ = function(details) { 139 Authenticator.prototype.onRequestCompleted_ = function(details) {
184 var currentUrl = details.url; 140 var currentUrl = details.url;
141 if (currentUrl.indexOf('https') != 0) {
142 this.trusted_ = false;
noms (inactive) 2014/12/19 19:48:59 nit: no {}
Roger Tawa OOO till Jul 10th 2014/12/19 22:23:59 The convention in this file is to include { } in t
143 }
144
185 if (currentUrl.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) { 145 if (currentUrl.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) {
186 if (currentUrl.indexOf('ntp=1') >= 0) { 146 if (currentUrl.indexOf('ntp=1') >= 0) {
187 this.skipForNow_ = true; 147 this.skipForNow_ = true;
188 } 148 }
189 this.onAuthCompleted_(); 149 this.onAuthCompleted_();
190 return; 150 return;
191 } 151 }
192 152
193 if (this.isConstrainedWindow_) { 153 if (this.isConstrainedWindow_) {
194 var isEmbeddedPage = false; 154 var isEmbeddedPage = false;
195 if (this.idpOrigin_ && currentUrl.lastIndexOf(this.idpOrigin_) == 0) { 155 if (this.idpOrigin_ && currentUrl.lastIndexOf(this.idpOrigin_) == 0) {
196 var headers = details.responseHeaders; 156 var headers = details.responseHeaders;
197 for (var i = 0; headers && i < headers.length; ++i) { 157 for (var i = 0; headers && i < headers.length; ++i) {
198 if (headers[i].name.toLowerCase() == EMBEDDED_FORM_HEADER) { 158 if (headers[i].name.toLowerCase() == EMBEDDED_FORM_HEADER) {
199 isEmbeddedPage = true; 159 isEmbeddedPage = true;
200 break; 160 break;
201 } 161 }
202 } 162 }
203 } 163 }
204 if (!isEmbeddedPage && this.listener_) { 164 if (!isEmbeddedPage) {
205 this.listener_.onResize(currentUrl); 165 this.dispatchEvent(new CustomEvent('resize', {detail: currentUrl}));
206 return; 166 return;
207 } 167 }
208 } 168 }
209 169
210 if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) { 170 if (currentUrl.lastIndexOf(this.idpOrigin_) == 0) {
211 this.webview_.contentWindow.postMessage({}, currentUrl); 171 this.webview_.contentWindow.postMessage({}, currentUrl);
212 } 172 }
213
214 if (!this.loaded_) {
215 this.loaded_ = true;
216 if (this.listener_) {
217 this.listener_.onReady();
218 }
219 }
220 }; 173 };
221 174
222 /** 175 /**
223 * Invoked when headers are received in the main frame of the webview. It 176 * Invoked when headers are received in the main frame of the webview. It
224 * 1) reads the authenticated user info from a signin header, 177 * 1) reads the authenticated user info from a signin header,
225 * 2) signals the start of a saml flow upon receiving a saml header. 178 * 2) signals the start of a saml flow upon receiving a saml header.
226 * @return {!Object} Modified request headers. 179 * @return {!Object} Modified request headers.
227 * @private 180 * @private
228 */ 181 */
229 Authenticator.prototype.onHeadersReceived_ = function(details) { 182 Authenticator.prototype.onHeadersReceived_ = function(details) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 this.password_ = msg.password; 223 this.password_ = msg.password;
271 this.chooseWhatToSync_ = msg.chooseWhatToSync; 224 this.chooseWhatToSync_ = msg.chooseWhatToSync;
272 } 225 }
273 }; 226 };
274 227
275 /** 228 /**
276 * Invoked to process authentication completion. 229 * Invoked to process authentication completion.
277 * @private 230 * @private
278 */ 231 */
279 Authenticator.prototype.onAuthCompleted_ = function() { 232 Authenticator.prototype.onAuthCompleted_ = function() {
280 if (!this.listener_) {
281 return;
282 }
283
284 if (!this.email_ && !this.skipForNow_) { 233 if (!this.email_ && !this.skipForNow_) {
285 this.webview_.src = this.initialFrameUrl_; 234 this.webview_.src = this.initialFrameUrl_;
286 return; 235 return;
287 } 236 }
288 237
289 this.listener_.onSuccess({email: this.email_, 238 this.dispatchEvent(
290 gaiaId: this.gaiaId_, 239 new CustomEvent('authCompleted',
291 password: this.password_, 240 {detail: {email: this.email_,
292 usingSAML: this.authFlow_ == AuthFlow.SAML, 241 gaiaId: this.gaiaId_,
293 chooseWhatToSync: this.chooseWhatToSync_, 242 password: this.password_,
294 skipForNow: this.skipForNow_, 243 usingSAML: this.authFlow_ == AuthFlow.SAML,
295 sessionIndex: this.sessionIndex_ || ''}); 244 chooseWhatToSync: this.chooseWhatToSync_,
245 skipForNow: this.skipForNow_,
246 sessionIndex: this.sessionIndex_ || '',
247 trusted: this.trusted_}}));
296 }; 248 };
297 249
298 /** 250 /**
299 * Invoked when the webview attempts to open a new window. 251 * Invoked when the webview attempts to open a new window.
300 * @private 252 * @private
301 */ 253 */
302 Authenticator.prototype.onNewWindow_ = function(e) { 254 Authenticator.prototype.onNewWindow_ = function(e) {
303 if (!this.listener_) { 255 this.dispatchEvent(new CustomEvent('newWindow', {detail: e}));
304 return; 256 };
257
258 /**
259 * Invoked when the webview finishes loading a page.
260 * @private
261 */
262 Authenticator.prototype.onLoadStop_ = function(e) {
263 if (!this.loaded_) {
264 this.loaded_ = true;
265 this.dispatchEvent(new Event('ready'));
305 } 266 }
306
307 this.listener_.onNewWindow(e);
308 }; 267 };
309 268
310 Authenticator.AuthFlow = AuthFlow; 269 Authenticator.AuthFlow = AuthFlow;
311 Authenticator.AuthMode = AuthMode; 270 Authenticator.AuthMode = AuthMode;
312 271
313 return { 272 return {
314 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old 273 // TODO(guohui, xiyuan): Rename GaiaAuthHost to Authenticator once the old
315 // iframe-based flow is deprecated. 274 // iframe-based flow is deprecated.
316 GaiaAuthHost: Authenticator 275 GaiaAuthHost: Authenticator
317 }; 276 };
318 }); 277 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698