diff options
author | vasilii <vasilii@chromium.org> | 2016-03-07 05:54:20 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-03-07 13:55:30 +0000 |
commit | 8037efe8c78edae8993540b99d13341499e9edb2 (patch) | |
tree | 3580868f5b8ddd532c1c40177c9ba3d950a51b1b | |
parent | 8cc8a0e9395a2fc70d1a048e7e2862a9081cc70d (diff) | |
download | chromium_src-8037efe8c78edae8993540b99d13341499e9edb2.zip chromium_src-8037efe8c78edae8993540b99d13341499e9edb2.tar.gz chromium_src-8037efe8c78edae8993540b99d13341499e9edb2.tar.bz2 |
Show the federated credentials in the Manage passwords bubble.
The only unsupported backend is KWallet. PSL matching isn't implemented for it as well.
BUG=582087
Review URL: https://codereview.chromium.org/1758313004
Cr-Commit-Position: refs/heads/master@{#379550}
10 files changed, 250 insertions, 66 deletions
diff --git a/chrome/browser/password_manager/native_backend_gnome_x.cc b/chrome/browser/password_manager/native_backend_gnome_x.cc index 53c671b..a0d4f1f 100644 --- a/chrome/browser/password_manager/native_backend_gnome_x.cc +++ b/chrome/browser/password_manager/native_backend_gnome_x.cc @@ -185,6 +185,10 @@ ScopedVector<PasswordForm> ConvertFormList(GList* found, ScopedVector<PasswordForm> forms; password_manager::PSLDomainMatchMetric psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_NONE; + const bool allow_psl_match = + lookup_form && password_manager::ShouldPSLDomainMatchingApply( + password_manager::GetRegistryControlledDomain( + GURL(lookup_form->signon_realm))); for (GList* element = g_list_first(found); element; element = g_list_next(element)) { GnomeKeyringFound* data = static_cast<GnomeKeyringFound*>(element->data); @@ -193,15 +197,21 @@ ScopedVector<PasswordForm> ConvertFormList(GList* found, scoped_ptr<PasswordForm> form(FormFromAttributes(attrs)); if (form) { if (lookup_form && form->signon_realm != lookup_form->signon_realm) { - // This is not an exact match, we try PSL matching. if (lookup_form->scheme != PasswordForm::SCHEME_HTML || - form->scheme != PasswordForm::SCHEME_HTML || - !(password_manager::IsPublicSuffixDomainMatch( - lookup_form->signon_realm, form->signon_realm))) { + form->scheme != PasswordForm::SCHEME_HTML) + continue; // Ignore non-HTML matches. + // This is not an exact match, we try PSL matching and federated match. + if (allow_psl_match && + password_manager::IsPublicSuffixDomainMatch( + form->signon_realm, lookup_form->signon_realm)) { + psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; + form->is_public_suffix_match = true; + } else if (!form->federation_origin.unique() && + password_manager::IsFederatedMatch(form->signon_realm, + lookup_form->origin)) { + } else { continue; } - psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; - form->is_public_suffix_match = true; } if (data->secret) { form->password_value = UTF8ToUTF16(data->secret); @@ -214,15 +224,11 @@ ScopedVector<PasswordForm> ConvertFormList(GList* found, } } if (lookup_form) { - const GURL signon_realm(lookup_form->signon_realm); - std::string registered_domain = - password_manager::GetRegistryControlledDomain(signon_realm); - UMA_HISTOGRAM_ENUMERATION( - "PasswordManager.PslDomainMatchTriggering", - password_manager::ShouldPSLDomainMatchingApply(registered_domain) - ? psl_domain_match_metric - : password_manager::PSL_DOMAIN_MATCH_NOT_USED, - password_manager::PSL_DOMAIN_MATCH_COUNT); + UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", + allow_psl_match + ? psl_domain_match_metric + : password_manager::PSL_DOMAIN_MATCH_NOT_USED, + password_manager::PSL_DOMAIN_MATCH_COUNT); } return forms; } @@ -426,7 +432,9 @@ void GKRMethod::GetLogins(const PasswordForm& form, const char* app_string) { ScopedAttributeList attrs(gnome_keyring_attribute_list_new()); if (!password_manager::ShouldPSLDomainMatchingApply( password_manager::GetRegistryControlledDomain( - GURL(form.signon_realm)))) { + GURL(form.signon_realm))) && + form.scheme != PasswordForm::SCHEME_HTML) { + // Don't retrieve the PSL matched and federated credentials. AppendString(&attrs, "signon_realm", form.signon_realm); } AppendString(&attrs, "application", app_string); diff --git a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc index 36c0a36..85e027c 100644 --- a/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc +++ b/chrome/browser/password_manager/native_backend_gnome_x_unittest.cc @@ -884,6 +884,14 @@ TEST_F(NativeBackendGnomeTest, PSLUpdatingStrictAddLogin) { CheckPSLUpdate(UPDATE_BY_ADDLOGIN); } +TEST_F(NativeBackendGnomeTest, FetchFederatedCredential) { + other_auth_.signon_realm = "federation://www.example.com/google.com"; + other_auth_.federation_origin = url::Origin(GURL("https://google.com/")); + EXPECT_TRUE(CheckCredentialAvailability(other_auth_, + GURL("http://www.example.com/"), + PasswordForm::SCHEME_HTML, nullptr)); +} + TEST_F(NativeBackendGnomeTest, BasicUpdateLogin) { NativeBackendGnome backend(42); backend.Init(); diff --git a/chrome/browser/password_manager/native_backend_libsecret.cc b/chrome/browser/password_manager/native_backend_libsecret.cc index 8c65356..9887500 100644 --- a/chrome/browser/password_manager/native_backend_libsecret.cc +++ b/chrome/browser/password_manager/native_backend_libsecret.cc @@ -541,7 +541,8 @@ bool NativeBackendLibsecret::GetLoginsList( if (lookup_form && !password_manager::ShouldPSLDomainMatchingApply( password_manager::GetRegistryControlledDomain( - GURL(lookup_form->signon_realm)))) + GURL(lookup_form->signon_realm))) && + lookup_form->scheme != PasswordForm::SCHEME_HTML) attrs.Append("signon_realm", lookup_form->signon_realm); GError* error = nullptr; @@ -631,6 +632,10 @@ ScopedVector<autofill::PasswordForm> NativeBackendLibsecret::ConvertFormList( password_manager::PSLDomainMatchMetric psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_NONE; GError* error = nullptr; + const bool allow_psl_match = + lookup_form && password_manager::ShouldPSLDomainMatchingApply( + password_manager::GetRegistryControlledDomain( + GURL(lookup_form->signon_realm))); for (GList* element = g_list_first(found); element != nullptr; element = g_list_next(element)) { SecretItem* secretItem = static_cast<SecretItem*>(element->data); @@ -646,15 +651,21 @@ ScopedVector<autofill::PasswordForm> NativeBackendLibsecret::ConvertFormList( g_hash_table_unref(attrs); if (form) { if (lookup_form && form->signon_realm != lookup_form->signon_realm) { - // This is not an exact match, we try PSL matching. if (lookup_form->scheme != PasswordForm::SCHEME_HTML || - form->scheme != PasswordForm::SCHEME_HTML || - !(password_manager::IsPublicSuffixDomainMatch( - lookup_form->signon_realm, form->signon_realm))) { + form->scheme != PasswordForm::SCHEME_HTML) + continue; + // This is not an exact match, we try PSL matching and federated match. + if (allow_psl_match && + password_manager::IsPublicSuffixDomainMatch( + form->signon_realm, lookup_form->signon_realm)) { + psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; + form->is_public_suffix_match = true; + } else if (!form->federation_origin.unique() && + password_manager::IsFederatedMatch(form->signon_realm, + lookup_form->origin)) { + } else { continue; } - psl_domain_match_metric = password_manager::PSL_DOMAIN_MATCH_FOUND; - form->is_public_suffix_match = true; } SecretValue* secretValue = secret_item_get_secret(secretItem); if (secretValue) { @@ -670,15 +681,11 @@ ScopedVector<autofill::PasswordForm> NativeBackendLibsecret::ConvertFormList( } if (lookup_form) { - const GURL signon_realm(lookup_form->signon_realm); - std::string registered_domain = - password_manager::GetRegistryControlledDomain(signon_realm); - UMA_HISTOGRAM_ENUMERATION( - "PasswordManager.PslDomainMatchTriggering", - password_manager::ShouldPSLDomainMatchingApply(registered_domain) - ? psl_domain_match_metric - : password_manager::PSL_DOMAIN_MATCH_NOT_USED, - password_manager::PSL_DOMAIN_MATCH_COUNT); + UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", + allow_psl_match + ? psl_domain_match_metric + : password_manager::PSL_DOMAIN_MATCH_NOT_USED, + password_manager::PSL_DOMAIN_MATCH_COUNT); } g_list_free(found); return forms; diff --git a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc index 2fa1cf4..d032803 100644 --- a/chrome/browser/password_manager/native_backend_libsecret_unittest.cc +++ b/chrome/browser/password_manager/native_backend_libsecret_unittest.cc @@ -694,6 +694,14 @@ TEST_F(NativeBackendLibsecretTest, PSLUpdatingStrictAddLogin) { CheckPSLUpdate(UPDATE_BY_ADDLOGIN); } +TEST_F(NativeBackendLibsecretTest, FetchFederatedCredential) { + other_auth_.signon_realm = "federation://www.example.com/google.com"; + other_auth_.federation_origin = url::Origin(GURL("https://google.com/")); + EXPECT_TRUE(CheckCredentialAvailability(other_auth_, + GURL("http://www.example.com/"), + PasswordForm::SCHEME_HTML, nullptr)); +} + TEST_F(NativeBackendLibsecretTest, BasicUpdateLogin) { NativeBackendLibsecret backend(42); diff --git a/components/password_manager/core/browser/login_database.cc b/components/password_manager/core/browser/login_database.cc index fa1eb1b..9e781d5 100644 --- a/components/password_manager/core/browser/login_database.cc +++ b/components/password_manager/core/browser/login_database.cc @@ -1127,7 +1127,7 @@ bool LoginDatabase::GetLogins( ScopedVector<autofill::PasswordForm>* forms) const { DCHECK(forms); // You *must* change LoginTableColumns if this query changes. - const std::string sql_query = + std::string sql_query = "SELECT origin_url, action_url, " "username_element, username_value, " "password_element, password_value, submit_element, " @@ -1136,12 +1136,23 @@ bool LoginDatabase::GetLogins( "date_synced, display_name, icon_url, " "federation_url, skip_zero_click, generation_upload_status " "FROM logins WHERE signon_realm == ? "; - sql::Statement s; const GURL signon_realm(form.signon_realm); std::string registered_domain = GetRegistryControlledDomain(signon_realm); const bool should_PSL_matching_apply = form.scheme == PasswordForm::SCHEME_HTML && ShouldPSLDomainMatchingApply(registered_domain); + const bool should_federated_apply = form.scheme == PasswordForm::SCHEME_HTML; + if (should_PSL_matching_apply) + sql_query += "OR signon_realm REGEXP ? "; + if (should_federated_apply) + sql_query += "OR (signon_realm LIKE ? AND password_type == 2) "; + + // TODO(nyquist) Consider usage of GetCachedStatement when + // http://crbug.com/248608 is fixed. + sql::Statement s(db_.GetUniqueStatement(sql_query.c_str())); + s.BindString(0, form.signon_realm); + int placeholder = 1; + // PSL matching only applies to HTML forms. if (should_PSL_matching_apply) { // We are extending the original SQL query with one that includes more @@ -1150,11 +1161,6 @@ bool LoginDatabase::GetLogins( // in the |logins| table. The result (scheme, domain and port) is verified // further down using GURL. See the functions SchemeMatches, // RegistryControlledDomainMatches and PortMatches. - const std::string extended_sql_query = - sql_query + "OR signon_realm REGEXP ? "; - // TODO(nyquist) Re-enable usage of GetCachedStatement when - // http://crbug.com/248608 is fixed. - s.Assign(db_.GetUniqueStatement(extended_sql_query.c_str())); // We need to escape . in the domain. Since the domain has already been // sanitized using GURL, we do not need to escape any other characters. base::ReplaceChars(registered_domain, ".", "\\.", ®istered_domain); @@ -1170,18 +1176,24 @@ bool LoginDatabase::GetLogins( // The scheme and port has to be the same as the observed form. std::string regexp = "^(" + scheme + ":\\/\\/)([\\w-]+\\.)*" + registered_domain + "(:" + port + ")?\\/$"; - s.BindString(0, form.signon_realm); - s.BindString(1, regexp); - } else { + s.BindString(placeholder++, regexp); + } + if (should_federated_apply) { + std::string expression = + base::StringPrintf("federation://%s/%%", form.origin.host().c_str()); + s.BindString(placeholder++, expression); + } + + if (!should_PSL_matching_apply && !should_federated_apply) { + // Otherwise the histogram is reported in StatementToForms. UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", PSL_DOMAIN_MATCH_NOT_USED, PSL_DOMAIN_MATCH_COUNT); - s.Assign(db_.GetCachedStatement(SQL_FROM_HERE, sql_query.c_str())); - s.BindString(0, form.signon_realm); } - return StatementToForms(&s, should_PSL_matching_apply ? &form : nullptr, - forms); + return StatementToForms( + &s, should_PSL_matching_apply || should_federated_apply ? &form : nullptr, + forms); } bool LoginDatabase::GetLoginsCreatedBetween( @@ -1297,7 +1309,7 @@ std::string LoginDatabase::GetEncryptedPassword( // static bool LoginDatabase::StatementToForms( sql::Statement* statement, - const autofill::PasswordForm* psl_match, + const autofill::PasswordForm* matched_form, ScopedVector<autofill::PasswordForm>* forms) { PSLDomainMatchMetric psl_domain_match_metric = PSL_DOMAIN_MATCH_NONE; @@ -1310,23 +1322,26 @@ bool LoginDatabase::StatementToForms( return false; if (result == ENCRYPTION_RESULT_ITEM_FAILURE) continue; - DCHECK(result == ENCRYPTION_RESULT_SUCCESS); - if (psl_match && psl_match->signon_realm != new_form->signon_realm) { + DCHECK_EQ(ENCRYPTION_RESULT_SUCCESS, result); + if (matched_form && matched_form->signon_realm != new_form->signon_realm) { if (new_form->scheme != PasswordForm::SCHEME_HTML) continue; // Ignore non-HTML matches. - if (!IsPublicSuffixDomainMatch(new_form->signon_realm, - psl_match->signon_realm)) { + if (IsPublicSuffixDomainMatch(new_form->signon_realm, + matched_form->signon_realm)) { + psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND; + new_form->is_public_suffix_match = true; + } else if (!new_form->federation_origin.unique() && + IsFederatedMatch(new_form->signon_realm, + matched_form->origin)) { + } else { continue; } - - psl_domain_match_metric = PSL_DOMAIN_MATCH_FOUND; - new_form->is_public_suffix_match = true; } forms->push_back(std::move(new_form)); } - if (psl_match) { + if (matched_form) { UMA_HISTOGRAM_ENUMERATION("PasswordManager.PslDomainMatchTriggering", psl_domain_match_metric, PSL_DOMAIN_MATCH_COUNT); } diff --git a/components/password_manager/core/browser/login_database.h b/components/password_manager/core/browser/login_database.h index 3568fc3..c992f3e 100644 --- a/components/password_manager/core/browser/login_database.h +++ b/components/password_manager/core/browser/login_database.h @@ -83,7 +83,8 @@ class LoginDatabase { // All Get* methods below overwrite |forms| with the returned credentials. On // success, those methods return true. - // Gets a list of credentials matching |form|, including blacklisted matches. + // Gets a list of credentials matching |form|, including blacklisted matches + // and federated credentials. bool GetLogins(const autofill::PasswordForm& form, ScopedVector<autofill::PasswordForm>* forms) const WARN_UNUSED_RESULT; @@ -188,10 +189,10 @@ class LoginDatabase { ScopedVector<autofill::PasswordForm>* forms) const; // Overwrites |forms| with credentials retrieved from |statement|. If - // |psl_match| is not null, filters out all results but thos PSL-matching - // |*psl_match|. On success returns true. + // |matched_form| is not null, filters out all results but those PSL-matching + // |*matched_form| or federated credentials for it. On success returns true. static bool StatementToForms(sql::Statement* statement, - const autofill::PasswordForm* psl_match, + const autofill::PasswordForm* matched_form, ScopedVector<autofill::PasswordForm>* forms); base::FilePath db_path_; diff --git a/components/password_manager/core/browser/login_database_unittest.cc b/components/password_manager/core/browser/login_database_unittest.cc index 859aca1..46ba8f5 100644 --- a/components/password_manager/core/browser/login_database_unittest.cc +++ b/components/password_manager/core/browser/login_database_unittest.cc @@ -373,6 +373,52 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatching) { result.clear(); } +TEST_F(LoginDatabaseTest, TestFederatedMatching) { + ScopedVector<autofill::PasswordForm> result; + + // Example password form. + PasswordForm form; + form.origin = GURL("https://foo.com/"); + form.action = GURL("https://foo.com/login"); + form.username_value = ASCIIToUTF16("test@gmail.com"); + form.password_value = ASCIIToUTF16("test"); + form.signon_realm = "https://foo.com/"; + form.ssl_valid = true; + form.preferred = false; + form.scheme = PasswordForm::SCHEME_HTML; + + // We go to the mobile site. + PasswordForm form2(form); + form2.origin = GURL("https://mobile.foo.com/"); + form2.action = GURL("https://mobile.foo.com/login"); + form2.signon_realm = "federation://mobile.foo.com/accounts.google.com"; + form2.username_value = ASCIIToUTF16("test1@gmail.com"); + form2.type = autofill::PasswordForm::TYPE_API; + form2.federation_origin = url::Origin(GURL("https://accounts.google.com/")); + + // Add it and make sure it is there. + EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form)); + EXPECT_EQ(AddChangeForForm(form2), db().AddLogin(form2)); + EXPECT_TRUE(db().GetAutofillableLogins(&result)); + EXPECT_EQ(2U, result.size()); + + // Match against desktop. + PasswordForm form_request; + form_request.origin = GURL("https://foo.com/"); + form_request.signon_realm = "https://foo.com/"; + form_request.scheme = PasswordForm::SCHEME_HTML; + EXPECT_TRUE(db().GetLogins(form_request, &result)); + EXPECT_THAT(result, testing::ElementsAre(testing::Pointee(form))); + + // Match against the mobile site. + form_request.origin = GURL("https://mobile.foo.com/"); + form_request.signon_realm = "https://mobile.foo.com/"; + EXPECT_TRUE(db().GetLogins(form_request, &result)); + form.is_public_suffix_match = true; + EXPECT_THAT(result, testing::UnorderedElementsAre(testing::Pointee(form), + testing::Pointee(form2))); +} + TEST_F(LoginDatabaseTest, TestPublicSuffixDisabledForNonHTMLForms) { TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_BASIC); TestNonHTMLFormPSLMatching(PasswordForm::SCHEME_DIGEST); @@ -435,10 +481,60 @@ TEST_F(LoginDatabaseTest, TestPublicSuffixDomainMatchingShouldMatchingApply) { // Match against the other site. Should not match since feature should not be // enabled for this domain. + ASSERT_FALSE(ShouldPSLDomainMatchingApply( + GetRegistryControlledDomain(GURL(form2.signon_realm)))); + EXPECT_TRUE(db().GetLogins(form2, &result)); EXPECT_EQ(0U, result.size()); } +TEST_F(LoginDatabaseTest, TestFederatedMatchingWithoutPSLMatching) { + ScopedVector<autofill::PasswordForm> result; + + // Example password form. + PasswordForm form; + form.origin = GURL("https://accounts.google.com/"); + form.action = GURL("https://accounts.google.com/login"); + form.username_value = ASCIIToUTF16("test@gmail.com"); + form.password_value = ASCIIToUTF16("test"); + form.signon_realm = "https://accounts.google.com/"; + form.ssl_valid = true; + form.preferred = false; + form.scheme = PasswordForm::SCHEME_HTML; + + // We go to a different site on the same domain where PSL is disabled. + PasswordForm form2(form); + form2.origin = GURL("https://some.other.google.com/"); + form2.action = GURL("https://some.other.google.com/login"); + form2.signon_realm = "federation://some.other.google.com/accounts.google.com"; + form2.username_value = ASCIIToUTF16("test1@gmail.com"); + form2.type = autofill::PasswordForm::TYPE_API; + form2.federation_origin = url::Origin(GURL("https://accounts.google.com/")); + + // Add it and make sure it is there. + EXPECT_EQ(AddChangeForForm(form), db().AddLogin(form)); + EXPECT_EQ(AddChangeForForm(form2), db().AddLogin(form2)); + EXPECT_TRUE(db().GetAutofillableLogins(&result)); + EXPECT_EQ(2U, result.size()); + + // Match against the first one. + PasswordForm form_request; + form_request.origin = form.origin; + form_request.signon_realm = form.signon_realm; + form_request.scheme = PasswordForm::SCHEME_HTML; + EXPECT_TRUE(db().GetLogins(form_request, &result)); + EXPECT_THAT(result, testing::ElementsAre(testing::Pointee(form))); + + // Match against the second one. + ASSERT_FALSE(ShouldPSLDomainMatchingApply( + GetRegistryControlledDomain(GURL(form2.signon_realm)))); + form_request.origin = form2.origin; + form_request.signon_realm = form2.signon_realm; + EXPECT_TRUE(db().GetLogins(form_request, &result)); + form.is_public_suffix_match = true; + EXPECT_THAT(result, testing::ElementsAre(testing::Pointee(form2))); +} + // This test fails if the implementation of GetLogins uses GetCachedStatement // instead of GetUniqueStatement, since REGEXP is in use. See // http://crbug.com/248608. diff --git a/components/password_manager/core/browser/psl_matching_helper.cc b/components/password_manager/core/browser/psl_matching_helper.cc index 2f7f9d6..5482feb 100644 --- a/components/password_manager/core/browser/psl_matching_helper.cc +++ b/components/password_manager/core/browser/psl_matching_helper.cc @@ -7,6 +7,7 @@ #include "base/command_line.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/string_util.h" #include "components/autofill/core/common/password_form.h" #include "components/password_manager/core/common/password_manager_switches.h" #include "net/base/registry_controlled_domains/registry_controlled_domain.h" @@ -49,4 +50,12 @@ std::string GetRegistryControlledDomain(const GURL& signon_realm) { net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); } +bool IsFederatedMatch(const std::string& signon_realm, const GURL& origin) { + // The format should be "federation://origin.host/federation.host; + std::string federated_realm = "federation://" + origin.host() + "/"; + return signon_realm.size() > federated_realm.size() && + base::StartsWith(signon_realm, federated_realm, + base::CompareCase::INSENSITIVE_ASCII); +} + } // namespace password_manager diff --git a/components/password_manager/core/browser/psl_matching_helper.h b/components/password_manager/core/browser/psl_matching_helper.h index 9e9a10e..22071b6 100644 --- a/components/password_manager/core/browser/psl_matching_helper.h +++ b/components/password_manager/core/browser/psl_matching_helper.h @@ -44,6 +44,10 @@ bool IsPublicSuffixDomainMatch(const std::string& url1, // registry-controlled domain part. std::string GetRegistryControlledDomain(const GURL& signon_realm); +// Returns true iff |signon_realm| designates a federated credential for the +// |origin|. +bool IsFederatedMatch(const std::string& signon_realm, const GURL& origin); + } // namespace password_manager #endif // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PSL_MATCHING_HELPER_H_ diff --git a/components/password_manager/core/browser/psl_matching_helper_unittest.cc b/components/password_manager/core/browser/psl_matching_helper_unittest.cc index 01f4e8a..68381d2 100644 --- a/components/password_manager/core/browser/psl_matching_helper_unittest.cc +++ b/components/password_manager/core/browser/psl_matching_helper_unittest.cc @@ -21,7 +21,7 @@ TEST(PSLMatchingUtilsTest, IsPublicSuffixDomainMatch) { bool should_match; }; - TestPair pairs[] = { + const TestPair pairs[] = { {"http://facebook.com", "http://facebook.com", true}, {"http://facebook.com/path", "http://facebook.com/path", true}, {"http://facebook.com/path1", "http://facebook.com/path2", true}, @@ -44,17 +44,45 @@ TEST(PSLMatchingUtilsTest, IsPublicSuffixDomainMatch) { {"", "http://www.example.com", false}, {"http://www.example.com", "bad url", false}, {"http://www.example.com/%00", "http://www.example.com/%00", false}, + {"federation://example.com/google.com", "https://example.com/", false}, }; - for (size_t i = 0; i < arraysize(pairs); ++i) { + for (const TestPair& pair : pairs) { autofill::PasswordForm form1; - form1.signon_realm = pairs[i].url1; + form1.signon_realm = pair.url1; autofill::PasswordForm form2; - form2.signon_realm = pairs[i].url2; - EXPECT_EQ(pairs[i].should_match, + form2.signon_realm = pair.url2; + EXPECT_EQ(pair.should_match, IsPublicSuffixDomainMatch(form1.signon_realm, form2.signon_realm)) - << "First URL = " << pairs[i].url1 - << ", second URL = " << pairs[i].url2; + << "First URL = " << pair.url1 << ", second URL = " << pair.url2; + } +} + +TEST(PSLMatchingUtilsTest, IsFederatedMatch) { + struct TestPair { + const char* signon_realm; + const char* origin; + bool should_match; + }; + + const TestPair pairs[] = { + {"https://facebook.com", "https://facebook.com", false}, + {"", "", false}, + {"", "https://facebook.com/", false}, + {"https://facebook.com/", "", false}, + {"federation://example.com/google.com", "https://example.com/", true}, + {"federation://example.com/google.com", "http://example.com/", true}, + {"federation://example.com/google.com", "example.com", false}, + {"federation://example.com/", "http://example.com/", false}, + {"federation://example.com/google.com", "example", false}, + }; + + for (const TestPair& pair : pairs) { + std::string signon_realm = pair.signon_realm; + GURL origin(pair.origin); + EXPECT_EQ(pair.should_match, IsFederatedMatch(signon_realm, origin)) + << "signon_realm = " << pair.signon_realm + << ", origin = " << pair.origin; } } |