Make sure the sync directory is deleted on sign-out.
[chromium-blink-merge.git] / chrome / browser / password_manager / password_manager_browsertest.cc
blobf0a766f8a1ffc5f005168db5200bd4e9e1fd6b2d
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
3 // found in the LICENSE file.
5 #include <string>
7 #include "base/command_line.h"
8 #include "base/metrics/histogram_samples.h"
9 #include "base/metrics/statistics_recorder.h"
10 #include "base/path_service.h"
11 #include "base/run_loop.h"
12 #include "base/stl_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/infobars/infobar_service.h"
17 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
18 #include "chrome/browser/password_manager/password_store_factory.h"
19 #include "chrome/browser/password_manager/test_password_store_service.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/login/login_prompt.h"
22 #include "chrome/browser/ui/login/login_prompt_test_utils.h"
23 #include "chrome/browser/ui/passwords/manage_passwords_ui_controller.h"
24 #include "chrome/browser/ui/tabs/tab_strip_model.h"
25 #include "chrome/common/chrome_paths.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/chrome_version_info.h"
28 #include "chrome/test/base/in_process_browser_test.h"
29 #include "chrome/test/base/test_switches.h"
30 #include "chrome/test/base/ui_test_utils.h"
31 #include "components/autofill/core/browser/autofill_test_utils.h"
32 #include "components/infobars/core/confirm_infobar_delegate.h"
33 #include "components/infobars/core/infobar.h"
34 #include "components/infobars/core/infobar_manager.h"
35 #include "components/password_manager/core/browser/test_password_store.h"
36 #include "components/password_manager/core/common/password_manager_switches.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/notification_service.h"
39 #include "content/public/browser/render_frame_host.h"
40 #include "content/public/browser/render_view_host.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/browser/web_contents_observer.h"
43 #include "content/public/common/content_switches.h"
44 #include "content/public/test/browser_test_utils.h"
45 #include "content/public/test/test_utils.h"
46 #include "net/base/filename_util.h"
47 #include "net/test/embedded_test_server/embedded_test_server.h"
48 #include "net/test/embedded_test_server/http_request.h"
49 #include "net/test/embedded_test_server/http_response.h"
50 #include "net/test/spawned_test_server/spawned_test_server.h"
51 #include "net/url_request/test_url_fetcher_factory.h"
52 #include "testing/gmock/include/gmock/gmock.h"
53 #include "third_party/WebKit/public/web/WebInputEvent.h"
54 #include "ui/events/keycodes/keyboard_codes.h"
55 #include "ui/gfx/geometry/point.h"
58 // NavigationObserver ---------------------------------------------------------
60 namespace {
62 // Observer that waits for navigation to complete and for the password infobar
63 // to be shown.
64 class NavigationObserver : public content::WebContentsObserver {
65 public:
66 explicit NavigationObserver(content::WebContents* web_contents)
67 : content::WebContentsObserver(web_contents),
68 message_loop_runner_(new content::MessageLoopRunner) {}
70 ~NavigationObserver() override {}
72 // Normally Wait() will not return until a main frame navigation occurs.
73 // If a path is set, Wait() will return after this path has been seen,
74 // regardless of the frame that navigated. Useful for multi-frame pages.
75 void SetPathToWaitFor(const std::string& path) {
76 wait_for_path_ = path;
79 // content::WebContentsObserver:
80 void DidFinishLoad(content::RenderFrameHost* render_frame_host,
81 const GURL& validated_url) override {
82 if (!wait_for_path_.empty()) {
83 if (validated_url.path() == wait_for_path_)
84 message_loop_runner_->Quit();
85 } else if (!render_frame_host->GetParent()) {
86 message_loop_runner_->Quit();
90 void Wait() { message_loop_runner_->Run(); }
92 private:
93 std::string wait_for_path_;
94 scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
96 DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
99 // Observes the save password prompt (bubble or infobar) for a specified
100 // WebContents, keeps track of whether or not it is currently shown, and allows
101 // accepting saving passwords through it.
102 class PromptObserver {
103 public:
104 virtual ~PromptObserver() {}
106 // Checks if the prompt is being currently shown.
107 virtual bool IsShowingPrompt() const = 0;
109 // Expecting that the prompt is shown, saves the password. Checks that the
110 // prompt is no longer visible afterwards.
111 void Accept() const {
112 EXPECT_TRUE(IsShowingPrompt());
113 AcceptImpl();
116 // Chooses the right implementation of PromptObserver and creates an instance
117 // of it.
118 static scoped_ptr<PromptObserver> Create(content::WebContents* web_contents);
120 protected:
121 PromptObserver() {}
123 // Accepts the password. The implementation can assume that the prompt is
124 // currently shown, but is required to verify that the prompt is eventually
125 // closed.
126 virtual void AcceptImpl() const = 0;
128 private:
129 DISALLOW_COPY_AND_ASSIGN(PromptObserver);
132 class InfoBarObserver : public PromptObserver,
133 public infobars::InfoBarManager::Observer {
134 public:
135 explicit InfoBarObserver(content::WebContents* web_contents)
136 : infobar_is_being_shown_(false),
137 infobar_service_(InfoBarService::FromWebContents(web_contents)) {
138 infobar_service_->AddObserver(this);
141 ~InfoBarObserver() override {
142 if (infobar_service_)
143 infobar_service_->RemoveObserver(this);
146 private:
147 // PromptObserver:
148 bool IsShowingPrompt() const override { return infobar_is_being_shown_; }
150 void AcceptImpl() const override {
151 EXPECT_EQ(1u, infobar_service_->infobar_count());
152 if (!infobar_service_->infobar_count())
153 return; // Let the test finish to gather possibly more diagnostics.
155 // ConfirmInfoBarDelegate::Accept returning true means the infobar is
156 // immediately closed. Checking the return value is preferred to testing
157 // IsShowingPrompt() here, for it avoids the delay until the closing
158 // notification is received.
159 EXPECT_TRUE(infobar_service_->infobar_at(0)
160 ->delegate()
161 ->AsConfirmInfoBarDelegate()
162 ->Accept());
165 // infobars::InfoBarManager::Observer:
166 void OnInfoBarAdded(infobars::InfoBar* infobar) override {
167 infobar_is_being_shown_ = true;
170 void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override {
171 infobar_is_being_shown_ = false;
174 void OnManagerShuttingDown(infobars::InfoBarManager* manager) override {
175 ASSERT_EQ(infobar_service_, manager);
176 infobar_service_->RemoveObserver(this);
177 infobar_service_ = NULL;
180 bool infobar_is_being_shown_;
181 InfoBarService* infobar_service_;
183 DISALLOW_COPY_AND_ASSIGN(InfoBarObserver);
186 class BubbleObserver : public PromptObserver {
187 public:
188 explicit BubbleObserver(content::WebContents* web_contents)
189 : ui_controller_(
190 ManagePasswordsUIController::FromWebContents(web_contents)) {}
192 ~BubbleObserver() override {}
194 private:
195 // PromptObserver:
196 bool IsShowingPrompt() const override {
197 return ui_controller_->PasswordPendingUserDecision();
200 void AcceptImpl() const override {
201 ui_controller_->SavePassword();
202 EXPECT_FALSE(IsShowingPrompt());
205 ManagePasswordsUIController* const ui_controller_;
207 DISALLOW_COPY_AND_ASSIGN(BubbleObserver);
210 GURL GetFileURL(const char* filename) {
211 base::FilePath path;
212 PathService::Get(chrome::DIR_TEST_DATA, &path);
213 path = path.AppendASCII("password").AppendASCII(filename);
214 CHECK(base::PathExists(path));
215 return net::FilePathToFileURL(path);
218 // static
219 scoped_ptr<PromptObserver> PromptObserver::Create(
220 content::WebContents* web_contents) {
221 if (ChromePasswordManagerClient::IsTheHotNewBubbleUIEnabled()) {
222 return scoped_ptr<PromptObserver>(new BubbleObserver(web_contents));
223 } else {
224 return scoped_ptr<PromptObserver>(new InfoBarObserver(web_contents));
228 // Handles |request| to "/basic_auth". If "Authorization" header is present,
229 // responds with a non-empty HTTP 200 page (regardless of its value). Otherwise
230 // serves a Basic Auth challenge.
231 scoped_ptr<net::test_server::HttpResponse> HandleTestAuthRequest(
232 const net::test_server::HttpRequest& request) {
233 if (!StartsWithASCII(request.relative_url, "/basic_auth", true))
234 return scoped_ptr<net::test_server::HttpResponse>();
236 if (ContainsKey(request.headers, "Authorization")) {
237 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
238 new net::test_server::BasicHttpResponse);
239 http_response->set_code(net::HTTP_OK);
240 http_response->set_content("Success!");
241 return http_response.Pass();
242 } else {
243 scoped_ptr<net::test_server::BasicHttpResponse> http_response(
244 new net::test_server::BasicHttpResponse);
245 http_response->set_code(net::HTTP_UNAUTHORIZED);
246 http_response->AddCustomHeader("WWW-Authenticate",
247 "Basic realm=\"test realm\"");
248 return http_response.Pass();
252 } // namespace
255 // PasswordManagerBrowserTest -------------------------------------------------
257 class PasswordManagerBrowserTest : public InProcessBrowserTest {
258 public:
259 PasswordManagerBrowserTest() {}
260 ~PasswordManagerBrowserTest() override {}
262 // InProcessBrowserTest:
263 void SetUpOnMainThread() override {
264 // Use TestPasswordStore to remove a possible race. Normally the
265 // PasswordStore does its database manipulation on the DB thread, which
266 // creates a possible race during navigation. Specifically the
267 // PasswordManager will ignore any forms in a page if the load from the
268 // PasswordStore has not completed.
269 PasswordStoreFactory::GetInstance()->SetTestingFactory(
270 browser()->profile(), TestPasswordStoreService::Build);
271 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
272 ASSERT_FALSE(CommandLine::ForCurrentProcess()->HasSwitch(
273 password_manager::switches::kEnableAutomaticPasswordSaving));
276 void TearDownOnMainThread() override {
277 ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
280 protected:
281 content::WebContents* WebContents() {
282 return browser()->tab_strip_model()->GetActiveWebContents();
285 content::RenderViewHost* RenderViewHost() {
286 return WebContents()->GetRenderViewHost();
289 // Wrapper around ui_test_utils::NavigateToURL that waits until
290 // DidFinishLoad() fires. Normally this function returns after
291 // DidStopLoading(), which caused flakiness as the NavigationObserver
292 // would sometimes see the DidFinishLoad event from a previous navigation and
293 // return immediately.
294 void NavigateToFile(const std::string& path) {
295 NavigationObserver observer(WebContents());
296 GURL url = embedded_test_server()->GetURL(path);
297 ui_test_utils::NavigateToURL(browser(), url);
298 observer.Wait();
301 // Waits until the "value" attribute of the HTML element with |element_id| is
302 // equal to |expected_value|. If the current value is not as expected, this
303 // waits until the "change" event is fired for the element. This also
304 // guarantees that once the real value matches the expected, the JavaScript
305 // event loop is spun to allow all other possible events to take place.
306 void WaitForElementValue(const std::string& element_id,
307 const std::string& expected_value);
308 // Checks that the current "value" attribute of the HTML element with
309 // |element_id| is equal to |expected_value|.
310 void CheckElementValue(const std::string& element_id,
311 const std::string& expected_value);
313 private:
314 DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
317 void PasswordManagerBrowserTest::WaitForElementValue(
318 const std::string& element_id,
319 const std::string& expected_value) {
320 enum ReturnCodes { // Possible results of the JavaScript code.
321 RETURN_CODE_OK,
322 RETURN_CODE_NO_ELEMENT,
323 RETURN_CODE_WRONG_VALUE,
324 RETURN_CODE_INVALID,
326 const std::string value_check_function = base::StringPrintf(
327 "function valueCheck() {"
328 " var element = document.getElementById('%s');"
329 " return element && element.value == '%s';"
330 "}",
331 element_id.c_str(),
332 expected_value.c_str());
333 const std::string script =
334 value_check_function +
335 base::StringPrintf(
336 "if (valueCheck()) {"
337 " /* Spin the event loop with setTimeout. */"
338 " setTimeout(window.domAutomationController.send(%d), 0);"
339 "} else {"
340 " var element = document.getElementById('%s');"
341 " if (!element)"
342 " window.domAutomationController.send(%d);"
343 " element.onchange = function() {"
344 " if (valueCheck()) {"
345 " /* Spin the event loop with setTimeout. */"
346 " setTimeout(window.domAutomationController.send(%d), 0);"
347 " } else {"
348 " window.domAutomationController.send(%d);"
349 " }"
350 " };"
351 "}",
352 RETURN_CODE_OK,
353 element_id.c_str(),
354 RETURN_CODE_NO_ELEMENT,
355 RETURN_CODE_OK,
356 RETURN_CODE_WRONG_VALUE);
357 int return_value = RETURN_CODE_INVALID;
358 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
359 RenderViewHost(), script, &return_value));
360 EXPECT_EQ(RETURN_CODE_OK, return_value)
361 << "element_id = " << element_id
362 << ", expected_value = " << expected_value;
365 void PasswordManagerBrowserTest::CheckElementValue(
366 const std::string& element_id,
367 const std::string& expected_value) {
368 const std::string value_check_script = base::StringPrintf(
369 "var element = document.getElementById('%s');"
370 "window.domAutomationController.send(element && element.value == '%s');",
371 element_id.c_str(),
372 expected_value.c_str());
373 bool return_value = false;
374 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
375 RenderViewHost(), value_check_script, &return_value));
376 EXPECT_TRUE(return_value) << "element_id = " << element_id
377 << ", expected_value = " << expected_value;
380 // Actual tests ---------------------------------------------------------------
381 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
382 PromptForNormalSubmit) {
383 NavigateToFile("/password/password_form.html");
385 // Fill a form and submit through a <input type="submit"> button. Nothing
386 // special.
387 NavigationObserver observer(WebContents());
388 scoped_ptr<PromptObserver> prompt_observer(
389 PromptObserver::Create(WebContents()));
390 std::string fill_and_submit =
391 "document.getElementById('username_field').value = 'temp';"
392 "document.getElementById('password_field').value = 'random';"
393 "document.getElementById('input_submit_button').click()";
394 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
395 observer.Wait();
396 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
399 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
400 PromptForSubmitWithInPageNavigation) {
401 NavigateToFile("/password/password_navigate_before_submit.html");
403 // Fill a form and submit through a <input type="submit"> button. Nothing
404 // special. The form does an in-page navigation before submitting.
405 NavigationObserver observer(WebContents());
406 scoped_ptr<PromptObserver> prompt_observer(
407 PromptObserver::Create(WebContents()));
408 std::string fill_and_submit =
409 "document.getElementById('username_field').value = 'temp';"
410 "document.getElementById('password_field').value = 'random';"
411 "document.getElementById('input_submit_button').click()";
412 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
413 observer.Wait();
414 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
417 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
418 LoginSuccessWithUnrelatedForm) {
419 // Log in, see a form on the landing page. That form is not related to the
420 // login form (=has a different action), so we should offer saving the
421 // password.
422 NavigateToFile("/password/password_form.html");
424 NavigationObserver observer(WebContents());
425 scoped_ptr<PromptObserver> prompt_observer(
426 PromptObserver::Create(WebContents()));
427 std::string fill_and_submit =
428 "document.getElementById('username_unrelated').value = 'temp';"
429 "document.getElementById('password_unrelated').value = 'random';"
430 "document.getElementById('submit_unrelated').click()";
431 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
432 observer.Wait();
433 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
436 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, LoginFailed) {
437 // Log in, see a form on the landing page. That form is not related to the
438 // login form (=has a different action), so we should offer saving the
439 // password.
440 NavigateToFile("/password/password_form.html");
442 NavigationObserver observer(WebContents());
443 scoped_ptr<PromptObserver> prompt_observer(
444 PromptObserver::Create(WebContents()));
445 std::string fill_and_submit =
446 "document.getElementById('username_failed').value = 'temp';"
447 "document.getElementById('password_failed').value = 'random';"
448 "document.getElementById('submit_failed').click()";
449 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
450 observer.Wait();
451 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
454 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, Redirects) {
455 NavigateToFile("/password/password_form.html");
457 // Fill a form and submit through a <input type="submit"> button. The form
458 // points to a redirection page.
459 NavigationObserver observer(WebContents());
460 scoped_ptr<PromptObserver> prompt_observer(
461 PromptObserver::Create(WebContents()));
462 std::string fill_and_submit =
463 "document.getElementById('username_redirect').value = 'temp';"
464 "document.getElementById('password_redirect').value = 'random';"
465 "document.getElementById('submit_redirect').click()";
466 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
467 observer.Wait();
468 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
470 // The redirection page now redirects via Javascript. We check that the
471 // infobar stays.
472 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
473 "window.location.href = 'done.html';"));
474 observer.Wait();
475 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
478 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
479 PromptForSubmitUsingJavaScript) {
480 NavigateToFile("/password/password_form.html");
482 // Fill a form and submit using <button> that calls submit() on the form.
483 // This should work regardless of the type of element, as long as submit() is
484 // called.
485 NavigationObserver observer(WebContents());
486 scoped_ptr<PromptObserver> prompt_observer(
487 PromptObserver::Create(WebContents()));
488 std::string fill_and_submit =
489 "document.getElementById('username_field').value = 'temp';"
490 "document.getElementById('password_field').value = 'random';"
491 "document.getElementById('submit_button').click()";
492 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
493 observer.Wait();
494 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
497 // Flaky: crbug.com/301547, observed on win and mac. Probably happens on all
498 // platforms.
499 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
500 DISABLED_PromptForDynamicForm) {
501 NavigateToFile("/password/dynamic_password_form.html");
503 // Fill the dynamic password form and submit.
504 NavigationObserver observer(WebContents());
505 scoped_ptr<PromptObserver> prompt_observer(
506 PromptObserver::Create(WebContents()));
507 std::string fill_and_submit =
508 "document.getElementById('create_form_button').click();"
509 "window.setTimeout(function() {"
510 " document.dynamic_form.username.value = 'tempro';"
511 " document.dynamic_form.password.value = 'random';"
512 " document.dynamic_form.submit();"
513 "}, 0)";
514 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
515 observer.Wait();
516 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
519 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
520 NavigateToFile("/password/password_form.html");
522 // Don't fill the password form, just navigate away. Shouldn't prompt.
523 NavigationObserver observer(WebContents());
524 scoped_ptr<PromptObserver> prompt_observer(
525 PromptObserver::Create(WebContents()));
526 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(),
527 "window.location.href = 'done.html';"));
528 observer.Wait();
529 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
532 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
533 NoPromptForSubFrameNavigation) {
534 NavigateToFile("/password/multi_frames.html");
536 // If you are filling out a password form in one frame and a different frame
537 // navigates, this should not trigger the infobar.
538 NavigationObserver observer(WebContents());
539 scoped_ptr<PromptObserver> prompt_observer(
540 PromptObserver::Create(WebContents()));
541 observer.SetPathToWaitFor("/password/done.html");
542 std::string fill =
543 "var first_frame = document.getElementById('first_frame');"
544 "var frame_doc = first_frame.contentDocument;"
545 "frame_doc.getElementById('username_field').value = 'temp';"
546 "frame_doc.getElementById('password_field').value = 'random';";
547 std::string navigate_frame =
548 "var second_iframe = document.getElementById('second_frame');"
549 "second_iframe.contentWindow.location.href = 'done.html';";
551 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
552 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
553 observer.Wait();
554 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
557 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
558 PromptAfterSubmitWithSubFrameNavigation) {
559 NavigateToFile("/password/multi_frames.html");
561 // Make sure that we prompt to save password even if a sub-frame navigation
562 // happens first.
563 NavigationObserver observer(WebContents());
564 scoped_ptr<PromptObserver> prompt_observer(
565 PromptObserver::Create(WebContents()));
566 observer.SetPathToWaitFor("/password/done.html");
567 std::string navigate_frame =
568 "var second_iframe = document.getElementById('second_frame');"
569 "second_iframe.contentWindow.location.href = 'other.html';";
570 std::string fill_and_submit =
571 "var first_frame = document.getElementById('first_frame');"
572 "var frame_doc = first_frame.contentDocument;"
573 "frame_doc.getElementById('username_field').value = 'temp';"
574 "frame_doc.getElementById('password_field').value = 'random';"
575 "frame_doc.getElementById('input_submit_button').click();";
577 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
578 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
579 observer.Wait();
580 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
583 IN_PROC_BROWSER_TEST_F(
584 PasswordManagerBrowserTest,
585 NoPromptForFailedLoginFromMainFrameWithMultiFramesInPage) {
586 NavigateToFile("/password/multi_frames.html");
588 // Make sure that we don't prompt to save the password for a failed login
589 // from the main frame with multiple frames in the same page.
590 NavigationObserver observer(WebContents());
591 scoped_ptr<PromptObserver> prompt_observer(
592 PromptObserver::Create(WebContents()));
593 std::string fill_and_submit =
594 "document.getElementById('username_failed').value = 'temp';"
595 "document.getElementById('password_failed').value = 'random';"
596 "document.getElementById('submit_failed').click();";
598 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
599 observer.Wait();
600 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
603 IN_PROC_BROWSER_TEST_F(
604 PasswordManagerBrowserTest,
605 NoPromptForFailedLoginFromSubFrameWithMultiFramesInPage) {
606 NavigateToFile("/password/multi_frames.html");
608 // Make sure that we don't prompt to save the password for a failed login
609 // from a sub-frame with multiple frames in the same page.
610 NavigationObserver observer(WebContents());
611 scoped_ptr<PromptObserver> prompt_observer(
612 PromptObserver::Create(WebContents()));
613 std::string fill_and_submit =
614 "var first_frame = document.getElementById('first_frame');"
615 "var frame_doc = first_frame.contentDocument;"
616 "frame_doc.getElementById('username_failed').value = 'temp';"
617 "frame_doc.getElementById('password_failed').value = 'random';"
618 "frame_doc.getElementById('submit_failed').click();"
619 "window.parent.location.href = 'multi_frames.html';";
621 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
622 observer.Wait();
623 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
626 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForXHRSubmit) {
627 #if defined(OS_WIN) && defined(USE_ASH)
628 // Disable this test in Metro+Ash for now (http://crbug.com/262796).
629 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
630 return;
631 #endif
632 NavigateToFile("/password/password_xhr_submit.html");
634 // Verify that we show the save password prompt if a form returns false
635 // in its onsubmit handler but instead logs in/navigates via XHR.
636 // Note that calling 'submit()' on a form with javascript doesn't call
637 // the onsubmit handler, so we click the submit button instead.
638 NavigationObserver observer(WebContents());
639 scoped_ptr<PromptObserver> prompt_observer(
640 PromptObserver::Create(WebContents()));
641 std::string fill_and_submit =
642 "document.getElementById('username_field').value = 'temp';"
643 "document.getElementById('password_field').value = 'random';"
644 "document.getElementById('submit_button').click()";
645 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
646 observer.Wait();
647 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
650 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
651 PromptForXHRWithoutOnSubmit) {
652 NavigateToFile("/password/password_xhr_submit.html");
654 // Verify that if XHR navigation occurs and the form is properly filled out,
655 // we try and save the password even though onsubmit hasn't been called.
656 NavigationObserver observer(WebContents());
657 scoped_ptr<PromptObserver> prompt_observer(
658 PromptObserver::Create(WebContents()));
659 std::string fill_and_navigate =
660 "document.getElementById('username_field').value = 'temp';"
661 "document.getElementById('password_field').value = 'random';"
662 "send_xhr()";
663 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate));
664 observer.Wait();
665 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
668 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
669 PromptForXHRWithNewPasswordsWithoutOnSubmit) {
670 NavigateToFile("/password/password_xhr_submit.html");
672 // Verify that if XHR navigation occurs and the form is properly filled out,
673 // we try and save the password even though onsubmit hasn't been called.
674 // Specifically verify that the password form saving new passwords is treated
675 // the same as a login form.
676 NavigationObserver observer(WebContents());
677 scoped_ptr<PromptObserver> prompt_observer(
678 PromptObserver::Create(WebContents()));
679 std::string fill_and_navigate =
680 "document.getElementById('signup_username_field').value = 'temp';"
681 "document.getElementById('signup_password_field').value = 'random';"
682 "document.getElementById('confirmation_password_field').value = 'random';"
683 "send_xhr()";
684 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_navigate));
685 observer.Wait();
686 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
689 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptIfLinkClicked) {
690 NavigateToFile("/password/password_form.html");
692 // Verify that if the user takes a direct action to leave the page, we don't
693 // prompt to save the password even if the form is already filled out.
694 NavigationObserver observer(WebContents());
695 scoped_ptr<PromptObserver> prompt_observer(
696 PromptObserver::Create(WebContents()));
697 std::string fill_and_click_link =
698 "document.getElementById('username_field').value = 'temp';"
699 "document.getElementById('password_field').value = 'random';"
700 "document.getElementById('link').click();";
701 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_click_link));
702 observer.Wait();
703 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
706 // TODO(jam): http://crbug.com/350550
707 #if !defined(OS_WIN)
708 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
709 VerifyPasswordGenerationUpload) {
710 // Prevent Autofill requests from actually going over the wire.
711 net::TestURLFetcherFactory factory;
712 // Disable Autofill requesting access to AddressBook data. This causes
713 // the test to hang on Mac.
714 autofill::test::DisableSystemServices(browser()->profile()->GetPrefs());
716 // Visit a signup form.
717 NavigateToFile("/password/signup_form.html");
719 // Enter a password and save it.
720 NavigationObserver first_observer(WebContents());
721 scoped_ptr<PromptObserver> prompt_observer(
722 PromptObserver::Create(WebContents()));
723 std::string fill_and_submit =
724 "document.getElementById('other_info').value = 'stuff';"
725 "document.getElementById('username_field').value = 'my_username';"
726 "document.getElementById('password_field').value = 'password';"
727 "document.getElementById('input_submit_button').click()";
728 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
730 first_observer.Wait();
731 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
732 prompt_observer->Accept();
734 // Now navigate to a login form that has similar HTML markup.
735 NavigateToFile("/password/password_form.html");
737 // Simulate a user click to force an autofill of the form's DOM value, not
738 // just the suggested value.
739 content::SimulateMouseClick(
740 WebContents(), 0, blink::WebMouseEvent::ButtonLeft);
742 // The form should be filled with the previously submitted username.
743 std::string get_username =
744 "window.domAutomationController.send("
745 "document.getElementById('username_field').value);";
746 std::string actual_username;
747 ASSERT_TRUE(content::ExecuteScriptAndExtractString(RenderViewHost(),
748 get_username,
749 &actual_username));
750 ASSERT_EQ("my_username", actual_username);
752 // Submit the form and verify that there is no infobar (as the password
753 // has already been saved).
754 NavigationObserver second_observer(WebContents());
755 scoped_ptr<PromptObserver> second_prompt_observer(
756 PromptObserver::Create(WebContents()));
757 std::string submit_form =
758 "document.getElementById('input_submit_button').click()";
759 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit_form));
760 second_observer.Wait();
761 EXPECT_FALSE(second_prompt_observer->IsShowingPrompt());
763 // Verify that we sent two pings to Autofill. One vote for of PASSWORD for
764 // the current form, and one vote for ACCOUNT_CREATION_PASSWORD on the
765 // original form since it has more than 2 text input fields and was used for
766 // the first time on a different form.
767 base::HistogramBase* upload_histogram =
768 base::StatisticsRecorder::FindHistogram(
769 "PasswordGeneration.UploadStarted");
770 ASSERT_TRUE(upload_histogram);
771 scoped_ptr<base::HistogramSamples> snapshot =
772 upload_histogram->SnapshotSamples();
773 EXPECT_EQ(0, snapshot->GetCount(0 /* failure */));
774 EXPECT_EQ(2, snapshot->GetCount(1 /* success */));
776 #endif
778 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForSubmitFromIframe) {
779 NavigateToFile("/password/password_submit_from_iframe.html");
781 // Submit a form in an iframe, then cause the whole page to navigate without a
782 // user gesture. We expect the save password prompt to be shown here, because
783 // some pages use such iframes for login forms.
784 NavigationObserver observer(WebContents());
785 scoped_ptr<PromptObserver> prompt_observer(
786 PromptObserver::Create(WebContents()));
787 std::string fill_and_submit =
788 "var iframe = document.getElementById('test_iframe');"
789 "var iframe_doc = iframe.contentDocument;"
790 "iframe_doc.getElementById('username_field').value = 'temp';"
791 "iframe_doc.getElementById('password_field').value = 'random';"
792 "iframe_doc.getElementById('submit_button').click()";
794 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
795 observer.Wait();
796 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
799 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
800 PromptForInputElementWithoutName) {
801 // Check that the prompt is shown for forms where input elements lack the
802 // "name" attribute but the "id" is present.
803 NavigateToFile("/password/password_form.html");
805 NavigationObserver observer(WebContents());
806 scoped_ptr<PromptObserver> prompt_observer(
807 PromptObserver::Create(WebContents()));
808 std::string fill_and_submit =
809 "document.getElementById('username_field_no_name').value = 'temp';"
810 "document.getElementById('password_field_no_name').value = 'random';"
811 "document.getElementById('input_submit_button_no_name').click()";
812 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
813 observer.Wait();
814 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
817 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
818 PromptForInputElementWithoutId) {
819 // Check that the prompt is shown for forms where input elements lack the
820 // "id" attribute but the "name" attribute is present.
821 NavigateToFile("/password/password_form.html");
823 NavigationObserver observer(WebContents());
824 scoped_ptr<PromptObserver> prompt_observer(
825 PromptObserver::Create(WebContents()));
826 std::string fill_and_submit =
827 "document.getElementsByName('username_field_no_id')[0].value = 'temp';"
828 "document.getElementsByName('password_field_no_id')[0].value = 'random';"
829 "document.getElementsByName('input_submit_button_no_id')[0].click()";
830 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
831 observer.Wait();
832 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
835 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
836 NoPromptForInputElementWithoutIdAndName) {
837 // Check that no prompt is shown for forms where the input fields lack both
838 // the "id" and the "name" attributes.
839 NavigateToFile("/password/password_form.html");
841 NavigationObserver observer(WebContents());
842 scoped_ptr<PromptObserver> prompt_observer(
843 PromptObserver::Create(WebContents()));
844 std::string fill_and_submit =
845 "var form = document.getElementById('testform_elements_no_id_no_name');"
846 "var username = form.children[0];"
847 "username.value = 'temp';"
848 "var password = form.children[1];"
849 "password.value = 'random';"
850 "form.children[2].click()"; // form.children[2] is the submit button.
851 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
852 observer.Wait();
853 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
856 // Test for checking that no prompt is shown for URLs with file: scheme.
857 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
858 NoPromptForFileSchemeURLs) {
859 GURL url = GetFileURL("password_form.html");
860 ui_test_utils::NavigateToURL(browser(), url);
862 NavigationObserver observer(WebContents());
863 scoped_ptr<PromptObserver> prompt_observer(
864 PromptObserver::Create(WebContents()));
865 std::string fill_and_submit =
866 "document.getElementById('username_field').value = 'temp';"
867 "document.getElementById('password_field').value = 'random';"
868 "document.getElementById('input_submit_button').click();";
869 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
870 observer.Wait();
871 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
874 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, DeleteFrameBeforeSubmit) {
875 NavigateToFile("/password/multi_frames.html");
877 NavigationObserver observer(WebContents());
878 // Make sure we save some password info from an iframe and then destroy it.
879 std::string save_and_remove =
880 "var first_frame = document.getElementById('first_frame');"
881 "var frame_doc = first_frame.contentDocument;"
882 "frame_doc.getElementById('username_field').value = 'temp';"
883 "frame_doc.getElementById('password_field').value = 'random';"
884 "frame_doc.getElementById('input_submit_button').click();"
885 "first_frame.parentNode.removeChild(first_frame);";
886 // Submit from the main frame, but without navigating through the onsubmit
887 // handler.
888 std::string navigate_frame =
889 "document.getElementById('username_field').value = 'temp';"
890 "document.getElementById('password_field').value = 'random';"
891 "document.getElementById('input_submit_button').click();"
892 "window.location.href = 'done.html';";
894 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), save_and_remove));
895 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
896 observer.Wait();
897 // The only thing we check here is that there is no use-after-free reported.
900 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PasswordValueAccessible) {
901 NavigateToFile("/password/form_and_link.html");
903 // Click on a link to open a new tab, then switch back to the first one.
904 EXPECT_EQ(1, browser()->tab_strip_model()->count());
905 std::string click =
906 "document.getElementById('testlink').click();";
907 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), click));
908 EXPECT_EQ(2, browser()->tab_strip_model()->count());
909 browser()->tab_strip_model()->ActivateTabAt(0, false);
911 // Fill in the credentials, and make sure they are saved.
912 NavigationObserver form_submit_observer(WebContents());
913 scoped_ptr<PromptObserver> prompt_observer(
914 PromptObserver::Create(WebContents()));
915 std::string fill_and_submit =
916 "document.getElementById('username_field').value = 'temp';"
917 "document.getElementById('password_field').value = 'random';"
918 "document.getElementById('input_submit_button').click();";
919 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
920 form_submit_observer.Wait();
921 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
922 prompt_observer->Accept();
924 // Reload the original page to have the saved credentials autofilled.
925 NavigationObserver reload_observer(WebContents());
926 NavigateToFile("/password/form_and_link.html");
927 reload_observer.Wait();
929 // Wait until the username is filled, to make sure autofill kicked in.
930 WaitForElementValue("username_field", "temp");
931 // Now check that the password is not accessible yet.
932 CheckElementValue("password_field", "");
933 // Let the user interact with the page.
934 content::SimulateMouseClickAt(
935 WebContents(), 0, blink::WebMouseEvent::ButtonLeft, gfx::Point(1, 1));
936 // Wait until that interaction causes the password value to be revealed.
937 WaitForElementValue("password_field", "random");
938 // And check that after the side-effects of the interaction took place, the
939 // username value stays the same.
940 CheckElementValue("username_field", "temp");
943 // The following test is limited to Aura, because
944 // RenderWidgetHostViewGuest::ProcessAckedTouchEvent is, and
945 // ProcessAckedTouchEvent is what triggers the translation of touch events to
946 // gesture events.
947 #if defined(USE_AURA)
948 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
949 PasswordValueAccessibleOnSubmit) {
950 NavigateToFile("/password/form_and_link.html");
952 // Fill in the credentials, and make sure they are saved.
953 NavigationObserver form_submit_observer(WebContents());
954 scoped_ptr<PromptObserver> prompt_observer(
955 PromptObserver::Create(WebContents()));
956 std::string fill_and_submit =
957 "document.getElementById('username_field').value = 'temp';"
958 "document.getElementById('password_field').value = 'random_secret';"
959 "document.getElementById('input_submit_button').click();";
960 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
961 form_submit_observer.Wait();
962 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
963 prompt_observer->Accept();
965 // Reload the original page to have the saved credentials autofilled.
966 NavigationObserver reload_observer(WebContents());
967 NavigateToFile("/password/form_and_link.html");
968 reload_observer.Wait();
970 NavigationObserver submit_observer(WebContents());
971 // Submit the form via a tap on the submit button. The button is placed at 0,
972 // 100, and has height 300 and width 700.
973 content::SimulateTapAt(WebContents(), gfx::Point(350, 250));
974 submit_observer.Wait();
975 std::string query = WebContents()->GetURL().query();
976 EXPECT_NE(std::string::npos, query.find("random_secret")) << query;
978 #endif
980 // Test fix for crbug.com/338650.
981 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
982 DontPromptForPasswordFormWithDefaultValue) {
983 NavigateToFile("/password/password_form_with_default_value.html");
985 // Don't prompt if we navigate away even if there is a password value since
986 // it's not coming from the user.
987 NavigationObserver observer(WebContents());
988 scoped_ptr<PromptObserver> prompt_observer(
989 PromptObserver::Create(WebContents()));
990 NavigateToFile("/password/done.html");
991 observer.Wait();
992 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
995 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
996 PromptWhenEnableAutomaticPasswordSavingSwitchIsNotSet) {
997 NavigateToFile("/password/password_form.html");
999 // Fill a form and submit through a <input type="submit"> button.
1000 NavigationObserver observer(WebContents());
1001 scoped_ptr<PromptObserver> prompt_observer(
1002 PromptObserver::Create(WebContents()));
1003 std::string fill_and_submit =
1004 "document.getElementById('username_field').value = 'temp';"
1005 "document.getElementById('password_field').value = 'random';"
1006 "document.getElementById('input_submit_button').click()";
1007 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
1008 observer.Wait();
1009 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1012 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1013 DontPromptWhenEnableAutomaticPasswordSavingSwitchIsSet) {
1014 password_manager::TestPasswordStore* password_store =
1015 static_cast<password_manager::TestPasswordStore*>(
1016 PasswordStoreFactory::GetForProfile(browser()->profile(),
1017 Profile::IMPLICIT_ACCESS).get());
1019 EXPECT_TRUE(password_store->IsEmpty());
1021 NavigateToFile("/password/password_form.html");
1023 // Add the enable-automatic-password-saving switch.
1024 CommandLine::ForCurrentProcess()->AppendSwitch(
1025 password_manager::switches::kEnableAutomaticPasswordSaving);
1027 // Fill a form and submit through a <input type="submit"> button.
1028 NavigationObserver observer(WebContents());
1029 scoped_ptr<PromptObserver> prompt_observer(
1030 PromptObserver::Create(WebContents()));
1031 // Make sure that the only passwords saved are the auto-saved ones.
1032 std::string fill_and_submit =
1033 "document.getElementById('username_field').value = 'temp';"
1034 "document.getElementById('password_field').value = 'random';"
1035 "document.getElementById('input_submit_button').click()";
1036 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
1037 observer.Wait();
1038 if (chrome::VersionInfo::GetChannel() ==
1039 chrome::VersionInfo::CHANNEL_UNKNOWN) {
1040 // Passwords getting auto-saved, no prompt.
1041 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1042 EXPECT_FALSE(password_store->IsEmpty());
1043 } else {
1044 // Prompt shown, and no passwords saved automatically.
1045 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1046 EXPECT_TRUE(password_store->IsEmpty());
1050 // Test fix for crbug.com/368690.
1051 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptWhenReloading) {
1052 NavigateToFile("/password/password_form.html");
1054 std::string fill =
1055 "document.getElementById('username_redirect').value = 'temp';"
1056 "document.getElementById('password_redirect').value = 'random';";
1057 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
1059 NavigationObserver observer(WebContents());
1060 scoped_ptr<PromptObserver> prompt_observer(
1061 PromptObserver::Create(WebContents()));
1062 GURL url = embedded_test_server()->GetURL("/password/password_form.html");
1063 chrome::NavigateParams params(browser(), url,
1064 ui::PAGE_TRANSITION_RELOAD);
1065 ui_test_utils::NavigateToURL(&params);
1066 observer.Wait();
1067 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1070 // Test that if a form gets dynamically added between the form parsing and
1071 // rendering, and while the main frame still loads, it still is registered, and
1072 // thus saving passwords from it works.
1073 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1074 FormsAddedBetweenParsingAndRendering) {
1075 NavigateToFile("/password/between_parsing_and_rendering.html");
1077 NavigationObserver observer(WebContents());
1078 scoped_ptr<PromptObserver> prompt_observer(
1079 PromptObserver::Create(WebContents()));
1080 std::string submit =
1081 "document.getElementById('username').value = 'temp';"
1082 "document.getElementById('password').value = 'random';"
1083 "document.getElementById('submit-button').click();";
1084 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1085 observer.Wait();
1087 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1090 // Test that if there was no previous page load then the PasswordManagerDriver
1091 // does not think that there were SSL errors on the current page. The test opens
1092 // a new tab with a URL for which the embedded test server issues a basic auth
1093 // challenge.
1094 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoLastLoadGoodLastLoad) {
1095 // Teach the embedded server to handle requests by issuing the basic auth
1096 // challenge.
1097 embedded_test_server()->RegisterRequestHandler(
1098 base::Bind(&HandleTestAuthRequest));
1100 LoginPromptBrowserTestObserver login_observer;
1101 // We need to register to all sources, because the navigation observer we are
1102 // interested in is for a new tab to be opened, and thus does not exist yet.
1103 login_observer.Register(content::NotificationService::AllSources());
1105 password_manager::TestPasswordStore* password_store =
1106 static_cast<password_manager::TestPasswordStore*>(
1107 PasswordStoreFactory::GetForProfile(browser()->profile(),
1108 Profile::IMPLICIT_ACCESS).get());
1109 EXPECT_TRUE(password_store->IsEmpty());
1111 // Navigate to a page requiring HTTP auth. Wait for the tab to get the correct
1112 // WebContents, but don't wait for navigation, which only finishes after
1113 // authentication.
1114 ui_test_utils::NavigateToURLWithDisposition(
1115 browser(),
1116 embedded_test_server()->GetURL("/basic_auth"),
1117 NEW_FOREGROUND_TAB,
1118 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
1120 content::NavigationController* nav_controller =
1121 &WebContents()->GetController();
1122 NavigationObserver nav_observer(WebContents());
1123 scoped_ptr<PromptObserver> prompt_observer(
1124 PromptObserver::Create(WebContents()));
1125 WindowedAuthNeededObserver auth_needed_observer(nav_controller);
1126 auth_needed_observer.Wait();
1128 WindowedAuthSuppliedObserver auth_supplied_observer(nav_controller);
1129 // Offer valid credentials on the auth challenge.
1130 ASSERT_EQ(1u, login_observer.handlers().size());
1131 LoginHandler* handler = *login_observer.handlers().begin();
1132 ASSERT_TRUE(handler);
1133 // Any username/password will work.
1134 handler->SetAuth(base::UTF8ToUTF16("user"), base::UTF8ToUTF16("pwd"));
1135 auth_supplied_observer.Wait();
1137 // The password manager should be working correctly.
1138 nav_observer.Wait();
1139 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1140 prompt_observer->Accept();
1142 // Spin the message loop to make sure the password store had a chance to save
1143 // the password.
1144 base::RunLoop run_loop;
1145 run_loop.RunUntilIdle();
1146 EXPECT_FALSE(password_store->IsEmpty());
1149 // In some situations, multiple PasswordFormManager instances from
1150 // PasswordManager::pending_login_managers_ would match (via DoesManage) a form
1151 // to be provisionally saved. One of them might be a complete match, the other
1152 // all-but-action match. Normally, the former should be preferred, but if the
1153 // former has not finished matching, and the latter has, the latter should be
1154 // used (otherwise we'd give up even though we could have saved the password).
1155 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1156 PreferPasswordFormManagerWhichFinishedMatching) {
1157 NavigateToFile("/password/create_form_copy_on_submit.html");
1159 NavigationObserver observer(WebContents());
1160 scoped_ptr<PromptObserver> prompt_observer(
1161 PromptObserver::Create(WebContents()));
1162 std::string submit =
1163 "document.getElementById('username').value = 'overwrite_me';"
1164 "document.getElementById('password').value = 'random';"
1165 "document.getElementById('non-form-button').click();";
1166 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1167 observer.Wait();
1169 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1172 // Test that if login fails and content server pushes a different login form
1173 // with action URL having different schemes. Heuristic shall be able
1174 // identify such cases and *shall not* prompt to save incorrect password.
1175 IN_PROC_BROWSER_TEST_F(
1176 PasswordManagerBrowserTest,
1177 NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpToHttps) {
1178 std::string path =
1179 "/password/separate_login_form_with_onload_submit_script.html";
1180 GURL http_url(embedded_test_server()->GetURL(path));
1181 ASSERT_TRUE(http_url.SchemeIs(url::kHttpScheme));
1183 NavigationObserver observer(WebContents());
1184 scoped_ptr<PromptObserver> prompt_observer(
1185 PromptObserver::Create(WebContents()));
1186 ui_test_utils::NavigateToURL(browser(), http_url);
1188 observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1189 observer.Wait();
1191 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1194 IN_PROC_BROWSER_TEST_F(
1195 PasswordManagerBrowserTest,
1196 NoPromptForLoginFailedAndServerPushSeperateLoginForm_HttpsToHttp) {
1197 CommandLine::ForCurrentProcess()->AppendSwitch(
1198 switches::kAllowRunningInsecureContent);
1199 CommandLine::ForCurrentProcess()->AppendSwitch(
1200 switches::kIgnoreCertificateErrors);
1201 const base::FilePath::CharType kDocRoot[] =
1202 FILE_PATH_LITERAL("chrome/test/data");
1203 net::SpawnedTestServer https_test_server(
1204 net::SpawnedTestServer::TYPE_HTTPS,
1205 net::SpawnedTestServer::SSLOptions(
1206 net::SpawnedTestServer::SSLOptions::CERT_OK),
1207 base::FilePath(kDocRoot));
1208 ASSERT_TRUE(https_test_server.Start());
1210 // This test case cannot inject the scripts via content::ExecuteScript() in
1211 // files served through HTTPS. Therefore the scripts are made part of the HTML
1212 // site and executed on load.
1213 std::string path =
1214 "password/separate_login_form_with_onload_submit_script.html";
1215 GURL https_url(https_test_server.GetURL(path));
1216 ASSERT_TRUE(https_url.SchemeIs(url::kHttpsScheme));
1218 NavigationObserver observer(WebContents());
1219 scoped_ptr<PromptObserver> prompt_observer(
1220 PromptObserver::Create(WebContents()));
1221 ui_test_utils::NavigateToURL(browser(), https_url);
1223 observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1224 observer.Wait();
1226 EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1229 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1230 PromptWhenPasswordFormWithoutUsernameFieldSubmitted) {
1231 password_manager::TestPasswordStore* password_store =
1232 static_cast<password_manager::TestPasswordStore*>(
1233 PasswordStoreFactory::GetForProfile(browser()->profile(),
1234 Profile::IMPLICIT_ACCESS).get());
1236 EXPECT_TRUE(password_store->IsEmpty());
1238 NavigateToFile("/password/form_with_only_password_field.html");
1240 NavigationObserver observer(WebContents());
1241 scoped_ptr<PromptObserver> prompt_observer(
1242 PromptObserver::Create(WebContents()));
1243 std::string submit =
1244 "document.getElementById('password').value = 'password';"
1245 "document.getElementById('submit-button').click();";
1246 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1247 observer.Wait();
1249 EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1250 prompt_observer->Accept();
1252 // Spin the message loop to make sure the password store had a chance to save
1253 // the password.
1254 base::RunLoop run_loop;
1255 run_loop.RunUntilIdle();
1256 EXPECT_FALSE(password_store->IsEmpty());
1259 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
1260 AutofillSuggetionsForPasswordFormWithoutUsernameField) {
1261 password_manager::TestPasswordStore* password_store =
1262 static_cast<password_manager::TestPasswordStore*>(
1263 PasswordStoreFactory::GetForProfile(browser()->profile(),
1264 Profile::IMPLICIT_ACCESS).get());
1266 EXPECT_TRUE(password_store->IsEmpty());
1268 // Password form without username-field.
1269 NavigateToFile("/password/form_with_only_password_field.html");
1271 NavigationObserver observer(WebContents());
1272 scoped_ptr<PromptObserver> prompt_observer(
1273 PromptObserver::Create(WebContents()));
1274 std::string submit =
1275 "document.getElementById('password').value = 'mypassword';"
1276 "document.getElementById('submit-button').click();";
1277 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), submit));
1278 observer.Wait();
1280 prompt_observer->Accept();
1282 // Spin the message loop to make sure the password store had a chance to save
1283 // the password.
1284 base::RunLoop run_loop;
1285 run_loop.RunUntilIdle();
1286 EXPECT_FALSE(password_store->IsEmpty());
1288 // Now, navigate to same html password form and verify whether password is
1289 // autofilled.
1290 NavigateToFile("/password/form_with_only_password_field.html");
1292 // Let the user interact with the page, so that DOM gets modification events,
1293 // needed for autofilling fields.
1294 content::SimulateMouseClickAt(
1295 WebContents(), 0, blink::WebMouseEvent::ButtonLeft, gfx::Point(1, 1));
1297 // Wait until that interaction causes the password value to be revealed.
1298 WaitForElementValue("password", "mypassword");