summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp9
-rw-r--r--src/network/kernel/qauthenticator.cpp66
-rw-r--r--src/network/kernel/qauthenticator_p.h2
-rw-r--r--src/network/socket/qhttpsocketengine.cpp2
4 files changed, 65 insertions, 14 deletions
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 24be5b1464..c133a09044 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -449,7 +449,14 @@ bool QHttpNetworkConnectionPrivate::handleAuthenticateChallenge(QAbstractSocket
if (auth->isNull())
auth->detach();
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(*auth);
- priv->parseHttpResponse(fields, isProxy);
+ priv->parseHttpResponse(fields, isProxy, reply->url().host());
+ // Update method in case it changed
+ if (priv->method == QAuthenticatorPrivate::None)
+ return false;
+ if (isProxy)
+ channels[i].proxyAuthMethod = priv->method;
+ else
+ channels[i].authMethod = priv->method;
if (priv->phase == QAuthenticatorPrivate::Done) {
pauseConnection();
diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp
index c23e82dd85..3db7161add 100644
--- a/src/network/kernel/qauthenticator.cpp
+++ b/src/network/kernel/qauthenticator.cpp
@@ -81,6 +81,7 @@ static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate
static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method,
const QString& host, const QByteArray& challenge = QByteArray());
#elif QT_CONFIG(gssapi) // GSSAPI
+static bool qGssapiTestGetCredentials(const QString &host);
static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString& host);
static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx,
const QByteArray& challenge = QByteArray());
@@ -422,7 +423,7 @@ void QAuthenticatorPrivate::updateCredentials()
}
}
-void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy)
+void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByteArray> > &values, bool isProxy, const QString &host)
{
const char *search = isProxy ? "proxy-authenticate" : "www-authenticate";
@@ -454,6 +455,13 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt
headerVal = current.second.mid(7);
} else if (method < Negotiate && str.startsWith("negotiate")) {
#if QT_CONFIG(sspi) || QT_CONFIG(gssapi) // if it's not supported then we shouldn't try to use it
+#if QT_CONFIG(gssapi)
+ // For GSSAPI there needs to be a KDC set up for the host (afaict).
+ // So let's only conditionally use it if we can fetch the credentials.
+ // Sadly it's a bit slow because it requires a DNS lookup.
+ if (!qGssapiTestGetCredentials(host))
+ continue;
+#endif
method = Negotiate;
headerVal = current.second.mid(10);
#endif
@@ -583,6 +591,7 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
phase = Phase2;
} else {
phase = Done;
+ return "";
}
} else {
QByteArray phase3Token;
@@ -595,6 +604,9 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet
response = phase3Token.toBase64();
phase = Done;
challenge = "";
+ } else {
+ phase = Done;
+ return "";
}
}
@@ -1677,26 +1689,36 @@ static void q_GSSAPI_error(const char *message, OM_uint32 majStat, OM_uint32 min
q_GSSAPI_error_int(message, minStat, GSS_C_MECH_CODE);
}
+static gss_name_t qGSsapiGetServiceName(const QString &host)
+{
+ QByteArray serviceName = "HTTPS@" + host.toLocal8Bit();
+ gss_buffer_desc nameDesc = {static_cast<std::size_t>(serviceName.size()), serviceName.data()};
+
+ gss_name_t importedName;
+ OM_uint32 minStat;
+ OM_uint32 majStat = gss_import_name(&minStat, &nameDesc,
+ GSS_C_NT_HOSTBASED_SERVICE, &importedName);
+
+ if (majStat != GSS_S_COMPLETE) {
+ q_GSSAPI_error("gss_import_name error", majStat, minStat);
+ return nullptr;
+ }
+ return importedName;
+}
+
// Send initial GSS authentication token
static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString &host)
{
- OM_uint32 majStat, minStat;
-
if (!ctx->gssApiHandles)
ctx->gssApiHandles.reset(new QGssApiHandles);
// Convert target name to internal form
- QByteArray serviceName = QStringLiteral("HTTPS@%1").arg(host).toLocal8Bit();
- gss_buffer_desc nameDesc = {static_cast<std::size_t>(serviceName.size()), serviceName.data()};
-
- majStat = gss_import_name(&minStat, &nameDesc,
- GSS_C_NT_HOSTBASED_SERVICE, &ctx->gssApiHandles->targetName);
-
- if (majStat != GSS_S_COMPLETE) {
- q_GSSAPI_error("gss_import_name error", majStat, minStat);
+ gss_name_t name = qGSsapiGetServiceName(host);
+ if (name == nullptr) {
ctx->gssApiHandles.reset(nullptr);
return QByteArray();
}
+ ctx->gssApiHandles->targetName = name;
// Call qGssapiContinue with GSS_C_NO_CONTEXT to get initial packet
ctx->gssApiHandles->gssCtx = GSS_C_NO_CONTEXT;
@@ -1750,6 +1772,28 @@ static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray&
return result;
}
+static bool qGssapiTestGetCredentials(const QString &host)
+{
+ gss_name_t serviceName = qGSsapiGetServiceName(host);
+ if (!serviceName)
+ return false; // Something was wrong with the service name, so skip this
+ OM_uint32 minStat;
+ gss_cred_id_t cred;
+ OM_uint32 majStat = gss_acquire_cred(&minStat, serviceName, GSS_C_INDEFINITE,
+ GSS_C_NO_OID_SET, GSS_C_INITIATE, &cred, nullptr,
+ nullptr);
+
+ OM_uint32 ignored;
+ gss_release_name(&ignored, &serviceName);
+ gss_release_cred(&ignored, &cred);
+
+ if (majStat != GSS_S_COMPLETE) {
+ q_GSSAPI_error("gss_acquire_cred", majStat, minStat);
+ return false;
+ }
+ return true;
+}
+
// ---------------------------- End of GSSAPI code ----------------------------------------------
#endif // gssapi
diff --git a/src/network/kernel/qauthenticator_p.h b/src/network/kernel/qauthenticator_p.h
index 99dfdbda2c..1813634ee0 100644
--- a/src/network/kernel/qauthenticator_p.h
+++ b/src/network/kernel/qauthenticator_p.h
@@ -113,7 +113,7 @@ public:
QByteArray digestMd5Response(const QByteArray &challenge, const QByteArray &method, const QByteArray &path);
static QHash<QByteArray, QByteArray> parseDigestAuthenticationChallenge(const QByteArray &challenge);
- void parseHttpResponse(const QList<QPair<QByteArray, QByteArray> >&, bool isProxy);
+ void parseHttpResponse(const QList<QPair<QByteArray, QByteArray> >&, bool isProxy, const QString &host);
void updateCredentials();
};
diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp
index a23e2d3071..5324038dbd 100644
--- a/src/network/socket/qhttpsocketengine.cpp
+++ b/src/network/socket/qhttpsocketengine.cpp
@@ -607,7 +607,7 @@ void QHttpSocketEngine::slotSocketReadNotification()
priv->hasFailed = true;
}
- priv->parseHttpResponse(d->reply->header(), true);
+ priv->parseHttpResponse(d->reply->header(), true, d->proxy.hostName());
if (priv->phase == QAuthenticatorPrivate::Invalid) {
// problem parsing the reply