Test case for QTBUG-22875

Test the authentication cache works properly with "cancelled dialogs"
or if the user enters username/password incorrectly.
Expected behaviour is based on web browsers:
If cancelled, current request fails, and prompt again the next time.
If wrong password is given, prompt again and retry the current request.
If bad credentials are in the cache, prompt again

Task-number: QTBUG-22875
Change-Id: Ic02ccac8dbeb3f2580ca4ffe47d0773982c4ab25
Reviewed-by: Peter Hartmann <peter.hartmann@nokia.com>
bb10
Shane Kearns 2011-12-13 15:50:59 +00:00 committed by Qt by Nokia
parent d62228a77e
commit 4be2430925
1 changed files with 188 additions and 1 deletions

View File

@ -73,7 +73,9 @@
#include <QtNetwork/qnetworkconfiguration.h>
#include <QtNetwork/qnetworksession.h>
#endif
#ifdef QT_BUILD_INTERNAL
#include <QtNetwork/private/qnetworkaccessmanager_p.h>
#endif
#include <time.h>
#include "../../../network-settings.h"
@ -378,6 +380,8 @@ private Q_SLOTS:
void dontInsertPartialContentIntoTheCache();
void httpUserAgent();
void authenticationCacheAfterCancel_data();
void authenticationCacheAfterCancel();
void synchronousAuthenticationCache();
// NOTE: This test must be last!
@ -6025,6 +6029,189 @@ void tst_QNetworkReply::qtbug4121unknownAuthentication()
QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
}
void tst_QNetworkReply::authenticationCacheAfterCancel_data()
{
QTest::addColumn<QNetworkProxy>("proxy");
QTest::addColumn<bool>("proxyAuth");
QTest::addColumn<QUrl>("url");
for (int i = 0; i < proxies.count(); ++i) {
QTest::newRow("http" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
#ifndef QT_NO_OPENSSL
QTest::newRow("https" + proxies.at(i).tag) << proxies.at(i).proxy << proxies.at(i).requiresAuthentication << QUrl("https://" + QtNetworkSettings::serverName() + "/qtest/rfcs-auth/rfc3252.txt");
#endif
}
}
class AuthenticationCacheHelper : public QObject
{
Q_OBJECT
public:
AuthenticationCacheHelper()
{}
public slots:
void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth)
{
if (!proxyPassword.isNull()) {
auth->setUser(proxyUserName);
auth->setPassword(proxyPassword);
//clear credentials, if they are asked again, they were bad
proxyUserName.clear();
proxyPassword.clear();
}
}
void authenticationRequired(QNetworkReply*,QAuthenticator *auth)
{
if (!httpPassword.isNull()) {
auth->setUser(httpUserName);
auth->setPassword(httpPassword);
//clear credentials, if they are asked again, they were bad
httpUserName.clear();
httpPassword.clear();
}
}
public:
QString httpUserName;
QString httpPassword;
QString proxyUserName;
QString proxyPassword;
};
/* Purpose of this test is to check credentials are cached correctly.
- If user cancels authentication dialog (i.e. nothing is set to the QAuthenticator by the callback) then this is not cached
- if user supplies a wrong password, then this is not cached
- if user supplies a correct user/password combination then this is cached
Test is checking both the proxyAuthenticationRequired and authenticationRequired signals.
*/
void tst_QNetworkReply::authenticationCacheAfterCancel()
{
QFETCH(QNetworkProxy, proxy);
QFETCH(bool, proxyAuth);
QFETCH(QUrl, url);
QNetworkAccessManager manager;
#ifndef QT_NO_OPENSSL
connect(&manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)),
SLOT(sslErrors(QNetworkReply*,QList<QSslError>)));
#endif
manager.setProxy(proxy);
QSignalSpy authSpy(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)));
QSignalSpy proxyAuthSpy(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
AuthenticationCacheHelper helper;
connect(&manager, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)), &helper, SLOT(proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *)));
connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), &helper, SLOT(authenticationRequired(QNetworkReply*,QAuthenticator*)));
QNetworkRequest request(url);
QNetworkReplyPtr reply;
if (proxyAuth) {
//should fail due to no credentials
reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
QCOMPARE(authSpy.count(), 0);
QCOMPARE(proxyAuthSpy.count(), 1);
proxyAuthSpy.clear();
//should fail due to bad credentials
helper.proxyUserName = "qsockstest";
helper.proxyPassword = "badpassword";
reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QEXPECT_FAIL("http+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
QEXPECT_FAIL("https+socksauth", "QTBUG-23136 - danted accepts bad authentication but blocks the connection", Continue);
QCOMPARE(reply->error(), QNetworkReply::ProxyAuthenticationRequiredError);
QCOMPARE(authSpy.count(), 0);
QVERIFY(proxyAuthSpy.count() > 0);
proxyAuthSpy.clear();
//QTBUG-23136 workaround
if (proxy.port() == 1081) {
#ifdef QT_BUILD_INTERNAL
QNetworkAccessManagerPrivate::clearCache(&manager);
#else
return; //XFAIL result above
#endif
}
//next proxy auth should succeed, due to correct credentials
helper.proxyUserName = "qsockstest";
helper.proxyPassword = "password";
}
//should fail due to no credentials
reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
QVERIFY(authSpy.count() > 0);
authSpy.clear();
if (proxyAuth) {
QVERIFY(proxyAuthSpy.count() > 0);
proxyAuthSpy.clear();
}
//should fail due to bad credentials
helper.httpUserName = "baduser";
helper.httpPassword = "badpassword";
reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::AuthenticationRequiredError);
QVERIFY(authSpy.count() > 0);
authSpy.clear();
if (proxyAuth) {
//should be supplied from cache
QCOMPARE(proxyAuthSpy.count(), 0);
proxyAuthSpy.clear();
}
//next auth should succeed, due to correct credentials
helper.httpUserName = "httptest";
helper.httpPassword = "httptest";
reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::NoError);
QVERIFY(authSpy.count() > 0);
authSpy.clear();
if (proxyAuth) {
//should be supplied from cache
QCOMPARE(proxyAuthSpy.count(), 0);
proxyAuthSpy.clear();
}
//next auth should use cached credentials
reply = manager.get(request);
connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection);
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(reply->error(), QNetworkReply::NoError);
//should be supplied from cache
QCOMPARE(authSpy.count(), 0);
authSpy.clear();
if (proxyAuth) {
//should be supplied from cache
QCOMPARE(proxyAuthSpy.count(), 0);
proxyAuthSpy.clear();
}
}
class QtBug13431Helper : public QObject {
Q_OBJECT
public: