blob: e0a09f1636c79cd295ee75b949e47d6a4b4b1bf5 [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/android/password_edit_delegate_settings_impl.h"
#include <memory>
#include <string>
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/strings/strcat.h"
#include "base/strings/string16.h"
#include "base/strings/string_piece_forward.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/android/password_edit_delegate_settings_impl.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/test/base/testing_profile.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/password_list_sorter.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/test_password_store.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using testing::ElementsAre;
using testing::Pair;
using testing::UnorderedElementsAre;
namespace {
constexpr char kExampleCom[] = "https://example.com/";
constexpr char kExampleOrg[] = "https://example.org/";
constexpr char kNewPassword[] = "new_pass";
constexpr char kNewUser[] = "new_user";
constexpr char kPassword1[] = "pass";
constexpr char kPassword2[] = "pass2";
constexpr char kUsername1[] = "user";
constexpr char kUsername2[] = "user2";
std::vector<std::pair<std::string, std::string>> GetUsernamesAndPasswords(
const std::vector<autofill::PasswordForm>& forms) {
std::vector<std::pair<std::string, std::string>> result;
result.reserve(forms.size());
for (const auto& form : forms) {
result.emplace_back(base::UTF16ToUTF8(form.username_value),
base::UTF16ToUTF8(form.password_value));
}
return result;
}
autofill::PasswordForm MakeSavedForm(const GURL& origin,
base::StringPiece username,
base::StringPiece password) {
autofill::PasswordForm form;
form.origin = origin;
form.signon_realm = origin.GetOrigin().spec();
form.username_element = base::ASCIIToUTF16("Email");
form.username_value = base::ASCIIToUTF16(username);
form.password_element = base::ASCIIToUTF16("Passwd");
form.password_value = base::ASCIIToUTF16(password);
return form;
}
std::vector<std::unique_ptr<autofill::PasswordForm>> ExtractEquivalentForms(
const autofill::PasswordForm& edited_form,
const std::vector<autofill::PasswordForm>& saved_forms) {
std::string sort_key = password_manager::CreateSortKey(edited_form);
std::vector<std::unique_ptr<autofill::PasswordForm>> equivalent_forms;
for (const autofill::PasswordForm& form : saved_forms) {
if (password_manager::CreateSortKey(form) == sort_key) {
equivalent_forms.push_back(
std::make_unique<autofill::PasswordForm>(form));
}
}
return equivalent_forms;
}
std::vector<base::string16> ExtractUsernamesSameOrigin(
const GURL& origin,
const std::vector<autofill::PasswordForm>& saved_forms) {
std::vector<base::string16> existing_usernames;
for (const auto& form : saved_forms) {
if (form.origin == origin) {
existing_usernames.push_back(form.username_value);
}
}
return existing_usernames;
}
} // namespace
class PasswordEditDelegateSettingsImplTest : public testing::Test {
protected:
PasswordEditDelegateSettingsImplTest() = default;
~PasswordEditDelegateSettingsImplTest() override {
store_->ShutdownOnUIThread();
task_environment_.RunUntilIdle();
}
password_manager::TestPasswordStore* GetStore() { return store_.get(); }
void RunUntilIdle() { task_environment_.RunUntilIdle(); }
std::unique_ptr<PasswordEditDelegateSettingsImpl> CreateTestDelegate(
const std::vector<std::unique_ptr<autofill::PasswordForm>>& forms,
std::vector<base::string16> existing_usernames);
const std::vector<autofill::PasswordForm>& GetStoredPasswordsForRealm(
base::StringPiece signon_realm);
void InitializeStoreWithForms(
const std::vector<autofill::PasswordForm>& saved_forms);
private:
content::BrowserTaskEnvironment task_environment_;
TestingProfile profile_;
scoped_refptr<password_manager::TestPasswordStore> store_ =
base::WrapRefCounted(static_cast<password_manager::TestPasswordStore*>(
PasswordStoreFactory::GetInstance()
->SetTestingFactoryAndUse(
&profile_,
base::BindRepeating(&password_manager::BuildPasswordStore<
content::BrowserContext,
password_manager::TestPasswordStore>))
.get()));
};
std::unique_ptr<PasswordEditDelegateSettingsImpl>
PasswordEditDelegateSettingsImplTest::CreateTestDelegate(
const std::vector<std::unique_ptr<autofill::PasswordForm>>& forms,
std::vector<base::string16> existing_usernames) {
return std::make_unique<PasswordEditDelegateSettingsImpl>(
&profile_, forms, std::move(existing_usernames));
}
const std::vector<autofill::PasswordForm>&
PasswordEditDelegateSettingsImplTest::GetStoredPasswordsForRealm(
base::StringPiece signon_realm) {
const auto& stored_passwords = GetStore()->stored_passwords();
auto for_realm_it = stored_passwords.find(signon_realm);
return for_realm_it->second;
}
void PasswordEditDelegateSettingsImplTest::InitializeStoreWithForms(
const std::vector<autofill::PasswordForm>& saved_forms) {
for (const auto& form : saved_forms) {
GetStore()->AddLogin(form);
}
RunUntilIdle();
}
TEST_F(PasswordEditDelegateSettingsImplTest, EditPassword) {
autofill::PasswordForm edited_form =
MakeSavedForm(GURL(kExampleCom), kUsername1, kPassword1);
std::vector<autofill::PasswordForm> saved_forms = {edited_form};
InitializeStoreWithForms(saved_forms);
std::vector<std::unique_ptr<autofill::PasswordForm>> forms_to_change =
ExtractEquivalentForms(edited_form, saved_forms);
std::vector<base::string16> existing_usernames =
ExtractUsernamesSameOrigin(edited_form.origin, saved_forms);
std::unique_ptr<PasswordEditDelegateSettingsImpl> password_edit_delegate =
CreateTestDelegate(forms_to_change, std::move(existing_usernames));
password_edit_delegate->EditSavedPassword(base::ASCIIToUTF16(kUsername1),
base::ASCIIToUTF16(kNewPassword));
RunUntilIdle();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
ElementsAre(Pair(kUsername1, kNewPassword)));
}
TEST_F(PasswordEditDelegateSettingsImplTest, EditUsername) {
autofill::PasswordForm edited_form =
MakeSavedForm(GURL(kExampleCom), kUsername1, kPassword1);
std::vector<autofill::PasswordForm> saved_forms = {edited_form};
InitializeStoreWithForms(saved_forms);
std::vector<std::unique_ptr<autofill::PasswordForm>> forms_to_change =
ExtractEquivalentForms(edited_form, saved_forms);
std::vector<base::string16> existing_usernames =
ExtractUsernamesSameOrigin(edited_form.origin, saved_forms);
std::unique_ptr<PasswordEditDelegateSettingsImpl> password_edit_delegate =
CreateTestDelegate(forms_to_change, std::move(existing_usernames));
password_edit_delegate->EditSavedPassword(base::ASCIIToUTF16(kNewUser),
base::ASCIIToUTF16(kPassword1));
RunUntilIdle();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
ElementsAre(Pair(kNewUser, kPassword1)));
}
TEST_F(PasswordEditDelegateSettingsImplTest, EditUsernameAndPassword) {
autofill::PasswordForm edited_form =
MakeSavedForm(GURL(kExampleCom), kUsername1, kPassword1);
std::vector<autofill::PasswordForm> saved_forms = {edited_form};
InitializeStoreWithForms(saved_forms);
std::vector<std::unique_ptr<autofill::PasswordForm>> forms_to_change =
ExtractEquivalentForms(edited_form, saved_forms);
std::vector<base::string16> existing_usernames =
ExtractUsernamesSameOrigin(edited_form.origin, saved_forms);
std::unique_ptr<PasswordEditDelegateSettingsImpl> password_edit_delegate =
CreateTestDelegate(forms_to_change, std::move(existing_usernames));
password_edit_delegate->EditSavedPassword(base::ASCIIToUTF16(kNewUser),
base::ASCIIToUTF16(kNewPassword));
RunUntilIdle();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
ElementsAre(Pair(kNewUser, kNewPassword)));
}
TEST_F(PasswordEditDelegateSettingsImplTest, RejectSameUsernameForSameRealm) {
autofill::PasswordForm edited_form =
MakeSavedForm(GURL(kExampleCom), kUsername1, kPassword1);
autofill::PasswordForm other_form =
MakeSavedForm(GURL(kExampleCom), kUsername2, kPassword2);
std::vector<autofill::PasswordForm> saved_forms = {edited_form, other_form};
InitializeStoreWithForms(saved_forms);
std::vector<std::unique_ptr<autofill::PasswordForm>> forms_to_change =
ExtractEquivalentForms(edited_form, saved_forms);
std::vector<base::string16> existing_usernames =
ExtractUsernamesSameOrigin(edited_form.origin, saved_forms);
std::unique_ptr<PasswordEditDelegateSettingsImpl> password_edit_delegate =
CreateTestDelegate(forms_to_change, std::move(existing_usernames));
password_edit_delegate->EditSavedPassword(base::ASCIIToUTF16(kUsername2),
base::ASCIIToUTF16(kPassword1));
RunUntilIdle();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
UnorderedElementsAre(Pair(kUsername1, kPassword1),
Pair(kUsername2, kPassword2)));
}
TEST_F(PasswordEditDelegateSettingsImplTest, UpdateDuplicates) {
autofill::PasswordForm edited_form = MakeSavedForm(
GURL(base::StrCat({kExampleCom, "pathA"})), kUsername1, kPassword1);
autofill::PasswordForm other_form = MakeSavedForm(
GURL(base::StrCat({kExampleCom, "pathB"})), kUsername1, kPassword1);
std::vector<autofill::PasswordForm> saved_forms = {edited_form, other_form};
InitializeStoreWithForms(saved_forms);
std::vector<std::unique_ptr<autofill::PasswordForm>> forms_to_change =
ExtractEquivalentForms(edited_form, saved_forms);
std::vector<base::string16> existing_usernames =
ExtractUsernamesSameOrigin(edited_form.origin, saved_forms);
std::unique_ptr<PasswordEditDelegateSettingsImpl> password_edit_delegate =
CreateTestDelegate(forms_to_change, std::move(existing_usernames));
password_edit_delegate->EditSavedPassword(base::ASCIIToUTF16(kNewUser),
base::ASCIIToUTF16(kNewPassword));
RunUntilIdle();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
UnorderedElementsAre(Pair(kNewUser, kNewPassword),
Pair(kNewUser, kNewPassword)));
}
TEST_F(PasswordEditDelegateSettingsImplTest,
EditUsernameForTheRightCredential) {
autofill::PasswordForm edited_form =
MakeSavedForm(GURL(kExampleCom), kUsername1, kPassword1);
autofill::PasswordForm other_form1 =
MakeSavedForm(GURL(kExampleCom), kUsername2, kPassword2);
autofill::PasswordForm other_form2 =
MakeSavedForm(GURL(kExampleOrg), kUsername1, kPassword1);
autofill::PasswordForm other_form3 =
MakeSavedForm(GURL(kExampleOrg), kUsername2, kPassword2);
std::vector<autofill::PasswordForm> saved_forms = {edited_form, other_form1,
other_form2, other_form3};
InitializeStoreWithForms(saved_forms);
std::vector<std::unique_ptr<autofill::PasswordForm>> forms_to_change =
ExtractEquivalentForms(edited_form, saved_forms);
std::vector<base::string16> existing_usernames =
ExtractUsernamesSameOrigin(edited_form.origin, saved_forms);
std::unique_ptr<PasswordEditDelegateSettingsImpl> password_edit_delegate =
CreateTestDelegate(forms_to_change, std::move(existing_usernames));
password_edit_delegate->EditSavedPassword(base::ASCIIToUTF16(kNewUser),
base::ASCIIToUTF16(kPassword1));
RunUntilIdle();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
UnorderedElementsAre(Pair(kNewUser, kPassword1),
Pair(kUsername2, kPassword2)));
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleOrg)),
UnorderedElementsAre(Pair(kUsername1, kPassword1),
Pair(kUsername2, kPassword2)));
}
TEST_F(PasswordEditDelegateSettingsImplTest,
EditPasswordForTheRightCredential) {
autofill::PasswordForm edited_form =
MakeSavedForm(GURL(kExampleCom), kUsername1, kPassword1);
autofill::PasswordForm other_form1 =
MakeSavedForm(GURL(kExampleCom), kUsername2, kPassword2);
autofill::PasswordForm other_form2 =
MakeSavedForm(GURL(kExampleOrg), kUsername1, kPassword1);
autofill::PasswordForm other_form3 =
MakeSavedForm(GURL(kExampleOrg), kUsername2, kPassword2);
std::vector<autofill::PasswordForm> saved_forms = {edited_form, other_form1,
other_form2, other_form3};
InitializeStoreWithForms(saved_forms);
std::vector<std::unique_ptr<autofill::PasswordForm>> forms_to_change =
ExtractEquivalentForms(edited_form, saved_forms);
std::vector<base::string16> existing_usernames =
ExtractUsernamesSameOrigin(edited_form.origin, saved_forms);
std::unique_ptr<PasswordEditDelegateSettingsImpl> password_edit_delegate =
CreateTestDelegate(forms_to_change, std::move(existing_usernames));
password_edit_delegate->EditSavedPassword(base::ASCIIToUTF16(kUsername1),
base::ASCIIToUTF16(kNewPassword));
RunUntilIdle();
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleCom)),
UnorderedElementsAre(Pair(kUsername1, kNewPassword),
Pair(kUsername2, kPassword2)));
EXPECT_THAT(GetUsernamesAndPasswords(GetStoredPasswordsForRealm(kExampleOrg)),
UnorderedElementsAre(Pair(kUsername1, kPassword1),
Pair(kUsername2, kPassword2)));
}