1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the FOO module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtCore/QString>
31#include <QtTest/QtTest>
32#include <QtCore/QCoreApplication>
33#include <QtNetwork/QAuthenticator>
34
35#include <private/qauthenticator_p.h>
36
37class tst_QAuthenticator : public QObject
38{
39 Q_OBJECT
40
41public:
42 tst_QAuthenticator();
43
44private Q_SLOTS:
45 void basicAuth();
46 void basicAuth_data();
47
48 void ntlmAuth_data();
49 void ntlmAuth();
50
51 void sha256AndMd5Digest();
52
53 void equalityOperators();
54};
55
56tst_QAuthenticator::tst_QAuthenticator()
57{
58}
59
60void tst_QAuthenticator::basicAuth_data()
61{
62 QTest::addColumn<QString>(name: "data");
63 QTest::addColumn<QString>(name: "realm");
64 QTest::addColumn<QString>(name: "user");
65 QTest::addColumn<QString>(name: "password");
66 QTest::addColumn<QByteArray>(name: "expectedReply");
67
68 QTest::newRow(dataTag: "just-user") << "" << "" << "foo" << "" << QByteArray("foo:").toBase64();
69 QTest::newRow(dataTag: "user-password") << "" << "" << "foo" << "bar" << QByteArray("foo:bar").toBase64();
70 QTest::newRow(dataTag: "user-password-realm") << "realm=\"secure area\"" << "secure area" << "foo" << "bar" << QByteArray("foo:bar").toBase64();
71}
72
73void tst_QAuthenticator::basicAuth()
74{
75 QFETCH(QString, data);
76 QFETCH(QString, realm);
77 QFETCH(QString, user);
78 QFETCH(QString, password);
79 QFETCH(QByteArray, expectedReply);
80
81 QAuthenticator auth;
82 auth.detach();
83 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth);
84 QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
85
86 QList<QPair<QByteArray, QByteArray> > headers;
87 headers << qMakePair<QByteArray, QByteArray>(x: QByteArray("WWW-Authenticate"), y: "Basic " + data.toUtf8());
88 priv->parseHttpResponse(headers, /*isProxy = */ false, host: {});
89
90 QCOMPARE(auth.realm(), realm);
91 QCOMPARE(auth.option("realm").toString(), realm);
92
93 auth.setUser(user);
94 auth.setPassword(password);
95
96 QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
97
98 QCOMPARE(priv->calculateResponse("GET", "/", "").constData(), QByteArray("Basic " + expectedReply).constData());
99}
100
101void tst_QAuthenticator::ntlmAuth_data()
102{
103 QTest::addColumn<QString>(name: "data");
104 QTest::addColumn<QString>(name: "realm");
105 QTest::addColumn<bool>(name: "sso");
106
107 QTest::newRow(dataTag: "no-realm") << "TlRMTVNTUAACAAAAHAAcADAAAAAFAoEATFZ3OLRQADIAAAAAAAAAAJYAlgBMAAAAUQBUAC0AVABFAFMAVAAtAEQATwBNAEEASQBOAAIAHABRAFQALQBUAEUAUwBUAC0ARABPAE0AQQBJAE4AAQAcAFEAVAAtAFQARQBTAFQALQBTAEUAUgBWAEUAUgAEABYAcQB0AC0AdABlAHMAdAAtAG4AZQB0AAMANABxAHQALQB0AGUAcwB0AC0AcwBlAHIAdgBlAHIALgBxAHQALQB0AGUAcwB0AC0AbgBlAHQAAAAAAA==" << "" << false;
108 QTest::newRow(dataTag: "with-realm") << "TlRMTVNTUAACAAAADAAMADgAAAAFAoECWCZkccFFAzwAAAAAAAAAAL4AvgBEAAAABQLODgAAAA9NAEcARABOAE8ASwACAAwATQBHAEQATgBPAEsAAQAcAE4ATwBLAC0AQQBNAFMAUwBTAEYARQAtADAAMQAEACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQADAD4AbgBvAGsALQBhAG0AcwBzAHMAZgBlAC0AMAAxAC4AbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAFACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAAAAAA" << "NOE" << false;
109 QTest::newRow(dataTag: "no-realm-sso") << "TlRMTVNTUAACAAAAHAAcADAAAAAFAoEATFZ3OLRQADIAAAAAAAAAAJYAlgBMAAAAUQBUAC0AVABFAFMAVAAtAEQATwBNAEEASQBOAAIAHABRAFQALQBUAEUAUwBUAC0ARABPAE0AQQBJAE4AAQAcAFEAVAAtAFQARQBTAFQALQBTAEUAUgBWAEUAUgAEABYAcQB0AC0AdABlAHMAdAAtAG4AZQB0AAMANABxAHQALQB0AGUAcwB0AC0AcwBlAHIAdgBlAHIALgBxAHQALQB0AGUAcwB0AC0AbgBlAHQAAAAAAA==" << "" << true;
110 QTest::newRow(dataTag: "with-realm-sso") << "TlRMTVNTUAACAAAADAAMADgAAAAFAoECWCZkccFFAzwAAAAAAAAAAL4AvgBEAAAABQLODgAAAA9NAEcARABOAE8ASwACAAwATQBHAEQATgBPAEsAAQAcAE4ATwBLAC0AQQBNAFMAUwBTAEYARQAtADAAMQAEACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQADAD4AbgBvAGsALQBhAG0AcwBzAHMAZgBlAC0AMAAxAC4AbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAFACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAAAAAA" << "NOE" << true;
111}
112
113void tst_QAuthenticator::ntlmAuth()
114{
115 QFETCH(QString, data);
116 QFETCH(QString, realm);
117 QFETCH(bool, sso);
118
119 QAuthenticator auth;
120 if (!sso) {
121 auth.setUser("unimportant");
122 auth.setPassword("unimportant");
123 }
124
125 auth.detach();
126 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth);
127 QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
128
129 QList<QPair<QByteArray, QByteArray> > headers;
130
131 // NTLM phase 1: negotiate
132 // This phase of NTLM contains no information, other than what we're willing to negotiate
133 // Current implementation uses flags:
134 // NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_REQUEST_TARGET
135 headers << qMakePair<QByteArray, QByteArray>(x: "WWW-Authenticate", y: "NTLM");
136 priv->parseHttpResponse(headers, /*isProxy = */ false, host: {});
137 if (sso)
138 QVERIFY(priv->calculateResponse("GET", "/", "").startsWith("NTLM "));
139 else
140 QCOMPARE(priv->calculateResponse("GET", "/", "").constData(), "NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAA=");
141
142 // NTLM phase 2: challenge
143 headers.clear();
144 headers << qMakePair<QByteArray, QByteArray>(x: QByteArray("WWW-Authenticate"), y: "NTLM " + data.toUtf8());
145 priv->parseHttpResponse(headers, /*isProxy = */ false, host: {});
146
147 QEXPECT_FAIL("with-realm", "NTLM authentication code doesn't extract the realm", Continue);
148 QEXPECT_FAIL("with-realm-sso", "NTLM authentication code doesn't extract the realm", Continue);
149 QCOMPARE(auth.realm(), realm);
150
151 QVERIFY(priv->calculateResponse("GET", "/", "").startsWith("NTLM "));
152}
153
154// We don't (currently) support SHA256. So, when presented with the option of MD5 or SHA256,
155// we should always pick MD5.
156void tst_QAuthenticator::sha256AndMd5Digest()
157{
158 QByteArray md5 = "Digest realm=\"\", nonce=\"\", algorithm=MD5, qop=\"auth\"";
159 QByteArray sha256 = "Digest realm=\"\", nonce=\"\", algorithm=SHA-256, qop=\"auth\"";
160
161 QAuthenticator auth;
162 auth.setUser("unimportant");
163 auth.setPassword("unimportant");
164
165 QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth);
166
167 QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
168 QList<QPair<QByteArray, QByteArray>> headers;
169 // Put sha256 first, so that its parsed first...
170 headers.push_back(t: {"WWW-Authenticate", sha256});
171 headers.push_back(t: {"WWW-Authenticate", md5});
172 priv->parseHttpResponse(headers, isProxy: false, host: QString());
173
174 QByteArray response = priv->calculateResponse(method: "GET", path: "/index", host: {});
175 QCOMPARE(priv->phase, QAuthenticatorPrivate::Done);
176
177 QVERIFY(!response.isEmpty());
178 QVERIFY(!response.contains("algorithm=SHA-256"));
179 QVERIFY(response.contains("algorithm=MD5"));
180}
181
182void tst_QAuthenticator::equalityOperators()
183{
184 QAuthenticator s1, s2;
185 QVERIFY(s2 == s1);
186 QVERIFY(s1 == s2);
187 QVERIFY(!(s1 != s2));
188 QVERIFY(!(s2 != s1));
189 s1.setUser("User");
190 QVERIFY(!(s2 == s1));
191 QVERIFY(!(s1 == s2));
192 QVERIFY(s1 != s2);
193 QVERIFY(s2 != s1);
194}
195
196QTEST_MAIN(tst_QAuthenticator);
197
198#include "tst_qauthenticator.moc"
199

source code of qtbase/tests/auto/network/kernel/qauthenticator/tst_qauthenticator.cpp