1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef nsHttpAuthCache_h__
7 #define nsHttpAuthCache_h__
8 
9 #include "nsError.h"
10 #include "nsTArray.h"
11 #include "nsClassHashtable.h"
12 #include "nsCOMPtr.h"
13 #include "nsHashKeys.h"
14 #include "nsStringFwd.h"
15 #include "nsIObserver.h"
16 
17 namespace mozilla {
18 
19 class OriginAttributesPattern;
20 
21 namespace net {
22 
23 struct nsHttpAuthPath {
24   struct nsHttpAuthPath* mNext;
25   char mPath[1];
26 };
27 
28 //-----------------------------------------------------------------------------
29 // nsHttpAuthIdentity
30 //-----------------------------------------------------------------------------
31 
32 class nsHttpAuthIdentity {
33  public:
nsHttpAuthIdentity()34   nsHttpAuthIdentity() : mUser(nullptr), mPass(nullptr), mDomain(nullptr) {}
nsHttpAuthIdentity(const char16_t * domain,const char16_t * user,const char16_t * password)35   nsHttpAuthIdentity(const char16_t* domain, const char16_t* user,
36                      const char16_t* password)
37       : mUser(nullptr), mPass{nullptr}, mDomain{nullptr} {
38     DebugOnly<nsresult> rv = Set(domain, user, password);
39     MOZ_ASSERT(NS_SUCCEEDED(rv));
40   }
~nsHttpAuthIdentity()41   ~nsHttpAuthIdentity() { Clear(); }
42 
Domain()43   const char16_t* Domain() const { return mDomain; }
User()44   const char16_t* User() const { return mUser; }
Password()45   const char16_t* Password() const { return mPass; }
46 
47   [[nodiscard]] nsresult Set(const char16_t* domain, const char16_t* user,
48                              const char16_t* password);
Set(const nsHttpAuthIdentity & other)49   [[nodiscard]] nsresult Set(const nsHttpAuthIdentity& other) {
50     return Set(other.mDomain, other.mUser, other.mPass);
51   }
52   void Clear();
53 
54   bool Equals(const nsHttpAuthIdentity& other) const;
IsEmpty()55   bool IsEmpty() const { return !mUser; }
56 
57  private:
58   // allocated as one contiguous blob, starting at mUser.
59   char16_t* mUser;
60   char16_t* mPass;
61   char16_t* mDomain;
62 };
63 
64 //-----------------------------------------------------------------------------
65 // nsHttpAuthEntry
66 //-----------------------------------------------------------------------------
67 
68 class nsHttpAuthEntry {
69  public:
Realm()70   const char* Realm() const { return mRealm; }
Creds()71   const char* Creds() const { return mCreds; }
Challenge()72   const char* Challenge() const { return mChallenge; }
Domain()73   const char16_t* Domain() const { return mIdent.Domain(); }
User()74   const char16_t* User() const { return mIdent.User(); }
Pass()75   const char16_t* Pass() const { return mIdent.Password(); }
RootPath()76   nsHttpAuthPath* RootPath() { return mRoot; }
77 
Identity()78   const nsHttpAuthIdentity& Identity() const { return mIdent; }
79 
80   [[nodiscard]] nsresult AddPath(const char* aPath);
81 
82   nsCOMPtr<nsISupports> mMetaData;
83 
84  private:
nsHttpAuthEntry(const char * path,const char * realm,const char * creds,const char * challenge,const nsHttpAuthIdentity * ident,nsISupports * metadata)85   nsHttpAuthEntry(const char* path, const char* realm, const char* creds,
86                   const char* challenge, const nsHttpAuthIdentity* ident,
87                   nsISupports* metadata)
88       : mRoot(nullptr),
89         mTail(nullptr),
90         mRealm(nullptr),
91         mCreds{nullptr},
92         mChallenge{nullptr} {
93     DebugOnly<nsresult> rv =
94         Set(path, realm, creds, challenge, ident, metadata);
95     MOZ_ASSERT(NS_SUCCEEDED(rv));
96   }
97   ~nsHttpAuthEntry();
98 
99   [[nodiscard]] nsresult Set(const char* path, const char* realm,
100                              const char* creds, const char* challenge,
101                              const nsHttpAuthIdentity* ident,
102                              nsISupports* metadata);
103 
104   nsHttpAuthIdentity mIdent;
105 
106   nsHttpAuthPath* mRoot;  // root pointer
107   nsHttpAuthPath* mTail;  // tail pointer
108 
109   // allocated together in one blob, starting with mRealm.
110   char* mRealm;
111   char* mCreds;
112   char* mChallenge;
113 
114   friend class nsHttpAuthNode;
115   friend class nsHttpAuthCache;
116   friend class mozilla::DefaultDelete<nsHttpAuthEntry>;  // needs to call the
117                                                          // destructor
118 };
119 
120 //-----------------------------------------------------------------------------
121 // nsHttpAuthNode
122 //-----------------------------------------------------------------------------
123 
124 class nsHttpAuthNode {
125  private:
126   using EntryList = nsTArray<UniquePtr<nsHttpAuthEntry>>;
127 
128   nsHttpAuthNode();
129   ~nsHttpAuthNode();
130 
131   // path can be null, in which case we'll search for an entry
132   // with a null path.
133   nsHttpAuthEntry* LookupEntryByPath(const char* path);
134 
135   // realm must not be null
136   nsHttpAuthEntry* LookupEntryByRealm(const char* realm);
137   EntryList::const_iterator LookupEntryItrByRealm(const char* realm) const;
138 
139   // if a matching entry is found, then credentials will be changed.
140   [[nodiscard]] nsresult SetAuthEntry(const char* path, const char* realm,
141                                       const char* credentials,
142                                       const char* challenge,
143                                       const nsHttpAuthIdentity* ident,
144                                       nsISupports* metadata);
145 
146   void ClearAuthEntry(const char* realm);
147 
EntryCount()148   uint32_t EntryCount() { return mList.Length(); }
149 
150  private:
151   EntryList mList;
152 
153   friend class nsHttpAuthCache;
154   friend class mozilla::DefaultDelete<nsHttpAuthNode>;  // needs to call the
155                                                         // destructor
156 };
157 
158 //-----------------------------------------------------------------------------
159 // nsHttpAuthCache
160 //  (holds a hash table from host:port to nsHttpAuthNode)
161 //-----------------------------------------------------------------------------
162 
163 class nsHttpAuthCache {
164  public:
165   nsHttpAuthCache();
166   ~nsHttpAuthCache();
167 
168   // |scheme|, |host|, and |port| are required
169   // |path| can be null
170   // |entry| is either null or a weak reference
171   [[nodiscard]] nsresult GetAuthEntryForPath(const char* scheme,
172                                              const char* host, int32_t port,
173                                              const char* path,
174                                              nsACString const& originSuffix,
175                                              nsHttpAuthEntry** entry);
176 
177   // |scheme|, |host|, and |port| are required
178   // |realm| must not be null
179   // |entry| is either null or a weak reference
180   [[nodiscard]] nsresult GetAuthEntryForDomain(const char* scheme,
181                                                const char* host, int32_t port,
182                                                const char* realm,
183                                                nsACString const& originSuffix,
184                                                nsHttpAuthEntry** entry);
185 
186   // |scheme|, |host|, and |port| are required
187   // |path| can be null
188   // |realm| must not be null
189   // if |credentials|, |user|, |pass|, and |challenge| are each
190   // null, then the entry is deleted.
191   [[nodiscard]] nsresult SetAuthEntry(
192       const char* scheme, const char* host, int32_t port, const char* directory,
193       const char* realm, const char* credentials, const char* challenge,
194       nsACString const& originSuffix, const nsHttpAuthIdentity* ident,
195       nsISupports* metadata);
196 
197   void ClearAuthEntry(const char* scheme, const char* host, int32_t port,
198                       const char* realm, nsACString const& originSuffix);
199 
200   // expire all existing auth list entries including proxy auths.
201   void ClearAll();
202 
203  private:
204   nsHttpAuthNode* LookupAuthNode(const char* scheme, const char* host,
205                                  int32_t port, nsACString const& originSuffix,
206                                  nsCString& key);
207 
208   class OriginClearObserver : public nsIObserver {
209     virtual ~OriginClearObserver() = default;
210 
211    public:
212     NS_DECL_ISUPPORTS
213     NS_DECL_NSIOBSERVER
OriginClearObserver(nsHttpAuthCache * aOwner)214     explicit OriginClearObserver(nsHttpAuthCache* aOwner) : mOwner(aOwner) {}
215     nsHttpAuthCache* mOwner;
216   };
217 
218   void ClearOriginData(OriginAttributesPattern const& pattern);
219 
220  private:
221   using AuthNodeTable = nsClassHashtable<nsCStringHashKey, nsHttpAuthNode>;
222   AuthNodeTable mDB;  // "host:port" --> nsHttpAuthNode
223   RefPtr<OriginClearObserver> mObserver;
224 };
225 
226 }  // namespace net
227 }  // namespace mozilla
228 
229 #endif  // nsHttpAuthCache_h__
230