OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 | 6 * @fileoverview |
7 * A background script of the auth extension that bridges the communication | 7 * A background script of the auth extension that bridges the communication |
8 * between the main and injected scripts. | 8 * between the main and injected scripts. |
9 * | 9 * |
10 * Here is an overview of the communication flow when SAML is being used: | 10 * Here is an overview of the communication flow when SAML is being used: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
51 return this.bridges_[details.tabId].onBeforeSendHeaders(details); | 51 return this.bridges_[details.tabId].onBeforeSendHeaders(details); |
52 else | 52 else |
53 return {requestHeaders: details.requestHeaders}; | 53 return {requestHeaders: details.requestHeaders}; |
54 }.bind(this), | 54 }.bind(this), |
55 {urls: ['*://*/*'], types: ['sub_frame']}, | 55 {urls: ['*://*/*'], types: ['sub_frame']}, |
56 ['blocking', 'requestHeaders']); | 56 ['blocking', 'requestHeaders']); |
57 | 57 |
58 chrome.webRequest.onHeadersReceived.addListener( | 58 chrome.webRequest.onHeadersReceived.addListener( |
59 function(details) { | 59 function(details) { |
60 if (this.bridges_[details.tabId]) | 60 if (this.bridges_[details.tabId]) |
61 this.bridges_[details.tabId].onHeadersReceived(details); | 61 return this.bridges_[details.tabId].onHeadersReceived(details); |
62 }.bind(this), | 62 }.bind(this), |
63 {urls: ['*://*/*'], types: ['sub_frame']}, | 63 {urls: ['*://*/*'], types: ['sub_frame']}, |
64 ['responseHeaders']); | 64 ['blocking', 'responseHeaders']); |
65 | 65 |
66 chrome.webRequest.onCompleted.addListener( | 66 chrome.webRequest.onCompleted.addListener( |
67 function(details) { | 67 function(details) { |
68 if (this.bridges_[details.tabId]) | 68 if (this.bridges_[details.tabId]) |
69 this.bridges_[details.tabId].onCompleted(details); | 69 this.bridges_[details.tabId].onCompleted(details); |
70 }.bind(this), | 70 }.bind(this), |
71 {urls: ['*://*/*'], types: ['sub_frame']}, | 71 {urls: ['*://*/*'], types: ['sub_frame']}, |
72 ['responseHeaders']); | 72 ['responseHeaders']); |
73 }, | 73 }, |
74 | 74 |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
253 onInsecureRequest: function(url) { | 253 onInsecureRequest: function(url) { |
254 if (!this.blockInsecureContent_) | 254 if (!this.blockInsecureContent_) |
255 return {}; | 255 return {}; |
256 this.channelMain_.send({name: 'onInsecureContentBlocked', url: url}); | 256 this.channelMain_.send({name: 'onInsecureContentBlocked', url: url}); |
257 return {cancel: true}; | 257 return {cancel: true}; |
258 }, | 258 }, |
259 | 259 |
260 /** | 260 /** |
261 * Handler or webRequest.onHeadersReceived. It reads the authenticated user | 261 * Handler or webRequest.onHeadersReceived. It reads the authenticated user |
262 * email from google-accounts-signin-header. | 262 * email from google-accounts-signin-header. |
263 * @return {!Object} Modified request headers. | |
263 */ | 264 */ |
264 onHeadersReceived: function(details) { | 265 onHeadersReceived: function(details) { |
265 if (!this.isDesktopFlow_ || | 266 var headers = details.responseHeaders; |
266 !this.gaiaUrl_ || | 267 |
267 details.url.lastIndexOf(this.gaiaUrl_) != 0) { | 268 if (this.isDesktopFlow_ && |
269 this.gaiaUrl_ && | |
270 details.url.lastIndexOf(this.gaiaUrl_) == 0) { | |
268 // TODO(xiyuan, guohui): CrOS should reuse the logic below for reading the | 271 // TODO(xiyuan, guohui): CrOS should reuse the logic below for reading the |
269 // email for SAML users and cut off the /ListAccount call. | 272 // email for SAML users and cut off the /ListAccount call. |
270 return; | 273 for (var i = 0; headers && i < headers.length; ++i) { |
274 if (headers[i].name.toLowerCase() == 'google-accounts-signin') { | |
275 var headerValues = headers[i].value.toLowerCase().split(','); | |
276 var signinDetails = {}; | |
277 headerValues.forEach(function(e) { | |
278 var pair = e.split('='); | |
279 signinDetails[pair[0].trim()] = pair[1].trim(); | |
280 }); | |
281 // Remove "" around. | |
282 this.email_ = signinDetails['email'].slice(1, -1); | |
283 this.sessionIndex_ = signinDetails['sessionindex']; | |
284 break; | |
285 } | |
286 } | |
271 } | 287 } |
272 | 288 |
273 var headers = details.responseHeaders; | 289 if (!this.isDesktopFlow_) { |
274 for (var i = 0; headers && i < headers.length; ++i) { | 290 // Check whether GAIA headers indicating the start or end of a SAML |
275 if (headers[i].name.toLowerCase() == 'google-accounts-signin') { | 291 // redirect are present. If so, synthesize cookies to mark these points. |
276 var headerValues = headers[i].value.toLowerCase().split(','); | 292 for (var i = 0; headers && i < headers.length; ++i) { |
277 var signinDetails = {}; | 293 if (headers[i].name.toLowerCase() == 'google-accounts-saml') { |
278 headerValues.forEach(function(e) { | 294 var action = headers[i].value.toLowerCase(); |
279 var pair = e.split('='); | 295 if (action == 'start') { |
280 signinDetails[pair[0].trim()] = pair[1].trim(); | 296 // GAIA is redirecting to a SAML IdP. Any cookies contained in the |
281 }); | 297 // current |headers| were set by GAIA. Any cookies set in future |
282 // Remove "" around. | 298 // requests will be coming from the IdP. Append a cookie to the |
283 this.email_ = signinDetails['email'].slice(1, -1); | 299 // current |headers| that marks the point at which the redirect |
284 this.sessionIndex_ = signinDetails['sessionindex']; | 300 // occurred. |
285 return; | 301 headers.push({name: 'Set-Cookie', |
302 value: 'google-accounts-saml-start=now'}); | |
303 return {responseHeaders: headers}; | |
304 } else if (action == 'end') { | |
305 // The SAML IdP has redirected back to GAIA. Any cookies contained | |
306 // in the current |headers| were already set by GAIA, not the IdP. A | |
307 // cookie that marks the point at which the redirect occurred must | |
308 // therefore be prepended to the |headers|. | |
309 // | |
310 // Due to limitations in the webRequest API, it is not possible to | |
311 // prepend headers. It is only possible to delete and append headers | |
xiyuan
2014/08/06 21:20:11
It took me a while to understand why we need to do
bartfab (slow)
2014/08/07 11:59:45
Done.
| |
312 // but the same header cannot both be deleted and appended again. To | |
313 // work around this, all headers that set cookies are deleted and | |
314 // then appended again with a trailing semicolon. The trailing | |
315 // semicolon is ignored by Chrome, causing the modified header to | |
316 // actually set exactly the same cookie. | |
317 var otherHeaders = []; | |
318 var cookies = [{name: 'Set-Cookie', | |
319 value: 'google-accounts-saml-end=now'}]; | |
320 for (var j = 0; j < headers.length; ++j) { | |
321 if (headers[j].name.toLowerCase().indexOf('set-cookie') == 0) { | |
322 var header = headers[j]; | |
323 header.value += ';'; | |
324 cookies.push(header); | |
325 } else { | |
326 otherHeaders.push(headers[j]); | |
327 } | |
328 } | |
329 return {responseHeaders: otherHeaders.concat(cookies)}; | |
330 } | |
331 } | |
286 } | 332 } |
287 } | 333 } |
334 | |
335 return {}; | |
288 }, | 336 }, |
289 | 337 |
290 /** | 338 /** |
291 * Handler for webRequest.onBeforeSendHeaders. | 339 * Handler for webRequest.onBeforeSendHeaders. |
292 * @return {!Object} Modified request headers. | 340 * @return {!Object} Modified request headers. |
293 */ | 341 */ |
294 onBeforeSendHeaders: function(details) { | 342 onBeforeSendHeaders: function(details) { |
295 if (!this.isDesktopFlow_ && this.gaiaUrl_ && | 343 if (!this.isDesktopFlow_ && this.gaiaUrl_ && |
296 details.url.indexOf(this.gaiaUrl_) == 0) { | 344 details.url.indexOf(this.gaiaUrl_) == 0) { |
297 details.requestHeaders.push({ | 345 details.requestHeaders.push({ |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
364 }, | 412 }, |
365 | 413 |
366 onPageLoaded_: function(msg) { | 414 onPageLoaded_: function(msg) { |
367 if (this.channelMain_) | 415 if (this.channelMain_) |
368 this.channelMain_.send({name: 'onAuthPageLoaded', url: msg.url}); | 416 this.channelMain_.send({name: 'onAuthPageLoaded', url: msg.url}); |
369 } | 417 } |
370 }; | 418 }; |
371 | 419 |
372 var backgroundBridgeManager = new BackgroundBridgeManager(); | 420 var backgroundBridgeManager = new BackgroundBridgeManager(); |
373 backgroundBridgeManager.run(); | 421 backgroundBridgeManager.run(); |
OLD | NEW |