gpt4 book ai didi

qt - 在 Qt 中实现 SPNEGO

转载 作者:行者123 更新时间:2023-12-01 10:34:35 24 4
gpt4 key购买 nike

我需要使用 Qt 客户端实现 SPNEGO。服务器以 401/Unauthorized 响应并发送 WWW-Authenticate: Negotiate header 。

最佳答案

首先,通过此处的 RFC 了解该协议(protocol):https://www.rfc-editor.org/rfc/rfc4559

另一个很好的引用是 https://github.com/requests/requests-kerberos

了解 GSSAPI,虽然有一个跨平台的实现,但在 Windows 上并不是开箱即用的,您需要使用 SSPI。这个答案将展示如何在 Windows 上实现它。您可以将函数映射到其他平台的 GSSAPI。你永远不会真正编写这样的代码,但我为需要在没有太多抽象的情况下实现 SPNEGO 的人创建了这个代码。

此示例使用此处创建的奇妙 Kerberos 环境:https://github.com/Brandon-Godwin/vagrant-kerberos-environment

#include <QCoreApplication>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QtDebug>
#include <QNetworkReply>
#include <QAuthenticator>
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QNetworkCookieJar>
#include <QNetworkCookie>
#define SECURITY_WIN32
#include <windows.h>
#include <security.h>
#pragma comment(lib,"secur32.lib")

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

QNetworkAccessManager manager;

manager.connect(&manager,&QNetworkAccessManager::authenticationRequired,
[](QNetworkReply * reply, QAuthenticator * authenticator) {
qDebug() << "AUTH REQUIRED" << reply << authenticator;
});


manager.connect(&manager,&QNetworkAccessManager::proxyAuthenticationRequired,
[](const QNetworkProxy & proxy, QAuthenticator * authenticator) {
qDebug() << "AUTH REQUIRED" << proxy << authenticator;
});


qDebug() << "RUNNING";

QNetworkRequest request;
request.setUrl(QUrl("http://dc.testdomain.lan:8080/hello"));

auto reply = manager.get(request);
reply->connect(reply,&QNetworkReply::finished,
[reply,request,&manager](){
reply->deleteLater();
if(reply->rawHeader("www-authenticate") == "Negotiate") {
qDebug() << reply->rawHeaderList();
qDebug() << reply->rawHeader("set-cookie");
CredHandle cred = {0};
TimeStamp exp;
qDebug() << "Acquire"
<< AcquireCredentialsHandleA(NULL,(LPSTR)"Kerberos",SECPKG_CRED_OUTBOUND,NULL,NULL,NULL,NULL,&cred,&exp);

CtxtHandle ctx;
SecBufferDesc outputBufferDesc;
SecBuffer outputBuffers[1];
outputBuffers[0].pvBuffer = NULL;
outputBuffers[0].BufferType = SECBUFFER_TOKEN;
outputBuffers[0].cbBuffer = 0;

outputBufferDesc.ulVersion = SECBUFFER_VERSION;
outputBufferDesc.cBuffers = 1;
outputBufferDesc.pBuffers = outputBuffers;
ULONG contextAttr;

auto ret = InitializeSecurityContextA(&cred,NULL,(LPSTR)"HTTP/dc.testdomain.lan:8080",ISC_REQ_ALLOCATE_MEMORY,0,
SECURITY_NATIVE_DREP,NULL,0,&ctx,&outputBufferDesc,&contextAttr,&exp);
// TODO: De-allocate outputBufferDesc.pBuffers[0]
#define CASE(X) case X: qDebug() << #X; return;
switch(ret) {
case SEC_E_OK:
break;
CASE(SEC_E_INSUFFICIENT_MEMORY);
CASE(SEC_E_INTERNAL_ERROR);
CASE(SEC_E_INVALID_HANDLE);
CASE(SEC_E_INVALID_TOKEN);
CASE(SEC_E_LOGON_DENIED);
CASE(SEC_E_NO_AUTHENTICATING_AUTHORITY);
CASE(SEC_E_NO_CREDENTIALS);
CASE(SEC_E_TARGET_UNKNOWN);
CASE(SEC_E_UNSUPPORTED_FUNCTION);
CASE(SEC_E_WRONG_PRINCIPAL);
default:
qDebug() << "WAT" << ret;
return;
}

auto pBuffer = outputBufferDesc.pBuffers[0];
QByteArray array((const char *)pBuffer.pvBuffer,pBuffer.cbBuffer);
QNetworkRequest request2 = request;
request2.setRawHeader("Authorization","Negotiate " + array.toBase64());
auto reply2 = manager.get(request2);
reply2->connect(reply2,&QNetworkReply::finished,
[&manager,request,reply2]() {
qDebug() << reply2->rawHeaderList();
qDebug() << reply2->rawHeader("set-cookie");
qDebug() << reply2->readAll();
reply2->deleteLater();

auto reply3 = manager.get(request);
reply3->connect(reply3,&QNetworkReply::finished,
[reply3]() {
qDebug() << reply3->readAll();
qDebug() << reply3->rawHeaderList();
qDebug() << reply3->rawHeader("set-cookie");
reply3->deleteLater();
});
});

}
});

return a.exec();
}

关于qt - 在 Qt 中实现 SPNEGO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37968689/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com