summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorguohui@chromium.org <guohui@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-20 02:15:04 +0000
committerguohui@chromium.org <guohui@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-20 02:15:04 +0000
commit20686e053f5e0fcf70913d042cbf9fa99ca8ce92 (patch)
treea20bf0760a7dbef854be539c7dda44e20b84bfc7
parente21d83397eb9fd0e4bd833fd8d4615c36a97d2e0 (diff)
downloadchromium_src-20686e053f5e0fcf70913d042cbf9fa99ca8ce92.zip
chromium_src-20686e053f5e0fcf70913d042cbf9fa99ca8ce92.tar.gz
chromium_src-20686e053f5e0fcf70913d042cbf9fa99ca8ce92.tar.bz2
Revert 251503 "Implement inline signin with iframe"
> Implement inline signin with iframe > > =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= > This is a dup of https://codereview.chromium.org/130963006/ since I cannot > upload to that issue. The only change is to address Xiyuan's two comments > in patchset 3 of that CL. > =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+= > > Inline signin chrome://chrome-signin is currently implemented using webview embedded in webUI, which breaks a couple of features in webUI and has serious accessbility issues. Since webview will be reimplemented based on OOPIF in the near future, and all the issues we have today will no longer apply, thus it is not worth the effort to fix them as they are throw away work. Instead, as suggested by John and prototyped in https://codereview.chromium.org/141363006/, we decide to switch to iframe instead. A few issues worth to mention, > > 1. The iframe shares the same renderer as the embedder webUI, and thus could be potentially exposed to dangerous webUI privileges. John suggested a fix by assigning a unique storage partition ID to the inline signin page. As a result the inline signin and its embedded web content should never share the same renderer with other webUI pages. > > 2. webview provides a direct API to inject script and to monitor requests/responses, which is not (directly) available with iframe. The CL works around the issue using content script and background script, quite similar to what CrOS is doing for SAML flow today. Thus it is also the first step towards unifying SAML flows on CrOS and desktop. > > 3. with webview approach, we used to have a unique temporary partition for each instance of inline signin, in order to make sure multiple instances do not interfere with each other. This is more difficult with the iframe approach, since the partition ID is hardcoded in a quite low layer. In this CL, all inline signin pages share the same persistent partition, which means we have to handle the case when user loads the sign in page with a dirty cookie jar, and thus the newly connected user may not be stored in the primary session. The CL solves the issue by reading 'session_index' from 'google-accounts-signin' header. > > BUG=338127 > > Review URL: https://codereview.chromium.org/134263005 TBR=rogerta@chromium.org Review URL: https://codereview.chromium.org/173193005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@252159 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/browser_resources.grd2
-rw-r--r--chrome/browser/chrome_content_browser_client.cc4
-rw-r--r--chrome/browser/extensions/signin/gaia_auth_extension_loader.cc2
-rw-r--r--chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc9
-rw-r--r--chrome/browser/resources/component_extension_resources.grd3
-rw-r--r--chrome/browser/resources/gaia_auth/background.js155
-rw-r--r--chrome/browser/resources/gaia_auth/inline_injected.js (renamed from chrome/browser/resources/gaia_auth/desktop_injected.js)22
-rw-r--r--chrome/browser/resources/gaia_auth/inline_main.html13
-rw-r--r--chrome/browser/resources/gaia_auth/main.js205
-rw-r--r--chrome/browser/resources/gaia_auth/manifest_inline.json (renamed from chrome/browser/resources/gaia_auth/manifest_desktop.json)32
-rw-r--r--chrome/browser/resources/gaia_auth_host/gaia_auth_host.js67
-rw-r--r--chrome/browser/resources/inline_login/inline_login.js5
-rw-r--r--chrome/browser/ui/webui/signin/inline_login_handler.h2
-rw-r--r--chrome/browser/ui/webui/signin/inline_login_handler_impl.cc31
-rw-r--r--chrome/browser/ui/webui/signin/inline_login_handler_impl.h3
-rw-r--r--chrome/browser/ui/webui/signin/inline_login_ui.cc5
-rw-r--r--chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc163
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--content/browser/webui/url_data_manager_backend.cc52
19 files changed, 283 insertions, 493 deletions
diff --git a/chrome/browser/browser_resources.grd b/chrome/browser/browser_resources.grd
index 9fc5e87..35683a5 100644
--- a/chrome/browser/browser_resources.grd
+++ b/chrome/browser/browser_resources.grd
@@ -296,7 +296,7 @@
<include name="IDR_GAIA_AUTH_MANIFEST" file="resources\gaia_auth\manifest.json" type="BINDATA" />
<include name="IDR_GAIA_AUTH_KEYBOARD_MANIFEST" file="resources\gaia_auth\manifest_keyboard.json" type="BINDATA" />
<include name="IDR_GAIA_AUTH_SAML_MANIFEST" file="resources\gaia_auth\manifest_saml.json" type="BINDATA" />
- <include name="IDR_GAIA_AUTH_DESKTOP_MANIFEST" file="resources\gaia_auth\manifest_desktop.json" type="BINDATA" />
+ <include name="IDR_GAIA_AUTH_INLINE_MANIFEST" file="resources\gaia_auth\manifest_inline.json" type="BINDATA" />
<if expr="chromeos">
<include name="IDR_BACKLOADER_MANIFEST" file="resources\backloader\manifest.json" type="BINDATA" />
<include name="IDR_CHOOSE_MOBILE_NETWORK_HTML" file="resources\chromeos\choose_mobile_network.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index b4533cf..3fe2b78 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -808,10 +808,6 @@ void ChromeContentBrowserClient::GetStoragePartitionConfigForSite(
*in_memory = false;
partition_name->clear();
}
- } else if (site.GetOrigin().spec() == kChromeUIChromeSigninURL) {
- // Chrome signin page has an embedded iframe of extension and web content,
- // thus it must be isolated from other webUI pages.
- *partition_domain = chrome::kChromeUIChromeSigninHost;
}
// Assert that if |can_be_default| is false, the code above must have found a
diff --git a/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc b/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc
index 627d2b3..ab44f50 100644
--- a/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc
+++ b/chrome/browser/extensions/signin/gaia_auth_extension_loader.cc
@@ -68,7 +68,7 @@ void LoadGaiaAuthExtension(Profile* profile) {
manifest_resource_id = IDR_GAIA_AUTH_SAML_MANIFEST;
}
#else
- int manifest_resource_id = IDR_GAIA_AUTH_DESKTOP_MANIFEST;
+ int manifest_resource_id = IDR_GAIA_AUTH_INLINE_MANIFEST;
#endif
component_loader->Add(manifest_resource_id,
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
index 71b1e44..f439c42 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc
@@ -38,7 +38,6 @@
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/mime_types_handler.h"
#include "chrome/common/render_messages.h"
-#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_process_host.h"
@@ -635,14 +634,6 @@ void ChromeResourceDispatcherHostDelegate::OnResponseStarted(
}
}
- // Ignores x-frame-options for the chrome signin UI.
- if (request->first_party_for_cookies().GetOrigin().spec() ==
- chrome::kChromeUIChromeSigninURL) {
- net::HttpResponseHeaders* response_headers = request->response_headers();
- if (response_headers->HasHeader("x-frame-options"))
- response_headers->RemoveHeader("x-frame-options");
- }
-
prerender::URLRequestResponseStarted(request);
}
diff --git a/chrome/browser/resources/component_extension_resources.grd b/chrome/browser/resources/component_extension_resources.grd
index b390f24..a98ba06 100644
--- a/chrome/browser/resources/component_extension_resources.grd
+++ b/chrome/browser/resources/component_extension_resources.grd
@@ -61,7 +61,8 @@
<include name="IDR_GAIA_AUTH_BACKGROUND_JS" file="gaia_auth/background.js" type="BINDATA" />
<include name="IDR_GAIA_AUTH_SAML_INJECTED_JS" file="gaia_auth/saml_injected.js" type="BINDATA" />
<include name="IDR_GAIA_AUTH_CHANNEL_JS" file="gaia_auth/channel.js" type="BINDATA" />
- <include name="IDR_GAIA_AUTH_DESKTOP_INJECTED_JS" file="gaia_auth/desktop_injected.js" type="BINDATA" />
+ <include name="IDR_GAIA_AUTH_INLINE_INJECTED_JS" file="gaia_auth/inline_injected.js" type="BINDATA" />
+ <include name="IDR_GAIA_AUTH_INLINE_MAIN" file="gaia_auth/inline_main.html" allowexternalscript="true" type="BINDATA" />
<!-- Hangout Services extension, included in Google Chrome builds only. -->
<if expr="_google_chrome or enable_hangout_services_extension">
<include name="IDR_HANGOUT_SERVICES_BACKGROUND_HTML" file="hangout_services/background.html" type="BINDATA" />
diff --git a/chrome/browser/resources/gaia_auth/background.js b/chrome/browser/resources/gaia_auth/background.js
index dcbeb0c..a571c10 100644
--- a/chrome/browser/resources/gaia_auth/background.js
+++ b/chrome/browser/resources/gaia_auth/background.js
@@ -32,21 +32,6 @@ function BackgroundBridge() {
}
BackgroundBridge.prototype = {
- // Continue URL that is set from main auth script.
- continueUrl_: null,
-
- // Whether the extension is loaded in a constrained window.
- // Set from main auth script.
- isConstrainedWindow_: null,
-
- // Email of the newly authenticated user based on the gaia response header
- // 'google-accounts-signin'.
- email_: null,
-
- // Session index of the newly authenticated user based on the gaia response
- // header 'google-accounts-signin'.
- sessionIndex_: null,
-
// Gaia URL base that is set from main auth script.
gaiaUrl_: null,
@@ -56,8 +41,8 @@ BackgroundBridge.prototype = {
passwordStore_: {},
- channelMain_: {},
- channelInjected_: {},
+ channelMain_: null,
+ channelInjected_: null,
run: function() {
chrome.runtime.onConnect.addListener(this.onConnect_.bind(this));
@@ -94,129 +79,31 @@ BackgroundBridge.prototype = {
* Sets up the communication channel with the main script.
*/
setupForAuthMain_: function(port) {
- var currentChannel = new Channel();
- currentChannel.init(port);
-
- // Registers for desktop related messages.
- currentChannel.registerMessage(
- 'initDesktopFlow', this.onInitDesktopFlow_.bind(this));
-
- // Registers for SAML related messages.
- currentChannel.registerMessage(
+ this.channelMain_ = new Channel();
+ this.channelMain_.init(port);
+ this.channelMain_.registerMessage(
'setGaiaUrl', this.onSetGaiaUrl_.bind(this));
- currentChannel.registerMessage(
+ this.channelMain_.registerMessage(
'resetAuth', this.onResetAuth_.bind(this));
- currentChannel.registerMessage(
+ this.channelMain_.registerMessage(
'startAuth', this.onAuthStarted_.bind(this));
- currentChannel.registerMessage(
+ this.channelMain_.registerMessage(
'getScrapedPasswords',
this.onGetScrapedPasswords_.bind(this));
-
- this.channelMain_[this.getTabIdFromPort_(port)] = currentChannel;
-
},
/**
* Sets up the communication channel with the injected script.
*/
setupForInjected_: function(port) {
- var currentChannel = new Channel();
- currentChannel.init(port);
-
- var tabId = this.getTabIdFromPort_(port);
- currentChannel.registerMessage(
- 'apiCall', this.onAPICall_.bind(this, tabId));
- currentChannel.registerMessage(
+ this.channelInjected_ = new Channel();
+ this.channelInjected_.init(port);
+ this.channelInjected_.registerMessage(
+ 'apiCall', this.onAPICall_.bind(this));
+ this.channelInjected_.registerMessage(
'updatePassword', this.onUpdatePassword_.bind(this));
- currentChannel.registerMessage(
- 'pageLoaded', this.onPageLoaded_.bind(this, tabId));
-
- this.channelInjected_[this.getTabIdFromPort_(port)] = currentChannel;
- },
-
- getTabIdFromPort_: function(port) {
- return port.sender.tab ? port.sender.tab.id : -1;
- },
-
- /**
- * Handler for 'initDesktopFlow' signal sent from the main script.
- * Only called in desktop mode.
- */
- onInitDesktopFlow_: function(msg) {
- this.gaiaUrl_ = msg.gaiaUrl;
- this.continueUrl_ = msg.continueUrl;
- this.isConstrainedWindow_ = msg.isConstrainedWindow;
-
- var urls = [];
- var filter = {urls: urls, types: ['sub_frame']};
- var optExtraInfoSpec = [];
- if (msg.isConstrainedWindow) {
- urls.push('<all_urls>');
- optExtraInfoSpec.push('responseHeaders');
- } else {
- urls.push(this.continueUrl_ + '*');
- }
-
- chrome.webRequest.onCompleted.addListener(
- this.onRequestCompletedInDesktopMode_.bind(this),
- filter, optExtraInfoSpec);
- chrome.webRequest.onHeadersReceived.addListener(
- this.onHeadersReceivedInDesktopMode_.bind(this),
- {urls: [this.gaiaUrl_ + '*'], types: ['sub_frame']},
- ['responseHeaders']);
- },
-
- /**
- * Event listener for webRequest.onCompleted in desktop mode.
- */
- onRequestCompletedInDesktopMode_: function(details) {
- var msg = null;
- if (details.url.lastIndexOf(this.continueUrl_, 0) == 0) {
- var skipForNow = false;
- if (details.url.indexOf('ntp=1') >= 0) {
- skipForNow = true;
- }
- msg = {
- 'name': 'completeLogin',
- 'email': this.email_,
- 'sessionIndex': this.sessionIndex_,
- 'skipForNow': skipForNow
- };
- } else if (this.isConstrainedWindow_) {
- var headers = details.responseHeaders;
- for (var i = 0; headers && i < headers.length; ++i) {
- if (headers[i].name.toLowerCase() == 'google-accounts-embedded') {
- return;
- }
- }
- msg = {
- 'name': 'switchToFullTab',
- 'url': details.url
- };
- }
-
- if (msg != null)
- this.channelMain_[details.tabId].send(msg);
- },
-
- /**
- * Event listener for webRequest.onHeadersReceived in desktop mode.
- */
- onHeadersReceivedInDesktopMode_: function(details) {
- var headers = details.responseHeaders;
- for (var i = 0; headers && i < headers.length; ++i) {
- if (headers[i].name.toLowerCase() == 'google-accounts-signin') {
- var headerValues = headers[i].value.toLowerCase().split(',');
- var signinDetails = {};
- headerValues.forEach(function(e) {
- var pair = e.split('=');
- signinDetails[pair[0].trim()] = pair[1].trim();
- });
- this.email_ = signinDetails['email'].slice(1, -1); // Remove "" around.
- this.sessionIndex_ = signinDetails['sessionindex'];
- return;
- }
- }
+ this.channelInjected_.registerMessage(
+ 'pageLoaded', this.onPageLoaded_.bind(this));
},
/**
@@ -266,10 +153,8 @@ BackgroundBridge.prototype = {
return Object.keys(passwords);
},
- onAPICall_: function(tabId, msg) {
- if (tabId in this.channelMain_) {
- this.channelMain_[tabId].send(msg);
- }
+ onAPICall_: function(msg) {
+ this.channelMain_.send(msg);
},
onUpdatePassword_: function(msg) {
@@ -279,10 +164,8 @@ BackgroundBridge.prototype = {
this.passwordStore_[msg.id] = msg.password;
},
- onPageLoaded_: function(tabId, msg) {
- if (tabId in this.channelMain_) {
- this.channelMain_[tabId].send({name: 'onAuthPageLoaded', url: msg.url});
- }
+ onPageLoaded_: function(msg) {
+ this.channelMain_.send({name: 'onAuthPageLoaded', url: msg.url});
}
};
diff --git a/chrome/browser/resources/gaia_auth/desktop_injected.js b/chrome/browser/resources/gaia_auth/inline_injected.js
index f4c69e9..b0b8473 100644
--- a/chrome/browser/resources/gaia_auth/desktop_injected.js
+++ b/chrome/browser/resources/gaia_auth/inline_injected.js
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,14 +11,23 @@
*/
(function() {
- var $ = function(id) { return document.getElementById(id); };
+ var extWindow;
+ var $ = function(id) { return document.getElementById(id); };
var gaiaLoginForm = $('gaia_loginform');
- if (!gaiaLoginForm) {
- return;
- }
+
+ var onMessage = function(e) {
+ extWindow = e.source;
+ };
+ window.addEventListener('message', onMessage);
var onLoginSubmit = function(e) {
+ if (!extWindow) {
+ console.log('ERROR: no initial message received from the gaia ext');
+ e.preventDefault();
+ return;
+ }
+
var checkboxElement = $('advanced-box');
var chooseWhatToSync = checkboxElement && checkboxElement.checked;
var msg = {method: 'attemptLogin',
@@ -27,8 +36,7 @@
attemptToken: new Date().getTime(),
chooseWhatToSync: chooseWhatToSync};
- window.parent.postMessage(
- msg, 'chrome-extension://mfffpogegjflfpflabcdkioaeobkgjik');
+ extWindow.postMessage(msg, 'chrome://chrome-signin');
console.log('Credentials sent');
return;
diff --git a/chrome/browser/resources/gaia_auth/inline_main.html b/chrome/browser/resources/gaia_auth/inline_main.html
new file mode 100644
index 0000000..00ed78b
--- /dev/null
+++ b/chrome/browser/resources/gaia_auth/inline_main.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <link rel="stylesheet" href="main.css">
+ <meta charset="utf-8">
+ <script src="channel.js"></script>
+ <script src="util.js"></script>
+ <script src="main.js"></script>
+</head>
+<body>
+ <webview id="gaia-frame"></webview>
+</body>
+</html>
diff --git a/chrome/browser/resources/gaia_auth/main.js b/chrome/browser/resources/gaia_auth/main.js
index 2d19c7d..d3b01c7 100644
--- a/chrome/browser/resources/gaia_auth/main.js
+++ b/chrome/browser/resources/gaia_auth/main.js
@@ -36,8 +36,7 @@ Authenticator.prototype = {
intputEmail_: undefined,
isSAMLFlow_: false,
- isSAMLEnabled_: false,
- supportChannel_: null,
+ samlSupportChannel_: null,
GAIA_URL: 'https://accounts.google.com/',
GAIA_PAGE_PATH: 'ServiceLogin?skipvpage=true&sarp=1&rm=hide',
@@ -55,29 +54,15 @@ Authenticator.prototype = {
this.inputEmail_ = params.email;
this.service_ = params.service || this.SERVICE_ID;
this.continueUrl_ = params.continueUrl || this.CONTINUE_URL;
- this.desktopMode_ = params.desktopMode == '1';
- this.isConstrainedWindow_ = params.constrained == '1';
+ this.continueUrlWithoutParams_ = stripParams(this.continueUrl_);
+ this.inlineMode_ = params.inlineMode == '1';
+ this.constrained_ = params.constrained == '1';
+ this.partitionId_ = params.partitionId || '';
this.initialFrameUrl_ = params.frameUrl || this.constructInitialFrameUrl_();
this.initialFrameUrlWithoutParams_ = stripParams(this.initialFrameUrl_);
+ this.loaded_ = false;
- if (this.desktopMode_) {
- this.supportChannel_ = new Channel();
- this.supportChannel_.connect('authMain');
-
- this.supportChannel_.send({
- name: 'initDesktopFlow',
- gaiaUrl: this.gaiaUrl_,
- continueUrl: stripParams(this.continueUrl_),
- isConstrainedWindow: this.isConstrainedWindow_
- });
-
- this.supportChannel_.registerMessage(
- 'switchToFullTab', this.switchToFullTab_.bind(this));
- this.supportChannel_.registerMessage(
- 'completeLogin', this.completeLogin_.bind(this));
- }
-
- document.addEventListener('DOMContentLoaded', this.onPageLoad_.bind(this));
+ document.addEventListener('DOMContentLoaded', this.onPageLoad.bind(this));
document.addEventListener('enableSAML', this.onEnableSAML_.bind(this));
},
@@ -104,87 +89,129 @@ Authenticator.prototype = {
url = appendParam(url, 'hl', this.inputLang_);
if (this.inputEmail_)
url = appendParam(url, 'Email', this.inputEmail_);
- if (this.isConstrainedWindow_)
+ if (this.constrained_)
url = appendParam(url, 'source', this.CONSTRAINED_FLOW_SOURCE);
return url;
},
- onPageLoad_: function() {
- window.addEventListener('message', this.onMessage.bind(this), false);
- this.loadFrame_();
- },
-
- loadFrame_: function() {
- var gaiaFrame = $('gaia-frame');
- gaiaFrame.src = this.initialFrameUrl_;
- if (this.desktopMode_) {
- var handler = function() {
- this.onLoginUILoaded_();
- gaiaFrame.removeEventListener('load', handler);
- }.bind(this);
- gaiaFrame.addEventListener('load', handler);
+ /** Callback when all loads in the gaia webview is complete. */
+ onWebviewLoadstop_: function(gaiaFrame) {
+ if (gaiaFrame.src.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) {
+ // Detect when login is finished by the load stop event of the continue
+ // URL. Cannot reuse the login complete flow in success.html, because
+ // webview does not support extension pages yet.
+ var skipForNow = false;
+ if (this.inlineMode_ && gaiaFrame.src.indexOf('ntp=1') >= 0) {
+ skipForNow = true;
+ }
+ msg = {
+ 'method': 'completeLogin',
+ 'skipForNow': skipForNow
+ };
+ window.parent.postMessage(msg, this.parentPage_);
+ // Do no report state to the parent for the continue URL, since it is a
+ // blank page.
+ return;
}
- },
- /**
- * Invoked when the login UI is initialized or reset.
- */
- onLoginUILoaded_: function() {
+ // Report the current state to the parent which will then update the
+ // browser history so that later it could respond properly to back/forward.
var msg = {
- 'method': 'loginUILoaded'
+ 'method': 'reportState',
+ 'src': gaiaFrame.src
};
window.parent.postMessage(msg, this.parentPage_);
+
+ if (gaiaFrame.src.lastIndexOf(this.gaiaUrl_, 0) == 0) {
+ gaiaFrame.executeScript({file: 'inline_injected.js'}, function() {
+ // Send an initial message to gaia so that it has an JavaScript
+ // reference to the embedder.
+ gaiaFrame.contentWindow.postMessage('', gaiaFrame.src);
+ });
+ if (this.constrained_) {
+ var preventContextMenu = 'document.addEventListener("contextmenu", ' +
+ 'function(e) {e.preventDefault();})';
+ gaiaFrame.executeScript({code: preventContextMenu});
+ }
+ }
+
+ this.loaded_ || this.onLoginUILoaded();
},
/**
- * Invoked when the background script sends a message to indicate that the
- * current content does not fit in a constrained window.
- * @param {Object=} opt_extraMsg Optional extra info to send.
+ * Callback when the gaia webview attempts to open a new window.
*/
- switchToFullTab_: function(msg) {
- var parentMsg = {
+ onWebviewNewWindow_: function(gaiaFrame, e) {
+ window.open(e.targetUrl, '_blank');
+ e.window.discard();
+ },
+
+ onWebviewRequestCompleted_: function(details) {
+ if (details.url.lastIndexOf(this.continueUrlWithoutParams_, 0) == 0) {
+ return;
+ }
+
+ var headers = details.responseHeaders;
+ for (var i = 0; headers && i < headers.length; ++i) {
+ if (headers[i].name.toLowerCase() == 'google-accounts-embedded') {
+ return;
+ }
+ }
+ var msg = {
'method': 'switchToFullTab',
- 'url': msg.url
+ 'url': details.url
};
- window.parent.postMessage(parentMsg, this.parentPage_);
+ window.parent.postMessage(msg, this.parentPage_);
},
- /**
- * Invoked when the signin flow is complete.
- * @param {Object=} opt_extraMsg Optional extra info to send.
- */
- completeLogin_: function(opt_extraMsg) {
+ loadFrame_: function() {
+ var gaiaFrame = $('gaia-frame');
+ gaiaFrame.partition = this.partitionId_;
+ gaiaFrame.src = this.initialFrameUrl_;
+ if (this.inlineMode_) {
+ gaiaFrame.addEventListener(
+ 'loadstop', this.onWebviewLoadstop_.bind(this, gaiaFrame));
+ gaiaFrame.addEventListener(
+ 'newwindow', this.onWebviewNewWindow_.bind(this, gaiaFrame));
+ }
+ if (this.constrained_) {
+ gaiaFrame.request.onCompleted.addListener(
+ this.onWebviewRequestCompleted_.bind(this),
+ {urls: ['<all_urls>'], types: ['main_frame']},
+ ['responseHeaders']);
+ }
+ },
+
+ completeLogin: function() {
var msg = {
'method': 'completeLogin',
- 'email': (opt_extraMsg && opt_extraMsg.email) || this.email_,
+ 'email': this.email_,
'password': this.password_,
- 'usingSAML': this.isSAMLFlow_,
- 'chooseWhatToSync': this.chooseWhatToSync_ || false,
- 'skipForNow': opt_extraMsg && opt_extraMsg.skipForNow,
- 'sessionIndex': opt_extraMsg && opt_extraMsg.sessionIndex
+ 'usingSAML': this.isSAMLFlow_
};
window.parent.postMessage(msg, this.parentPage_);
- if (this.isSAMLEnabled_)
- this.supportChannel_.send({name: 'resetAuth'});
+ if (this.samlSupportChannel_)
+ this.samlSupportChannel_.send({name: 'resetAuth'});
+ },
+
+ onPageLoad: function(e) {
+ window.addEventListener('message', this.onMessage.bind(this), false);
+ this.loadFrame_();
},
/**
* Invoked when 'enableSAML' event is received to initialize SAML support.
*/
onEnableSAML_: function() {
- this.isSAMLEnabled_ = true;
this.isSAMLFlow_ = false;
- if (!this.supportChannel_) {
- this.supportChannel_ = new Channel();
- this.supportChannel_.connect('authMain');
- }
-
- this.supportChannel_.registerMessage(
+ this.samlSupportChannel_ = new Channel();
+ this.samlSupportChannel_.connect('authMain');
+ this.samlSupportChannel_.registerMessage(
'onAuthPageLoaded', this.onAuthPageLoaded_.bind(this));
- this.supportChannel_.registerMessage(
+ this.samlSupportChannel_.registerMessage(
'apiCall', this.onAPICall_.bind(this));
- this.supportChannel_.send({
+ this.samlSupportChannel_.send({
name: 'setGaiaUrl',
gaiaUrl: this.gaiaUrl_
});
@@ -232,9 +259,26 @@ Authenticator.prototype = {
}
},
+ onLoginUILoaded: function() {
+ var msg = {
+ 'method': 'loginUILoaded'
+ };
+ window.parent.postMessage(msg, this.parentPage_);
+ if (this.inlineMode_) {
+ // TODO(guohui): temporary workaround until webview team fixes the focus
+ // on their side.
+ var gaiaFrame = $('gaia-frame');
+ gaiaFrame.focus();
+ gaiaFrame.onblur = function() {
+ gaiaFrame.focus();
+ };
+ }
+ this.loaded_ = true;
+ },
+
onConfirmLogin_: function() {
if (!this.isSAMLFlow_) {
- this.completeLogin_();
+ this.completeLogin();
return;
}
@@ -247,7 +291,7 @@ Authenticator.prototype = {
this.parentPage_);
if (!apiUsed) {
- this.supportChannel_.sendWithCallback(
+ this.samlSupportChannel_.sendWithCallback(
{name: 'getScrapedPasswords'},
function(passwords) {
if (passwords.length == 0) {
@@ -268,11 +312,11 @@ Authenticator.prototype = {
// SAML login is complete when the user's e-mail address has been retrieved
// from GAIA and the user has successfully confirmed the password.
if (this.email_ !== null && this.password_ !== null)
- this.completeLogin_();
+ this.completeLogin();
},
onVerifyConfirmedPassword_: function(password) {
- this.supportChannel_.sendWithCallback(
+ this.samlSupportChannel_.sendWithCallback(
{name: 'getScrapedPasswords'},
function(passwords) {
for (var i = 0; i < passwords.length; ++i) {
@@ -294,18 +338,17 @@ Authenticator.prototype = {
this.email_ = msg.email;
this.password_ = msg.password;
this.attemptToken_ = msg.attemptToken;
- this.chooseWhatToSync_ = msg.chooseWhatToSync;
this.isSAMLFlow_ = false;
- if (this.isSAMLEnabled_)
- this.supportChannel_.send({name: 'startAuth'});
+ if (this.samlSupportChannel_)
+ this.samlSupportChannel_.send({name: 'startAuth'});
} else if (msg.method == 'clearOldAttempts' && this.isGaiaMessage_(e)) {
this.email_ = null;
this.password_ = null;
this.attemptToken_ = null;
this.isSAMLFlow_ = false;
- this.onLoginUILoaded_();
- if (this.isSAMLEnabled_)
- this.supportChannel_.send({name: 'resetAuth'});
+ this.onLoginUILoaded();
+ if (this.samlSupportChannel_)
+ this.samlSupportChannel_.send({name: 'resetAuth'});
} else if (msg.method == 'setAuthenticatedUserEmail' &&
this.isParentMessage_(e)) {
if (this.attemptToken_ == msg.attemptToken) {
diff --git a/chrome/browser/resources/gaia_auth/manifest_desktop.json b/chrome/browser/resources/gaia_auth/manifest_inline.json
index 698239a..2040360 100644
--- a/chrome/browser/resources/gaia_auth/manifest_desktop.json
+++ b/chrome/browser/resources/gaia_auth/manifest_inline.json
@@ -4,29 +4,29 @@
"name": "GaiaAuthExtension",
"version": "0.0.1",
"manifest_version": 2,
- "background" : {
- "scripts": ["background.js", "channel.js"]
- },
- "content_scripts": [
- {
- "matches": [
- "<all_urls>"
- ],
- "js": ["channel.js", "desktop_injected.js"],
- "all_frames": true
- }
- ],
"content_security_policy": "default-src 'self'; script-src 'self'; frame-src *; style-src 'self' 'unsafe-inline'",
"description": "GAIA Component Extension",
"web_accessible_resources": [
"main.css",
- "main.html",
+ "inline_main.html",
"main.js",
+ "offline.css",
+ "offline.html",
+ "offline.js",
+ "success.html",
+ "success.js",
"util.js"
],
+ // <all_urls> for intercepting all URL requests in the main frame, and
+ // switching to a full tab if needed.
+ // cookies for getting hash passed back from GAIA on login success.
+ // tabs for calling current webui's login. This might not be needed once
+ // we have extension API.
+ // webview for interacting with the GAIA sign in page loaded in a webview.
"permissions": [
- "<all_urls>",
- "tabs",
- "webRequest"
+ "<all_urls>",
+ "cookies",
+ "tabs",
+ "webview"
]
}
diff --git a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
index a7dadc9..3acfcc3 100644
--- a/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
+++ b/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js
@@ -35,6 +35,12 @@ cr.define('cr.login', function() {
var OFFLINE_AUTH_URL = AUTH_URL_BASE + '/offline.html';
/**
+ * Auth URL to use for inline flow.
+ * @const
+ */
+ var INLINE_AUTH_URL = AUTH_URL_BASE + '/inline_main.html';
+
+ /**
* Origin of the gaia sign in page.
* @const
*/
@@ -53,6 +59,7 @@ cr.define('cr.login', function() {
'email', // Pre-fill the email field in Gaia UI;
'service', // Name of Gaia service;
'continueUrl', // Continue url to use;
+ 'partitionId', // Partition ID for the embedded Gaia webview;
'frameUrl', // Initial frame URL to use. If empty defaults to gaiaUrl.
'constrained' // Whether the extension is loaded in a constrained window;
];
@@ -80,7 +87,7 @@ cr.define('cr.login', function() {
var AuthMode = {
DEFAULT: 0,
OFFLINE: 1,
- DESKTOP: 2
+ INLINE: 2
};
/**
@@ -104,6 +111,8 @@ cr.define('cr.login', function() {
assert(this.frame_);
window.addEventListener('message',
this.onMessage_.bind(this), false);
+ window.addEventListener('popstate',
+ this.onPopState_.bind(this), false);
}
GaiaAuthHost.prototype = {
@@ -131,7 +140,7 @@ cr.define('cr.login', function() {
* email: 'xx@gmail.com',
* password: 'xxxx', // May not present
* authCode: 'x/xx', // May not present
- * authMode: 'x', // Authorization mode, default/offline/desktop.
+ * authMode: 'x', // Authorization mode, default/inline/offline.
* }
* }
* </pre>
@@ -236,9 +245,9 @@ cr.define('cr.login', function() {
case AuthMode.OFFLINE:
url = OFFLINE_AUTH_URL;
break;
- case AuthMode.DESKTOP:
- url = AUTH_URL;
- params.push('desktopMode=1');
+ case AuthMode.INLINE:
+ url = INLINE_AUTH_URL;
+ params.push('inlineMode=1');
break;
default:
url = AUTH_URL;
@@ -317,6 +326,17 @@ cr.define('cr.login', function() {
onMessage_: function(e) {
var msg = e.data;
+ // In the inline sign in flow, the embedded gaia webview posts credential
+ // directly to the inline sign in page, because its parent JavaScript
+ // reference points to the top frame of the embedder instead of the sub
+ // frame of the gaia auth extension.
+ if (e.origin == GAIA_ORIGIN && msg.method == 'attemptLogin') {
+ this.email_ = msg.email;
+ this.password_ = msg.password;
+ this.chooseWhatToSync_ = msg.chooseWhatToSync;
+ return;
+ }
+
if (!this.isAuthExtMessage_(e))
return;
@@ -331,13 +351,13 @@ cr.define('cr.login', function() {
this.frame_.contentWindow.postMessage(msg, AUTH_URL_BASE);
return;
}
- this.onAuthSuccess_({email: msg.email,
- password: msg.password,
+ this.onAuthSuccess_({email: msg.email || this.email_,
+ password: msg.password || this.password_,
+ authCode: msg.authCode,
useOffline: msg.method == 'offlineLogin',
usingSAML: msg.usingSAML || false,
- chooseWhatToSync: msg.chooseWhatToSync,
- skipForNow: msg.skipForNow || false,
- sessionIndex: msg.sessionIndex || ''});
+ chooseWhatToSync: this.chooseWhatToSync_,
+ skipForNow: msg.skipForNow || false });
return;
}
@@ -374,12 +394,39 @@ cr.define('cr.login', function() {
return;
}
+ if (msg.method == 'reportState') {
+ var newUrl = setQueryParam(location, 'frameUrl', msg.src);
+ if (history.state) {
+ if (history.state.src != msg.src) {
+ history.pushState({src: msg.src}, '', newUrl);
+ }
+ } else {
+ history.replaceState({src: msg.src});
+ }
+ return;
+ }
+
if (msg.method == 'switchToFullTab') {
chrome.send('switchToFullTab', [msg.url]);
return;
}
console.error('Unknown message method=' + msg.method);
+ },
+
+ /**
+ * Event handler that is invoked when the history state is changed.
+ * @param {object} e The popstate event being triggered.
+ */
+ onPopState_: function(e) {
+ var state = e.state;
+ if (state) {
+ var msg = {
+ method: 'navigate',
+ src: state.src
+ };
+ this.frame_.contentWindow.postMessage(msg, AUTH_URL_BASE);
+ }
}
};
diff --git a/chrome/browser/resources/inline_login/inline_login.js b/chrome/browser/resources/inline_login/inline_login.js
index 6e09bb6..fbd30c9 100644
--- a/chrome/browser/resources/inline_login/inline_login.js
+++ b/chrome/browser/resources/inline_login/inline_login.js
@@ -49,7 +49,10 @@ cr.define('inline.login', function() {
*/
function loadAuthExtension(data) {
authExtHost.load(data.authMode, data, onAuthCompleted);
- $('contents').classList.toggle('loading', true);
+ // Do not show loading spinner to give user a faster response
+ // with inline flows.
+ $('contents').classList.toggle('loading',
+ data.authMode != cr.login.GaiaAuthHost.AuthMode.INLINE);
}
/**
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler.h b/chrome/browser/ui/webui/signin/inline_login_handler.h
index 6bda701..b3650fb 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler.h
@@ -22,7 +22,7 @@ class InlineLoginHandler : public content::WebUIMessageHandler {
enum AuthMode {
kDefaultAuthMode = 0,
kOfflineAuthMode = 1,
- kDesktopAuthMode = 2
+ kInlineAuthMode = 2
};
private:
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
index 7b403c6..cf30c5a 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.cc
@@ -4,6 +4,7 @@
#include "chrome/browser/ui/webui/signin/inline_login_handler_impl.h"
+#include "base/atomic_sequence_num.h"
#include "base/bind.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_number_conversions.h"
@@ -19,7 +20,6 @@
#include "chrome/browser/ui/sync/one_click_signin_helper.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/pref_names.h"
-#include "chrome/common/url_constants.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
@@ -30,10 +30,13 @@
namespace {
+// Global SequenceNumber used for generating unique webview partition IDs.
+base::StaticAtomicSequenceNumber next_partition_id;
+
} // empty namespace
InlineLoginHandlerImpl::InlineLoginHandlerImpl()
- : weak_factory_(this), choose_what_to_sync_(false) {
+ : weak_factory_(this), choose_what_to_sync_(false), partition_id_("") {
}
InlineLoginHandlerImpl::~InlineLoginHandlerImpl() {}
@@ -47,7 +50,7 @@ void InlineLoginHandlerImpl::RegisterMessages() {
}
void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
- params.SetInteger("authMode", InlineLoginHandler::kDesktopAuthMode);
+ params.SetInteger("authMode", InlineLoginHandler::kInlineAuthMode);
const GURL& current_url = web_ui()->GetWebContents()->GetURL();
signin::Source source = signin::GetSourceForPromoURL(current_url);
@@ -89,6 +92,13 @@ void InlineLoginHandlerImpl::SetExtraInitParams(base::DictionaryValue& params) {
net::GetValueForKeyInQuery(current_url, "readOnlyEmail", &read_only_email);
if (!read_only_email.empty())
params.SetString("readOnlyEmail", read_only_email);
+
+ net::GetValueForKeyInQuery(current_url, "partitionId", &partition_id_);
+ if (partition_id_.empty()) {
+ partition_id_ =
+ "gaia-webview-" + base::IntToString(next_partition_id.GetNext());
+ }
+ params.SetString("partitionId", partition_id_);
}
@@ -101,6 +111,8 @@ void InlineLoginHandlerImpl::HandleSwitchToFullTabMessage(
GURL main_frame_url(web_contents->GetURL());
main_frame_url = net::AppendOrReplaceQueryParameter(
main_frame_url, "frameUrl", UTF16ToASCII(url_str));
+ main_frame_url = net::AppendOrReplaceQueryParameter(
+ main_frame_url, "partitionId", partition_id_);
chrome::NavigateParams params(
Profile::FromWebUI(web_ui()),
net::AppendOrReplaceQueryParameter(main_frame_url, "constrained", "0"),
@@ -111,7 +123,7 @@ void InlineLoginHandlerImpl::HandleSwitchToFullTabMessage(
}
void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
- DCHECK(email_.empty() && password_.empty() && session_index_.empty());
+ DCHECK(email_.empty() && password_.empty());
content::WebContents* contents = web_ui()->GetWebContents();
const GURL& current_url = contents->GetURL();
@@ -150,10 +162,6 @@ void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
}
}
- base::string16 session_index;
- dict->GetString("sessionIndex", &session_index);
- session_index_ = UTF16ToASCII(session_index);
- DCHECK(!session_index_.empty());
dict->GetBoolean("chooseWhatToSync", &choose_what_to_sync_);
signin::Source source = signin::GetSourceForPromoURL(current_url);
@@ -172,12 +180,13 @@ void InlineLoginHandlerImpl::CompleteLogin(const base::ListValue* args) {
content::StoragePartition* partition =
content::BrowserContext::GetStoragePartitionForSite(
contents->GetBrowserContext(),
- GURL(chrome::kChromeUIChromeSigninURL));
+ GURL("chrome-guest://mfffpogegjflfpflabcdkioaeobkgjik/?" +
+ partition_id_));
auth_fetcher_.reset(new GaiaAuthFetcher(this,
GaiaConstants::kChromeSource,
partition->GetURLRequestContext()));
- auth_fetcher_->StartCookieForOAuthCodeExchange(session_index_);
+ auth_fetcher_->StartCookieForOAuthCodeExchange("0");
}
void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
@@ -244,7 +253,6 @@ void InlineLoginHandlerImpl::OnClientOAuthCodeSuccess(
email_.clear();
password_.clear();
- session_index_.clear();
web_ui()->CallJavascriptFunction("inline.login.closeDialog");
}
@@ -268,7 +276,6 @@ void InlineLoginHandlerImpl::HandleLoginError(const std::string& error_msg) {
email_.clear();
password_.clear();
- session_index_.clear();
}
void InlineLoginHandlerImpl::SyncStarterCallback(
diff --git a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
index b107006..9193d34 100644
--- a/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
+++ b/chrome/browser/ui/webui/signin/inline_login_handler_impl.h
@@ -43,8 +43,9 @@ class InlineLoginHandlerImpl : public GaiaAuthConsumer,
scoped_ptr<GaiaAuthFetcher> auth_fetcher_;
std::string email_;
std::string password_;
- std::string session_index_;
bool choose_what_to_sync_;
+ // Partition id for the gaia webview;
+ std::string partition_id_;
DISALLOW_COPY_AND_ASSIGN(InlineLoginHandlerImpl);
};
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui.cc b/chrome/browser/ui/webui/signin/inline_login_ui.cc
index 7c547e2..4748c04 100644
--- a/chrome/browser/ui/webui/signin/inline_login_ui.cc
+++ b/chrome/browser/ui/webui/signin/inline_login_ui.cc
@@ -4,7 +4,6 @@
#include "chrome/browser/ui/webui/signin/inline_login_ui.h"
-#include "chrome/browser/extensions/extension_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/web_ui.h"
@@ -23,7 +22,6 @@ namespace {
content::WebUIDataSource* CreateWebUIDataSource() {
content::WebUIDataSource* source =
content::WebUIDataSource::Create(chrome::kChromeUIChromeSigninHost);
- source->OverrideContentSecurityPolicyFrameSrc("frame-src chrome-extension:;");
source->SetUseJsonJSFormatV2();
source->SetJsonPath("strings.js");
@@ -50,8 +48,7 @@ InlineLoginUI::InlineLoginUI(content::WebUI* web_ui)
// Required for intercepting extension function calls when the page is loaded
// in a bubble (not a full tab, thus tab helpers are not registered
// automatically).
- extensions::ExtensionWebContentsObserver::CreateForWebContents(
- web_ui->GetWebContents());
+ extensions::TabHelper::CreateForWebContents(web_ui->GetWebContents());
#endif
}
diff --git a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc b/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
deleted file mode 100644
index 11b44a5..0000000
--- a/chrome/browser/ui/webui/signin/inline_login_ui_browsertest.cc
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/signin/signin_promo.h"
-#include "chrome/browser/ui/browser.h"
-#include "chrome/browser/ui/tabs/tab_strip_model.h"
-#include "chrome/common/chrome_switches.h"
-#include "chrome/common/url_constants.h"
-#include "chrome/test/base/in_process_browser_test.h"
-#include "chrome/test/base/test_chrome_web_ui_controller_factory.h"
-#include "chrome/test/base/testing_browser_process.h"
-#include "chrome/test/base/ui_test_utils.h"
-#include "content/public/browser/render_process_host.h"
-#include "content/public/browser/session_storage_namespace.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_ui_controller.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/test/browser_test_utils.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::_;
-
-namespace {
-
-struct ContentInfo {
- ContentInfo(int pid, content::StoragePartition* storage_partition) {
- this->pid = pid;
- this->storage_partition = storage_partition;
- }
-
- int pid;
- content::StoragePartition* storage_partition;
-};
-
-ContentInfo NavigateAndGetInfo(
- Browser* browser,
- const GURL& url,
- WindowOpenDisposition disposition) {
- ui_test_utils::NavigateToURLWithDisposition(
- browser, url, disposition,
- ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
- content::WebContents* contents =
- browser->tab_strip_model()->GetActiveWebContents();
- content::RenderProcessHost* process = contents->GetRenderProcessHost();
- return ContentInfo(process->GetID(), process->GetStoragePartition());
-}
-
-// Returns a new WebUI object for the WebContents from |arg0|.
-ACTION(ReturnNewWebUI) {
- return new content::WebUIController(arg0);
-}
-
-// Mock the TestChromeWebUIControllerFactory::WebUIProvider to prove that we are
-// not called as expected.
-class FooWebUIProvider
- : public TestChromeWebUIControllerFactory::WebUIProvider {
- public:
- MOCK_METHOD2(NewWebUI, content::WebUIController*(content::WebUI* web_ui,
- const GURL& url));
-};
-
-const char kFooWebUIURL[] = "chrome://foo/";
-
-} // namespace
-
-class InlineLoginUIBrowserTest : public InProcessBrowserTest {
- public:
- InlineLoginUIBrowserTest() {}
-};
-
-IN_PROC_BROWSER_TEST_F(InlineLoginUIBrowserTest, DifferentStorageId) {
- GURL test_url = ui_test_utils::GetTestUrl(
- base::FilePath(base::FilePath::kCurrentDirectory),
- base::FilePath(FILE_PATH_LITERAL("title1.html")));
-
- ContentInfo info1 =
- NavigateAndGetInfo(browser(), test_url, CURRENT_TAB);
- ContentInfo info2 =
- NavigateAndGetInfo(browser(),
- signin::GetPromoURL(signin::SOURCE_START_PAGE, false),
- CURRENT_TAB);
- NavigateAndGetInfo(browser(), test_url, CURRENT_TAB);
- ContentInfo info3 =
- NavigateAndGetInfo(browser(),
- signin::GetPromoURL( signin::SOURCE_START_PAGE, false),
- NEW_FOREGROUND_TAB);
-
- // The info for signin should be the same.
- ASSERT_EQ(info2.storage_partition, info3.storage_partition);
- // The info for test_url and signin should be different.
- ASSERT_NE(info1.storage_partition, info2.storage_partition);
-}
-
-IN_PROC_BROWSER_TEST_F(InlineLoginUIBrowserTest, OneProcessLimit) {
- GURL test_url_1 = ui_test_utils::GetTestUrl(
- base::FilePath(base::FilePath::kCurrentDirectory),
- base::FilePath(FILE_PATH_LITERAL("title1.html")));
- GURL test_url_2 = ui_test_utils::GetTestUrl(
- base::FilePath(base::FilePath::kCurrentDirectory),
- base::FilePath(FILE_PATH_LITERAL("data:text/html,Hello world!")));
-
- // Even when the process limit is set to one, the signin process should
- // still be given its own process and storage partition.
- content::RenderProcessHost::SetMaxRendererProcessCount(1);
-
- ContentInfo info1 =
- NavigateAndGetInfo(browser(), test_url_1, CURRENT_TAB);
- ContentInfo info2 =
- NavigateAndGetInfo(browser(), test_url_2, CURRENT_TAB);
- ContentInfo info3 =
- NavigateAndGetInfo(browser(),
- signin::GetPromoURL( signin::SOURCE_START_PAGE, false),
- CURRENT_TAB);
-
- ASSERT_EQ(info1.pid, info2.pid);
- ASSERT_NE(info1.pid, info3.pid);
-}
-
-class InlineLoginUISafeIframeBrowserTest : public InProcessBrowserTest {
- public:
- FooWebUIProvider& foo_provider() { return foo_provider_; }
-
- private:
- virtual void SetUpOnMainThread() OVERRIDE {
- content::WebUIControllerFactory::UnregisterFactoryForTesting(
- ChromeWebUIControllerFactory::GetInstance());
- test_factory_.reset(new TestChromeWebUIControllerFactory);
- content::WebUIControllerFactory::RegisterFactory(test_factory_.get());
- test_factory_->AddFactoryOverride(
- GURL(kFooWebUIURL).host(), &foo_provider_);
- }
-
- virtual void CleanUpOnMainThread() OVERRIDE {
- test_factory_->RemoveFactoryOverride(GURL(kFooWebUIURL).host());
- content::WebUIControllerFactory::UnregisterFactoryForTesting(
- test_factory_.get());
- test_factory_.reset();
- }
-
- FooWebUIProvider foo_provider_;
- scoped_ptr<TestChromeWebUIControllerFactory> test_factory_;
-};
-
-// Make sure that the foo webui handler is working properly and that it gets
-// created when navigated to normally.
-IN_PROC_BROWSER_TEST_F(InlineLoginUISafeIframeBrowserTest, Basic) {
- const GURL kUrl(kFooWebUIURL);
- EXPECT_CALL(foo_provider(), NewWebUI(_, ::testing::Eq(kUrl)))
- .WillOnce(ReturnNewWebUI());
- ui_test_utils::NavigateToURL(browser(), GURL(kFooWebUIURL));
-}
-
-// Make sure that the foo webui handler does not get created when we try to
-// load it inside the iframe of the login ui.
-IN_PROC_BROWSER_TEST_F(InlineLoginUISafeIframeBrowserTest, NoWebUIInIframe) {
- GURL url = signin::GetPromoURL(signin::SOURCE_START_PAGE, false).
- Resolve("?source=0&frameUrl=chrome://foo");
- EXPECT_CALL(foo_provider(), NewWebUI(_, _)).Times(0);
- ui_test_utils::NavigateToURL(browser(), url);
-}
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 271009e..de4a328 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1575,7 +1575,6 @@
'browser/ui/webui/policy_ui_browsertest.cc',
'browser/ui/webui/print_preview/print_preview_ui_browsertest.cc',
'browser/ui/webui/signin/user_manager_ui_browsertest.cc',
- 'browser/ui/webui/signin/inline_login_ui_browsertest.cc',
'browser/ui/webui/sync_internals_browsertest.js',
'browser/ui/webui/sync_setup_browsertest.js',
'browser/ui/webui/web_ui_test_handler.cc',
diff --git a/content/browser/webui/url_data_manager_backend.cc b/content/browser/webui/url_data_manager_backend.cc
index 9313d9f..3f24b6c 100644
--- a/content/browser/webui/url_data_manager_backend.cc
+++ b/content/browser/webui/url_data_manager_backend.cc
@@ -26,7 +26,6 @@
#include "content/browser/tcmalloc_internals_request_job.h"
#include "content/browser/webui/shared_resources_data_source.h"
#include "content/browser/webui/url_data_source_impl.h"
-#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_process_host.h"
@@ -161,13 +160,7 @@ class URLRequestChromeJob : public net::URLRequestJob,
// Helper for Start(), to let us start asynchronously.
// (This pattern is shared by most net::URLRequestJob implementations.)
- void StartAsync(bool allowed);
-
- // Called on the UI thread to check if this request is allowed.
- static void CheckStoragePartitionMatches(
- int render_process_id,
- const GURL& url,
- const base::WeakPtr<URLRequestChromeJob>& job);
+ void StartAsync();
// Do the actual copy from data_ (the data we're serving) into |buf|.
// Separate from ReadRawData so we can handle async I/O.
@@ -236,14 +229,12 @@ URLRequestChromeJob::~URLRequestChromeJob() {
}
void URLRequestChromeJob::Start() {
- int render_process_id, unused;
- ResourceRequestInfo::GetRenderFrameForRequest(
- request_, &render_process_id, &unused);
- BrowserThread::PostTask(
- BrowserThread::UI,
+ // Start reading asynchronously so that all error reporting and data
+ // callbacks happen as they would for network requests.
+ base::MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&URLRequestChromeJob::CheckStoragePartitionMatches,
- render_process_id, request_->url(), AsWeakPtr()));
+ base::Bind(&URLRequestChromeJob::StartAsync, weak_factory_.GetWeakPtr()));
+
TRACE_EVENT_ASYNC_BEGIN1("browser", "DataManager:Request", this, "URL",
request_->url().possibly_invalid_spec());
}
@@ -347,38 +338,11 @@ void URLRequestChromeJob::CompleteRead(net::IOBuffer* buf, int buf_size,
*bytes_read = buf_size;
}
-void URLRequestChromeJob::CheckStoragePartitionMatches(
- int render_process_id,
- const GURL& url,
- const base::WeakPtr<URLRequestChromeJob>& job) {
- // The embedder could put some webui pages in separate storage partition.
- // RenderProcessHostImpl::IsSuitableHost would guard against top level pages
- // being in the same process. We do an extra check to guard against an
- // exploited renderer pretending to add them as a subframe. We skip this check
- // for resources.
- bool allowed = false;
- if (url.SchemeIs(kChromeUIScheme) && url.host() == kChromeUIResourcesHost) {
- allowed = true;
- } else {
- RenderProcessHost* process = RenderProcessHost::FromID(render_process_id);
- if (process) {
- StoragePartition* partition = BrowserContext::GetStoragePartitionForSite(
- process->GetBrowserContext(), url);
- allowed = partition == process->GetStoragePartition();
- }
- }
-
- BrowserThread::PostTask(
- BrowserThread::IO,
- FROM_HERE,
- base::Bind(&URLRequestChromeJob::StartAsync, job, allowed));
-}
-
-void URLRequestChromeJob::StartAsync(bool allowed) {
+void URLRequestChromeJob::StartAsync() {
if (!request_)
return;
- if (!allowed || !backend_->StartRequest(request_, this)) {
+ if (!backend_->StartRequest(request_, this)) {
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_INVALID_URL));
}