File indexing completed on 2025-03-16 10:02:23
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2008, 2009 Andreas Hartmetz <ahartmetz@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #ifndef HTTPAUTHENTICATION_H 0009 #define HTTPAUTHENTICATION_H 0010 0011 #include <config-gssapi.h> 0012 0013 #include <QByteArray> 0014 #include <QList> 0015 #include <QString> 0016 #include <QUrl> 0017 0018 #include <QLoggingCategory> 0019 Q_DECLARE_LOGGING_CATEGORY(KIO_HTTP_AUTH) 0020 0021 namespace KIO 0022 { 0023 class AuthInfo; 0024 } 0025 0026 class KConfigGroup; 0027 0028 class KAbstractHttpAuthentication 0029 { 0030 public: 0031 explicit KAbstractHttpAuthentication(KConfigGroup *config = nullptr); 0032 virtual ~KAbstractHttpAuthentication(); 0033 0034 /** 0035 * Choose the best authentication mechanism from the offered ones 0036 * 0037 * This will return the most secure mechanism from the list of 0038 * mechanisms returned by the server. 0039 */ 0040 static QByteArray bestOffer(const QList<QByteArray> &offers); 0041 0042 /** 0043 * Returns authentication object instance appropriate for @p offer. 0044 * 0045 * @param offer the header from which an authentication object is created. 0046 * @param config the config object to read stored authentication information. 0047 */ 0048 static KAbstractHttpAuthentication *newAuth(const QByteArray &offer, KConfigGroup *config = nullptr); 0049 0050 /** 0051 * Split all headers containing multiple authentication offers. 0052 * 0053 * @param offers the offers from multiple HTTP authentication header lines. 0054 * @return a list where each entry contains only a single offer 0055 */ 0056 static QList<QByteArray> splitOffers(const QList<QByteArray> &offers); 0057 0058 /** 0059 * reset to state after default construction. 0060 */ 0061 void reset(); 0062 /** 0063 * the authentication scheme: "Negotiate", "Digest", "Basic", "NTLM" 0064 */ 0065 virtual QByteArray scheme() const = 0; 0066 /** 0067 * initiate authentication with challenge string (from HTTP header) 0068 */ 0069 virtual void setChallenge(const QByteArray &c, const QUrl &resource, const QByteArray &httpMethod); 0070 /** 0071 * return value updated by setChallenge() 0072 * 0073 * if this is false user and password passed to generateResponse 0074 * will be ignored and may be empty. 0075 */ 0076 bool needCredentials() const 0077 { 0078 return m_needCredentials; 0079 } 0080 /** 0081 * KIO compatible data to find cached credentials. 0082 * 0083 * Note that username and/or password as well as UI text will NOT be filled in. 0084 */ 0085 virtual void fillKioAuthInfo(KIO::AuthInfo *ai) const = 0; 0086 /** 0087 * what to do in response to challenge 0088 */ 0089 virtual void generateResponse(const QString &user, const QString &password) = 0; 0090 0091 /** 0092 * returns true when the final stage of authentication is reached. 0093 * 0094 * Unless the authentication scheme requires multiple stages like NTLM this 0095 * function will always return true. 0096 */ 0097 bool wasFinalStage() const 0098 { 0099 return m_finalAuthStage; 0100 } 0101 /** 0102 * Returns true if the authentication scheme supports path matching to identify 0103 * resources that belong to the same protection space (realm). 0104 * 0105 * See RFC 2617. 0106 */ 0107 virtual bool supportsPathMatching() const 0108 { 0109 return false; 0110 } 0111 0112 // the following accessors return useful data after generateResponse() has been called. 0113 // clients process the following fields top to bottom: highest priority is on top 0114 0115 // malformed challenge and similar problems - it is advisable to reconnect 0116 bool isError() const 0117 { 0118 return m_isError; 0119 } 0120 /** 0121 * force keep-alive connection because the authentication method requires it 0122 */ 0123 bool forceKeepAlive() const 0124 { 0125 return m_forceKeepAlive; 0126 } 0127 /** 0128 * force disconnection because the authentication method requires it 0129 */ 0130 bool forceDisconnect() const 0131 { 0132 return m_forceDisconnect; 0133 } 0134 0135 /** 0136 * insert this into the next request header after "Authorization: " 0137 * or "Proxy-Authorization: " 0138 */ 0139 QByteArray headerFragment() const 0140 { 0141 return m_headerFragment; 0142 } 0143 /** 0144 * Returns the realm sent by the server. 0145 * 0146 * This is mainly for GUI shown to the user. This is the identification of 0147 * the protected area on the server (e.g. "Konquis home directory" or 0148 * "KDE files"). 0149 */ 0150 QString realm() const; 0151 0152 /** 0153 * Sets the cache password flag to @p enable. 0154 */ 0155 void setCachePasswordEnabled(bool enable) 0156 { 0157 m_keepPassword = enable; 0158 } 0159 0160 #ifdef ENABLE_HTTP_AUTH_NONCE_SETTER 0161 // NOTE: FOR USE in unit testing ONLY. 0162 virtual void setDigestNonceValue(const QByteArray &) 0163 { 0164 } 0165 #endif 0166 0167 protected: 0168 void authInfoBoilerplate(KIO::AuthInfo *a) const; 0169 /** 0170 * Returns any authentication data that should be cached for future use. 0171 * 0172 * NOTE: Do not reimplement this function for connection based authentication 0173 * schemes such as NTLM. 0174 */ 0175 virtual QByteArray authDataToCache() const 0176 { 0177 return QByteArray(); 0178 } 0179 void generateResponseCommon(const QString &user, const QString &password); 0180 0181 KConfigGroup *m_config; 0182 QByteArray m_scheme; ///< this is parsed from the header and not necessarily == scheme(). 0183 QByteArray m_challengeText; 0184 QList<QByteArray> m_challenge; 0185 QUrl m_resource; 0186 QByteArray m_httpMethod; 0187 0188 bool m_isError; 0189 bool m_needCredentials; 0190 bool m_forceKeepAlive; 0191 bool m_forceDisconnect; 0192 bool m_finalAuthStage; 0193 bool m_keepPassword; 0194 QByteArray m_headerFragment; 0195 0196 QString m_username; 0197 QString m_password; 0198 }; 0199 0200 class KHttpBasicAuthentication : public KAbstractHttpAuthentication 0201 { 0202 public: 0203 QByteArray scheme() const override; 0204 void fillKioAuthInfo(KIO::AuthInfo *ai) const override; 0205 void generateResponse(const QString &user, const QString &password) override; 0206 bool supportsPathMatching() const override 0207 { 0208 return true; 0209 } 0210 0211 protected: 0212 QByteArray authDataToCache() const override 0213 { 0214 return m_challengeText; 0215 } 0216 0217 private: 0218 friend class KAbstractHttpAuthentication; 0219 KHttpBasicAuthentication(KConfigGroup *config = nullptr) 0220 : KAbstractHttpAuthentication(config) 0221 { 0222 } 0223 }; 0224 0225 class KHttpDigestAuthentication : public KAbstractHttpAuthentication 0226 { 0227 public: 0228 QByteArray scheme() const override; 0229 void setChallenge(const QByteArray &c, const QUrl &resource, const QByteArray &httpMethod) override; 0230 void fillKioAuthInfo(KIO::AuthInfo *ai) const override; 0231 void generateResponse(const QString &user, const QString &password) override; 0232 bool supportsPathMatching() const override 0233 { 0234 return true; 0235 } 0236 #ifdef ENABLE_HTTP_AUTH_NONCE_SETTER 0237 void setDigestNonceValue(const QByteArray &) override; 0238 #endif 0239 0240 protected: 0241 QByteArray authDataToCache() const override 0242 { 0243 return m_challengeText; 0244 } 0245 0246 private: 0247 friend class KAbstractHttpAuthentication; 0248 KHttpDigestAuthentication(KConfigGroup *config = nullptr) 0249 : KAbstractHttpAuthentication(config) 0250 { 0251 } 0252 #ifdef ENABLE_HTTP_AUTH_NONCE_SETTER 0253 QByteArray m_nonce; 0254 #endif 0255 }; 0256 0257 class KHttpNtlmAuthentication : public KAbstractHttpAuthentication 0258 { 0259 public: 0260 QByteArray scheme() const override; 0261 void setChallenge(const QByteArray &c, const QUrl &resource, const QByteArray &httpMethod) override; 0262 void fillKioAuthInfo(KIO::AuthInfo *ai) const override; 0263 void generateResponse(const QString &user, const QString &password) override; 0264 0265 private: 0266 friend class KAbstractHttpAuthentication; 0267 explicit KHttpNtlmAuthentication(KConfigGroup *config = nullptr) 0268 : KAbstractHttpAuthentication(config) 0269 , m_stage1State(Init) 0270 { 0271 } 0272 enum Stage1State { 0273 Init = 0, 0274 SentNTLMv1, 0275 SentNTLMv2, 0276 }; 0277 Stage1State m_stage1State; 0278 }; 0279 0280 #if HAVE_LIBGSSAPI 0281 class KHttpNegotiateAuthentication : public KAbstractHttpAuthentication 0282 { 0283 public: 0284 QByteArray scheme() const override; 0285 void setChallenge(const QByteArray &c, const QUrl &resource, const QByteArray &httpMethod) override; 0286 void fillKioAuthInfo(KIO::AuthInfo *ai) const override; 0287 void generateResponse(const QString &user, const QString &password) override; 0288 0289 private: 0290 friend class KAbstractHttpAuthentication; 0291 explicit KHttpNegotiateAuthentication(KConfigGroup *config = nullptr) 0292 : KAbstractHttpAuthentication(config) 0293 { 0294 } 0295 }; 0296 #endif // HAVE_LIBGSSAPI 0297 0298 #endif // HTTPAUTHENTICATION_H