Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / password_manager / password_manager_browsertest.cc
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.
4
5 #include <string>
6
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"
56
57
58 // NavigationObserver ---------------------------------------------------------
59
60 namespace {
61
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) {}
69
70   ~NavigationObserver() override {}
71
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;
77   }
78
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();
87     }
88   }
89
90   void Wait() { message_loop_runner_->Run(); }
91
92  private:
93   std::string wait_for_path_;
94   scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
95
96   DISALLOW_COPY_AND_ASSIGN(NavigationObserver);
97 };
98
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() {}
105
106   // Checks if the prompt is being currently shown.
107   virtual bool IsShowingPrompt() const = 0;
108
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();
114   }
115
116   // Chooses the right implementation of PromptObserver and creates an instance
117   // of it.
118   static scoped_ptr<PromptObserver> Create(content::WebContents* web_contents);
119
120  protected:
121   PromptObserver() {}
122
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;
127
128  private:
129   DISALLOW_COPY_AND_ASSIGN(PromptObserver);
130 };
131
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);
139   }
140
141   ~InfoBarObserver() override {
142     if (infobar_service_)
143       infobar_service_->RemoveObserver(this);
144   }
145
146  private:
147   // PromptObserver:
148   bool IsShowingPrompt() const override { return infobar_is_being_shown_; }
149
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.
154
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());
163   }
164
165   // infobars::InfoBarManager::Observer:
166   void OnInfoBarAdded(infobars::InfoBar* infobar) override {
167     infobar_is_being_shown_ = true;
168   }
169
170   void OnInfoBarRemoved(infobars::InfoBar* infobar, bool animate) override {
171     infobar_is_being_shown_ = false;
172   }
173
174   void OnManagerShuttingDown(infobars::InfoBarManager* manager) override {
175     ASSERT_EQ(infobar_service_, manager);
176     infobar_service_->RemoveObserver(this);
177     infobar_service_ = NULL;
178   }
179
180   bool infobar_is_being_shown_;
181   InfoBarService* infobar_service_;
182
183   DISALLOW_COPY_AND_ASSIGN(InfoBarObserver);
184 };
185
186 class BubbleObserver : public PromptObserver {
187  public:
188   explicit BubbleObserver(content::WebContents* web_contents)
189       : ui_controller_(
190             ManagePasswordsUIController::FromWebContents(web_contents)) {}
191
192   ~BubbleObserver() override {}
193
194  private:
195   // PromptObserver:
196   bool IsShowingPrompt() const override {
197     return ui_controller_->PasswordPendingUserDecision();
198   }
199
200   void AcceptImpl() const override {
201     ui_controller_->SavePassword();
202     EXPECT_FALSE(IsShowingPrompt());
203   }
204
205   ManagePasswordsUIController* const ui_controller_;
206
207   DISALLOW_COPY_AND_ASSIGN(BubbleObserver);
208 };
209
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);
216 }
217
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));
225   }
226 }
227
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>();
235
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();
249   }
250 }
251
252 }  // namespace
253
254
255 // PasswordManagerBrowserTest -------------------------------------------------
256
257 class PasswordManagerBrowserTest : public InProcessBrowserTest {
258  public:
259   PasswordManagerBrowserTest() {}
260   ~PasswordManagerBrowserTest() override {}
261
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));
274   }
275
276   void TearDownOnMainThread() override {
277     ASSERT_TRUE(embedded_test_server()->ShutdownAndWaitUntilComplete());
278   }
279
280  protected:
281   content::WebContents* WebContents() {
282     return browser()->tab_strip_model()->GetActiveWebContents();
283   }
284
285   content::RenderViewHost* RenderViewHost() {
286     return WebContents()->GetRenderViewHost();
287   }
288
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();
299   }
300
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);
312
313  private:
314   DISALLOW_COPY_AND_ASSIGN(PasswordManagerBrowserTest);
315 };
316
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,
325   };
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;
363 }
364
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;
378 }
379
380 // Actual tests ---------------------------------------------------------------
381 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
382                        PromptForNormalSubmit) {
383   NavigateToFile("/password/password_form.html");
384
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());
397 }
398
399 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
400                        PromptForSubmitWithInPageNavigation) {
401   NavigateToFile("/password/password_navigate_before_submit.html");
402
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());
415 }
416
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");
423
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());
434 }
435
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");
441
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());
452 }
453
454 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, Redirects) {
455   NavigateToFile("/password/password_form.html");
456
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());
469
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());
476 }
477
478 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
479                        PromptForSubmitUsingJavaScript) {
480   NavigateToFile("/password/password_form.html");
481
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());
495 }
496
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");
502
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());
517 }
518
519 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptForNavigation) {
520   NavigateToFile("/password/password_form.html");
521
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());
530 }
531
532 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
533                        NoPromptForSubFrameNavigation) {
534   NavigateToFile("/password/multi_frames.html");
535
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';";
550
551   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill));
552   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), navigate_frame));
553   observer.Wait();
554   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
555 }
556
557 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
558                        PromptAfterSubmitWithSubFrameNavigation) {
559   NavigateToFile("/password/multi_frames.html");
560
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();";
576
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());
581 }
582
583 IN_PROC_BROWSER_TEST_F(
584     PasswordManagerBrowserTest,
585     NoPromptForFailedLoginFromMainFrameWithMultiFramesInPage) {
586   NavigateToFile("/password/multi_frames.html");
587
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();";
597
598   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
599   observer.Wait();
600   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
601 }
602
603 IN_PROC_BROWSER_TEST_F(
604     PasswordManagerBrowserTest,
605     NoPromptForFailedLoginFromSubFrameWithMultiFramesInPage) {
606   NavigateToFile("/password/multi_frames.html");
607
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';";
620
621   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
622   observer.Wait();
623   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
624 }
625
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");
633
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());
648 }
649
650 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
651                        PromptForXHRWithoutOnSubmit) {
652   NavigateToFile("/password/password_xhr_submit.html");
653
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());
666 }
667
668 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
669                        PromptForXHRWithNewPasswordsWithoutOnSubmit) {
670   NavigateToFile("/password/password_xhr_submit.html");
671
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());
687 }
688
689 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptIfLinkClicked) {
690   NavigateToFile("/password/password_form.html");
691
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());
704 }
705
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());
715
716   // Visit a signup form.
717   NavigateToFile("/password/signup_form.html");
718
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));
729
730   first_observer.Wait();
731   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
732   prompt_observer->Accept();
733
734   // Now navigate to a login form that has similar HTML markup.
735   NavigateToFile("/password/password_form.html");
736
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);
741
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);
751
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());
762
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 */));
775 }
776 #endif
777
778 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PromptForSubmitFromIframe) {
779   NavigateToFile("/password/password_submit_from_iframe.html");
780
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()";
793
794   ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_and_submit));
795   observer.Wait();
796   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
797 }
798
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");
804
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());
815 }
816
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");
822
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());
833 }
834
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");
840
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());
854 }
855
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);
861
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());
872 }
873
874 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, DeleteFrameBeforeSubmit) {
875   NavigateToFile("/password/multi_frames.html");
876
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';";
893
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.
898 }
899
900 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, PasswordValueAccessible) {
901   NavigateToFile("/password/form_and_link.html");
902
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);
910
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();
923
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();
928
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");
941 }
942
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");
951
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();
964
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();
969
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;
977 }
978 #endif
979
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");
984
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());
993 }
994
995 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest,
996                        PromptWhenEnableAutomaticPasswordSavingSwitchIsNotSet) {
997   NavigateToFile("/password/password_form.html");
998
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());
1010 }
1011
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());
1018
1019   EXPECT_TRUE(password_store->IsEmpty());
1020
1021   NavigateToFile("/password/password_form.html");
1022
1023   // Add the enable-automatic-password-saving switch.
1024   CommandLine::ForCurrentProcess()->AppendSwitch(
1025       password_manager::switches::kEnableAutomaticPasswordSaving);
1026
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());
1047   }
1048 }
1049
1050 // Test fix for crbug.com/368690.
1051 IN_PROC_BROWSER_TEST_F(PasswordManagerBrowserTest, NoPromptWhenReloading) {
1052   NavigateToFile("/password/password_form.html");
1053
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));
1058
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());
1068 }
1069
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");
1076
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();
1086
1087   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1088 }
1089
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));
1099
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());
1104
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());
1110
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);
1119
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();
1127
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();
1136
1137   // The password manager should be working correctly.
1138   nav_observer.Wait();
1139   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1140   prompt_observer->Accept();
1141
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());
1147 }
1148
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");
1158
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();
1168
1169   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1170 }
1171
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));
1182
1183   NavigationObserver observer(WebContents());
1184   scoped_ptr<PromptObserver> prompt_observer(
1185       PromptObserver::Create(WebContents()));
1186   ui_test_utils::NavigateToURL(browser(), http_url);
1187
1188   observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1189   observer.Wait();
1190
1191   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1192 }
1193
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());
1209
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));
1217
1218   NavigationObserver observer(WebContents());
1219   scoped_ptr<PromptObserver> prompt_observer(
1220       PromptObserver::Create(WebContents()));
1221   ui_test_utils::NavigateToURL(browser(), https_url);
1222
1223   observer.SetPathToWaitFor("/password/done_and_separate_login_form.html");
1224   observer.Wait();
1225
1226   EXPECT_FALSE(prompt_observer->IsShowingPrompt());
1227 }
1228
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());
1235
1236   EXPECT_TRUE(password_store->IsEmpty());
1237
1238   NavigateToFile("/password/form_with_only_password_field.html");
1239
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();
1248
1249   EXPECT_TRUE(prompt_observer->IsShowingPrompt());
1250   prompt_observer->Accept();
1251
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());
1257 }
1258
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());
1265
1266   EXPECT_TRUE(password_store->IsEmpty());
1267
1268   // Password form without username-field.
1269   NavigateToFile("/password/form_with_only_password_field.html");
1270
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();
1279
1280   prompt_observer->Accept();
1281
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());
1287
1288   // Now, navigate to same html password form and verify whether password is
1289   // autofilled.
1290   NavigateToFile("/password/form_with_only_password_field.html");
1291
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));
1296
1297   // Wait until that interaction causes the password value to be revealed.
1298   WaitForElementValue("password", "mypassword");
1299 }