Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Side by Side Diff: chrome/renderer/autofill/password_autofill_agent_browsertest.cc

Issue 414013003: Password autofill should not override explicitly typed password (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Comments addressed Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | components/autofill/content/renderer/password_autofill_agent.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/strings/string_util.h" 5 #include "base/strings/string_util.h"
6 #include "base/strings/utf_string_conversions.h" 6 #include "base/strings/utf_string_conversions.h"
7 #include "chrome/test/base/chrome_render_view_test.h" 7 #include "chrome/test/base/chrome_render_view_test.h"
8 #include "components/autofill/content/common/autofill_messages.h" 8 #include "components/autofill/content/common/autofill_messages.h"
9 #include "components/autofill/content/renderer/autofill_agent.h" 9 #include "components/autofill/content/renderer/autofill_agent.h"
10 #include "components/autofill/content/renderer/form_autofill_util.h" 10 #include "components/autofill/content/renderer/form_autofill_util.h"
(...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 password_element_ = element.to<blink::WebInputElement>(); 254 password_element_ = element.to<blink::WebInputElement>();
255 } 255 }
256 256
257 void ClearUsernameAndPasswordFields() { 257 void ClearUsernameAndPasswordFields() {
258 username_element_.setValue(""); 258 username_element_.setValue("");
259 username_element_.setAutofilled(false); 259 username_element_.setAutofilled(false);
260 password_element_.setValue(""); 260 password_element_.setValue("");
261 password_element_.setAutofilled(false); 261 password_element_.setAutofilled(false);
262 } 262 }
263 263
264 void SimulateUsernameChangeForElement(const std::string& username, 264 void SimulateDidEndEditing(WebFrame* input_frame, WebInputElement& input) {
265 bool move_caret_to_end, 265 autofill_agent_->textFieldDidEndEditing(input);
266 WebFrame* input_frame, 266 }
267 WebInputElement& username_input, 267
268 bool is_user_input) { 268 void SimulateInputChangeForElement(const std::string& new_value,
269 username_input.setValue(WebString::fromUTF8(username), is_user_input); 269 bool move_caret_to_end,
270 WebFrame* input_frame,
271 WebInputElement& input,
272 bool is_user_input) {
273 input.setValue(WebString::fromUTF8(new_value), is_user_input);
270 // The field must have focus or AutofillAgent will think the 274 // The field must have focus or AutofillAgent will think the
271 // change should be ignored. 275 // change should be ignored.
272 while (!username_input.focused()) 276 while (!input.focused())
273 input_frame->document().frame()->view()->advanceFocus(false); 277 input_frame->document().frame()->view()->advanceFocus(false);
274 if (move_caret_to_end) 278 if (move_caret_to_end)
275 username_input.setSelectionRange(username.length(), username.length()); 279 input.setSelectionRange(new_value.length(), new_value.length());
276 if (is_user_input) 280 if (is_user_input)
277 password_autofill_agent()->FirstUserGestureObserved(); 281 password_autofill_agent()->FirstUserGestureObserved();
278 autofill_agent_->textFieldDidChange(username_input); 282 autofill_agent_->textFieldDidChange(input);
279 // Processing is delayed because of a Blink bug: 283 // Processing is delayed because of a Blink bug:
280 // https://bugs.webkit.org/show_bug.cgi?id=16976 284 // https://bugs.webkit.org/show_bug.cgi?id=16976
281 // See PasswordAutofillAgent::TextDidChangeInTextField() for details. 285 // See PasswordAutofillAgent::TextDidChangeInTextField() for details.
282 286
283 // Autocomplete will trigger a style recalculation when we put up the next 287 // Autocomplete will trigger a style recalculation when we put up the next
284 // frame, but we don't want to wait that long. Instead, trigger a style 288 // frame, but we don't want to wait that long. Instead, trigger a style
285 // recalcuation manually after TextFieldDidChangeImpl runs. 289 // recalcuation manually after TextFieldDidChangeImpl runs.
286 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 290 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(
287 &PasswordAutofillAgentTest::LayoutMainFrame, base::Unretained(this))); 291 &PasswordAutofillAgentTest::LayoutMainFrame, base::Unretained(this)));
288 292
(...skipping 14 matching lines...) Expand all
303 autofill_agent_->OnFillPasswordSuggestion(blink_username, blink_password); 307 autofill_agent_->OnFillPasswordSuggestion(blink_username, blink_password);
304 } 308 }
305 309
306 void LayoutMainFrame() { 310 void LayoutMainFrame() {
307 GetMainFrame()->view()->layout(); 311 GetMainFrame()->view()->layout();
308 } 312 }
309 313
310 void SimulateUsernameChange(const std::string& username, 314 void SimulateUsernameChange(const std::string& username,
311 bool move_caret_to_end, 315 bool move_caret_to_end,
312 bool is_user_input = false) { 316 bool is_user_input = false) {
313 SimulateUsernameChangeForElement(username, 317 SimulateInputChangeForElement(username,
314 move_caret_to_end, 318 move_caret_to_end,
315 GetMainFrame(), 319 GetMainFrame(),
316 username_element_, 320 username_element_,
317 is_user_input); 321 is_user_input);
318 } 322 }
319 323
320 // Tests that no suggestion popup is generated when the username_element_ is 324 // Tests that no suggestion popup is generated when the username_element_ is
321 // edited. 325 // edited.
322 void ExpectNoSuggestionsPopup() { 326 void ExpectNoSuggestionsPopup() {
323 // The first test below ensures that the suggestions have been handled by 327 // The first test below ensures that the suggestions have been handled by
324 // the password_autofill_agent, even though autocomplete='off' is set. The 328 // the password_autofill_agent, even though autocomplete='off' is set. The
325 // second check ensures that, although handled, no "show suggestions" IPC to 329 // second check ensures that, although handled, no "show suggestions" IPC to
326 // the browser was generated. 330 // the browser was generated.
327 // 331 //
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 const WebInputElement& password_element, 365 const WebInputElement& password_element,
362 const std::string& password, 366 const std::string& password,
363 bool password_autofilled, 367 bool password_autofilled,
364 bool checkSuggestedValue) { 368 bool checkSuggestedValue) {
365 EXPECT_EQ(username, 369 EXPECT_EQ(username,
366 static_cast<std::string>(username_element.value().utf8())); 370 static_cast<std::string>(username_element.value().utf8()));
367 EXPECT_EQ(username_autofilled, username_element.isAutofilled()); 371 EXPECT_EQ(username_autofilled, username_element.isAutofilled());
368 EXPECT_EQ(password, 372 EXPECT_EQ(password,
369 static_cast<std::string>( 373 static_cast<std::string>(
370 checkSuggestedValue ? password_element.suggestedValue().utf8() 374 checkSuggestedValue ? password_element.suggestedValue().utf8()
371 : password_element.value().utf8())); 375 : password_element.value().utf8()))
376 << "checkSuggestedValue == " << checkSuggestedValue;
372 EXPECT_EQ(password_autofilled, password_element.isAutofilled()); 377 EXPECT_EQ(password_autofilled, password_element.isAutofilled());
373 } 378 }
374 379
375 // Checks the DOM-accessible value of the username element and the 380 // Checks the DOM-accessible value of the username element and the
376 // *suggested* value of the password element. 381 // *suggested* value of the password element.
377 void CheckTextFieldsState(const std::string& username, 382 void CheckTextFieldsState(const std::string& username,
378 bool username_autofilled, 383 bool username_autofilled,
379 const std::string& password, 384 const std::string& password,
380 bool password_autofilled) { 385 bool password_autofilled) {
381 CheckTextFieldsStateForElements(username_element_, 386 CheckTextFieldsStateForElements(username_element_,
(...skipping 531 matching lines...) Expand 10 before | Expand all | Expand 10 after
913 918
914 WebInputElement username_input = username_element.to<WebInputElement>(); 919 WebInputElement username_input = username_element.to<WebInputElement>();
915 WebInputElement password_input = password_element.to<WebInputElement>(); 920 WebInputElement password_input = password_element.to<WebInputElement>();
916 ASSERT_FALSE(username_element.isNull()); 921 ASSERT_FALSE(username_element.isNull());
917 922
918 CheckTextFieldsStateForElements( 923 CheckTextFieldsStateForElements(
919 username_input, "", false, password_input, "", false, false); 924 username_input, "", false, password_input, "", false, false);
920 925
921 // Simulate the user typing in the username in the iframe which should cause 926 // Simulate the user typing in the username in the iframe which should cause
922 // an autofill. 927 // an autofill.
923 SimulateUsernameChangeForElement( 928 SimulateInputChangeForElement(
924 kAliceUsername, true, iframe, username_input, true); 929 kAliceUsername, true, iframe, username_input, true);
925 930
926 CheckTextFieldsStateForElements(username_input, 931 CheckTextFieldsStateForElements(username_input,
927 kAliceUsername, 932 kAliceUsername,
928 true, 933 true,
929 password_input, 934 password_input,
930 kAlicePassword, 935 kAlicePassword,
931 true, 936 true,
932 false); 937 false);
933 } 938 }
(...skipping 554 matching lines...) Expand 10 before | Expand all | Expand 10 after
1488 render_thread_->sink().ClearMessages(); 1493 render_thread_->sink().ClearMessages();
1489 autofill_agent_->FormControlElementClicked(username_element_, true); 1494 autofill_agent_->FormControlElementClicked(username_element_, true);
1490 ExpectAllCredentials(); 1495 ExpectAllCredentials();
1491 } 1496 }
1492 1497
1493 // The user types in a password, but then just before sending the form off, a 1498 // The user types in a password, but then just before sending the form off, a
1494 // script clears that password. This test checks that PasswordAutofillAgent can 1499 // script clears that password. This test checks that PasswordAutofillAgent can
1495 // still remember the password typed by the user. 1500 // still remember the password typed by the user.
1496 TEST_F(PasswordAutofillAgentTest, 1501 TEST_F(PasswordAutofillAgentTest,
1497 RememberLastNonEmptyPasswordOnSubmit_ScriptCleared) { 1502 RememberLastNonEmptyPasswordOnSubmit_ScriptCleared) {
1498 SimulateUsernameChangeForElement( 1503 SimulateInputChangeForElement(
1499 "temp", true, GetMainFrame(), username_element_, true); 1504 "temp", true, GetMainFrame(), username_element_, true);
1500 SimulateUsernameChangeForElement( 1505 SimulateInputChangeForElement(
1501 "random", true, GetMainFrame(), password_element_, true); 1506 "random", true, GetMainFrame(), password_element_, true);
1502 1507
1503 // Simulate that the password value was cleared by the site's JavaScript 1508 // Simulate that the password value was cleared by the site's JavaScript
1504 // before submit. 1509 // before submit.
1505 password_element_.setValue(WebString()); 1510 password_element_.setValue(WebString());
1506 static_cast<content::RenderViewObserver*>(password_autofill_agent()) 1511 static_cast<content::RenderViewObserver*>(password_autofill_agent())
1507 ->WillSubmitForm(GetMainFrame(), username_element_.form()); 1512 ->WillSubmitForm(GetMainFrame(), username_element_.form());
1508 1513
1509 // Observe that the PasswordAutofillAgent still remembered the last non-empty 1514 // Observe that the PasswordAutofillAgent still remembered the last non-empty
1510 // password and sent that to the browser. 1515 // password and sent that to the browser.
1511 ExpectFormSubmittedWithPasswords("random", ""); 1516 ExpectFormSubmittedWithPasswords("random", "");
1512 } 1517 }
1513 1518
1514 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but this time 1519 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but this time
1515 // it's the user who clears the password. This test checks that in that case, 1520 // it's the user who clears the password. This test checks that in that case,
1516 // the last non-empty password is not remembered. 1521 // the last non-empty password is not remembered.
1517 TEST_F(PasswordAutofillAgentTest, 1522 TEST_F(PasswordAutofillAgentTest,
1518 RememberLastNonEmptyPasswordOnSubmit_UserCleared) { 1523 RememberLastNonEmptyPasswordOnSubmit_UserCleared) {
1519 SimulateUsernameChangeForElement( 1524 SimulateInputChangeForElement(
1520 "temp", true, GetMainFrame(), username_element_, true); 1525 "temp", true, GetMainFrame(), username_element_, true);
1521 SimulateUsernameChangeForElement( 1526 SimulateInputChangeForElement(
1522 "random", true, GetMainFrame(), password_element_, true); 1527 "random", true, GetMainFrame(), password_element_, true);
1523 1528
1524 // Simulate that the user actually cleared the password again. 1529 // Simulate that the user actually cleared the password again.
1525 SimulateUsernameChangeForElement( 1530 SimulateInputChangeForElement(
1526 "", true, GetMainFrame(), password_element_, true); 1531 "", true, GetMainFrame(), password_element_, true);
1527 static_cast<content::RenderViewObserver*>(password_autofill_agent()) 1532 static_cast<content::RenderViewObserver*>(password_autofill_agent())
1528 ->WillSubmitForm(GetMainFrame(), username_element_.form()); 1533 ->WillSubmitForm(GetMainFrame(), username_element_.form());
1529 1534
1530 // Observe that the PasswordAutofillAgent respects the user having cleared the 1535 // Observe that the PasswordAutofillAgent respects the user having cleared the
1531 // password. 1536 // password.
1532 ExpectFormSubmittedWithPasswords("", ""); 1537 ExpectFormSubmittedWithPasswords("", "");
1533 } 1538 }
1534 1539
1535 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but uses the 1540 // Similar to RememberLastNonEmptyPasswordOnSubmit_ScriptCleared, but uses the
1536 // new password instead of the current password. 1541 // new password instead of the current password.
1537 TEST_F(PasswordAutofillAgentTest, 1542 TEST_F(PasswordAutofillAgentTest,
1538 RememberLastNonEmptyPasswordOnSubmit_NewPassword) { 1543 RememberLastNonEmptyPasswordOnSubmit_NewPassword) {
1539 const char kNewPasswordFormHTML[] = 1544 const char kNewPasswordFormHTML[] =
1540 "<FORM name='LoginTestForm'>" 1545 "<FORM name='LoginTestForm'>"
1541 " <INPUT type='text' id='username' autocomplete='username'/>" 1546 " <INPUT type='text' id='username' autocomplete='username'/>"
1542 " <INPUT type='password' id='password' autocomplete='new-password'/>" 1547 " <INPUT type='password' id='password' autocomplete='new-password'/>"
1543 " <INPUT type='submit' value='Login'/>" 1548 " <INPUT type='submit' value='Login'/>"
1544 "</FORM>"; 1549 "</FORM>";
1545 LoadHTML(kNewPasswordFormHTML); 1550 LoadHTML(kNewPasswordFormHTML);
1546 UpdateUsernameAndPasswordElements(); 1551 UpdateUsernameAndPasswordElements();
1547 1552
1548 SimulateUsernameChangeForElement( 1553 SimulateInputChangeForElement(
1549 "temp", true, GetMainFrame(), username_element_, true); 1554 "temp", true, GetMainFrame(), username_element_, true);
1550 SimulateUsernameChangeForElement( 1555 SimulateInputChangeForElement(
1551 "random", true, GetMainFrame(), password_element_, true); 1556 "random", true, GetMainFrame(), password_element_, true);
1552 1557
1553 // Simulate that the password value was cleared by the site's JavaScript 1558 // Simulate that the password value was cleared by the site's JavaScript
1554 // before submit. 1559 // before submit.
1555 password_element_.setValue(WebString()); 1560 password_element_.setValue(WebString());
1556 static_cast<content::RenderViewObserver*>(password_autofill_agent()) 1561 static_cast<content::RenderViewObserver*>(password_autofill_agent())
1557 ->WillSubmitForm(GetMainFrame(), username_element_.form()); 1562 ->WillSubmitForm(GetMainFrame(), username_element_.form());
1558 1563
1559 // Observe that the PasswordAutofillAgent still remembered the last non-empty 1564 // Observe that the PasswordAutofillAgent still remembered the last non-empty
1560 // password and sent that to the browser. 1565 // password and sent that to the browser.
1561 ExpectFormSubmittedWithPasswords("", "random"); 1566 ExpectFormSubmittedWithPasswords("", "random");
1562 } 1567 }
1563 1568
1569 // The user first accepts a suggestion, but then overwrites the password. This
1570 // test checks that the overwritten password is not reverted back if the user
1571 // triggers autofill through focusing (but not changing) the username again.
1572 TEST_F(PasswordAutofillAgentTest,
1573 NoopEditingDoesNotOverwriteManuallyEditedPassword) {
1574 // Simulate having credentials which needed to wait until the user starts
1575 // typing the username to be filled (e.g., PSL-matched credentials). Those are
1576 // the ones which can be filled as a result of TextFieldDidEndEditing.
1577 fill_data_.wait_for_username = true;
1578 SimulateOnFillPasswordForm(fill_data_);
1579 // Simulate that the user typed her name to make the autofill work.
1580 SimulateInputChangeForElement(kAliceUsername,
1581 /*move_caret_to_end=*/true,
1582 GetMainFrame(),
1583 username_element_,
1584 /*is_user_input=*/true);
1585 SimulateDidEndEditing(GetMainFrame(), username_element_);
1586 const std::string old_username(username_element_.value().utf8());
1587 const std::string old_password(password_element_.value().utf8());
1588 const std::string new_password(old_password + "modify");
1589
1590 // The user changes the password.
1591 SimulateInputChangeForElement(new_password,
1592 /*move_caret_to_end=*/true,
1593 GetMainFrame(),
1594 password_element_,
1595 /*is_user_input=*/true);
1596
1597 // The user switches back into the username field, but leaves that without
1598 // changes.
1599 SimulateDidEndEditing(GetMainFrame(), username_element_);
1600
1601 // The password should have stayed as the user changed it.
1602 CheckTextFieldsDOMState(old_username, true, new_password, false);
1603 // The password should not have a suggested value.
1604 CheckTextFieldsState(old_username, true, std::string(), false);
1605 }
1606
1607 TEST_F(PasswordAutofillAgentTest,
1608 InlineAutocompleteOverwritesManuallyEditedPassword) {
1609 // Simulate the browser sending back the login info.
1610 SimulateOnFillPasswordForm(fill_data_);
1611
1612 ClearUsernameAndPasswordFields();
1613
1614 // The user enters a password
1615 SimulateInputChangeForElement("someOtherPassword",
1616 /*move_caret_to_end=*/true,
1617 GetMainFrame(),
1618 password_element_,
1619 /*is_user_input=*/true);
1620
1621 // Simulate the user typing a stored username.
1622 SimulateUsernameChange(kAliceUsername, true);
1623 // The autofileld password should replace the typed one.
1624 CheckTextFieldsDOMState(kAliceUsername, true, kAlicePassword, true);
1625 }
1626
1564 } // namespace autofill 1627 } // namespace autofill
OLDNEW
« no previous file with comments | « no previous file | components/autofill/content/renderer/password_autofill_agent.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698