Chromium Code Reviews| 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 |