Commit 072ed581 authored by Milica Selakovic's avatar Milica Selakovic Committed by Commit Bot

[Autofill assistant] Fix autobot add multiple entries to password store

Form digest was not aware of real url, that led that matched forms were not
proceed correctly. This CL fix issue and add test. Test for other
WebsiteLoginManager methods will be added in separate CL.

Bug: 1090286
Change-Id: I910b02d4ddd82e213eb3baaceb5f055a1d9b36f6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2267078
Commit-Queue: Milica Selakovic <selakovic@google.com>
Reviewed-by: default avatarClemens Arbesser <arbesser@google.com>
Reviewed-by: default avatarMohamed Amir Yosef <mamir@chromium.org>
Cr-Commit-Position: refs/heads/master@{#783030}
parent b32e0d1c
...@@ -277,6 +277,7 @@ source_set("unit_tests") { ...@@ -277,6 +277,7 @@ source_set("unit_tests") {
"user_data_util_unittest.cc", "user_data_util_unittest.cc",
"user_model_unittest.cc", "user_model_unittest.cc",
"value_util_unittest.cc", "value_util_unittest.cc",
"website_login_manager_impl_unittest.cc",
] ]
deps = [ deps = [
......
...@@ -183,7 +183,8 @@ class WebsiteLoginManagerImpl::UpdatePasswordRequest ...@@ -183,7 +183,8 @@ class WebsiteLoginManagerImpl::UpdatePasswordRequest
DCHECK_CURRENTLY_ON(content::BrowserThread::UI); DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
password_manager::PasswordStore::FormDigest digest( password_manager::PasswordStore::FormDigest digest(
autofill::PasswordForm::Scheme::kHtml, login.origin.spec(), GURL()); autofill::PasswordForm::Scheme::kHtml, password_form_.signon_realm,
password_form_.url);
form_fetcher_ = std::make_unique<password_manager::FormFetcherImpl>( form_fetcher_ = std::make_unique<password_manager::FormFetcherImpl>(
digest, client, true); digest, client, true);
} }
......
// Copyright (c) 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/autofill_assistant/browser/website_login_manager_impl.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "components/password_manager/core/browser/stub_password_manager_driver.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using autofill::FormData;
using autofill::FormFieldData;
using autofill::PasswordForm;
using base::ASCIIToUTF16;
using testing::_;
using testing::Invoke;
using testing::Mock;
using testing::Return;
using testing::WithArg;
namespace autofill_assistant {
namespace {
const char kFakeUrl[] = "http://www.example.com/";
const char kFakeUsername[] = "user@example.com";
const char kFakePassword[] = "old_password";
const char kFakeNewPassword[] = "new_password";
const char kFormDataName[] = "the-form-name";
const char kPasswordElement[] = "password-element";
const char kUsernameElement[] = "username-element";
class MockPasswordManagerClient
: public password_manager::StubPasswordManagerClient {
public:
MockPasswordManagerClient() = default;
~MockPasswordManagerClient() override = default;
MOCK_CONST_METHOD0(GetProfilePasswordStore,
password_manager::PasswordStore*());
};
class MockPasswordManagerDriver
: public password_manager::StubPasswordManagerDriver {
public:
MockPasswordManagerDriver() = default;
MOCK_CONST_METHOD0(GetId, int());
MOCK_CONST_METHOD0(IsMainFrame, bool());
};
FormData MakeFormDataWithPasswordField() {
FormData form_data;
form_data.url = GURL(kFakeUrl);
form_data.action = GURL(kFakeUrl);
form_data.name = ASCIIToUTF16(kFormDataName);
FormFieldData field;
field.name = ASCIIToUTF16(kPasswordElement);
field.id_attribute = field.name;
field.name_attribute = field.name;
field.value = ASCIIToUTF16(kFakeNewPassword);
field.form_control_type = "password";
form_data.fields.push_back(field);
return form_data;
}
PasswordForm MakeSimplePasswordForm() {
PasswordForm form;
form.url = GURL(kFakeUrl);
form.signon_realm = form.url.GetOrigin().spec();
form.password_value = ASCIIToUTF16(kFakePassword);
form.username_value = ASCIIToUTF16(kFakeUsername);
form.username_element = ASCIIToUTF16(kUsernameElement);
form.password_element = ASCIIToUTF16(kPasswordElement);
return form;
}
PasswordForm MakeSimplePasswordFormWithoutUsername() {
PasswordForm form;
form.url = GURL(kFakeUrl);
form.signon_realm = form.url.GetOrigin().spec();
form.password_value = ASCIIToUTF16(kFakeNewPassword);
return form;
}
} // namespace
class WebsiteLoginManagerImplTest : public testing::Test {
public:
WebsiteLoginManagerImplTest() = default;
~WebsiteLoginManagerImplTest() override = default;
protected:
void SetUp() override {
store_ = new password_manager::MockPasswordStore;
ASSERT_TRUE(store_->Init(/*prefs=*/nullptr));
ON_CALL(client_, GetProfilePasswordStore())
.WillByDefault(Return(store_.get()));
ON_CALL(driver_, GetId()).WillByDefault(Return(0));
ON_CALL(driver_, IsMainFrame()).WillByDefault(Return(true));
manager_ = std::make_unique<WebsiteLoginManagerImpl>(&client_, &driver_);
}
void TearDown() override { store_->ShutdownOnUIThread(); }
WebsiteLoginManagerImpl* manager() { return manager_.get(); }
password_manager::MockPasswordStore* store() { return store_.get(); }
void WaitForPasswordStore() { task_environment_.RunUntilIdle(); }
private:
testing::NiceMock<MockPasswordManagerClient> client_;
MockPasswordManagerDriver driver_;
std::unique_ptr<WebsiteLoginManagerImpl> manager_;
scoped_refptr<password_manager::MockPasswordStore> store_;
content::BrowserTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME,
content::BrowserTaskEnvironment::IO_MAINLOOP};
};
// Checks if PasswordForm matches other PasswordForm.
MATCHER_P(FormMatches, form, "") {
return form.signon_realm == arg.signon_realm && form.url == arg.url &&
form.username_element == arg.username_element &&
form.username_value == arg.username_value &&
form.password_element == arg.password_element &&
form.password_value == arg.password_value;
}
TEST_F(WebsiteLoginManagerImplTest, SaveGeneratedPassword) {
ON_CALL(*store(), GetLogins(_, _))
.WillByDefault(WithArg<1>(
Invoke([](password_manager::PasswordStoreConsumer* consumer) {
std::vector<std::unique_ptr<PasswordForm>> result;
result.push_back(
std::make_unique<PasswordForm>(MakeSimplePasswordForm()));
consumer->OnGetPasswordStoreResults(std::move(result));
})));
password_manager::PasswordStore::FormDigest form_digest(
autofill::PasswordForm::Scheme::kHtml, kFakeUrl, GURL(kFakeUrl));
// Presave generated password. Form with empty username is presaved.
EXPECT_CALL(*store(), GetLogins(form_digest, _));
EXPECT_CALL(*store(),
AddLogin(FormMatches(MakeSimplePasswordFormWithoutUsername())));
manager()->PresaveGeneratedPassword(
{GURL(kFakeUrl), kFakeUsername}, kFakeNewPassword,
MakeFormDataWithPasswordField(), base::OnceClosure());
// Commit generated password.
EXPECT_TRUE(manager()->ReadyToCommitGeneratedPassword());
PasswordForm new_form = MakeSimplePasswordForm();
new_form.password_value = ASCIIToUTF16(kFakeNewPassword);
// Check that additional data is populated correctly from matched form.
EXPECT_CALL(*store(), UpdateLoginWithPrimaryKey(FormMatches(new_form), _));
manager()->CommitGeneratedPassword();
WaitForPasswordStore();
}
} // namespace autofill_assistant
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment