1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/password_manager/core/browser/credential_cache.h"
6 
7 #include <memory>
8 #include <string>
9 
10 #include "base/strings/string_piece.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "components/autofill/core/common/password_form.h"
13 #include "components/password_manager/core/browser/origin_credential_store.h"
14 #include "components/password_manager/core/browser/password_manager_test_utils.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace password_manager {
19 
20 namespace {
21 
22 using autofill::PasswordForm;
23 using url::Origin;
24 
25 using IsPublicSuffixMatch = UiCredential::IsPublicSuffixMatch;
26 using IsAffiliationBasedMatch = UiCredential::IsAffiliationBasedMatch;
27 using IsOriginBlacklisted = CredentialCache::IsOriginBlacklisted;
28 
29 constexpr char kExampleSite[] = "https://example.com/";
30 constexpr char kExampleSite2[] = "https://example.two.com/";
31 constexpr char kExampleSiteMobile[] = "https://m.example.com/";
32 constexpr char kExampleSiteSubdomain[] = "https://accounts.example.com/";
33 
MakeUiCredential(base::StringPiece username,base::StringPiece password,base::StringPiece origin=kExampleSite,IsPublicSuffixMatch is_public_suffix_match=IsPublicSuffixMatch (false),IsAffiliationBasedMatch is_affiliation_based_match=IsAffiliationBasedMatch (false))34 UiCredential MakeUiCredential(
35     base::StringPiece username,
36     base::StringPiece password,
37     base::StringPiece origin = kExampleSite,
38     IsPublicSuffixMatch is_public_suffix_match = IsPublicSuffixMatch(false),
39     IsAffiliationBasedMatch is_affiliation_based_match =
40         IsAffiliationBasedMatch(false)) {
41   return UiCredential(base::UTF8ToUTF16(username), base::UTF8ToUTF16(password),
42                       Origin::Create(GURL(origin)), is_public_suffix_match,
43                       is_affiliation_based_match);
44 }
45 
46 }  // namespace
47 
48 class CredentialCacheTest : public testing::Test {
49  public:
cache()50   CredentialCache* cache() { return &cache_; }
51 
52  private:
53   CredentialCache cache_;
54 };
55 
TEST_F(CredentialCacheTest,ReturnsSameStoreForSameOriginOnly)56 TEST_F(CredentialCacheTest, ReturnsSameStoreForSameOriginOnly) {
57   EXPECT_EQ(&cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite))),
58             &cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite))));
59 
60   EXPECT_NE(&cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite))),
61             &cache()->GetCredentialStore(Origin::Create(GURL(kExampleSite2))));
62 }
63 
TEST_F(CredentialCacheTest,StoresCredentialsSortedByAplhabetAndOrigins)64 TEST_F(CredentialCacheTest, StoresCredentialsSortedByAplhabetAndOrigins) {
65   Origin origin = Origin::Create(GURL(kExampleSite));
66   cache()->SaveCredentialsAndBlacklistedForOrigin(
67       {CreateEntry("Berta", "30948", GURL(kExampleSite), false, false).get(),
68        CreateEntry("Adam", "Pas83B", GURL(kExampleSite), false, false).get(),
69        CreateEntry("Dora", "PakudC", GURL(kExampleSite), false, false).get(),
70        CreateEntry("Carl", "P1238C", GURL(kExampleSite), false, false).get(),
71        // These entries need to be ordered but come after the examples above.
72        CreateEntry("Cesar", "V3V1V", GURL(kExampleSite), false, true).get(),
73        CreateEntry("Rolf", "A4nd0m", GURL(kExampleSiteMobile), true, false)
74            .get(),
75        CreateEntry("Greg", "5fnd1m", GURL(kExampleSiteSubdomain), true, false)
76            .get(),
77        CreateEntry("Elfi", "a65ddm", GURL(kExampleSiteSubdomain), true, false)
78            .get(),
79        CreateEntry("Alf", "R4nd50m", GURL(kExampleSiteMobile), true, false)
80            .get()},
81       IsOriginBlacklisted(false), origin);
82 
83   EXPECT_THAT(
84       cache()->GetCredentialStore(origin).GetCredentials(),
85       testing::ElementsAre(
86 
87           // Alphabetical entries of the exactly matching https://example.com:
88           MakeUiCredential("Adam", "Pas83B"),
89           MakeUiCredential("Berta", "30948"),
90           MakeUiCredential("Carl", "P1238C"),
91           // Affiliation based matches are first class citizens and should be
92           // treated as a first-party credential.
93           MakeUiCredential("Cesar", "V3V1V", kExampleSite,
94                            IsPublicSuffixMatch(false),
95                            IsAffiliationBasedMatch(true)),
96           MakeUiCredential("Dora", "PakudC"),
97 
98           // Alphabetical entries of PSL-match https://accounts.example.com:
99           MakeUiCredential("Elfi", "a65ddm", kExampleSiteSubdomain,
100                            IsPublicSuffixMatch(true)),
101           MakeUiCredential("Greg", "5fnd1m", kExampleSiteSubdomain,
102                            IsPublicSuffixMatch(true)),
103 
104           // Alphabetical entries of PSL-match https://m.example.com:
105           MakeUiCredential("Alf", "R4nd50m", kExampleSiteMobile,
106                            IsPublicSuffixMatch(true)),
107           MakeUiCredential("Rolf", "A4nd0m", kExampleSiteMobile,
108                            IsPublicSuffixMatch(true))));
109 }
110 
TEST_F(CredentialCacheTest,StoredCredentialsForIndependentOrigins)111 TEST_F(CredentialCacheTest, StoredCredentialsForIndependentOrigins) {
112   Origin origin = Origin::Create(GURL(kExampleSite));
113   Origin origin2 = Origin::Create(GURL(kExampleSite2));
114 
115   cache()->SaveCredentialsAndBlacklistedForOrigin(
116       {CreateEntry("Ben", "S3cur3", GURL(kExampleSite), false, false).get()},
117       IsOriginBlacklisted(false), origin);
118   cache()->SaveCredentialsAndBlacklistedForOrigin(
119       {CreateEntry("Abe", "B4dPW", GURL(kExampleSite2), false, false).get()},
120       IsOriginBlacklisted(false), origin2);
121 
122   EXPECT_THAT(cache()->GetCredentialStore(origin).GetCredentials(),
123               testing::ElementsAre(MakeUiCredential("Ben", "S3cur3")));
124   EXPECT_THAT(
125       cache()->GetCredentialStore(origin2).GetCredentials(),
126       testing::ElementsAre(MakeUiCredential("Abe", "B4dPW", kExampleSite2)));
127 }
128 
TEST_F(CredentialCacheTest,ClearsCredentials)129 TEST_F(CredentialCacheTest, ClearsCredentials) {
130   Origin origin = Origin::Create(GURL(kExampleSite));
131   cache()->SaveCredentialsAndBlacklistedForOrigin(
132       {CreateEntry("Ben", "S3cur3", GURL(kExampleSite), false, false).get()},
133       IsOriginBlacklisted(false), Origin::Create(GURL(kExampleSite)));
134   ASSERT_THAT(cache()->GetCredentialStore(origin).GetCredentials(),
135               testing::ElementsAre(MakeUiCredential("Ben", "S3cur3")));
136 
137   cache()->ClearCredentials();
138   EXPECT_EQ(cache()->GetCredentialStore(origin).GetCredentials().size(), 0u);
139 }
140 
TEST_F(CredentialCacheTest,StoresBlacklistedWithCredentials)141 TEST_F(CredentialCacheTest, StoresBlacklistedWithCredentials) {
142   Origin origin = Origin::Create(GURL(kExampleSite));
143   cache()->SaveCredentialsAndBlacklistedForOrigin(
144       {CreateEntry("Ben", "S3cur3", GURL(kExampleSite), false, false).get()},
145       IsOriginBlacklisted(true), Origin::Create(GURL(kExampleSite)));
146   EXPECT_EQ(OriginCredentialStore::BlacklistedStatus::kIsBlacklisted,
147             cache()->GetCredentialStore(origin).GetBlacklistedStatus());
148 }
149 
150 }  // namespace password_manager
151