Commit 70cb0b55 authored by engedy's avatar engedy Committed by Commit bot

Introduce SuppressedHTTPSFormFetcher.

SuppressedHTTPSFormFetcher is a helper used by FormFetcherImpl to fetch
credentials stored for the HTTPS counterpart of a non-secure (i.e HTTP) origin,
when the FormFetcherImpl itself is created for an HTTP origin. The suppressed
forms are fetched asynchronously, without blocking Consumer::ProcessMatches.

This data will be used to measure how often HTTPS credentials cannot be filled
on HTTP sites. When no matching HTTP credentials exist for a non-secure origin,
but there are suppressed HTTPS credentials, that could indicate a premature
`move-to-HTTPS` migration, or simply that the site serves its sign-up or some
of its sign-in forms over HTTPS, while others still over HTTP.

BUG=720599

Review-Url: https://codereview.chromium.org/2878463003
Cr-Commit-Position: refs/heads/master@{#473725}
parent 56f8007e
...@@ -78,9 +78,11 @@ void CredentialManagerImpl::Store(const CredentialInfo& credential, ...@@ -78,9 +78,11 @@ void CredentialManagerImpl::Store(const CredentialInfo& credential,
std::unique_ptr<autofill::PasswordForm> observed_form = std::unique_ptr<autofill::PasswordForm> observed_form =
CreateObservedPasswordFormFromOrigin(origin); CreateObservedPasswordFormFromOrigin(origin);
// Create a custom form fetcher with suppressed HTTP->HTTPS migration. // Create a custom form fetcher without HTTP->HTTPS migration, as well as
// without fetching of suppressed HTTPS credentials on HTTP origins as the API
// is only available on HTTPS origins.
auto form_fetcher = base::MakeUnique<FormFetcherImpl>( auto form_fetcher = base::MakeUnique<FormFetcherImpl>(
PasswordStore::FormDigest(*observed_form), client_, false); PasswordStore::FormDigest(*observed_form), client_, false, false);
form_manager_ = base::MakeUnique<CredentialManagerPasswordFormManager>( form_manager_ = base::MakeUnique<CredentialManagerPasswordFormManager>(
client_, GetDriver(), *observed_form, std::move(form), this, nullptr, client_, GetDriver(), *observed_form, std::move(form), this, nullptr,
std::move(form_fetcher)); std::move(form_fetcher));
......
...@@ -122,6 +122,8 @@ static_library("browser") { ...@@ -122,6 +122,8 @@ static_library("browser") {
"sql_table_builder.h", "sql_table_builder.h",
"statistics_table.cc", "statistics_table.cc",
"statistics_table.h", "statistics_table.h",
"suppressed_https_form_fetcher.cc",
"suppressed_https_form_fetcher.h",
"test_affiliation_fetcher_factory.h", "test_affiliation_fetcher_factory.h",
"webdata/logins_table.cc", "webdata/logins_table.cc",
"webdata/logins_table.h", "webdata/logins_table.h",
...@@ -320,6 +322,7 @@ source_set("unit_tests") { ...@@ -320,6 +322,7 @@ source_set("unit_tests") {
"psl_matching_helper_unittest.cc", "psl_matching_helper_unittest.cc",
"sql_table_builder_unittest.cc", "sql_table_builder_unittest.cc",
"statistics_table_unittest.cc", "statistics_table_unittest.cc",
"suppressed_https_form_fetcher_unittest.cc",
] ]
if (is_mac) { if (is_mac) {
sources -= [ "password_store_default_unittest.cc" ] sources -= [ "password_store_default_unittest.cc" ]
......
...@@ -37,6 +37,15 @@ FakeFormFetcher::GetFederatedMatches() const { ...@@ -37,6 +37,15 @@ FakeFormFetcher::GetFederatedMatches() const {
return federated_; return federated_;
} }
const std::vector<const PasswordForm*>&
FakeFormFetcher::GetSuppressedHTTPSForms() const {
return suppressed_https_forms_;
}
bool FakeFormFetcher::DidCompleteQueryingSuppressedHTTPSForms() const {
return did_complete_querying_suppressed_https_forms_;
}
void FakeFormFetcher::SetNonFederated( void FakeFormFetcher::SetNonFederated(
const std::vector<const autofill::PasswordForm*>& non_federated, const std::vector<const autofill::PasswordForm*>& non_federated,
size_t filtered_count) { size_t filtered_count) {
......
...@@ -56,6 +56,21 @@ class FakeFormFetcher : public FormFetcher { ...@@ -56,6 +56,21 @@ class FakeFormFetcher : public FormFetcher {
federated_ = federated; federated_ = federated;
} }
const std::vector<const autofill::PasswordForm*>& GetSuppressedHTTPSForms()
const override;
// The pointees in |suppressed_forms| must outlive the fetcher.
void set_suppressed_https_forms(
const std::vector<const autofill::PasswordForm*>& suppressed_forms) {
suppressed_https_forms_ = suppressed_forms;
}
bool DidCompleteQueryingSuppressedHTTPSForms() const override;
void set_did_complete_querying_suppressed_https_forms(bool value) {
did_complete_querying_suppressed_https_forms_ = value;
}
void SetNonFederated( void SetNonFederated(
const std::vector<const autofill::PasswordForm*>& non_federated, const std::vector<const autofill::PasswordForm*>& non_federated,
size_t filtered_count); size_t filtered_count);
...@@ -71,6 +86,8 @@ class FakeFormFetcher : public FormFetcher { ...@@ -71,6 +86,8 @@ class FakeFormFetcher : public FormFetcher {
State state_ = State::NOT_WAITING; State state_ = State::NOT_WAITING;
std::vector<InteractionsStats> stats_; std::vector<InteractionsStats> stats_;
std::vector<const autofill::PasswordForm*> federated_; std::vector<const autofill::PasswordForm*> federated_;
std::vector<const autofill::PasswordForm*> suppressed_https_forms_;
bool did_complete_querying_suppressed_https_forms_ = false;
DISALLOW_COPY_AND_ASSIGN(FakeFormFetcher); DISALLOW_COPY_AND_ASSIGN(FakeFormFetcher);
}; };
......
...@@ -71,6 +71,23 @@ class FormFetcher { ...@@ -71,6 +71,23 @@ class FormFetcher {
virtual const std::vector<const autofill::PasswordForm*>& virtual const std::vector<const autofill::PasswordForm*>&
GetFederatedMatches() const = 0; GetFederatedMatches() const = 0;
// When this instance fetches forms for an HTTP origin: Returns credentials,
// if any, found for the HTTPS version of that origin. These results are
// queried on a best-effort basis, might be somewhat stale, and are normally
// available shortly after the first Consumer::ProcessMatches callback.
//
// When there exists no precisely matching HTTP credentials for an origin, but
// there are suppressed HTTPS credentials, that could indicate a premature
// `move-to-HTTPS` migration, or simply that the site serves its sign-up or
// some of its sign-in forms over HTTPS, while others still over HTTP.
virtual const std::vector<const autofill::PasswordForm*>&
GetSuppressedHTTPSForms() const = 0;
// Whether querying the results for GetSuppressedHTTPSForms was attempted and
// did complete at least once during the lifetime of this instance, regardless
// of whether there have been any suppressed HTTPS forms.
virtual bool DidCompleteQueryingSuppressedHTTPSForms() const = 0;
// Fetches stored matching logins. In addition the statistics is fetched on // Fetches stored matching logins. In addition the statistics is fetched on
// platforms with the password bubble. This is called automatically during // platforms with the password bubble. This is called automatically during
// construction and can be called manually later as well to cause an update // construction and can be called manually later as well to cause an update
......
...@@ -73,10 +73,13 @@ std::vector<std::unique_ptr<PasswordForm>> MakeCopies( ...@@ -73,10 +73,13 @@ std::vector<std::unique_ptr<PasswordForm>> MakeCopies(
FormFetcherImpl::FormFetcherImpl(PasswordStore::FormDigest form_digest, FormFetcherImpl::FormFetcherImpl(PasswordStore::FormDigest form_digest,
const PasswordManagerClient* client, const PasswordManagerClient* client,
bool should_migrate_http_passwords) bool should_migrate_http_passwords,
bool should_query_suppressed_https_forms)
: form_digest_(std::move(form_digest)), : form_digest_(std::move(form_digest)),
client_(client), client_(client),
should_migrate_http_passwords_(should_migrate_http_passwords) {} should_migrate_http_passwords_(should_migrate_http_passwords),
should_query_suppressed_https_forms_(
should_query_suppressed_https_forms) {}
FormFetcherImpl::~FormFetcherImpl() = default; FormFetcherImpl::~FormFetcherImpl() = default;
...@@ -106,6 +109,15 @@ const std::vector<const PasswordForm*>& FormFetcherImpl::GetFederatedMatches() ...@@ -106,6 +109,15 @@ const std::vector<const PasswordForm*>& FormFetcherImpl::GetFederatedMatches()
return weak_federated_; return weak_federated_;
} }
const std::vector<const PasswordForm*>&
FormFetcherImpl::GetSuppressedHTTPSForms() const {
return weak_suppressed_https_forms_;
}
bool FormFetcherImpl::DidCompleteQueryingSuppressedHTTPSForms() const {
return did_complete_querying_suppressed_https_forms_;
}
void FormFetcherImpl::OnGetPasswordStoreResults( void FormFetcherImpl::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<PasswordForm>> results) { std::vector<std::unique_ptr<PasswordForm>> results) {
DCHECK_EQ(State::WAITING, state_); DCHECK_EQ(State::WAITING, state_);
...@@ -126,6 +138,16 @@ void FormFetcherImpl::OnGetPasswordStoreResults( ...@@ -126,6 +138,16 @@ void FormFetcherImpl::OnGetPasswordStoreResults(
logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size()); logger->LogNumber(Logger::STRING_NUMBER_RESULTS, results.size());
} }
// If this is a non-secure Web origin (i.e. HTTP), kick off the discovery of
// credentials stored for the secure version of this origin (i.e. HTTPS),
// regardless of whether there are some precisely matching |results|.
if (should_query_suppressed_https_forms_ &&
form_digest_.origin.SchemeIs(url::kHttpScheme)) {
suppressed_https_form_fetcher_ =
base::MakeUnique<SuppressedHTTPSFormFetcher>(form_digest_.origin,
client_, this);
}
if (should_migrate_http_passwords_ && results.empty() && if (should_migrate_http_passwords_ && results.empty() &&
form_digest_.origin.SchemeIs(url::kHttpsScheme)) { form_digest_.origin.SchemeIs(url::kHttpsScheme)) {
http_migrator_ = base::MakeUnique<HttpPasswordStoreMigrator>( http_migrator_ = base::MakeUnique<HttpPasswordStoreMigrator>(
...@@ -148,6 +170,14 @@ void FormFetcherImpl::ProcessMigratedForms( ...@@ -148,6 +170,14 @@ void FormFetcherImpl::ProcessMigratedForms(
ProcessPasswordStoreResults(std::move(forms)); ProcessPasswordStoreResults(std::move(forms));
} }
void FormFetcherImpl::ProcessSuppressedHTTPSForms(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
did_complete_querying_suppressed_https_forms_ = true;
suppressed_https_forms_ = std::move(forms);
weak_suppressed_https_forms_ = MakeWeakCopies(suppressed_https_forms_);
}
void FormFetcherImpl::Fetch() { void FormFetcherImpl::Fetch() {
std::unique_ptr<BrowserSavePasswordProgressLogger> logger; std::unique_ptr<BrowserSavePasswordProgressLogger> logger;
if (password_manager_util::IsLoggingActive(client_)) { if (password_manager_util::IsLoggingActive(client_)) {
...@@ -188,14 +218,18 @@ std::unique_ptr<FormFetcher> FormFetcherImpl::Clone() { ...@@ -188,14 +218,18 @@ std::unique_ptr<FormFetcher> FormFetcherImpl::Clone() {
// Create the copy without the "HTTPS migration" activated. If it was needed, // Create the copy without the "HTTPS migration" activated. If it was needed,
// then it was done by |this| already. // then it was done by |this| already.
auto result = base::MakeUnique<FormFetcherImpl>(form_digest_, client_, false); auto result = base::MakeUnique<FormFetcherImpl>(
form_digest_, client_, false, should_query_suppressed_https_forms_);
result->non_federated_ = MakeCopies(this->non_federated_); result->non_federated_ = MakeCopies(this->non_federated_);
result->federated_ = MakeCopies(this->federated_); result->federated_ = MakeCopies(this->federated_);
result->interactions_stats_ = this->interactions_stats_; result->interactions_stats_ = this->interactions_stats_;
result->suppressed_https_forms_ = MakeCopies(this->suppressed_https_forms_);
result->weak_non_federated_ = MakeWeakCopies(result->non_federated_); result->weak_non_federated_ = MakeWeakCopies(result->non_federated_);
result->weak_federated_ = MakeWeakCopies(result->federated_); result->weak_federated_ = MakeWeakCopies(result->federated_);
result->weak_suppressed_https_forms_ =
MakeWeakCopies(result->suppressed_https_forms_);
result->filtered_count_ = this->filtered_count_; result->filtered_count_ = this->filtered_count_;
result->state_ = this->state_; result->state_ = this->state_;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "components/password_manager/core/browser/http_password_store_migrator.h" #include "components/password_manager/core/browser/http_password_store_migrator.h"
#include "components/password_manager/core/browser/password_store.h" #include "components/password_manager/core/browser/password_store.h"
#include "components/password_manager/core/browser/password_store_consumer.h" #include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/browser/suppressed_https_form_fetcher.h"
namespace password_manager { namespace password_manager {
...@@ -23,13 +24,15 @@ class PasswordManagerClient; ...@@ -23,13 +24,15 @@ class PasswordManagerClient;
// with a particular origin. // with a particular origin.
class FormFetcherImpl : public FormFetcher, class FormFetcherImpl : public FormFetcher,
public PasswordStoreConsumer, public PasswordStoreConsumer,
public HttpPasswordStoreMigrator::Consumer { public HttpPasswordStoreMigrator::Consumer,
public SuppressedHTTPSFormFetcher::Consumer {
public: public:
// |form_digest| describes what credentials need to be retrieved and // |form_digest| describes what credentials need to be retrieved and
// |client| serves the PasswordStore, the logging information etc. // |client| serves the PasswordStore, the logging information etc.
FormFetcherImpl(PasswordStore::FormDigest form_digest, FormFetcherImpl(PasswordStore::FormDigest form_digest,
const PasswordManagerClient* client, const PasswordManagerClient* client,
bool should_migrate_http_passwords); bool should_migrate_http_passwords,
bool should_query_suppressed_https_forms);
~FormFetcherImpl() override; ~FormFetcherImpl() override;
...@@ -40,6 +43,9 @@ class FormFetcherImpl : public FormFetcher, ...@@ -40,6 +43,9 @@ class FormFetcherImpl : public FormFetcher,
const std::vector<InteractionsStats>& GetInteractionsStats() const override; const std::vector<InteractionsStats>& GetInteractionsStats() const override;
const std::vector<const autofill::PasswordForm*>& GetFederatedMatches() const std::vector<const autofill::PasswordForm*>& GetFederatedMatches()
const override; const override;
const std::vector<const autofill::PasswordForm*>& GetSuppressedHTTPSForms()
const override;
bool DidCompleteQueryingSuppressedHTTPSForms() const override;
void Fetch() override; void Fetch() override;
std::unique_ptr<FormFetcher> Clone() override; std::unique_ptr<FormFetcher> Clone() override;
...@@ -52,6 +58,10 @@ class FormFetcherImpl : public FormFetcher, ...@@ -52,6 +58,10 @@ class FormFetcherImpl : public FormFetcher,
void ProcessMigratedForms( void ProcessMigratedForms(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override; std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
// SuppressedHTTPSFormFetcher::Consumer:
void ProcessSuppressedHTTPSForms(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms) override;
private: private:
// Processes password form results and forwards them to the |consumers_|. // Processes password form results and forwards them to the |consumers_|.
void ProcessPasswordStoreResults( void ProcessPasswordStoreResults(
...@@ -71,9 +81,19 @@ class FormFetcherImpl : public FormFetcher, ...@@ -71,9 +81,19 @@ class FormFetcherImpl : public FormFetcher,
// Statistics for the current domain. // Statistics for the current domain.
std::vector<InteractionsStats> interactions_stats_; std::vector<InteractionsStats> interactions_stats_;
// When |form_digest_.origin| is not secure, that is, its scheme is HTTP, this
// will be filled with credentials found for the HTTPS version of that origin.
std::vector<std::unique_ptr<autofill::PasswordForm>> suppressed_https_forms_;
// Whether querying |suppressed_https_forms_| was attempted and did complete
// at least once during the lifetime of this instance, regardless of whether
// there have been any results.
bool did_complete_querying_suppressed_https_forms_ = false;
// Non-owning copies of the vectors above. // Non-owning copies of the vectors above.
std::vector<const autofill::PasswordForm*> weak_non_federated_; std::vector<const autofill::PasswordForm*> weak_non_federated_;
std::vector<const autofill::PasswordForm*> weak_federated_; std::vector<const autofill::PasswordForm*> weak_federated_;
std::vector<const autofill::PasswordForm*> weak_suppressed_https_forms_;
// Consumers of the fetcher, all are assumed to outlive |this|. // Consumers of the fetcher, all are assumed to outlive |this|.
std::set<FormFetcher::Consumer*> consumers_; std::set<FormFetcher::Consumer*> consumers_;
...@@ -95,9 +115,17 @@ class FormFetcherImpl : public FormFetcher, ...@@ -95,9 +115,17 @@ class FormFetcherImpl : public FormFetcher,
// Indicates whether HTTP passwords should be migrated to HTTPS. // Indicates whether HTTP passwords should be migrated to HTTPS.
const bool should_migrate_http_passwords_; const bool should_migrate_http_passwords_;
// Indicates whether to query |suppressed_https_forms_| on HTTP origins.
const bool should_query_suppressed_https_forms_;
// Does the actual migration. // Does the actual migration.
std::unique_ptr<HttpPasswordStoreMigrator> http_migrator_; std::unique_ptr<HttpPasswordStoreMigrator> http_migrator_;
// When |form_digest_.origin| is not secure, responsible for looking up
// credentials stored for the HTTPS counterpart of that origin. This happens
// asynchronously, without blocking Consumer::ProcessMatches.
std::unique_ptr<SuppressedHTTPSFormFetcher> suppressed_https_form_fetcher_;
DISALLOW_COPY_AND_ASSIGN(FormFetcherImpl); DISALLOW_COPY_AND_ASSIGN(FormFetcherImpl);
}; };
......
...@@ -231,12 +231,13 @@ PasswordFormManager::PasswordFormManager( ...@@ -231,12 +231,13 @@ PasswordFormManager::PasswordFormManager(
submit_result_(kSubmitResultNotSubmitted), submit_result_(kSubmitResultNotSubmitted),
form_type_(kFormTypeUnspecified), form_type_(kFormTypeUnspecified),
form_saver_(std::move(form_saver)), form_saver_(std::move(form_saver)),
owned_form_fetcher_(form_fetcher owned_form_fetcher_(
? nullptr form_fetcher ? nullptr
: base::MakeUnique<FormFetcherImpl>( : base::MakeUnique<FormFetcherImpl>(
PasswordStore::FormDigest(observed_form), PasswordStore::FormDigest(observed_form),
client, client,
/* should_migrate_http_passwords */ true)), true /* should_migrate_http_passwords */,
false /* should_query_suppressed_https_forms */)),
form_fetcher_(form_fetcher ? form_fetcher : owned_form_fetcher_.get()), form_fetcher_(form_fetcher ? form_fetcher : owned_form_fetcher_.get()),
is_main_frame_secure_(client->IsMainFrameSecure()) { is_main_frame_secure_(client->IsMainFrameSecure()) {
if (owned_form_fetcher_) if (owned_form_fetcher_)
......
// Copyright 2017 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/password_manager/core/browser/suppressed_https_form_fetcher.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_store.h"
#include "url/gurl.h"
namespace password_manager {
SuppressedHTTPSFormFetcher::SuppressedHTTPSFormFetcher(
const GURL& http_origin,
const PasswordManagerClient* client,
Consumer* consumer)
: client_(client), consumer_(consumer) {
DCHECK(client_);
DCHECK(consumer_);
DCHECK(http_origin.is_valid());
DCHECK(http_origin.SchemeIs(url::kHttpScheme));
GURL::Replacements scheme_to_https;
scheme_to_https.SetSchemeStr(url::kHttpsScheme);
GURL https_origin = http_origin.ReplaceComponents(scheme_to_https);
PasswordStore::FormDigest synthetic_form_digest(
autofill::PasswordForm::SCHEME_HTML, https_origin.GetOrigin().spec(),
https_origin);
client_->GetPasswordStore()->GetLogins(synthetic_form_digest, this);
}
SuppressedHTTPSFormFetcher::~SuppressedHTTPSFormFetcher() = default;
void SuppressedHTTPSFormFetcher::OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) {
base::EraseIf(
results, [](const std::unique_ptr<autofill::PasswordForm>& form) {
return form->is_public_suffix_match || form->is_affiliation_based_match;
});
consumer_->ProcessSuppressedHTTPSForms(std::move(results));
}
} // namespace password_manager
// Copyright 2017 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.
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SUPPRESSED_HTTPS_FORM_FETCHER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SUPPRESSED_HTTPS_FORM_FETCHER_H_
#include <memory>
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
class GURL;
namespace password_manager {
class PasswordManagerClient;
// Fetches credentials saved for the HTTPS counterpart of the given HTTP origin.
//
// Filling these HTTPS credentials into forms served over HTTP is obviously
// suppressed, the purpose of doing such a query is to collect metrics on how
// often this happens and inconveniences the user.
//
// This logic is implemented by this class, a separate PasswordStore consumer,
// to make it very sure that these credentials will not get mistakenly filled.
class SuppressedHTTPSFormFetcher : public PasswordStoreConsumer {
public:
// Interface to be implemented by the consumer of this class.
class Consumer {
public:
virtual void ProcessSuppressedHTTPSForms(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms) = 0;
};
SuppressedHTTPSFormFetcher(const GURL& http_origin,
const PasswordManagerClient* client,
Consumer* consumer);
~SuppressedHTTPSFormFetcher() override;
protected:
// PasswordStoreConsumer:
void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<autofill::PasswordForm>> results) override;
private:
FRIEND_TEST_ALL_PREFIXES(SuppressedHTTPSFormFetcherTest, EmptyStore);
FRIEND_TEST_ALL_PREFIXES(SuppressedHTTPSFormFetcherTest, FullStore);
// The client and the consumer should outlive |this|.
const PasswordManagerClient* client_;
Consumer* consumer_;
DISALLOW_COPY_AND_ASSIGN(SuppressedHTTPSFormFetcher);
};
} // namespace password_manager
#endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_SUPPRESSED_HTTPS_FORM_FETCHER_H_
// Copyright 2017 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/password_manager/core/browser/suppressed_https_form_fetcher.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "components/password_manager/core/browser/mock_password_store.h"
#include "components/password_manager/core/browser/password_manager_test_utils.h"
#include "components/password_manager/core/browser/stub_password_manager_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace password_manager {
namespace {
using autofill::PasswordForm;
using testing::_;
const char kTestHttpsURL[] = "https://one.example.com/";
const char kTestPSLMatchingHttpsURL[] = "https://psl.example.com/";
const char kTestHttpURL[] = "http://one.example.com/";
const char kTestAndroidRealmURI[] = "android://hash@com.example.one.android/";
class MockConsumer : public SuppressedHTTPSFormFetcher::Consumer {
public:
MockConsumer() = default;
~MockConsumer() = default;
// GMock still cannot mock methods with move-only args.
MOCK_METHOD1(ProcessSuppressedHTTPSFormsConstRef,
void(const std::vector<std::unique_ptr<PasswordForm>>&));
protected:
// SuppressedHTTPSFormFetcher::Consumer:
void ProcessSuppressedHTTPSForms(
std::vector<std::unique_ptr<PasswordForm>> forms) override {
ProcessSuppressedHTTPSFormsConstRef(forms);
}
private:
DISALLOW_COPY_AND_ASSIGN(MockConsumer);
};
class PasswordManagerClientWithMockStore : public StubPasswordManagerClient {
public:
PasswordManagerClientWithMockStore()
: mock_store_(new ::testing::StrictMock<MockPasswordStore>()) {}
~PasswordManagerClientWithMockStore() override {
mock_store_->ShutdownOnUIThread();
}
MockPasswordStore& mock_password_store() const { return *mock_store_.get(); }
protected:
// StubPasswordManagerClient:
PasswordStore* GetPasswordStore() const override { return mock_store_.get(); }
private:
scoped_refptr<MockPasswordStore> mock_store_;
DISALLOW_COPY_AND_ASSIGN(PasswordManagerClientWithMockStore);
};
} // namespace
class SuppressedHTTPSFormFetcherTest : public testing::Test {
public:
SuppressedHTTPSFormFetcherTest() = default;
~SuppressedHTTPSFormFetcherTest() override = default;
MockConsumer* mock_consumer() { return &consumer_; }
MockPasswordStore* mock_store() { return &client_.mock_password_store(); }
PasswordManagerClientWithMockStore* mock_client() { return &client_; }
private:
base::MessageLoop message_loop_; // Needed by the MockPasswordStore.
MockConsumer consumer_;
PasswordManagerClientWithMockStore client_;
DISALLOW_COPY_AND_ASSIGN(SuppressedHTTPSFormFetcherTest);
};
TEST_F(SuppressedHTTPSFormFetcherTest, EmptyStore) {
PasswordStore::FormDigest observed_form_digest(
autofill::PasswordForm::SCHEME_HTML, kTestHttpURL, GURL(kTestHttpURL));
PasswordStore::FormDigest https_form_digest(
autofill::PasswordForm::SCHEME_HTML, kTestHttpsURL, GURL(kTestHttpsURL));
EXPECT_CALL(*mock_store(), GetLogins(https_form_digest, _));
EXPECT_CALL(*mock_consumer(),
ProcessSuppressedHTTPSFormsConstRef(::testing::IsEmpty()));
SuppressedHTTPSFormFetcher suppressed_form_fetcher(
observed_form_digest.origin, mock_client(), mock_consumer());
suppressed_form_fetcher.OnGetPasswordStoreResults(
std::vector<std::unique_ptr<PasswordForm>>());
}
TEST_F(SuppressedHTTPSFormFetcherTest, FullStore) {
static const PasswordFormData kTestCredentials[] = {
// Credential that is for the HTTPS counterpart of the observed form.
{PasswordForm::SCHEME_HTML, kTestHttpsURL, kTestHttpsURL, "", L"", L"",
L"", L"username_value_1", L"password_value_1", true, 1},
// Another credential for the HTTPS counterpart of the observed form.
{PasswordForm::SCHEME_HTML, kTestHttpsURL, kTestHttpsURL, "", L"", L"",
L"", L"username_value_2", L"password_value_2", true, 1},
// A PSL match of the HTTPS counterpart of the observed form.
{PasswordForm::SCHEME_HTML, kTestPSLMatchingHttpsURL,
kTestPSLMatchingHttpsURL, "", L"", L"", L"", L"username_value_3",
L"password_value_3", true, 1},
// Credential for an affiliated Android application.
{PasswordForm::SCHEME_HTML, kTestAndroidRealmURI, kTestAndroidRealmURI,
"", L"", L"", L"", L"username_value_4", L"password_value_4", true, 1}};
std::vector<std::unique_ptr<PasswordForm>> simulated_store_results;
for (const auto& form_data : kTestCredentials)
simulated_store_results.push_back(
CreatePasswordFormFromDataForTesting(form_data));
ASSERT_EQ(4u, simulated_store_results.size());
simulated_store_results[2]->is_public_suffix_match = true;
simulated_store_results[3]->is_affiliation_based_match = true;
// The PSL and affiliated matches should be filtered out.
std::vector<std::unique_ptr<PasswordForm>> expected_results;
expected_results.push_back(
base::MakeUnique<PasswordForm>(*simulated_store_results[0]));
expected_results.push_back(
base::MakeUnique<PasswordForm>(*simulated_store_results[1]));
PasswordStore::FormDigest observed_form_digest(
autofill::PasswordForm::SCHEME_HTML, kTestHttpURL, GURL(kTestHttpURL));
PasswordStore::FormDigest https_form_digest(
autofill::PasswordForm::SCHEME_HTML, kTestHttpsURL, GURL(kTestHttpsURL));
EXPECT_CALL(*mock_store(), GetLogins(https_form_digest, _));
EXPECT_CALL(*mock_consumer(),
ProcessSuppressedHTTPSFormsConstRef(
UnorderedPasswordFormElementsAre(&expected_results)));
SuppressedHTTPSFormFetcher suppressed_form_fetcher(
observed_form_digest.origin, mock_client(), mock_consumer());
suppressed_form_fetcher.OnGetPasswordStoreResults(
std::move(simulated_store_results));
}
} // namespace password_manager
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