Chromium Code Reviews| Index: chrome/browser/password_manager/password_manager_browsertest.cc |
| diff --git a/chrome/browser/password_manager/password_manager_browsertest.cc b/chrome/browser/password_manager/password_manager_browsertest.cc |
| index f759c2bb152c07a38ecf65c780b279a65185689a..df03e439cbc1262806c1c905e08f27843b698052 100644 |
| --- a/chrome/browser/password_manager/password_manager_browsertest.cc |
| +++ b/chrome/browser/password_manager/password_manager_browsertest.cc |
| @@ -48,6 +48,7 @@ |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "net/base/filename_util.h" |
| +#include "net/dns/mock_host_resolver.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| @@ -345,10 +346,18 @@ class PasswordManagerBrowserTest : public InProcessBrowserTest { |
| // event loop is spun to allow all other possible events to take place. |
| void WaitForElementValue(const std::string& element_id, |
| const std::string& expected_value); |
| + // Same as above except the element |element_id| is in iframe |iframe_id| |
| + void WaitForElementValue(const std::string& iframe_id, |
| + const std::string& element_id, |
| + const std::string& expected_value); |
| // Checks that the current "value" attribute of the HTML element with |
| // |element_id| is equal to |expected_value|. |
| void CheckElementValue(const std::string& element_id, |
| const std::string& expected_value); |
| + // Same as above except the element |element_id| is in iframe |iframe_id| |
| + void CheckElementValue(const std::string& iframe_id, |
| + const std::string& element_id, |
| + const std::string& expected_value); |
| // TODO(dvadym): Remove this once history.pushState() handling is not behind |
| // a flag. |
| @@ -366,6 +375,15 @@ class PasswordManagerBrowserTest : public InProcessBrowserTest { |
| void PasswordManagerBrowserTest::WaitForElementValue( |
| const std::string& element_id, |
| const std::string& expected_value) { |
| + PasswordManagerBrowserTest::WaitForElementValue("null", |
| + element_id, |
| + expected_value); |
| +} |
| + |
| +void PasswordManagerBrowserTest::WaitForElementValue( |
| + const std::string& iframe_id, |
| + const std::string& element_id, |
| + const std::string& expected_value) { |
| enum ReturnCodes { // Possible results of the JavaScript code. |
| RETURN_CODE_OK, |
| RETURN_CODE_NO_ELEMENT, |
| @@ -374,9 +392,16 @@ void PasswordManagerBrowserTest::WaitForElementValue( |
| }; |
| const std::string value_check_function = base::StringPrintf( |
| "function valueCheck() {" |
| - " var element = document.getElementById('%s');" |
| + " if (%s)" |
| + " var element = document.getElementById(" |
| + " '%s').contentDocument.getElementById('%s');" |
| + " else " |
| + " var element = document.getElementById('%s');" |
| " return element && element.value == '%s';" |
| "}", |
| + iframe_id.c_str(), |
| + iframe_id.c_str(), |
| + element_id.c_str(), |
| element_id.c_str(), |
| expected_value.c_str()); |
| const std::string script = |
| @@ -386,7 +411,11 @@ void PasswordManagerBrowserTest::WaitForElementValue( |
| " /* Spin the event loop with setTimeout. */" |
| " setTimeout(window.domAutomationController.send(%d), 0);" |
| "} else {" |
| - " var element = document.getElementById('%s');" |
| + " if (%s)" |
| + " var element = document.getElementById(" |
| + " '%s').contentDocument.getElementById('%s');" |
| + " else " |
| + " var element = document.getElementById('%s');" |
| " if (!element)" |
| " window.domAutomationController.send(%d);" |
| " element.onchange = function() {" |
| @@ -399,6 +428,9 @@ void PasswordManagerBrowserTest::WaitForElementValue( |
| " };" |
| "}", |
| RETURN_CODE_OK, |
| + iframe_id.c_str(), |
| + iframe_id.c_str(), |
| + element_id.c_str(), |
| element_id.c_str(), |
| RETURN_CODE_NO_ELEMENT, |
| RETURN_CODE_OK, |
| @@ -414,9 +446,25 @@ void PasswordManagerBrowserTest::WaitForElementValue( |
| void PasswordManagerBrowserTest::CheckElementValue( |
| const std::string& element_id, |
| const std::string& expected_value) { |
| + PasswordManagerBrowserTest::CheckElementValue("null", |
| + element_id, |
| + expected_value); |
| +} |
| + |
| +void PasswordManagerBrowserTest::CheckElementValue( |
| + const std::string& iframe_id, |
| + const std::string& element_id, |
| + const std::string& expected_value) { |
| const std::string value_check_script = base::StringPrintf( |
| - "var element = document.getElementById('%s');" |
| + "if (%s)" |
| + " var element = document.getElementById(" |
| + " '%s').contentDocument.getElementById('%s');" |
| + "else " |
| + " var element = document.getElementById('%s');" |
| "window.domAutomationController.send(element && element.value == '%s');", |
| + iframe_id.c_str(), |
| + iframe_id.c_str(), |
| + element_id.c_str(), |
| element_id.c_str(), |
| expected_value.c_str()); |
| bool return_value = false; |
| @@ -1913,3 +1961,122 @@ IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, BaseTagWithNoActionTest) { |
| // Wait until that interaction causes the password value to be revealed. |
| WaitForElementValue("password_field", "mypassword"); |
| } |
| + |
| +// Check that a password form in an iframe of different origin will not be |
| +// filled in until a user interact with the form. |
| +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, CrossSiteIframeNotFillTest) { |
| + // Setup the mock host resolver |
| + host_resolver()->AddRule("*", "127.0.0.1"); |
| + |
| + // Here we need to dynamically create the iframe because the port |
| + // embedded_test_server ran on was dynamically allocated, so the iframe's src |
| + // attribute can only be determined at run time. |
| + NavigateToFile("/password/password_form_in_crosssite_iframe.html"); |
| + NavigationObserver ifrm_observer(WebContents()); |
| + ifrm_observer.SetPathToWaitFor("/password/crossite_iframe_content.html"); |
| + |
| + std::string submit = base::StringPrintf( |
|
Garrett Casto
2015/05/28 18:08:18
Sorry, if this was clear, but the JS function name
xunlu
2015/05/28 22:28:16
Done.
|
| + "create_iframe(" |
| + "'http://randomsite.net:%d/password/crossite_iframe_content.html');", |
| + embedded_test_server()->port()); |
| + |
| + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit)); |
| + ifrm_observer.Wait(); |
| + |
| + NavigationObserver init_observer(WebContents()); |
| + init_observer.SetPathToWaitFor("/password/done.html"); |
| + scoped_ptr<PromptObserver> prompt_observer( |
| + PromptObserver::Create(WebContents())); |
| + // Store a password for autofill later |
|
Garrett Casto
2015/05/28 18:08:18
Nit: This isn't a rule, but we generally value con
xunlu
2015/05/28 22:28:15
Done.
|
| + std::string init_form = "sendMessage('fill_and_submit');"; |
| + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), init_form)); |
| + init_observer.Wait(); |
| + EXPECT_TRUE(prompt_observer->IsShowingPrompt()); |
| + prompt_observer->Accept(); |
| + |
| + // Visit the form again |
| + NavigationObserver reload_observer(WebContents()); |
| + NavigateToFile("/password/password_form_in_crosssite_iframe.html"); |
| + reload_observer.Wait(); |
| + |
| + NavigationObserver ifrm_observer_2(WebContents()); |
| + ifrm_observer_2.SetPathToWaitFor("/password/crossite_iframe_content.html"); |
| + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit)); |
| + ifrm_observer_2.Wait(); |
| + |
|
Garrett Casto
2015/05/28 18:08:18
So we talked about how it's probably okay here not
xunlu
2015/05/28 22:28:16
Done.
|
| + // Verfiy username is not autofilled |
|
Garrett Casto
2015/05/28 18:08:18
"Verify"
xunlu
2015/05/28 22:28:16
Done.
|
| + std::string empty_username; |
| + ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| + RenderViewHost(), |
| + "sendMessage('get_username');", |
| + &empty_username)); |
| + ASSERT_EQ("", empty_username); |
| + |
| + |
| + // Verfiy password is not autofilled |
|
Garrett Casto
2015/05/28 18:08:18
"Verify"
xunlu
2015/05/28 22:28:16
Done.
|
| + std::string empty_password; |
| + ASSERT_TRUE(content::ExecuteScriptAndExtractString( |
| + RenderViewHost(), |
| + "sendMessage('get_password');", |
| + &empty_password)); |
| + ASSERT_EQ("", empty_password); |
| +} |
| + |
| +// Check that a password form in an iframe of same origin will not be |
| +// filled in until user interact with the iframe. |
| +IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, |
| + SameOriginIframeAutoFillTest) { |
| + // Visit the sign-up form to store a password for autofill later |
| + NavigateToFile("/password/password_form_in_same_origin_iframe.html"); |
| + NavigationObserver observer(WebContents()); |
| + observer.SetPathToWaitFor("/password/done.html"); |
| + scoped_ptr<PromptObserver> prompt_observer( |
| + PromptObserver::Create(WebContents())); |
| + |
| + std::string submit = |
| + "var ifrmDoc = document.getElementById('iframe').contentDocument;" |
| + "ifrmDoc.getElementById('username_field').value = 'temp';" |
| + "ifrmDoc.getElementById('password_field').value = 'pa55w0rd';" |
| + "ifrmDoc.getElementById('input_submit_button').click();"; |
| + ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit)); |
| + observer.Wait(); |
| + EXPECT_TRUE(prompt_observer->IsShowingPrompt()); |
| + prompt_observer->Accept(); |
| + |
| + // Visit the form again |
| + NavigationObserver reload_observer(WebContents()); |
| + NavigateToFile("/password/password_form_in_same_origin_iframe.html"); |
| + reload_observer.Wait(); |
| + |
| + // Verfiy username is autofilled |
|
Garrett Casto
2015/05/28 18:08:18
"Verify"
xunlu
2015/05/28 22:28:16
Done.
|
| + CheckElementValue("iframe", "username_field", "temp"); |
| + |
| + // Verfiy password is not autofilled |
|
Garrett Casto
2015/05/28 18:08:18
"Verify"
xunlu
2015/05/28 22:28:16
Done.
|
| + CheckElementValue("iframe", "password_field", ""); |
| + |
| + // Simulate the user interaction in the iframe which should trigger autofill. |
| + ASSERT_TRUE(content::ExecuteScript( |
| + RenderViewHost(), |
| + "var iframeRect = document.getElementById(" |
| + "'iframe').getBoundingClientRect();")); |
| + int top; |
| + ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
| + RenderViewHost(), |
| + "window.domAutomationController.send(iframeRect.top);", |
| + &top)); |
| + int left; |
| + ASSERT_TRUE(content::ExecuteScriptAndExtractInt( |
| + RenderViewHost(), |
| + "window.domAutomationController.send(iframeRect.left);", |
| + &left)); |
| + |
| + content::SimulateMouseClickAt( |
| + WebContents(), 0, blink::WebMouseEvent::ButtonLeft, gfx::Point(left + 1, |
| + top + 1)); |
| + // Verify password has been autofilled |
| + WaitForElementValue("iframe", "password_field", "pa55w0rd"); |
| + |
| + // Verfiy username has been autofilled |
|
Garrett Casto
2015/05/28 18:08:18
"Verify"
xunlu
2015/05/28 22:28:15
Done.
|
| + CheckElementValue("iframe", "username_field", "temp"); |
| + |
| +} |