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