1 // Copyright 2011 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_HTTP_HTTP_AUTH_CACHE_H_ 6 #define NET_HTTP_HTTP_AUTH_CACHE_H_ 7 8 #include <stddef.h> 9 10 #include <list> 11 #include <map> 12 #include <string> 13 14 #include "base/functional/callback.h" 15 #include "base/gtest_prod_util.h" 16 #include "base/memory/raw_ptr.h" 17 #include "base/time/default_clock.h" 18 #include "base/time/default_tick_clock.h" 19 #include "base/time/time.h" 20 #include "net/base/net_export.h" 21 #include "net/base/network_anonymization_key.h" 22 #include "net/http/http_auth.h" 23 #include "url/scheme_host_port.h" 24 25 namespace net { 26 27 // HttpAuthCache stores HTTP authentication identities and challenge info. 28 // For each (scheme_host_port, realm, scheme) triple the cache stores a 29 // HttpAuthCache::Entry, which holds: 30 // - the origin server {protocol scheme, host, port} 31 // - the last identity used (username/password) 32 // - the last auth handler used (contains realm and authentication scheme) 33 // - the list of paths which used this realm 34 // Entries can be looked up by either (origin, realm, scheme) or (origin, path). 35 class NET_EXPORT HttpAuthCache { 36 public: 37 class NET_EXPORT Entry { 38 public: 39 Entry(const Entry& other); 40 ~Entry(); 41 scheme_host_port()42 const url::SchemeHostPort& scheme_host_port() const { 43 return scheme_host_port_; 44 } 45 46 // The case-sensitive realm string of the challenge. realm()47 const std::string& realm() const { return realm_; } 48 49 // The authentication scheme of the challenge. scheme()50 HttpAuth::Scheme scheme() const { 51 return scheme_; 52 } 53 54 // The authentication challenge. auth_challenge()55 const std::string& auth_challenge() const { return auth_challenge_; } 56 57 // The login credentials. credentials()58 const AuthCredentials& credentials() const { 59 return credentials_; 60 } 61 IncrementNonceCount()62 int IncrementNonceCount() { 63 return ++nonce_count_; 64 } 65 66 void UpdateStaleChallenge(const std::string& auth_challenge); 67 68 bool IsEqualForTesting(const Entry& other) const; 69 70 bool operator==(const Entry& other) const = delete; 71 72 private: 73 friend class HttpAuthCache; 74 FRIEND_TEST_ALL_PREFIXES(HttpAuthCacheTest, AddPath); 75 FRIEND_TEST_ALL_PREFIXES(HttpAuthCacheTest, AddToExistingEntry); 76 77 typedef std::list<std::string> PathList; 78 79 Entry(); 80 81 // Adds a path defining the realm's protection space. If the path is 82 // already contained in the protection space, is a no-op. 83 void AddPath(const std::string& path); 84 85 // Returns true if |dir| is contained within the realm's protection 86 // space. |*path_len| is set to the length of the enclosing path if 87 // such a path exists and |path_len| is non-nullptr. If no enclosing 88 // path is found, |*path_len| is left unmodified. 89 // 90 // If an enclosing path is found, moves it up by one place in the paths list 91 // so that more frequently used paths migrate to the front of the list. 92 // 93 // Note that proxy auth cache entries are associated with empty 94 // paths. Therefore it is possible for HasEnclosingPath() to return 95 // true and set |*path_len| to 0. 96 bool HasEnclosingPath(const std::string& dir, size_t* path_len); 97 98 // SchemeHostPort of the server. 99 url::SchemeHostPort scheme_host_port_; 100 std::string realm_; 101 HttpAuth::Scheme scheme_ = HttpAuth::AUTH_SCHEME_MAX; 102 103 // Identity. 104 std::string auth_challenge_; 105 AuthCredentials credentials_; 106 107 int nonce_count_ = 0; 108 109 // List of paths that define the realm's protection space. 110 PathList paths_; 111 112 // Times the entry was created and last used (by looking up, adding a path, 113 // or updating the challenge.) 114 base::TimeTicks creation_time_ticks_; 115 base::TimeTicks last_use_time_ticks_; 116 base::Time creation_time_; 117 }; 118 119 // Prevent unbounded memory growth. These are safeguards for abuse; it is 120 // not expected that the limits will be reached in ordinary usage. 121 // This also defines the worst-case lookup times (which grow linearly 122 // with number of elements in the cache). 123 enum { kMaxNumPathsPerRealmEntry = 10 }; 124 enum { kMaxNumRealmEntries = 20 }; 125 126 // If |key_server_entries_by_network_anonymization_key| is true, all 127 // HttpAuth::AUTH_SERVER operations are keyed by NetworkAnonymizationKey. 128 // Otherwise, NetworkAnonymizationKey arguments are ignored. 129 explicit HttpAuthCache(bool key_server_entries_by_network_anonymization_key); 130 131 HttpAuthCache(const HttpAuthCache&) = delete; 132 HttpAuthCache& operator=(const HttpAuthCache&) = delete; 133 134 ~HttpAuthCache(); 135 136 // Sets whether server entries are keyed by NetworkAnonymizationKey. 137 // If this results in changing the value of the setting, all current server 138 // entries are deleted. 139 void SetKeyServerEntriesByNetworkAnonymizationKey( 140 bool key_server_entries_by_network_anonymization_key); 141 142 // Find the realm entry on server |origin| for realm |realm| and 143 // scheme |scheme|. If a matching entry is found, move it up by one place 144 // in the entries list, so that more frequently used entries migrate to the 145 // front of the list. 146 // |scheme_host_port| - the {scheme, host, port} of the server. 147 // |target| - whether this is for server or proxy auth. 148 // |realm| - case sensitive realm string. 149 // |scheme| - the authentication scheme (i.e. basic, negotiate). 150 // returns - the matched entry or nullptr. 151 Entry* Lookup(const url::SchemeHostPort& scheme_host_port, 152 HttpAuth::Target target, 153 const std::string& realm, 154 HttpAuth::Scheme scheme, 155 const NetworkAnonymizationKey& network_anonymization_key); 156 157 // Find the entry on server |origin| whose protection space includes 158 // |path|. This uses the assumption in RFC 2617 section 2 that deeper 159 // paths lie in the same protection space. If a matching entry is found, move 160 // it up by one place in the entries list, so that more frequently used 161 // entries migrate to the front of the list. 162 // |scheme_host_port| - the {scheme, host, port} of the server. 163 // |path| - absolute path of the resource, or empty string in case of 164 // proxy auth (which does not use the concept of paths). 165 // returns - the matched entry or nullptr. 166 Entry* LookupByPath(const url::SchemeHostPort& scheme_host_port, 167 HttpAuth::Target target, 168 const NetworkAnonymizationKey& network_anonymization_key, 169 const std::string& path); 170 171 // Add an entry on server |scheme_host_port| for realm |handler->realm()| and 172 // scheme |handler->scheme()|. If an entry for this (realm,scheme) 173 // already exists, update it rather than replace it -- this preserves the 174 // paths list. 175 // |scheme_host_port| - the {scheme, host, port} of the server. 176 // |realm| - the auth realm for the challenge. 177 // |scheme| - the authentication scheme (i.e. basic, negotiate). 178 // |credentials| - login information for the realm. 179 // |path| - absolute path for a resource contained in the protection 180 // space; this will be added to the list of known paths. 181 // returns - the entry that was just added/updated. 182 Entry* Add(const url::SchemeHostPort& scheme_host_port, 183 HttpAuth::Target target, 184 const std::string& realm, 185 HttpAuth::Scheme scheme, 186 const NetworkAnonymizationKey& network_anonymization_key, 187 const std::string& auth_challenge, 188 const AuthCredentials& credentials, 189 const std::string& path); 190 191 // Remove entry on server |origin| for realm |realm| and scheme |scheme| 192 // if one exists AND if the cached credentials matches |credentials|. 193 // |scheme_host_port| - the {scheme, host, port} of the server. 194 // |realm| - case sensitive realm string. 195 // |scheme| - the authentication scheme (i.e. basic, negotiate). 196 // |credentials| - the credentials to match. 197 // returns - true if an entry was removed. 198 bool Remove(const url::SchemeHostPort& scheme_host_port, 199 HttpAuth::Target target, 200 const std::string& realm, 201 HttpAuth::Scheme scheme, 202 const NetworkAnonymizationKey& network_anonymization_key, 203 const AuthCredentials& credentials); 204 205 // Clears cache entries added between |begin_time| inclusively and |end_time| 206 // exclusively. Clears all entries if |begin_time| and |end_time| are equal to 207 // base::Time::Min() and base::Time::Max() respectively. 208 void ClearEntriesAddedBetween( 209 base::Time begin_time, 210 base::Time end_time, 211 base::RepeatingCallback<bool(const GURL&)> url_matcher); 212 213 // Clears all added entries. 214 void ClearAllEntries(); 215 216 // Updates a stale digest entry on server |scheme_host_port| for realm |realm| 217 // and scheme |scheme|. The cached auth challenge is replaced with 218 // |auth_challenge| and the nonce count is reset. 219 // |UpdateStaleChallenge()| returns true if a matching entry exists in the 220 // cache, false otherwise. 221 bool UpdateStaleChallenge( 222 const url::SchemeHostPort& scheme_host_port, 223 HttpAuth::Target target, 224 const std::string& realm, 225 HttpAuth::Scheme scheme, 226 const NetworkAnonymizationKey& network_anonymization_key, 227 const std::string& auth_challenge); 228 229 // Copies all entries from |other| cache with a target of 230 // HttpAuth::AUTH_PROXY. |this| and |other| need not have the same 231 // |key_server_entries_by_network_anonymization_key_| value, since proxy 232 // credentials are not keyed on NetworkAnonymizationKey. 233 void CopyProxyEntriesFrom(const HttpAuthCache& other); 234 235 size_t GetEntriesSizeForTesting(); set_tick_clock_for_testing(const base::TickClock * tick_clock)236 void set_tick_clock_for_testing(const base::TickClock* tick_clock) { 237 tick_clock_ = tick_clock; 238 } set_clock_for_testing(const base::Clock * clock)239 void set_clock_for_testing(const base::Clock* clock) { clock_ = clock; } 240 key_server_entries_by_network_anonymization_key()241 bool key_server_entries_by_network_anonymization_key() const { 242 return key_server_entries_by_network_anonymization_key_; 243 } 244 245 private: 246 struct EntryMapKey { 247 EntryMapKey(const url::SchemeHostPort& scheme_host_port, 248 HttpAuth::Target target, 249 const NetworkAnonymizationKey& network_anonymization_key, 250 bool key_server_entries_by_network_anonymization_key); 251 ~EntryMapKey(); 252 253 bool operator<(const EntryMapKey& other) const; 254 255 url::SchemeHostPort scheme_host_port; 256 HttpAuth::Target target; 257 // Empty if |key_server_entries_by_network_anonymization_key| is false, 258 // |target| is HttpAuth::AUTH_PROXY, or an empty NetworkAnonymizationKey is 259 // passed in to the EntryMap constructor. 260 NetworkAnonymizationKey network_anonymization_key; 261 }; 262 263 using EntryMap = std::multimap<EntryMapKey, Entry>; 264 265 raw_ptr<const base::TickClock> tick_clock_ = 266 base::DefaultTickClock::GetInstance(); 267 raw_ptr<const base::Clock> clock_ = base::DefaultClock::GetInstance(); 268 269 EntryMap::iterator LookupEntryIt( 270 const url::SchemeHostPort& scheme_host_port, 271 HttpAuth::Target target, 272 const std::string& realm, 273 HttpAuth::Scheme scheme, 274 const NetworkAnonymizationKey& network_anonymization_key); 275 276 void EvictLeastRecentlyUsedEntry(); 277 278 bool key_server_entries_by_network_anonymization_key_; 279 280 EntryMap entries_; 281 }; 282 283 // An authentication realm entry. 284 } // namespace net 285 286 #endif // NET_HTTP_HTTP_AUTH_CACHE_H_ 287