Commit 983d5f5d authored by jdoerrie's avatar jdoerrie Committed by Commit Bot

Inject Affiliation Information in Password Forms

This change adds additional fields for affiliation information to
password forms. In order to do so it modifies the existing Inject*
methods. This additional information will be needed to be able to show
Play Store names and icons for Android credentials in the password
settings page.

Bug: 628988
Change-Id: I37138f89c1fed826d151419ab296db322457aac7
Reviewed-on: https://chromium-review.googlesource.com/561380
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarBalazs Engedy <engedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#485600}
parent 8f6ba357
......@@ -4,7 +4,10 @@
#include "chrome/browser/password_manager/password_manager_test_base.h"
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "base/macros.h"
#include "base/memory/ptr_util.h"
......@@ -453,7 +456,8 @@ void PasswordManagerBrowserTestBase::WaitForPasswordStore() {
PasswordStoreFactory::GetForProfile(browser()->profile(),
ServiceAccessType::IMPLICIT_ACCESS);
PasswordStoreResultsObserver syncer;
password_store->GetAutofillableLoginsWithAffiliatedRealms(&syncer);
password_store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(
&syncer);
syncer.Wait();
}
......
......@@ -379,7 +379,7 @@ void PasswordManagerPresenter::PasswordListPopulater::Populate() {
PasswordStore* store = page_->GetPasswordStore();
if (store != NULL) {
cancelable_task_tracker()->TryCancelAll();
store->GetAutofillableLoginsWithAffiliatedRealms(this);
store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(this);
} else {
LOG(ERROR) << "No password store! Cannot display passwords.";
}
......@@ -403,7 +403,7 @@ void PasswordManagerPresenter::PasswordExceptionListPopulater::Populate() {
PasswordStore* store = page_->GetPasswordStore();
if (store != NULL) {
cancelable_task_tracker()->TryCancelAll();
store->GetBlacklistLoginsWithAffiliatedRealms(this);
store->GetBlacklistLoginsWithAffiliationAndBrandingInformation(this);
} else {
LOG(ERROR) << "No password store! Cannot display exceptions.";
}
......
......@@ -64,6 +64,8 @@ void PasswordFormToJSON(const PasswordForm& form,
target->SetBoolean("was_parsed_using_autofill_predictions",
form.was_parsed_using_autofill_predictions);
target->SetString("affiliated_web_realm", form.affiliated_web_realm);
target->SetString("app_display_name", form.app_display_name);
target->SetString("app_icon_url", form.app_icon_url.possibly_invalid_spec());
target->SetBoolean("does_look_like_signup_form",
form.does_look_like_signup_form);
std::ostringstream submission_event_string_stream;
......@@ -134,6 +136,8 @@ bool PasswordForm::operator==(const PasswordForm& form) const {
is_public_suffix_match == form.is_public_suffix_match &&
is_affiliation_based_match == form.is_affiliation_based_match &&
affiliated_web_realm == form.affiliated_web_realm &&
app_display_name == form.app_display_name &&
app_icon_url == form.app_icon_url &&
does_look_like_signup_form == form.does_look_like_signup_form &&
submission_event == form.submission_event;
}
......
......@@ -8,6 +8,7 @@
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/time/time.h"
......@@ -133,11 +134,26 @@ struct PasswordForm {
// The web realm affiliated with the Android application, if the form is an
// Android credential. Otherwise, the string is empty. If there are several
// realms affiliated with the application, an arbitrary realm is chosen.
// The field is filled out in PasswordStore's InjectAffiliatedWebRealms.
// If there was no call of InjectAffiliatedWebRealms, the string is empty.
// realms affiliated with the application, an arbitrary realm is chosen. The
// field is filled out when the PasswordStore injects affiliation and branding
// information, i.e. in InjectAffiliationAndBrandingInformation. If there was
// no prior call to this method, the string is empty.
std::string affiliated_web_realm;
// The display name (e.g. Play Store name) of the Android application if the
// form is an Android credential. Otherwise, the string is empty. The field is
// filled out when the PasswordStore injects affiliation and branding
// information, i.e. in InjectAffiliationAndBrandingInformation. If there was
// no prior call to this method, the string is empty.
std::string app_display_name;
// The icon URL (e.g. Play Store icon URL) of the Android application if the
// form is an Android credential. Otherwise, the URL is empty. The field is
// filled out when the PasswordStore injects affiliation and branding
// information, i.e. in InjectAffiliationAndBrandingInformation. If there was
// no prior call to this method, the URL is empty.
GURL app_icon_url;
// The name of the submit button used. Optional; only used in scoring
// of PasswordForm results from the database to make matches as tight as
// possible.
......
......@@ -4,6 +4,7 @@
#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
#include <algorithm>
#include <utility>
#include "base/barrier_closure.h"
......@@ -85,7 +86,7 @@ void AffiliatedMatchHelper::GetAffiliatedWebRealms(
}
}
void AffiliatedMatchHelper::InjectAffiliatedWebRealms(
void AffiliatedMatchHelper::InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback) {
std::vector<autofill::PasswordForm*> android_credentials;
......@@ -98,30 +99,52 @@ void AffiliatedMatchHelper::InjectAffiliatedWebRealms(
base::Closure barrier_closure =
base::BarrierClosure(android_credentials.size(), on_get_all_realms);
for (auto* form : android_credentials) {
// TODO(crbug.com/628988): Rename |GetAffiliations| to
// |GetAffiliationsAndBranding|.
affiliation_service_->GetAffiliations(
FacetURI::FromPotentiallyInvalidSpec(form->signon_realm),
AffiliationService::StrategyOnCacheMiss::FAIL,
base::Bind(&AffiliatedMatchHelper::CompleteInjectAffiliatedWebRealm,
base::Bind(&AffiliatedMatchHelper::
CompleteInjectAffiliationAndBrandingInformation,
weak_ptr_factory_.GetWeakPtr(), base::Unretained(form),
barrier_closure));
}
}
void AffiliatedMatchHelper::CompleteInjectAffiliatedWebRealm(
void AffiliatedMatchHelper::CompleteInjectAffiliationAndBrandingInformation(
autofill::PasswordForm* form,
base::Closure barrier_closure,
const AffiliatedFacets& results,
bool success) {
// If there is a number of realms, choose the first in the list.
if (success) {
for (const Facet& affiliated_facet : results) {
if (affiliated_facet.uri.IsValidWebFacetURI()) {
form->affiliated_web_realm =
affiliated_facet.uri.canonical_spec() + "/";
break;
}
}
if (!success) {
barrier_closure.Run();
return;
}
const FacetURI facet_uri(
FacetURI::FromPotentiallyInvalidSpec(form->signon_realm));
DCHECK(facet_uri.IsValidAndroidFacetURI());
// Inject branding information into the form (e.g. the Play Store name and
// icon URL). We expect to always find a matching facet URI in the results.
auto facet = std::find_if(results.begin(), results.end(),
[&facet_uri](const Facet& affiliated_facet) {
return affiliated_facet.uri == facet_uri;
});
DCHECK(facet != results.end());
form->app_display_name = facet->branding_info.name;
form->app_icon_url = facet->branding_info.icon_url;
// Inject the affiliated web realm into the form, if available. In case
// multiple web realms are available, this will always choose the first
// available web realm for injection.
auto affiliated_facet = std::find_if(
results.begin(), results.end(), [](const Facet& affiliated_facet) {
return affiliated_facet.uri.IsValidWebFacetURI();
});
if (affiliated_facet != results.end())
form->affiliated_web_realm = affiliated_facet->uri.canonical_spec() + "/";
barrier_closure.Run();
}
......
......@@ -80,12 +80,13 @@ class AffiliatedMatchHelper : public PasswordStore::Observer,
const PasswordStore::FormDigest& android_form,
const AffiliatedRealmsCallback& result_callback);
// Retrieves realms of web sites affiliated with the Android credentials in
// |forms|, sets |affiliated_web_realm| of forms, and invokes
// |result_callback|.
// Retrieves affiliation and branding information about the Android
// credentials in |forms|, sets |affiliated_web_realm|, |app_display_name| and
// |app_icon_url| of forms, and invokes |result_callback|.
// NOTE: This will not issue an on-demand network request. If a request to
// cache fails, no web realm will be injected into corresponding form.
virtual void InjectAffiliatedWebRealms(
// cache fails, no affiliation and branding information will be injected into
// corresponding form.
virtual void InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback);
......@@ -127,12 +128,15 @@ class AffiliatedMatchHelper : public PasswordStore::Observer,
bool success);
// Called back by AffiliationService to supply the list of facets affiliated
// with the Android credential in |form|. Sets |form->affiliated_web_realm|,
// if |success| is true and |results| is non-empty. Invokes |barrier_closure|.
void CompleteInjectAffiliatedWebRealm(autofill::PasswordForm* form,
base::Closure barrier_closure,
const AffiliatedFacets& results,
bool success);
// with the Android credential in |form|. Injects affiliation and branding
// information by setting |affiliated_web_realm|, |app_display_name| and
// |app_icon_url| on |form| if |success| is true and |results| is non-empty.
// Invokes |barrier_closure|.
void CompleteInjectAffiliationAndBrandingInformation(
autofill::PasswordForm* form,
base::Closure barrier_closure,
const AffiliatedFacets& results,
bool success);
// PasswordStore::Observer:
void OnLoginsChanged(const PasswordStoreChangeList& changes) override;
......
......@@ -94,6 +94,8 @@ const char kTestWebFacetURIAlpha1[] = "https://one.alpha.example.com";
const char kTestWebFacetURIAlpha2[] = "https://two.alpha.example.com";
const char kTestAndroidFacetURIAlpha3[] =
"android://hash@com.example.alpha.android";
const char kTestAndroidFacetNameAlpha3[] = "Facet Name Alpha 3";
const char kTestAndroidFacetIconURLAlpha3[] = "https://example.com/alpha_3.png";
const char kTestWebRealmAlpha1[] = "https://one.alpha.example.com/";
const char kTestWebRealmAlpha2[] = "https://two.alpha.example.com/";
const char kTestAndroidRealmAlpha3[] =
......@@ -102,8 +104,12 @@ const char kTestAndroidRealmAlpha3[] =
const char kTestWebFacetURIBeta1[] = "https://one.beta.example.com";
const char kTestAndroidFacetURIBeta2[] =
"android://hash@com.example.beta.android";
const char kTestAndroidFacetNameBeta2[] = "Facet Name Beta 2";
const char kTestAndroidFacetIconURLBeta2[] = "https://example.com/beta_2.png";
const char kTestAndroidFacetURIBeta3[] =
"android://hash@com.yetanother.beta.android";
const char kTestAndroidFacetNameBeta3[] = "Facet Name Beta 3";
const char kTestAndroidFacetIconURLBeta3[] = "https://example.com/beta_3.png";
const char kTestWebRealmBeta1[] = "https://one.beta.example.com/";
const char kTestAndroidRealmBeta2[] =
"android://hash@com.example.beta.android/";
......@@ -122,15 +128,21 @@ AffiliatedFacets GetTestEquivalenceClassAlpha() {
return {
{FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha1)},
{FacetURI::FromCanonicalSpec(kTestWebFacetURIAlpha2)},
{FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3)},
{FacetURI::FromCanonicalSpec(kTestAndroidFacetURIAlpha3),
FacetBrandingInfo{kTestAndroidFacetNameAlpha3,
GURL(kTestAndroidFacetIconURLAlpha3)}},
};
}
AffiliatedFacets GetTestEquivalenceClassBeta() {
return {
{FacetURI::FromCanonicalSpec(kTestWebFacetURIBeta1)},
{FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2)},
{FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3)},
{FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
FacetBrandingInfo{kTestAndroidFacetNameBeta2,
GURL(kTestAndroidFacetIconURLBeta2)}},
{FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
FacetBrandingInfo{kTestAndroidFacetNameBeta3,
GURL(kTestAndroidFacetIconURLBeta3)}},
};
}
......@@ -272,10 +284,10 @@ class AffiliatedMatchHelperTest : public testing::Test {
}
std::vector<std::unique_ptr<autofill::PasswordForm>>
InjectAffiliatedWebRealms(
InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms) {
expecting_result_callback_ = true;
match_helper()->InjectAffiliatedWebRealms(
match_helper()->InjectAffiliationAndBrandingInformation(
std::move(forms),
base::Bind(&AffiliatedMatchHelperTest::OnFormsCallback,
base::Unretained(this)));
......@@ -437,9 +449,11 @@ TEST_F(AffiliatedMatchHelperTest,
testing::IsEmpty());
}
// Verifies that InjectAffiliatedWebRealms() injects the realms of web sites
// affiliated with the given Android application into password forms, if any.
TEST_F(AffiliatedMatchHelperTest, InjectAffiliatedWebRealms) {
// Verifies that InjectAffiliationAndBrandingInformation() injects the realms of
// web sites affiliated with the given Android application into the password
// forms, as well as branding information corresponding to the application, if
// any.
TEST_F(AffiliatedMatchHelperTest, InjectAffiliationAndBrandingInformation) {
std::vector<std::unique_ptr<autofill::PasswordForm>> forms;
forms.push_back(base::MakeUnique<autofill::PasswordForm>(
......@@ -454,6 +468,12 @@ TEST_F(AffiliatedMatchHelperTest, InjectAffiliatedWebRealms) {
FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta2),
StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
forms.push_back(base::MakeUnique<autofill::PasswordForm>(
GetTestAndroidCredentials(kTestAndroidRealmBeta3)));
mock_affiliation_service()->ExpectCallToGetAffiliationsAndSucceedWithResult(
FacetURI::FromCanonicalSpec(kTestAndroidFacetURIBeta3),
StrategyOnCacheMiss::FAIL, GetTestEquivalenceClassBeta());
forms.push_back(base::MakeUnique<autofill::PasswordForm>(
GetTestAndroidCredentials(kTestAndroidRealmGamma)));
mock_affiliation_service()->ExpectCallToGetAffiliationsAndEmulateFailure(
......@@ -470,14 +490,25 @@ TEST_F(AffiliatedMatchHelperTest, InjectAffiliatedWebRealms) {
size_t expected_form_count = forms.size();
std::vector<std::unique_ptr<autofill::PasswordForm>> results(
InjectAffiliatedWebRealms(std::move(forms)));
InjectAffiliationAndBrandingInformation(std::move(forms)));
ASSERT_EQ(expected_form_count, results.size());
EXPECT_THAT(results[0]->affiliated_web_realm,
testing::AnyOf(kTestWebRealmAlpha1, kTestWebRealmAlpha2));
EXPECT_EQ(kTestAndroidFacetNameAlpha3, results[0]->app_display_name);
EXPECT_EQ(kTestAndroidFacetIconURLAlpha3,
results[0]->app_icon_url.possibly_invalid_spec());
EXPECT_THAT(results[1]->affiliated_web_realm,
testing::Eq(kTestWebRealmBeta1));
EXPECT_THAT(results[2]->affiliated_web_realm, testing::IsEmpty());
EXPECT_EQ(kTestAndroidFacetNameBeta2, results[1]->app_display_name);
EXPECT_EQ(kTestAndroidFacetIconURLBeta2,
results[1]->app_icon_url.possibly_invalid_spec());
EXPECT_THAT(results[2]->affiliated_web_realm,
testing::Eq(kTestWebRealmBeta1));
EXPECT_EQ(kTestAndroidFacetNameBeta3, results[2]->app_display_name);
EXPECT_EQ(kTestAndroidFacetIconURLBeta3,
results[2]->app_icon_url.possibly_invalid_spec());
EXPECT_THAT(results[3]->affiliated_web_realm, testing::IsEmpty());
EXPECT_THAT(results[4]->affiliated_web_realm, testing::IsEmpty());
}
// Note: IsValidWebCredential() is tested as part of GetAffiliatedAndroidRealms
......
......@@ -5,6 +5,8 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_AFFILIATION_FETCHER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_AFFILIATION_FETCHER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/macros.h"
......@@ -78,6 +80,8 @@ class AffiliationFetcher : net::URLFetcherDelegate {
// Parses and validates the response protocol buffer message for a list of
// equivalence classes, stores them into |result| and returns true on success.
// It is guaranteed that every one of the requested Facet URIs will be a
// member of exactly one returned equivalence class.
// Returns false if the response was gravely ill-formed or self-inconsistent.
// Unknown kinds of facet URIs and new protocol buffer fields will be ignored.
bool ParseResponse(AffiliationFetcherDelegate::Result* result) const;
......
......@@ -108,7 +108,9 @@ class AffiliationService : public KeyedService {
const base::FilePath& db_path);
// Looks up facets affiliated with the facet identified by |facet_uri|, and
// invokes |result_callback| with the results.
// invokes |result_callback| with the results. It is guaranteed that the
// results will contain one facet with URI equal to |facet_uri| when
// |result_callback| is invoked with success set to true.
//
// If the local cache contains fresh affiliation information for |facet_uri|,
// the request will be served from cache. Otherwise, |cache_miss_policy|
......
......@@ -112,7 +112,13 @@ TEST_F(AffiliationServiceTest, GetAffiliations) {
ASSERT_TRUE(fake_affiliation_api()->HasPendingRequest());
fake_affiliation_api()->ServeNextRequest();
mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
const auto equivalence_class_alpha(GetTestEquivalenceClassAlpha());
mock_consumer()->ExpectSuccessWithResult(equivalence_class_alpha);
EXPECT_THAT(
equivalence_class_alpha,
testing::Contains(testing::Field(
&Facet::uri, FacetURI::FromCanonicalSpec(kTestFacetURIAlpha1))));
main_task_runner()->RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(mock_consumer());
......@@ -124,7 +130,7 @@ TEST_F(AffiliationServiceTest, GetAffiliations) {
background_task_runner()->RunUntilIdle();
ASSERT_FALSE(fake_affiliation_api()->HasPendingRequest());
mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClassAlpha());
mock_consumer()->ExpectSuccessWithResult(equivalence_class_alpha);
main_task_runner()->RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(mock_consumer());
......
......@@ -6,6 +6,7 @@
#include <stddef.h>
#include <algorithm>
#include <memory>
#include "base/bind.h"
......@@ -92,6 +93,10 @@ class MockFacetManagerHost : public FacetManagerHost {
expected_facet_uri_ = facet_uri;
}
// Returns the facet URI that will be expected to appear in calls coming from
// the FacetManager under test.
const FacetURI& expected_facet_uri() const { return expected_facet_uri_; }
// Sets up fake |database_content| as the canned response to be returned to
// the FacetManager every time it calls ReadAffiliationsFromDatabase().
void set_fake_database_content(
......@@ -352,7 +357,13 @@ class FacetManagerTest : public testing::Test {
}
void ExpectConsumerSuccessCallback() {
mock_consumer()->ExpectSuccessWithResult(GetTestEquivalenceClass());
const auto equivalence_class(GetTestEquivalenceClass());
mock_consumer()->ExpectSuccessWithResult(equivalence_class);
EXPECT_THAT(
equivalence_class,
testing::Contains(testing::Field(
&Facet::uri, fake_facet_manager_host()->expected_facet_uri())));
consumer_task_runner()->RunUntilIdle();
testing::Mock::VerifyAndClearExpectations(mock_consumer());
}
......
......@@ -4,6 +4,8 @@
#include "components/password_manager/core/browser/android_affiliation/mock_affiliated_match_helper.h"
#include <utility>
#include "base/memory/ptr_util.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/android_affiliation/affiliation_service.h"
......@@ -32,9 +34,11 @@ void MockAffiliatedMatchHelper::ExpectCallToGetAffiliatedWebRealms(
.WillOnce(testing::Return(results_to_return));
}
void MockAffiliatedMatchHelper::ExpectCallToInjectAffiliatedWebRealms(
const std::vector<std::string>& results_to_inject) {
EXPECT_CALL(*this, OnInjectAffiliatedWebRealmsCalled())
void MockAffiliatedMatchHelper::
ExpectCallToInjectAffiliationAndBrandingInformation(
const std::vector<AffiliationAndBrandingInformation>&
results_to_inject) {
EXPECT_CALL(*this, OnInjectAffiliationAndBrandingInformationCalled())
.WillOnce(testing::Return(results_to_inject));
}
......@@ -54,14 +58,17 @@ void MockAffiliatedMatchHelper::GetAffiliatedWebRealms(
result_callback.Run(affiliated_web_realms);
}
void MockAffiliatedMatchHelper::InjectAffiliatedWebRealms(
void MockAffiliatedMatchHelper::InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback) {
std::vector<std::string> affiliated_web_realms =
OnInjectAffiliatedWebRealmsCalled();
DCHECK_EQ(affiliated_web_realms.size(), forms.size());
for (size_t i = 0; i < forms.size(); ++i)
forms[i]->affiliated_web_realm = affiliated_web_realms[i];
const std::vector<AffiliationAndBrandingInformation>& information =
OnInjectAffiliationAndBrandingInformationCalled();
ASSERT_EQ(information.size(), forms.size());
for (size_t i = 0; i < forms.size(); ++i) {
forms[i]->affiliated_web_realm = information[i].affiliated_web_realm;
forms[i]->app_display_name = information[i].app_display_name;
forms[i]->app_icon_url = information[i].app_icon_url;
}
result_callback.Run(std::move(forms));
}
......
......@@ -5,10 +5,15 @@
#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_MOCK_AFFILIATED_MATCH_HELPER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_ANDROID_AFFILIATION_MOCK_AFFILIATED_MATCH_HELPER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/macros.h"
#include "components/password_manager/core/browser/android_affiliation/affiliated_match_helper.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace autofill {
struct PasswordForm;
......@@ -18,6 +23,14 @@ namespace password_manager {
class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
public:
// This struct mirrors the corresponding affiliation and branding information
// related fields from autofill::PasswordForm.
struct AffiliationAndBrandingInformation {
std::string affiliated_web_realm;
std::string app_display_name;
GURL app_icon_url;
};
MockAffiliatedMatchHelper();
~MockAffiliatedMatchHelper() override;
......@@ -35,15 +48,16 @@ class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
const PasswordStore::FormDigest& expected_android_form,
const std::vector<std::string>& results_to_return);
void ExpectCallToInjectAffiliatedWebRealms(
const std::vector<std::string>& results_to_inject);
void ExpectCallToInjectAffiliationAndBrandingInformation(
const std::vector<AffiliationAndBrandingInformation>& results_to_inject);
private:
MOCK_METHOD1(OnGetAffiliatedAndroidRealmsCalled,
std::vector<std::string>(const PasswordStore::FormDigest&));
MOCK_METHOD1(OnGetAffiliatedWebRealmsCalled,
std::vector<std::string>(const PasswordStore::FormDigest&));
MOCK_METHOD0(OnInjectAffiliatedWebRealmsCalled, std::vector<std::string>());
MOCK_METHOD0(OnInjectAffiliationAndBrandingInformationCalled,
std::vector<AffiliationAndBrandingInformation>());
void GetAffiliatedAndroidRealms(
const PasswordStore::FormDigest& observed_form,
......@@ -52,7 +66,7 @@ class MockAffiliatedMatchHelper : public AffiliatedMatchHelper {
const PasswordStore::FormDigest& android_form,
const AffiliatedRealmsCallback& result_callback) override;
void InjectAffiliatedWebRealms(
void InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
const PasswordFormsCallback& result_callback) override;
......
......@@ -241,9 +241,10 @@ void PasswordStore::GetAutofillableLogins(PasswordStoreConsumer* consumer) {
Schedule(&PasswordStore::GetAutofillableLoginsImpl, consumer);
}
void PasswordStore::GetAutofillableLoginsWithAffiliatedRealms(
void PasswordStore::GetAutofillableLoginsWithAffiliationAndBrandingInformation(
PasswordStoreConsumer* consumer) {
Schedule(&PasswordStore::GetAutofillableLoginsWithAffiliatedRealmsImpl,
Schedule(&PasswordStore::
GetAutofillableLoginsWithAffiliationAndBrandingInformationImpl,
consumer);
}
......@@ -251,9 +252,10 @@ void PasswordStore::GetBlacklistLogins(PasswordStoreConsumer* consumer) {
Schedule(&PasswordStore::GetBlacklistLoginsImpl, consumer);
}
void PasswordStore::GetBlacklistLoginsWithAffiliatedRealms(
void PasswordStore::GetBlacklistLoginsWithAffiliationAndBrandingInformation(
PasswordStoreConsumer* consumer) {
Schedule(&PasswordStore::GetBlacklistLoginsWithAffiliatedRealmsImpl,
Schedule(&PasswordStore::
GetBlacklistLoginsWithAffiliationAndBrandingInformationImpl,
consumer);
}
......@@ -555,8 +557,9 @@ void PasswordStore::GetAutofillableLoginsImpl(
request->NotifyConsumerWithResults(std::move(obtained_forms));
}
void PasswordStore::GetAutofillableLoginsWithAffiliatedRealmsImpl(
std::unique_ptr<GetLoginsRequest> request) {
void PasswordStore::
GetAutofillableLoginsWithAffiliationAndBrandingInformationImpl(
std::unique_ptr<GetLoginsRequest> request) {
std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
if (!FillAutofillableLogins(&obtained_forms))
obtained_forms.clear();
......@@ -564,16 +567,10 @@ void PasswordStore::GetAutofillableLoginsWithAffiliatedRealmsImpl(
// post a request to UI thread.
main_thread_runner_->PostTask(
FROM_HERE,
base::Bind(&PasswordStore::InjectAffiliatedWebRealms, this,
base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
base::Passed(&obtained_forms), base::Passed(&request)));
}
void PasswordStore::NotifyLoginsWithAffiliatedRealms(
std::unique_ptr<GetLoginsRequest> request,
std::vector<std::unique_ptr<PasswordForm>> obtained_forms) {
request->NotifyConsumerWithResults(std::move(obtained_forms));
}
void PasswordStore::GetBlacklistLoginsImpl(
std::unique_ptr<GetLoginsRequest> request) {
std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
......@@ -582,7 +579,7 @@ void PasswordStore::GetBlacklistLoginsImpl(
request->NotifyConsumerWithResults(std::move(obtained_forms));
}
void PasswordStore::GetBlacklistLoginsWithAffiliatedRealmsImpl(
void PasswordStore::GetBlacklistLoginsWithAffiliationAndBrandingInformationImpl(
std::unique_ptr<GetLoginsRequest> request) {
std::vector<std::unique_ptr<PasswordForm>> obtained_forms;
if (!FillBlacklistLogins(&obtained_forms))
......@@ -591,7 +588,7 @@ void PasswordStore::GetBlacklistLoginsWithAffiliatedRealmsImpl(
// post a request to UI thread.
main_thread_runner_->PostTask(
FROM_HERE,
base::Bind(&PasswordStore::InjectAffiliatedWebRealms, this,
base::Bind(&PasswordStore::InjectAffiliationAndBrandingInformation, this,
base::Passed(&obtained_forms), base::Passed(&request)));
}
......@@ -625,11 +622,11 @@ void PasswordStore::GetLoginsWithAffiliationsImpl(
request->NotifyConsumerWithResults(std::move(results));
}
void PasswordStore::InjectAffiliatedWebRealms(
void PasswordStore::InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<PasswordForm>> forms,
std::unique_ptr<GetLoginsRequest> request) {
if (affiliated_match_helper_) {
affiliated_match_helper_->InjectAffiliatedWebRealms(
affiliated_match_helper_->InjectAffiliationAndBrandingInformation(
std::move(forms),
base::Bind(&PasswordStore::GetLoginsRequest::NotifyConsumerWithResults,
base::Owned(request.release())));
......
......@@ -199,9 +199,9 @@ class PasswordStore : protected PasswordStoreSync,
// The request will be cancelled if the consumer is destroyed.
virtual void GetAutofillableLogins(PasswordStoreConsumer* consumer);
// Same as above, but also fills in |affiliated_web_realm| for Android
// credentials.
virtual void GetAutofillableLoginsWithAffiliatedRealms(
// Same as above, but also fills in affiliation and branding information for
// Android credentials.
virtual void GetAutofillableLoginsWithAffiliationAndBrandingInformation(
PasswordStoreConsumer* consumer);
// Gets the complete list of PasswordForms that are blacklist entries,
......@@ -209,9 +209,9 @@ class PasswordStore : protected PasswordStoreSync,
// consumer is destroyed.
virtual void GetBlacklistLogins(PasswordStoreConsumer* consumer);
// Same as above, but also fills in |affiliated_web_realm| for Android
// credentials.
virtual void GetBlacklistLoginsWithAffiliatedRealms(
// Same as above, but also fills in affiliation and branding information for
// Android credentials.
virtual void GetBlacklistLoginsWithAffiliationAndBrandingInformation(
PasswordStoreConsumer* consumer);
// Reports usage metrics for the database. |sync_username| and
......@@ -501,17 +501,17 @@ class PasswordStore : protected PasswordStoreSync,
// Finds all non-blacklist PasswordForms, and notifies the consumer.
void GetAutofillableLoginsImpl(std::unique_ptr<GetLoginsRequest> request);
// Same as above, but also fills in |affiliated_web_realm| for Android
// credentials.
void GetAutofillableLoginsWithAffiliatedRealmsImpl(
// Same as above, but also fills in affiliation and branding information for
// Android credentials.
void GetAutofillableLoginsWithAffiliationAndBrandingInformationImpl(
std::unique_ptr<GetLoginsRequest> request);
// Finds all blacklist PasswordForms, and notifies the consumer.
void GetBlacklistLoginsImpl(std::unique_ptr<GetLoginsRequest> request);
// Same as above, but also fills in |affiliated_web_realm| for Android
// credentials.
void GetBlacklistLoginsWithAffiliatedRealmsImpl(
// Same as above, but also fills in affiliation and branding information for
// Android credentials.
void GetBlacklistLoginsWithAffiliationAndBrandingInformationImpl(
std::unique_ptr<GetLoginsRequest> request);
// Notifies |request| about the stats for all sites.
......@@ -521,12 +521,6 @@ class PasswordStore : protected PasswordStoreSync,
void NotifySiteStats(const GURL& origin_domain,
std::unique_ptr<GetLoginsRequest> request);
// Notifies |request| about the autofillable logins with affiliated web
// realms for Android credentials.
void NotifyLoginsWithAffiliatedRealms(
std::unique_ptr<GetLoginsRequest> request,
std::vector<std::unique_ptr<autofill::PasswordForm>> obtained_forms);
// Extended version of GetLoginsImpl that also returns credentials stored for
// the specified affiliated Android applications. That is, it finds all
// PasswordForms with a signon_realm that is either:
......@@ -539,9 +533,9 @@ class PasswordStore : protected PasswordStoreSync,
std::unique_ptr<GetLoginsRequest> request,
const std::vector<std::string>& additional_android_realms);
// Retrieves and fills in |affiliated_web_realm| values for Android
// Retrieves and fills in affiliation and branding information for Android
// credentials in |forms|. Called on the main thread.
void InjectAffiliatedWebRealms(
void InjectAffiliationAndBrandingInformation(
std::vector<std::unique_ptr<autofill::PasswordForm>> forms,
std::unique_ptr<GetLoginsRequest> request);
......
......@@ -79,6 +79,10 @@ constexpr const char kTestAndroidRealm3[] =
"android://hash@com.example.three.android/";
constexpr const char kTestUnrelatedAndroidRealm[] =
"android://hash@com.notexample.android/";
constexpr const char kTestAndroidName1[] = "Example Android App 1";
constexpr const char kTestAndroidIconURL1[] = "https://example.com/icon_1.png";
constexpr const char kTestAndroidName2[] = "Example Android App 2";
constexpr const char kTestAndroidIconURL2[] = "https://example.com/icon_2.png";
class MockPasswordStoreConsumer : public PasswordStoreConsumer {
public:
......@@ -813,28 +817,18 @@ TEST_F(PasswordStoreTest, MAYBE_UpdatePasswordsStoredForAffiliatedWebsites) {
}
}
TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
/* clang-format off */
TEST_F(PasswordStoreTest, GetLoginsWithAffiliationAndBrandingInformation) {
static const PasswordFormData kTestCredentials[] = {
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm1,
"", "", L"", L"", L"",
L"username_value_1",
L"", true, 1},
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm2,
"", "", L"", L"", L"",
L"username_value_2",
L"", true, 1},
{PasswordForm::SCHEME_HTML,
kTestAndroidRealm3,
"", "", L"", L"", L"",
L"username_value_3",
L"", true, 1}};
/* clang-format on */
{PasswordForm::SCHEME_HTML, kTestAndroidRealm1, "", "", L"", L"", L"",
L"username_value_1", L"", true, 1},
{PasswordForm::SCHEME_HTML, kTestAndroidRealm2, "", "", L"", L"", L"",
L"username_value_2", L"", true, 1},
{PasswordForm::SCHEME_HTML, kTestAndroidRealm3, "", "", L"", L"", L"",
L"username_value_3", L"", true, 1},
{PasswordForm::SCHEME_HTML, kTestWebRealm1, kTestWebOrigin1, "", L"", L"",
L"", L"username_value_4", L"", true, 1}};
const bool kFalseTrue[] = {false, true};
for (bool blacklisted : kFalseTrue) {
for (bool blacklisted : {false, true}) {
SCOPED_TRACE(testing::Message("use blacklisted logins: ") << blacklisted);
scoped_refptr<PasswordStoreDefault> store(new PasswordStoreDefault(
base::SequencedTaskRunnerHandle::Get(),
......@@ -845,44 +839,53 @@ TEST_F(PasswordStoreTest, GetLoginsWithAffiliatedRealms) {
base::Closure());
std::vector<std::unique_ptr<PasswordForm>> all_credentials;
for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
for (const auto& test_credential : kTestCredentials) {
all_credentials.push_back(
CreatePasswordFormFromDataForTesting(kTestCredentials[i]));
if (blacklisted)
all_credentials.back()->blacklisted_by_user = true;
CreatePasswordFormFromDataForTesting(test_credential));
all_credentials.back()->blacklisted_by_user = blacklisted;
store->AddLogin(*all_credentials.back());
base::RunLoop().RunUntilIdle();
}
MockPasswordStoreConsumer mock_consumer;
std::vector<std::unique_ptr<PasswordForm>> expected_results;
for (size_t i = 0; i < arraysize(kTestCredentials); ++i) {
expected_results.push_back(
base::MakeUnique<PasswordForm>(*all_credentials[i]));
for (const auto& credential : all_credentials)
expected_results.push_back(base::MakeUnique<PasswordForm>(*credential));
std::vector<MockAffiliatedMatchHelper::AffiliationAndBrandingInformation>
affiliation_info_for_results = {
{kTestWebRealm1, kTestAndroidName1, GURL(kTestAndroidIconURL1)},
{kTestWebRealm2, kTestAndroidName2, GURL(kTestAndroidIconURL2)},
{/* Pretend affiliation or branding info is unavailable. */},
{/* Pretend affiliation or branding info is unavailable. */}};
auto mock_helper = base::MakeUnique<MockAffiliatedMatchHelper>();
mock_helper->ExpectCallToInjectAffiliationAndBrandingInformation(
affiliation_info_for_results);
store->SetAffiliatedMatchHelper(std::move(mock_helper));
for (size_t i = 0; i < expected_results.size(); ++i) {
expected_results[i]->affiliated_web_realm =
affiliation_info_for_results[i].affiliated_web_realm;
expected_results[i]->app_display_name =
affiliation_info_for_results[i].app_display_name;
expected_results[i]->app_icon_url =
affiliation_info_for_results[i].app_icon_url;
}
MockAffiliatedMatchHelper* mock_helper = new MockAffiliatedMatchHelper;
store->SetAffiliatedMatchHelper(base::WrapUnique(mock_helper));
std::vector<std::string> affiliated_web_realms;
affiliated_web_realms.push_back(kTestWebRealm1);
affiliated_web_realms.push_back(kTestWebRealm2);
affiliated_web_realms.push_back(std::string());
mock_helper->ExpectCallToInjectAffiliatedWebRealms(affiliated_web_realms);
for (size_t i = 0; i < expected_results.size(); ++i)
expected_results[i]->affiliated_web_realm = affiliated_web_realms[i];
EXPECT_CALL(mock_consumer,
OnGetPasswordStoreResultsConstRef(
UnorderedPasswordFormElementsAre(&expected_results)));
if (blacklisted)
store->GetBlacklistLoginsWithAffiliatedRealms(&mock_consumer);
else
store->GetAutofillableLoginsWithAffiliatedRealms(&mock_consumer);
// Since GetAutofillableLoginsWithAffiliatedRealms schedules a request for
// affiliated realms to UI thread, don't shutdown UI thread until there are
// no tasks in the UI queue.
if (blacklisted) {
store->GetBlacklistLoginsWithAffiliationAndBrandingInformation(
&mock_consumer);
} else {
store->GetAutofillableLoginsWithAffiliationAndBrandingInformation(
&mock_consumer);
}
// Since GetAutofillableLoginsWithAffiliationAndBrandingInformation
// schedules a request for affiliation information to UI thread, don't
// shutdown UI thread until there are no tasks in the UI queue.
base::RunLoop().RunUntilIdle();
store->ShutdownOnUIThread();
base::RunLoop().RunUntilIdle();
......
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