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