summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDawit Alemayehu <adawit@kde.org>2011-07-17 18:09:19 (GMT)
committerDawit Alemayehu <adawit@kde.org>2011-07-26 16:11:07 (GMT)
commit0e0858618df8e3c06b4fc5253485bbe475a1e6b1 (patch)
treea2a02045fbb3452977005c2c6defa080e0c216d1
parent0dcf529708fcc2f0045abc660dd13b3754c68bc9 (diff)
- Fixed all the failing test cases at http://greenbytes.de/tech/tc/httpauth
except for "simplebasicrealmsqc" and the warnings. Note that the warnings are not fixed to keep compatability with the old spec (RFC 2617). - Made the authentication code standalone such that it no longer requires to be directly injected into http.cpp to compile. - Added unit test coverage for the HTTP authentication code. REVIEW: 101986
-rw-r--r--kioslave/http/CMakeLists.txt1
-rw-r--r--kioslave/http/http.cpp26
-rw-r--r--kioslave/http/http.h7
-rw-r--r--kioslave/http/httpauthentication.cpp145
-rw-r--r--kioslave/http/httpauthentication.h32
-rw-r--r--kioslave/http/tests/CMakeLists.txt11
-rw-r--r--kioslave/http/tests/httpauthenticationtest.cpp137
-rw-r--r--kioslave/http/tests/httpauthenticationtest.h31
8 files changed, 333 insertions, 57 deletions
diff --git a/kioslave/http/CMakeLists.txt b/kioslave/http/CMakeLists.txt
index 493bde6..95ed9cf 100644
--- a/kioslave/http/CMakeLists.txt
+++ b/kioslave/http/CMakeLists.txt
@@ -52,6 +52,7 @@ install(TARGETS kio_http_cache_cleaner DESTINATION ${LIBEXEC_INSTALL_DIR} )
set(kio_http_PART_SRCS
http.cpp
+ httpauthentication.cpp
${httpfilter_STAT_SRCS}
${CMAKE_SOURCE_DIR}/kio/httpfilter/httpfilter.cc
)
diff --git a/kioslave/http/http.cpp b/kioslave/http/http.cpp
index 9bbd531..6d41a13 100644
--- a/kioslave/http/http.cpp
+++ b/kioslave/http/http.cpp
@@ -50,7 +50,6 @@
#include <QtNetwork/QAuthenticator>
#include <QtNetwork/QNetworkProxy>
#include <QtNetwork/QTcpSocket>
-#include <QtNetwork/QHostInfo>
#include <kurl.h>
#include <kdebug.h>
@@ -60,7 +59,6 @@
#include <kservice.h>
#include <kdatetime.h>
#include <kcomponentdata.h>
-#include <krandom.h>
#include <kmimetype.h>
#include <ktoolinvocation.h>
#include <kstandarddirs.h>
@@ -75,32 +73,18 @@
#include <solid/networking.h>
-#ifdef HAVE_LIBGSSAPI
-#ifdef GSSAPI_MIT
-#include <gssapi/gssapi.h>
-#else
-#include <gssapi.h>
-#endif /* GSSAPI_MIT */
-
-// Catch uncompatible crap (BR86019)
-#if defined(GSS_RFC_COMPLIANT_OIDS) && (GSS_RFC_COMPLIANT_OIDS == 0)
-#include <gssapi/gssapi_generic.h>
-#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
-#endif
-
-#endif /* HAVE_LIBGSSAPI */
-
-#include <misc/kntlm/kntlm.h>
#include <kapplication.h>
#include <kaboutdata.h>
#include <kcmdlineargs.h>
#include <kde_file.h>
#include <ktemporaryfile.h>
+#include "httpauthentication.h"
+
+// HeaderTokenizer declarations
+#include "parsinghelpers.h"
//string parsing helpers and HeaderTokenizer implementation
#include "parsinghelpers.cpp"
-//authentication handlers
-#include "httpauthentication.cpp"
// see filenameFromUrl(): a sha1 hash is 160 bits
@@ -3375,7 +3359,7 @@ endParsing:
authinfo.commentLabel = i18n("Proxy:");
}
- QList<QByteArray> authTokens = tIt.all();
+ QList<QByteArray> authTokens = KAbstractHttpAuthentication::splitOffers(tIt.all());
// Workaround brain dead server responses that violate the spec and
// incorrectly return a 401/407 without the required WWW/Proxy-Authenticate
// header fields. See bug 215736...
diff --git a/kioslave/http/http.h b/kioslave/http/http.h
index 4d34af8..d8c47c7 100644
--- a/kioslave/http/http.h
+++ b/kioslave/http/http.h
@@ -41,10 +41,6 @@
#include "kio/tcpslavebase.h"
#include "kio/http.h"
-// HeaderTokenizer declarations
-#include "parsinghelpers.h"
-// KHttpAuthentication & KHttpAuthenticationOutcome declarations
-#include "httpauthentication.h"
class QDomNodeList;
class QFile;
@@ -54,6 +50,9 @@ namespace KIO {
class AuthInfo;
}
+class HeaderTokenizer;
+class KAbstractHttpAuthentication;
+
class HTTPProtocol : public QObject, public KIO::TCPSlaveBase
{
Q_OBJECT
diff --git a/kioslave/http/httpauthentication.cpp b/kioslave/http/httpauthentication.cpp
index 582a04d..42c9629 100644
--- a/kioslave/http/httpauthentication.cpp
+++ b/kioslave/http/httpauthentication.cpp
@@ -17,59 +17,112 @@
Boston, MA 02110-1301, USA.
*/
-
#include "httpauthentication.h"
+#ifdef HAVE_LIBGSSAPI
+#ifdef GSSAPI_MIT
+#include <gssapi/gssapi.h>
+#else
+#include <gssapi.h>
+#endif /* GSSAPI_MIT */
+
+// Catch uncompatible crap (BR86019)
+#if defined(GSS_RFC_COMPLIANT_OIDS) && (GSS_RFC_COMPLIANT_OIDS == 0)
+#include <gssapi/gssapi_generic.h>
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif
+
+#endif /* HAVE_LIBGSSAPI */
+
+#include <krandom.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+#include <kcodecs.h>
+#include <kconfiggroup.h>
+#include <kio/authinfo.h>
+#include <misc/kntlm/kntlm.h>
+
+#include <QtNetwork/QHostInfo>
+#include <QtCore/QTextCodec>
+
+
+static bool isWhiteSpace(char ch)
+{
+ return (ch == ' ' || ch == '\t' || ch == '\v' || ch == '\f');
+}
// keys on even indexes, values on odd indexes. Reduces code expansion for the templated
// alternatives.
-static QList<QByteArray> parseChallenge(const QByteArray &ba, QByteArray *scheme = 0)
+static QList<QByteArray> parseChallenge(const QByteArray &ba, QByteArray *scheme, QByteArray* nextAuth = 0)
{
QList<QByteArray> values;
const int len = ba.count();
const char *b = ba.constData();
int start = 0;
int end = 0;
+ int pos = 0;
// parse scheme
- while (start < len && (b[start] == ' ' || b[start] == '\t')) {
+ while (start < len && isWhiteSpace(b[start])) {
start++;
}
end = start;
- while (end < len && (b[end] != ' ' && b[end] != '\t')) {
+ while (end < len && !isWhiteSpace(b[end])) {
end++;
}
- if (scheme) {
- *scheme = QByteArray(b + start, end - start);
- }
+
+ Q_ASSERT(scheme);
+ *scheme = QByteArray(b + start, end - start);
while (end < len) {
start = end;
// parse key
- while (start < len && (b[start] == ' ' || b[start] == '\t')) {
+ while (start < len && isWhiteSpace(b[start])) {
start++;
}
end = start;
while (end < len && b[end] != '=') {
end++;
}
- values.append(QByteArray(b + start, end - start));
+ pos = end; // save the end position
+ while (end - 1 > start && isWhiteSpace(b[end - 1])) { // trim whitespace
+ end--;
+ }
+ const QByteArray key (b + start, end - start);
+ if (key.contains(' ') || key.contains('\t')) {
+ if (nextAuth) {
+ *nextAuth = QByteArray (b + start);
+ }
+ break; // break on start of next scheme.
+ }
+ values.append(key);
+ end = pos; // restore the end position
if (end == len) {
break;
}
// parse value
start = end + 1; //skip '='
- while (start < len && (b[start] == ' ' || b[start] == '\t')) {
+ while (start < len && isWhiteSpace(b[start])) {
start++;
}
if (start + 1 < len && b[start] == '"') {
end = ++start;
+ while (start + 1 < len && b[start] == '\\' && b[start+1] == '"') {
+ start += 2;
+ end = start;
+ }
//quoted string
while (end < len && b[end] != '"') {
end++;
}
+ pos = end; // save the end position
+ if (end-1 > start && b[end-1] == '\\') {
+ end--; // ignore escape char
+ }
values.append(QByteArray(b + start, end - start));
+ end = pos; // restore the end position
//the quoted string has ended, but only a comma ends a key-value pair
while (end < len && b[end] != ',') {
end++;
@@ -80,7 +133,12 @@ static QList<QByteArray> parseChallenge(const QByteArray &ba, QByteArray *scheme
while (end < len && b[end] != ',') {
end++;
}
+ pos = end; // save the end position
+ while (end - 1 > start && isWhiteSpace(b[end - 1])) { // trim whitespace
+ end--;
+ }
values.append(QByteArray(b + start, end - start));
+ end = pos; // restore the end position
}
// end may point beyond the buffer already here
end++; // skip comma
@@ -123,52 +181,74 @@ QByteArray KAbstractHttpAuthentication::bestOffer(const QList<QByteArray> &offer
QByteArray ntlmOffer;
QByteArray basicOffer;
Q_FOREACH (const QByteArray &offer, offers) {
- QByteArray scheme = offer.mid(0, 10).toLower();
+ const QByteArray scheme = offer.mid(0, offer.indexOf(' ')).toLower();
#ifdef HAVE_LIBGSSAPI
- if (scheme.startsWith("negotiate")) { // krazy:exclude=strings
+ if (scheme == "negotiate") { // krazy:exclude=strings
negotiateOffer = offer;
} else
#endif
- if (scheme.startsWith("digest")) { // krazy:exclude=strings
+ if (scheme == "digest") { // krazy:exclude=strings
digestOffer = offer;
- } else if (scheme.startsWith("ntlm")) { // krazy:exclude=strings
+ } else if (scheme == "ntlm") { // krazy:exclude=strings
ntlmOffer = offer;
- } else if (scheme.startsWith("basic")) { // krazy:exclude=strings
+ } else if (scheme == "basic") { // krazy:exclude=strings
basicOffer = offer;
}
}
if (!negotiateOffer.isEmpty()) {
return negotiateOffer;
- } else if (!digestOffer.isEmpty()) {
+ }
+
+ if (!digestOffer.isEmpty()) {
return digestOffer;
- } else if (!ntlmOffer.isEmpty()) {
+ }
+
+ if (!ntlmOffer.isEmpty()) {
return ntlmOffer;
}
+
return basicOffer; //empty or not...
}
KAbstractHttpAuthentication *KAbstractHttpAuthentication::newAuth(const QByteArray &offer, KConfigGroup* config)
{
- QByteArray scheme = offer.mid(0, 10).toLower();
+ const QByteArray scheme = offer.mid(0, offer.indexOf(' ')).toLower();
#ifdef HAVE_LIBGSSAPI
- if (scheme.startsWith("negotiate")) { // krazy:exclude=strings
+ if (scheme == "negotiate") { // krazy:exclude=strings
return new KHttpNegotiateAuthentication(config);
} else
-#else
- Q_UNUSED(config);
#endif
- if (scheme.startsWith("digest")) { // krazy:exclude=strings
+ if (scheme == "digest") { // krazy:exclude=strings
return new KHttpDigestAuthentication();
- } else if (scheme.startsWith("ntlm")) { // krazy:exclude=strings
- return new KHttpNtlmAuthentication();
- } else if (scheme.startsWith("basic")) { // krazy:exclude=strings
+ } else if (scheme == "ntlm") { // krazy:exclude=strings
+ return new KHttpNtlmAuthentication(config);
+ } else if (scheme == "basic") { // krazy:exclude=strings
return new KHttpBasicAuthentication();
}
return 0;
}
+QList< QByteArray > KAbstractHttpAuthentication::splitOffers(const QList< QByteArray >& offers)
+{
+ // first detect if one entry may contain multiple offers
+ QList<QByteArray> alloffers;
+ for(int i=0, count=offers.count(); i < count; ++i) {
+ QByteArray scheme, cont, offer = offers.at(i);
+ parseChallenge(offer, &scheme, &cont);
+
+ while (!cont.isEmpty()) {
+ offer.chop(cont.length());
+ alloffers << offer;
+ offer = cont;
+ cont.clear();
+ parseChallenge(offer, &scheme, &cont);
+ }
+ alloffers << offer;
+ }
+ return alloffers;
+}
void KAbstractHttpAuthentication::reset()
{
@@ -202,11 +282,12 @@ void KAbstractHttpAuthentication::setChallenge(const QByteArray &c, const KUrl &
QString KAbstractHttpAuthentication::realm() const
{
const QByteArray realm = valueForKey(m_challenge, "realm");
+ // TODO: Find out what this is supposed to address. The site mentioned below does not exist.
if (KGlobal::locale()->language().contains(QLatin1String("ru"))) {
//for sites like lib.homelinux.org
return QTextCodec::codecForName("CP1251")->toUnicode(realm);
}
- return QString::fromLatin1(realm);
+ return QString::fromLatin1(realm.constData(), realm.length());
}
void KAbstractHttpAuthentication::authInfoBoilerplate(KIO::AuthInfo *a) const
@@ -249,7 +330,6 @@ void KHttpBasicAuthentication::fillKioAuthInfo(KIO::AuthInfo *ai) const
authInfoBoilerplate(ai);
}
-
void KHttpBasicAuthentication::generateResponse(const QString &user, const QString &password)
{
generateResponseCommon(user, password);
@@ -402,7 +482,11 @@ void KHttpDigestAuthentication::generateResponse(const QString &user, const QStr
info.qop = "";
// cnonce is recommended to contain about 64 bits of entropy
+#ifdef ENABLE_HTTP_AUTH_NONCE_SETTER
+ info.cnonce = m_nonce;
+#else
info.cnonce = KRandom::randomString(16).toLatin1();
+#endif
// HACK: Should be fixed according to RFC 2617 section 3.2.2
info.nc = "00000001";
@@ -548,6 +632,13 @@ void KHttpDigestAuthentication::generateResponse(const QString &user, const QStr
m_headerFragment = auth;
}
+#ifdef ENABLE_HTTP_AUTH_NONCE_SETTER
+void KHttpDigestAuthentication::setDigestNonceValue(const QByteArray& nonce)
+{
+ m_nonce = nonce;
+}
+#endif
+
QByteArray KHttpNtlmAuthentication::scheme() const
{
diff --git a/kioslave/http/httpauthentication.h b/kioslave/http/httpauthentication.h
index fb4cace..ec3b5f7 100644
--- a/kioslave/http/httpauthentication.h
+++ b/kioslave/http/httpauthentication.h
@@ -22,12 +22,11 @@
#include <config-gssapi.h>
-#ifndef HTTP_H_ // if we're included from http.cpp all necessary headers are already included
+#include <kurl.h>
+
#include <QtCore/QByteArray>
#include <QtCore/QString>
#include <QtCore/QList>
-#include <kio/authinfo.h>
-#endif
namespace KIO {
class AuthInfo;
@@ -48,9 +47,24 @@ public:
* mechanisms retuned by the server.
*/
static QByteArray bestOffer(const QList<QByteArray> &offers);
+
+ /**
+ * Returns authentication object instance appropriate for @p offer.
+ *
+ * @param offer the header from which an authentication object is created.
+ * @param config the config object to read stored authentication information.
+ */
static KAbstractHttpAuthentication *newAuth(const QByteArray &offer, KConfigGroup *config = 0);
/**
+ * Split all headers containing multiple authentication offers.
+ *
+ * @param offers the offers from multiple HTTP authentication header lines.
+ * @return a list where each entry contains only a single offer
+ */
+ static QList<QByteArray> splitOffers(const QList<QByteArray> &offers);
+
+ /**
* reset to state after default construction.
*/
void reset();
@@ -124,6 +138,11 @@ public:
*/
QString realm() const;
+#ifdef ENABLE_HTTP_AUTH_NONCE_SETTER
+ // NOTE: FOR USE in unit testing ONLY.
+ virtual void setDigestNonceValue(const QByteArray&) {}
+#endif
+
protected:
void authInfoBoilerplate(KIO::AuthInfo *a) const;
virtual QByteArray authDataToCache() const { return QByteArray(); }
@@ -172,12 +191,19 @@ public:
virtual void fillKioAuthInfo(KIO::AuthInfo *ai) const;
virtual void generateResponse(const QString &user, const QString &password);
virtual bool supportsPathMatching() const { return true; }
+#ifdef ENABLE_HTTP_AUTH_NONCE_SETTER
+ virtual void setDigestNonceValue(const QByteArray&);
+#endif
+
protected:
virtual QByteArray authDataToCache() const { return m_challengeText; }
private:
friend class KAbstractHttpAuthentication;
KHttpDigestAuthentication(KConfigGroup *config = 0)
: KAbstractHttpAuthentication(config) {}
+#ifdef ENABLE_HTTP_AUTH_NONCE_SETTER
+ QByteArray m_nonce;
+#endif
};
diff --git a/kioslave/http/tests/CMakeLists.txt b/kioslave/http/tests/CMakeLists.txt
index c482eb5..7c45632 100644
--- a/kioslave/http/tests/CMakeLists.txt
+++ b/kioslave/http/tests/CMakeLists.txt
@@ -1,7 +1,7 @@
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR})
-include_directories(${KDE4_KIO_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR}/..
- ${CMAKE_SOURCE_DIR}/kio/httpfilter)
+include_directories(${KDE4_KIO_INCLUDES} ${CMAKE_CURRENT_SOURCE_DIR}/.. ${CMAKE_CURRENT_BINARY_DIR}/..
+ ${CMAKE_SOURCE_DIR}/kio/httpfilter)
kde4_add_unit_test(httpheadertokenizetest httpheadertokenizetest.cpp)
target_link_libraries(httpheadertokenizetest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY}
@@ -10,3 +10,10 @@ target_link_libraries(httpheadertokenizetest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LI
kde4_add_unit_test(httpheaderdispositiontest httpheaderdispositiontest.cpp)
target_link_libraries(httpheaderdispositiontest ${KDE4_KDECORE_LIBS} ${QT_QTTEST_LIBRARY}
${QT_QTGUI_LIBRARY})
+
+kde4_add_unit_test(httpauthenticationtest httpauthenticationtest.cpp)
+target_link_libraries(httpauthenticationtest ${KDE4_KDECORE_LIBS} kntlm ${QT_QTTEST_LIBRARY}
+ ${QT_QTGUI_LIBRARY})
+if(GSSAPI_FOUND)
+ target_link_libraries(httpauthenticationtest ${GSSAPI_LIBS})
+endif(GSSAPI_FOUND)
diff --git a/kioslave/http/tests/httpauthenticationtest.cpp b/kioslave/http/tests/httpauthenticationtest.cpp
new file mode 100644
index 0000000..1bdaee7
--- /dev/null
+++ b/kioslave/http/tests/httpauthenticationtest.cpp
@@ -0,0 +1,137 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2011 Dawit Alemayehu <adawit@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+
+#include "httpauthenticationtest.h"
+
+#include <qtest_kde.h>
+#include <kdebug.h>
+#include <kcodecs.h>
+#include <krandom.h>
+#include <kconfiggroup.h>
+#include <misc/kntlm/kntlm.h>
+
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtNetwork/QHostInfo>
+
+#include "httpauthentication.cpp"
+
+QTEST_KDEMAIN(HTTPAuthenticationTest, NoGUI)
+
+static void testAuthHeaderFormats(const QByteArray& authHeader,
+ const QByteArray& expectedScheme,
+ const QList<QByteArray> expectedValues)
+{
+ const QList<QByteArray> authHeaders = KAbstractHttpAuthentication::splitOffers(QList<QByteArray>() << authHeader);
+ const QByteArray bestOffer = KAbstractHttpAuthentication::bestOffer(authHeaders);
+
+ QByteArray scheme;
+ const QList<QByteArray> values = parseChallenge(bestOffer, &scheme);
+ QCOMPARE(scheme, expectedScheme);
+ QCOMPARE(values, expectedValues);
+}
+
+static void testGeneratedAuthResponse(const QByteArray& authHeader,
+ const QByteArray& expectedResponse,
+ const QString& user, const QString& password,
+ const KUrl& resource = KUrl(),
+ const QByteArray& httpMethod = "GET",
+ const QByteArray& cnonce = QByteArray())
+{
+ const QByteArray bestOffer = KAbstractHttpAuthentication::bestOffer(QList<QByteArray>() << authHeader);
+ KAbstractHttpAuthentication* authObj = KAbstractHttpAuthentication::newAuth(bestOffer);
+ QVERIFY(authObj);
+ if (!cnonce.isEmpty()) {
+ authObj->setDigestNonceValue(cnonce);
+ }
+ authObj->setChallenge(bestOffer, resource, httpMethod);
+ authObj->generateResponse(user, password);
+ QCOMPARE(authObj->headerFragment().trimmed(), expectedResponse);
+ delete authObj;
+}
+
+static void testAuthBestOffer(const QList<QByteArray>& offers,
+ const QByteArray& expectedBestOffer,
+ QByteArray* offer = 0)
+{
+ const QByteArray bestOffer = KAbstractHttpAuthentication::bestOffer(offers);
+ QCOMPARE(bestOffer, expectedBestOffer);
+ if (offer) {
+ *offer = bestOffer;
+ }
+}
+
+
+static QList<QByteArray> toByteArrayList(const QByteArray& value)
+{
+ return value.split(',');
+}
+
+void HTTPAuthenticationTest::testHeaderParsing()
+{
+ // Tests cases from http://greenbytes.de/tech/tc/httpauth/
+ testAuthHeaderFormats("Basic realm=\"foo\"", "Basic", toByteArrayList("realm,foo"));
+ testAuthHeaderFormats("Basic realm=foo", "Basic", toByteArrayList("realm,foo"));
+ testAuthHeaderFormats("Basic", "Basic", QList<QByteArray>());
+ testAuthHeaderFormats("Basic realm = \"foo\"", "Basic", toByteArrayList("realm,foo"));
+ // FIXME: Deal with quoted and escaped values...
+ //testAuthHeaderFormats("Basic realm=\"\\f\\o\\o\"", "Basic", toByteArrayList("realm,foo"));
+ testAuthHeaderFormats("Basic realm=\"\\\"foo\\\"\"", "Basic", toByteArrayList("realm,foo"));
+ testAuthHeaderFormats("Basic realm=\"foo\", bar=\"xyz\"", "Basic", toByteArrayList("realm,foo,bar,xyz"));
+ testAuthHeaderFormats("Basic bar=\"xyz\", realm=\"foo\"", "Basic", toByteArrayList("bar,xyz,realm,foo"));
+ testAuthHeaderFormats("bAsic bar\t =\t\"baz\", realm =\t\"foo\"", "bAsic", toByteArrayList("bar,baz,realm,foo"));
+}
+
+void HTTPAuthenticationTest::testAuthenticationSelection()
+{
+ // Tests cases from http://greenbytes.de/tech/tc/httpauth/
+ testAuthHeaderFormats("Basic realm=\"basic\", Newauth realm=\"newauth\"", "Basic", toByteArrayList("realm,basic"));
+ testAuthHeaderFormats("Basic realm=\"basic\", Newauth realm=\"newauth\"", "Basic", toByteArrayList("realm,basic"));
+
+ QByteArray bestOffer;
+ QList<QByteArray> authHeaders;
+ authHeaders << "NTLM" << "Basic" << "Negotiate" << "Digest" << "UnsupportedAuth";
+ testAuthBestOffer(authHeaders, "Negotiate", &bestOffer);
+ authHeaders.removeOne(bestOffer);
+ testAuthBestOffer(authHeaders, "Digest", &bestOffer);
+ authHeaders.removeOne(bestOffer);
+ testAuthBestOffer(authHeaders, "NTLM", &bestOffer);
+ authHeaders.removeOne(bestOffer);
+ testAuthBestOffer(authHeaders, "Basic", &bestOffer);
+ authHeaders.removeOne(bestOffer);
+ testAuthBestOffer(authHeaders, "", &bestOffer); // Unknown scheme should always return blank!
+ QVERIFY(!authHeaders.isEmpty());
+ QCOMPARE(authHeaders.first(), QByteArray("UnsupportedAuth"));
+}
+
+void HTTPAuthenticationTest::testAuthentication()
+{
+ // Test cases from RFC 2617...
+ testGeneratedAuthResponse("Basic realm=\"WallyWorld\"",
+ "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
+ QLatin1String("Aladdin"),
+ QLatin1String("open sesame"));
+ testGeneratedAuthResponse("Digest realm=\"testrealm@host.com\", qop=\"auth,auth-int\", nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"",
+ "Digest username=\"Mufasa\", realm=\"testrealm@host.com\", nonce=\"dcd98b7102dd2f0e8b11d0f600bfb0c093\", uri=\"/dir/index.html\", "
+ "algorithm=MD5, qop=auth, cnonce=\"0a4f113b\", nc=00000001, response=\"6629fae49393a05397450978507c4ef1\", opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"",
+ QLatin1String("Mufasa"),
+ QLatin1String("Circle Of Life"),
+ KUrl("http://www.nowhere.org/dir/index.html"), "GET", "0a4f113b");
+}
diff --git a/kioslave/http/tests/httpauthenticationtest.h b/kioslave/http/tests/httpauthenticationtest.h
new file mode 100644
index 0000000..28cb2290
--- /dev/null
+++ b/kioslave/http/tests/httpauthenticationtest.h
@@ -0,0 +1,31 @@
+/* This file is part of the KDE libraries
+ Copyright (c) 2011 Dawit Alemayehu <adawit@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include <QtCore/QObject>
+
+#define ENABLE_HTTP_AUTH_NONCE_SETTER
+
+class HTTPAuthenticationTest : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void testHeaderParsing();
+ void testAuthenticationSelection();
+ void testAuthentication();
+};