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