if (priv->phase == QAuthenticatorPrivate::Done) {
pauseConnection();
if (!isProxy) {
+ if (channels[i].authenticationCredentialsSent) {
+ auth->detach();
+ priv = QAuthenticatorPrivate::getPrivate(*auth);
+ priv->hasFailed = true;
+ priv->phase = QAuthenticatorPrivate::Done;
+ channels[i].authenticationCredentialsSent = false;
+ }
emit reply->authenticationRequired(reply->request(), auth);
#ifndef QT_NO_NETWORKPROXY
} else {
+ if (channels[i].proxyCredentialsSent) {
+ auth->detach();
+ priv = QAuthenticatorPrivate::getPrivate(*auth);
+ priv->hasFailed = true;
+ priv->phase = QAuthenticatorPrivate::Done;
+ channels[i].proxyCredentialsSent = false;
+ }
emit reply->proxyAuthenticationRequired(networkProxy, auth);
#endif
}
if (priv && priv->method != QAuthenticatorPrivate::None) {
QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));
request.setHeaderField("Authorization", response);
+ channels[i].authenticationCredentialsSent = true;
}
}
}
if (priv && priv->method != QAuthenticatorPrivate::None) {
QByteArray response = priv->calculateResponse(request.d->methodName(), request.d->uri(false));
request.setHeaderField("Proxy-Authorization", response);
+ channels[i].proxyCredentialsSent = true;
}
}
}
, lastStatus(0)
, pendingEncrypt(false)
, reconnectAttempts(2)
+ , authenticationCredentialsSent(false)
+ , proxyCredentialsSent(false)
, authMethod(QAuthenticatorPrivate::None)
, proxyAuthMethod(QAuthenticatorPrivate::None)
#ifndef QT_NO_OPENSSL
// reset state
pipeliningSupported = PipeliningSupportUnknown;
+ authenticationCredentialsSent = false;
+ proxyCredentialsSent = false;
+ authenticator.detach();
+ QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(authenticator);
+ priv->hasFailed = false;
+ proxyAuthenticator.detach();
+ priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
+ priv->hasFailed = false;
// This workaround is needed since we use QAuthenticator for NTLM authentication. The "phase == Done"
// is the usual criteria for emitting authentication signals. The "phase" is set to "Done" when the
// check the "phase" for generating the Authorization header. NTLM authentication is a two stage
// process & needs the "phase". To make sure the QAuthenticator uses the current username/password
// the phase is reset to Start.
- QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(authenticator);
+ priv = QAuthenticatorPrivate::getPrivate(authenticator);
if (priv && priv->phase == QAuthenticatorPrivate::Done)
priv->phase = QAuthenticatorPrivate::Start;
priv = QAuthenticatorPrivate::getPrivate(proxyAuthenticator);
QAuthenticatorPrivate::Method proxyAuthMethod;
QAuthenticator authenticator;
QAuthenticator proxyAuthenticator;
+ bool authenticationCredentialsSent;
+ bool proxyCredentialsSent;
#ifndef QT_NO_OPENSSL
bool ignoreAllSslErrors;
QList<QSslError> ignoreSslErrorsList;
#include "QtCore/qbuffer.h"
#include "QtCore/qurl.h"
#include "QtCore/qvector.h"
-#include "QtNetwork/qauthenticator.h"
+#include "QtNetwork/private/qauthenticator_p.h"
#include "QtNetwork/qsslconfiguration.h"
#include "QtNetwork/qnetworkconfigmanager.h"
#include "QtNetwork/qhttpmultipart.h"
QNetworkProxy *lastProxyAuthentication)
{
Q_Q(QNetworkAccessManager);
- // ### FIXME Tracking of successful authentications
- // This code is a bit broken right now for SOCKS authentication
- // first request: proxyAuthenticationRequired gets emitted, credentials gets saved
- // second request: (proxy != backend->reply->lastProxyAuthentication) does not evaluate to true,
- // proxyAuthenticationRequired gets emitted again
- // possible solution: some tracking inside the authenticator
- // or a new function proxyAuthenticationSucceeded(true|false)
- if (proxy != *lastProxyAuthentication) {
+ QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*authenticator);
+ if (proxy != *lastProxyAuthentication && (!priv || !priv->hasFailed)) {
QNetworkAuthenticationCredential cred = authenticationManager->fetchCachedProxyCredentials(proxy);
if (!cred.isNull()) {
authenticator->setUser(cred.user);
QAuthenticatorPrivate::QAuthenticatorPrivate()
: ref(0)
, method(None)
+ , hasFailed(false)
, phase(Start)
, nonceCount(0)
{
Method method;
QString realm;
QByteArray challenge;
+ bool hasFailed; //credentials have been tried but rejected by server.
enum Phase {
Start,
{
Q_D(QHttpSocketEngine);
+ d->credentialsSent = false;
+
// If the handshake is done, enter ConnectedState state and return true.
if (d->state == Connected) {
qWarning("QHttpSocketEngine::connectToHost: called when already connected");
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
//qDebug() << "slotSocketConnected: priv=" << priv << (priv ? (int)priv->method : -1);
if (priv && priv->method != QAuthenticatorPrivate::None) {
+ d->credentialsSent = true;
data += "Proxy-Authorization: " + priv->calculateResponse(method, path);
data += "\r\n";
}
d->readBuffer.clear(); // we parsed the proxy protocol response. from now on direct socket reading will be done
int statusCode = responseHeader.statusCode();
+ QAuthenticatorPrivate *priv = 0;
if (statusCode == 200) {
d->state = Connected;
setLocalAddress(d->socket->localAddress());
setLocalPort(d->socket->localPort());
setState(QAbstractSocket::ConnectedState);
+ d->authenticator.detach();
+ priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
+ priv->hasFailed = false;
} else if (statusCode == 407) {
- if (d->authenticator.isNull())
+ if (d->credentialsSent) {
+ //407 response again means the provided username/password were invalid.
+ d->authenticator = QAuthenticator(); //this is needed otherwise parseHttpResponse won't set the state, and then signal isn't emitted.
+ d->authenticator.detach();
+ priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
+ priv->hasFailed = true;
+ }
+ else if (d->authenticator.isNull())
d->authenticator.detach();
- QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
+ priv = QAuthenticatorPrivate::getPrivate(d->authenticator);
priv->parseHttpResponse(responseHeader, true);
if (priv->phase == QAuthenticatorPrivate::Done)
emit proxyAuthenticationRequired(d->proxy, &d->authenticator);
-
// priv->phase will get reset to QAuthenticatorPrivate::Start if the authenticator got modified in the signal above.
if (priv->phase == QAuthenticatorPrivate::Done) {
setError(QAbstractSocket::ProxyAuthenticationRequiredError, tr("Authentication required"));
, readNotificationPending(false)
, writeNotificationPending(false)
, connectionNotificationPending(false)
+ , credentialsSent(false)
, pendingResponseData(0)
{
socket = 0;
bool readNotificationPending;
bool writeNotificationPending;
bool connectionNotificationPending;
+ bool credentialsSent;
uint pendingResponseData;
};