| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/macros.h" | 5 #include "base/macros.h" |
| 6 #include "base/stl_util.h" | 6 #include "base/stl_util.h" |
| 7 #include "base/strings/stringprintf.h" |
| 7 #include "base/strings/utf_string_conversions.h" | 8 #include "base/strings/utf_string_conversions.h" |
| 9 #include "chrome/browser/password_manager/chrome_password_manager_client.h" |
| 8 #include "chrome/browser/password_manager/password_manager_test_base.h" | 10 #include "chrome/browser/password_manager/password_manager_test_base.h" |
| 9 #include "chrome/browser/password_manager/password_store_factory.h" | 11 #include "chrome/browser/password_manager/password_store_factory.h" |
| 10 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
| 11 #include "chrome/browser/profiles/profile_io_data.h" | 13 #include "chrome/browser/profiles/profile_io_data.h" |
| 12 #include "chrome/browser/ui/browser.h" | 14 #include "chrome/browser/ui/browser.h" |
| 13 #include "chrome/browser/ui/passwords/passwords_model_delegate.h" | 15 #include "chrome/browser/ui/passwords/passwords_model_delegate.h" |
| 16 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| 14 #include "chrome/test/base/ui_test_utils.h" | 17 #include "chrome/test/base/ui_test_utils.h" |
| 15 #include "components/password_manager/core/browser/password_bubble_experiment.h" | 18 #include "components/password_manager/core/browser/password_bubble_experiment.h" |
| 16 #include "components/password_manager/core/browser/test_password_store.h" | 19 #include "components/password_manager/core/browser/test_password_store.h" |
| 20 #include "content/public/browser/web_contents.h" |
| 21 #include "content/public/browser/web_contents_observer.h" |
| 17 #include "content/public/test/browser_test.h" | 22 #include "content/public/test/browser_test.h" |
| 18 #include "content/public/test/browser_test_utils.h" | 23 #include "content/public/test/browser_test_utils.h" |
| 19 #include "net/dns/mock_host_resolver.h" | 24 #include "net/dns/mock_host_resolver.h" |
| 20 | 25 |
| 21 namespace { | 26 namespace { |
| 22 | 27 |
| 23 class CredentialManagerBrowserTest : public PasswordManagerBrowserTestBase { | 28 class CredentialManagerBrowserTest : public PasswordManagerBrowserTestBase { |
| 24 public: | 29 public: |
| 25 CredentialManagerBrowserTest() = default; | 30 CredentialManagerBrowserTest() = default; |
| 26 | 31 |
| 27 void SetUpOnMainThread() override { | 32 void SetUpOnMainThread() override { |
| 28 PasswordManagerBrowserTestBase::SetUpOnMainThread(); | 33 PasswordManagerBrowserTestBase::SetUpOnMainThread(); |
| 29 // Redirect all requests to localhost. | 34 // Redirect all requests to localhost. |
| 30 host_resolver()->AddRule("*", "127.0.0.1"); | 35 host_resolver()->AddRule("*", "127.0.0.1"); |
| 31 } | 36 } |
| 32 | 37 |
| 33 bool IsShowingAccountChooser() { | 38 bool IsShowingAccountChooser() { |
| 34 return PasswordsModelDelegateFromWebContents(WebContents())-> | 39 return PasswordsModelDelegateFromWebContents(WebContents())->GetState() == |
| 35 GetState() == password_manager::ui::CREDENTIAL_REQUEST_STATE; | 40 password_manager::ui::CREDENTIAL_REQUEST_STATE; |
| 36 } | 41 } |
| 37 | 42 |
| 38 // Similarly to PasswordManagerBrowserTestBase::NavigateToFile this is a | 43 // Similarly to PasswordManagerBrowserTestBase::NavigateToFile this is a |
| 39 // wrapper around ui_test_utils::NavigateURL that waits until DidFinishLoad() | 44 // wrapper around ui_test_utils::NavigateURL that waits until DidFinishLoad() |
| 40 // fires. Different to NavigateToFile this method allows passing a test_server | 45 // fires. Different to NavigateToFile this method allows passing a test_server |
| 41 // and modifications to the hostname. | 46 // and modifications to the hostname. |
| 42 void NavigateToURL(const net::EmbeddedTestServer& test_server, | 47 void NavigateToURL(const net::EmbeddedTestServer& test_server, |
| 43 const std::string& hostname, | 48 const std::string& hostname, |
| 44 const std::string& relative_url) { | 49 const std::string& relative_url) { |
| 45 NavigationObserver observer(WebContents()); | 50 NavigationObserver observer(WebContents()); |
| 46 GURL url = test_server.GetURL(hostname, relative_url); | 51 GURL url = test_server.GetURL(hostname, relative_url); |
| 47 ui_test_utils::NavigateToURL(browser(), url); | 52 ui_test_utils::NavigateToURL(browser(), url); |
| 48 observer.Wait(); | 53 observer.Wait(); |
| 49 } | 54 } |
| 50 | 55 |
| 56 // Triggers a call to `navigator.credentials.get` to retrieve passwords, waits |
| 57 // for success, and ASSERTs that |expect_has_results| is satisfied. |
| 58 void TriggerNavigatorGetPasswordCredentialsAndExpectHasResult( |
| 59 content::WebContents* web_contents, |
| 60 bool expect_has_results) { |
| 61 bool result = false; |
| 62 ASSERT_TRUE(content::ExecuteScriptAndExtractBool( |
| 63 web_contents, |
| 64 "navigator.credentials.get({password: true}).then(c => {" |
| 65 " window.domAutomationController.send(!!c);" |
| 66 "});", |
| 67 &result)); |
| 68 ASSERT_EQ(expect_has_results, result); |
| 69 } |
| 70 |
| 71 // Schedules a call to be made to navigator.credentials.store() in the |
| 72 // `unload` handler to save a credential with |username| and |password|. |
| 73 void ScheduleNavigatorStoreCredentialAtUnload( |
| 74 content::WebContents* web_contents, |
| 75 const char* username, |
| 76 const char* password) { |
| 77 ASSERT_TRUE(content::ExecuteScript( |
| 78 web_contents, |
| 79 base::StringPrintf( |
| 80 "window.addEventListener(\"unload\", () => {" |
| 81 " var c = new PasswordCredential({ id: '%s', password: '%s' });" |
| 82 " navigator.credentials.store(c);" |
| 83 "});", |
| 84 username, password))); |
| 85 } |
| 86 |
| 87 // Tests that when navigator.credentials.store() is called in an `unload` |
| 88 // handler before a same-RenderFrame navigation, the request is guaranteed to |
| 89 // be serviced in the context of the initial document. |
| 90 // |
| 91 // If |preestablish_mojo_pipe| is set, then the CredentialManagerClient will |
| 92 // establish the Mojo connection to the CredentialManagerImpl ahead of time, |
| 93 // instead of letting the Mojo connection be established on-demand when the |
| 94 // call to store() triggered from the unload handler. |
| 95 void TestStoreInUnloadHandlerForSameSiteNavigation( |
| 96 bool preestablish_mojo_pipe) { |
| 97 // Use URLs that differ on subdomains so we can tell which one was used for |
| 98 // saving, but they still belong to the same SiteInstance, so they will be |
| 99 // renderered in the same RenderFrame (in the same process). |
| 100 const GURL a_url1 = https_test_server().GetURL("foo.a.com", "/title1.html"); |
| 101 const GURL a_url2 = https_test_server().GetURL("bar.a.com", "/title2.html"); |
| 102 |
| 103 // Navigate to a mostly empty page. |
| 104 ui_test_utils::NavigateToURL(browser(), a_url1); |
| 105 |
| 106 ChromePasswordManagerClient* client = |
| 107 ChromePasswordManagerClient::FromWebContents(WebContents()); |
| 108 |
| 109 if (preestablish_mojo_pipe) { |
| 110 EXPECT_FALSE(client->has_binding_for_credential_manager()); |
| 111 ASSERT_NO_FATAL_FAILURE( |
| 112 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult( |
| 113 WebContents(), false)); |
| 114 EXPECT_TRUE(client->has_binding_for_credential_manager()); |
| 115 } |
| 116 |
| 117 // Schedule storing a credential on the `unload` event. |
| 118 ASSERT_NO_FATAL_FAILURE(ScheduleNavigatorStoreCredentialAtUnload( |
| 119 WebContents(), "user", "hunter2")); |
| 120 |
| 121 // Trigger a same-site navigation carried out in the same RenderFrame. |
| 122 content::RenderFrameHost* old_rfh = WebContents()->GetMainFrame(); |
| 123 ui_test_utils::NavigateToURL(browser(), a_url2); |
| 124 ASSERT_EQ(old_rfh, WebContents()->GetMainFrame()); |
| 125 |
| 126 // Ensure that the old document no longer has a Mojo connection to the |
| 127 // CredentialManagerImpl, nor can it get one later. |
| 128 // |
| 129 // The sequence of events for same-RFH navigations is as follows: |
| 130 // 1.) FrameHostMsg_DidStartProvisionalLoad |
| 131 // 2.) FrameLoader::PrepareForCommit |
| 132 // 2.1) Document::Shutdown (old Document) |
| 133 // 3.) FrameHostMsg_DidCommitProvisionalLoad (new load) |
| 134 // ... loading ... |
| 135 // 4.) FrameHostMsg_DidStopLoading |
| 136 // 5.) content::WaitForLoadStop inside NavigateToURL returns |
| 137 // 6.) NavigateToURL returns |
| 138 // |
| 139 // After Step 2.1, the old Document cannot issue a new Mojo InterfaceRequest |
| 140 // anymore. Plus, because the AssociatedInterfaceRegistry, through which the |
| 141 // associated interface to the CredentialManagerImpl is retrieved, is itself |
| 142 // Channel-associated, any InterfaceRequest messages that may have been |
| 143 // issued before or during Step 2.1, will be guaranteed to arrive to the |
| 144 // browser side before FrameHostMsg_DidCommitProvisionalLoad in Step 3. |
| 145 // |
| 146 // Hence it is sufficient to check that the Mojo connection is closed now. |
| 147 EXPECT_FALSE(client->has_binding_for_credential_manager()); |
| 148 |
| 149 // Ensure that the navigator.credentials.store() call was serviced in the |
| 150 // context of the old URL, |a_url|. |
| 151 // |
| 152 // The CredentialManager Mojo interface is Channel-associated, so message |
| 153 // ordering with legacy IPC messages is preserved. Therefore, servicing the |
| 154 // store() called from the `unload` handler, triggered from |
| 155 // FrameLoader::PrepareForCommit, will be serviced before |
| 156 // FrameHostMsg_DidCommitProvisionalLoad, thus before DidFinishNavigation, |
| 157 ASSERT_TRUE(client->was_store_ever_called()); |
| 158 |
| 159 BubbleObserver prompt_observer(WebContents()); |
| 160 prompt_observer.WaitForSavePrompt(); |
| 161 ASSERT_TRUE(prompt_observer.IsShowingSavePrompt()); |
| 162 prompt_observer.AcceptSavePrompt(); |
| 163 |
| 164 WaitForPasswordStore(); |
| 165 |
| 166 password_manager::TestPasswordStore* test_password_store = |
| 167 static_cast<password_manager::TestPasswordStore*>( |
| 168 PasswordStoreFactory::GetForProfile( |
| 169 browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS) |
| 170 .get()); |
| 171 |
| 172 ASSERT_EQ(1u, test_password_store->stored_passwords().size()); |
| 173 autofill::PasswordForm signin_form = |
| 174 test_password_store->stored_passwords().begin()->second[0]; |
| 175 EXPECT_EQ(base::ASCIIToUTF16("user"), signin_form.username_value); |
| 176 EXPECT_EQ(base::ASCIIToUTF16("hunter2"), signin_form.password_value); |
| 177 EXPECT_EQ(a_url1.GetOrigin(), signin_form.origin); |
| 178 } |
| 179 |
| 180 // Tests the when navigator.credentials.store() is called in an `unload` |
| 181 // handler before a cross-site transfer navigation, the request is ignored. |
| 182 // |
| 183 // If |preestablish_mojo_pipe| is set, then the CredentialManagerClient will |
| 184 // establish the Mojo connection to the CredentialManagerImpl ahead of time, |
| 185 // instead of letting the Mojo connection be established on-demand when the |
| 186 // call to store() triggered from the unload handler. |
| 187 void TestStoreInUnloadHandlerForCrossSiteNavigation( |
| 188 bool preestablish_mojo_pipe) { |
| 189 const GURL a_url = https_test_server().GetURL("a.com", "/title1.html"); |
| 190 const GURL b_url = https_test_server().GetURL("b.com", "/title2.html"); |
| 191 |
| 192 // Navigate to a mostly empty page. |
| 193 ui_test_utils::NavigateToURL(browser(), a_url); |
| 194 |
| 195 ChromePasswordManagerClient* client = |
| 196 ChromePasswordManagerClient::FromWebContents(WebContents()); |
| 197 |
| 198 if (preestablish_mojo_pipe) { |
| 199 EXPECT_FALSE(client->has_binding_for_credential_manager()); |
| 200 ASSERT_NO_FATAL_FAILURE( |
| 201 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult( |
| 202 WebContents(), false)); |
| 203 EXPECT_TRUE(client->has_binding_for_credential_manager()); |
| 204 } |
| 205 |
| 206 // Schedule storing a credential on the `unload` event. |
| 207 ASSERT_NO_FATAL_FAILURE(ScheduleNavigatorStoreCredentialAtUnload( |
| 208 WebContents(), "user", "hunter2")); |
| 209 |
| 210 // Trigger a cross-site navigation that is carried out in a new renderer, |
| 211 // and which will swap out the old RenderFrameHost. |
| 212 content::RenderFrameDeletedObserver rfh_destruction_observer( |
| 213 WebContents()->GetMainFrame()); |
| 214 ui_test_utils::NavigateToURL(browser(), b_url); |
| 215 |
| 216 // Ensure that the navigator.credentials.store() call is never serviced. |
| 217 // The sufficient conditions for this are: |
| 218 // -- The swapped out RFH is destroyed, so the RenderFrame cannot |
| 219 // establish a new Mojo connection to CredentialManagerImpl anymore. |
| 220 // -- There is no already existing Mojo connection to CredentialManagerImpl |
| 221 // either, which could be used to call store() in the future. |
| 222 // -- There have not been any calls to store() in the past. |
| 223 rfh_destruction_observer.WaitUntilDeleted(); |
| 224 EXPECT_FALSE(client->has_binding_for_credential_manager()); |
| 225 EXPECT_FALSE(client->was_store_ever_called()); |
| 226 } |
| 227 |
| 51 private: | 228 private: |
| 52 DISALLOW_COPY_AND_ASSIGN(CredentialManagerBrowserTest); | 229 DISALLOW_COPY_AND_ASSIGN(CredentialManagerBrowserTest); |
| 53 }; | 230 }; |
| 54 | 231 |
| 55 // Tests. | 232 // Tests. |
| 56 | 233 |
| 57 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, | 234 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, |
| 58 AccountChooserWithOldCredentialAndNavigation) { | 235 AccountChooserWithOldCredentialAndNavigation) { |
| 59 // Save credentials with 'skip_zero_click'. | 236 // Save credentials with 'skip_zero_click'. |
| 60 scoped_refptr<password_manager::TestPasswordStore> password_store = | 237 scoped_refptr<password_manager::TestPasswordStore> password_store = |
| 61 static_cast<password_manager::TestPasswordStore*>( | 238 static_cast<password_manager::TestPasswordStore*>( |
| 62 PasswordStoreFactory::GetForProfile( | 239 PasswordStoreFactory::GetForProfile( |
| 63 browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS).get()); | 240 browser()->profile(), ServiceAccessType::IMPLICIT_ACCESS) |
| 241 .get()); |
| 64 autofill::PasswordForm signin_form; | 242 autofill::PasswordForm signin_form; |
| 65 signin_form.signon_realm = embedded_test_server()->base_url().spec(); | 243 signin_form.signon_realm = embedded_test_server()->base_url().spec(); |
| 66 signin_form.password_value = base::ASCIIToUTF16("password"); | 244 signin_form.password_value = base::ASCIIToUTF16("password"); |
| 67 signin_form.username_value = base::ASCIIToUTF16("user"); | 245 signin_form.username_value = base::ASCIIToUTF16("user"); |
| 68 signin_form.origin = embedded_test_server()->base_url(); | 246 signin_form.origin = embedded_test_server()->base_url(); |
| 69 signin_form.skip_zero_click = true; | 247 signin_form.skip_zero_click = true; |
| 70 password_store->AddLogin(signin_form); | 248 password_store->AddLogin(signin_form); |
| 71 | 249 |
| 72 NavigateToFile("/password/password_form.html"); | 250 NavigateToFile("/password/password_form.html"); |
| 73 std::string fill_password = | 251 std::string fill_password = |
| 74 "document.getElementById('username_field').value = 'user';" | 252 "document.getElementById('username_field').value = 'user';" |
| 75 "document.getElementById('password_field').value = 'password';"; | 253 "document.getElementById('password_field').value = 'password';"; |
| 76 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_password)); | 254 ASSERT_TRUE(content::ExecuteScript(RenderViewHost(), fill_password)); |
| 77 | 255 |
| 78 // Call the API to trigger the notification to the client. | 256 // Call the API to trigger the notification to the client. |
| 79 ASSERT_TRUE(content::ExecuteScript( | 257 ASSERT_TRUE(content::ExecuteScript( |
| 80 RenderViewHost(), | 258 RenderViewHost(), |
| 81 "navigator.credentials.get({password: true})" | 259 "navigator.credentials.get({password: true})" |
| 82 ".then(cred => window.location = '/password/done.html')")); | 260 ".then(cred => window.location = '/password/done.html')")); |
| 83 // Mojo calls from the renderer are asynchronous. | 261 // Mojo calls from the renderer are asynchronous. |
| 84 BubbleObserver(WebContents()).WaitForAccountChooser(); | 262 BubbleObserver(WebContents()).WaitForAccountChooser(); |
| 85 PasswordsModelDelegateFromWebContents(WebContents())->ChooseCredential( | 263 PasswordsModelDelegateFromWebContents(WebContents()) |
| 86 signin_form, | 264 ->ChooseCredential( |
| 87 password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD); | 265 signin_form, |
| 266 password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD); |
| 88 | 267 |
| 89 NavigationObserver observer(WebContents()); | 268 NavigationObserver observer(WebContents()); |
| 90 observer.SetPathToWaitFor("/password/done.html"); | 269 observer.SetPathToWaitFor("/password/done.html"); |
| 91 observer.Wait(); | 270 observer.Wait(); |
| 92 | 271 |
| 93 // Verify that the form's 'skip_zero_click' is updated and not overwritten | 272 // Verify that the form's 'skip_zero_click' is updated and not overwritten |
| 94 // by the autofill password manager on successful login. | 273 // by the autofill password manager on successful login. |
| 95 WaitForPasswordStore(); | 274 WaitForPasswordStore(); |
| 96 password_manager::TestPasswordStore::PasswordMap passwords_map = | 275 password_manager::TestPasswordStore::PasswordMap passwords_map = |
| 97 password_store->stored_passwords(); | 276 password_store->stored_passwords(); |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 NavigationObserver observer(WebContents()); | 417 NavigationObserver observer(WebContents()); |
| 239 observer.SetPathToWaitFor("/password/done.html"); | 418 observer.SetPathToWaitFor("/password/done.html"); |
| 240 observer.Wait(); | 419 observer.Wait(); |
| 241 | 420 |
| 242 BubbleObserver prompt_observer(WebContents()); | 421 BubbleObserver prompt_observer(WebContents()); |
| 243 // The autofill password manager shouldn't react to the successful login | 422 // The autofill password manager shouldn't react to the successful login |
| 244 // because it was suppressed when the site got the credential back. | 423 // because it was suppressed when the site got the credential back. |
| 245 EXPECT_FALSE(prompt_observer.IsShowingSavePrompt()); | 424 EXPECT_FALSE(prompt_observer.IsShowingSavePrompt()); |
| 246 } | 425 } |
| 247 | 426 |
| 427 // Regression test for https://crbug.com/736357. |
| 428 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, |
| 429 StoreInUnloadHandler_SameSite_OnDemandMojoPipe) { |
| 430 TestStoreInUnloadHandlerForSameSiteNavigation( |
| 431 false /* preestablish_mojo_pipe */); |
| 432 } |
| 433 |
| 434 // Regression test for https://crbug.com/736357. |
| 435 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, |
| 436 StoreInUnloadHandler_SameSite_PreestablishedPipe) { |
| 437 TestStoreInUnloadHandlerForSameSiteNavigation( |
| 438 true /* preestablish_mojo_pipe */); |
| 439 } |
| 440 // Regression test for https://crbug.com/736357. |
| 441 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, |
| 442 StoreInUnloadHandler_CrossSite_OnDemandMojoPipe) { |
| 443 TestStoreInUnloadHandlerForCrossSiteNavigation( |
| 444 false /* preestablish_mojo_pipe */); |
| 445 } |
| 446 |
| 447 // Regression test for https://crbug.com/736357. |
| 448 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, |
| 449 StoreInUnloadHandler_CrossSite_PreestablishedPipe) { |
| 450 TestStoreInUnloadHandlerForCrossSiteNavigation( |
| 451 true /* preestablish_mojo_pipe */); |
| 452 } |
| 453 |
| 454 // Regression test for https://crbug.com/736357. |
| 455 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, |
| 456 MojoConnectionRecreatedAfterNavigation) { |
| 457 const GURL a_url1 = https_test_server().GetURL("a.com", "/title1.html"); |
| 458 const GURL a_url2 = https_test_server().GetURL("a.com", "/title2.html"); |
| 459 const GURL a_url2_ref = https_test_server().GetURL("a.com", "/title2.html#r"); |
| 460 const GURL b_url = https_test_server().GetURL("b.com", "/title2.html#ref"); |
| 461 |
| 462 // Enable 'auto signin' for the profile. |
| 463 password_bubble_experiment::RecordAutoSignInPromptFirstRunExperienceWasShown( |
| 464 browser()->profile()->GetPrefs()); |
| 465 |
| 466 // Navigate to a mostly empty page. |
| 467 ui_test_utils::NavigateToURL(browser(), a_url1); |
| 468 |
| 469 ChromePasswordManagerClient* client = |
| 470 ChromePasswordManagerClient::FromWebContents(WebContents()); |
| 471 |
| 472 // Store a credential, and expect it to establish the Mojo connection. |
| 473 EXPECT_FALSE(client->has_binding_for_credential_manager()); |
| 474 EXPECT_FALSE(client->was_store_ever_called()); |
| 475 |
| 476 ASSERT_TRUE(content::ExecuteScript( |
| 477 WebContents(), |
| 478 "var c = new PasswordCredential({ id: 'user', password: 'hunter2' });" |
| 479 "navigator.credentials.store(c);")); |
| 480 |
| 481 BubbleObserver prompt_observer(WebContents()); |
| 482 prompt_observer.WaitForSavePrompt(); |
| 483 ASSERT_TRUE(prompt_observer.IsShowingSavePrompt()); |
| 484 prompt_observer.AcceptSavePrompt(); |
| 485 WaitForPasswordStore(); |
| 486 |
| 487 EXPECT_TRUE(client->has_binding_for_credential_manager()); |
| 488 EXPECT_TRUE(client->was_store_ever_called()); |
| 489 |
| 490 // Trigger a same-site navigation. |
| 491 content::RenderFrameHost* old_rfh = WebContents()->GetMainFrame(); |
| 492 ui_test_utils::NavigateToURL(browser(), a_url2); |
| 493 ASSERT_EQ(old_rfh, WebContents()->GetMainFrame()); |
| 494 |
| 495 // Expect the Mojo connection closed. |
| 496 EXPECT_FALSE(client->has_binding_for_credential_manager()); |
| 497 |
| 498 // Calling navigator.credentials.get() again should re-establish the Mojo |
| 499 // connection and succeed. |
| 500 ASSERT_NO_FATAL_FAILURE( |
| 501 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(), |
| 502 true)); |
| 503 EXPECT_TRUE(client->has_binding_for_credential_manager()); |
| 504 |
| 505 // Same-document navigation. Call to get() succeeds. |
| 506 ui_test_utils::NavigateToURL(browser(), a_url2_ref); |
| 507 ASSERT_EQ(old_rfh, WebContents()->GetMainFrame()); |
| 508 EXPECT_TRUE(client->has_binding_for_credential_manager()); |
| 509 ASSERT_NO_FATAL_FAILURE( |
| 510 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(), |
| 511 true)); |
| 512 |
| 513 // Cross-site navigation. Call to get() succeeds without results. |
| 514 ui_test_utils::NavigateToURL(browser(), b_url); |
| 515 ASSERT_NO_FATAL_FAILURE( |
| 516 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(), |
| 517 false)); |
| 518 |
| 519 // Trigger a cross-site navigation back. Call to get() should still succeed, |
| 520 // and once again with results. |
| 521 ui_test_utils::NavigateToURL(browser(), a_url1); |
| 522 ASSERT_NO_FATAL_FAILURE( |
| 523 TriggerNavigatorGetPasswordCredentialsAndExpectHasResult(WebContents(), |
| 524 true)); |
| 525 } |
| 526 |
| 248 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, SaveViaAPIAndAutofill) { | 527 IN_PROC_BROWSER_TEST_F(CredentialManagerBrowserTest, SaveViaAPIAndAutofill) { |
| 249 NavigateToFile("/password/password_form.html"); | 528 NavigateToFile("/password/password_form.html"); |
| 250 | 529 |
| 251 ASSERT_TRUE(content::ExecuteScript( | 530 ASSERT_TRUE(content::ExecuteScript( |
| 252 RenderViewHost(), | 531 RenderViewHost(), |
| 253 "document.getElementById('input_submit_button').addEventListener('click'," | 532 "document.getElementById('input_submit_button').addEventListener('click'," |
| 254 "function(event) {" | 533 "function(event) {" |
| 255 "var c = new PasswordCredential({ id: 'user', password: 'API' });" | 534 "var c = new PasswordCredential({ id: 'user', password: 'API' });" |
| 256 "navigator.credentials.store(c);" | 535 "navigator.credentials.store(c);" |
| 257 "});")); | 536 "});")); |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 349 | 628 |
| 350 // Reload the page and make sure it's autofilled. | 629 // Reload the page and make sure it's autofilled. |
| 351 NavigateToFile("/password/password_form.html"); | 630 NavigateToFile("/password/password_form.html"); |
| 352 WaitForElementValue("username_field", "user"); | 631 WaitForElementValue("username_field", "user"); |
| 353 content::SimulateMouseClickAt( | 632 content::SimulateMouseClickAt( |
| 354 WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1)); | 633 WebContents(), 0, blink::WebMouseEvent::Button::kLeft, gfx::Point(1, 1)); |
| 355 WaitForElementValue("password_field", "12345"); | 634 WaitForElementValue("password_field", "12345"); |
| 356 } | 635 } |
| 357 | 636 |
| 358 } // namespace | 637 } // namespace |
| OLD | NEW |