summaryrefslogtreecommitdiffstats
path: root/src/network/access
diff options
context:
space:
mode:
authorTimur Pocheptsov <timur.pocheptsov@qt.io>2022-11-07 11:09:06 +0100
committerTimur Pocheptsov <timur.pocheptsov@qt.io>2022-11-08 07:12:05 +0000
commit02b9033d50def3b4c70a4f0504b5894d4249be1b (patch)
tree54d21ce0e567c387caacfe64cd1910f20c2b1c67 /src/network/access
parent2ec77f4f11b5e01e25307a068cd3b360b37011e0 (diff)
getProxyAuth: stop using deprecated API
A new SDK marked several functions in SecKeychain family as deprecated. Fortunately for us, Security framework on the whole is not deprecated and thus provides an alternative API to inspect keychain items, and also much nicer one - instead of having a function with 15 parameters, those parameters are 'collapsed' into one, the 'query', which is a dictionary. Pick-to: 6.4 6.2 Fixes: QTBUG-108196 Change-Id: I602d1a846ff9683cac724859a776de2b901f5c1c Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Diffstat (limited to 'src/network/access')
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp106
1 files changed, 64 insertions, 42 deletions
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index d771485b2f..2e3a3d81f1 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -45,12 +45,15 @@
#include <QHostInfo>
#include "QtCore/qapplicationstatic.h"
+#include "QtCore/qloggingcategory.h"
#include <QtCore/private/qfactoryloader_p.h>
#if defined(Q_OS_MACOS)
+#include <QtCore/private/qcore_mac_p.h>
+
#include <CoreServices/CoreServices.h>
#include <SystemConfiguration/SystemConfiguration.h>
-#include <Security/SecKeychain.h>
+#include <Security/Security.h>
#endif
#ifdef Q_OS_WASM
#include "qnetworkreplywasmimpl_p.h"
@@ -66,6 +69,8 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+Q_LOGGING_CATEGORY(lcQnam, "qt.network.access.manager")
+
Q_APPLICATION_STATIC(QNetworkAccessFileBackendFactory, fileBackend)
#ifdef QT_BUILD_INTERNAL
@@ -77,55 +82,72 @@ Q_APPLICATION_STATIC(QFactoryLoader, loader, QNetworkAccessBackendFactory_iid, "
#if defined(Q_OS_MACOS)
bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password)
{
- OSStatus err;
- SecKeychainItemRef itemRef;
- bool retValue = false;
- SecProtocolType protocolType = kSecProtocolTypeAny;
+ CFStringRef protocolType = nullptr;
if (scheme.compare("ftp"_L1, Qt::CaseInsensitive) == 0) {
- protocolType = kSecProtocolTypeFTPProxy;
+ protocolType = kSecAttrProtocolFTPProxy;
} else if (scheme.compare("http"_L1, Qt::CaseInsensitive) == 0
|| scheme.compare("preconnect-http"_L1, Qt::CaseInsensitive) == 0) {
- protocolType = kSecProtocolTypeHTTPProxy;
+ protocolType = kSecAttrProtocolHTTPProxy;
} else if (scheme.compare("https"_L1,Qt::CaseInsensitive)==0
|| scheme.compare("preconnect-https"_L1, Qt::CaseInsensitive) == 0) {
- protocolType = kSecProtocolTypeHTTPSProxy;
+ protocolType = kSecAttrProtocolHTTPSProxy;
+ } else {
+ qCWarning(lcQnam) << "Cannot query user name and password for a proxy, unnknown protocol:"
+ << scheme;
+ return false;
}
- QByteArray proxyHostnameUtf8(proxyHostname.toUtf8());
- err = SecKeychainFindInternetPassword(NULL,
- proxyHostnameUtf8.length(), proxyHostnameUtf8.constData(),
- 0,NULL,
- 0, NULL,
- 0, NULL,
- 0,
- protocolType,
- kSecAuthenticationTypeAny,
- 0, NULL,
- &itemRef);
- if (err == noErr) {
-
- SecKeychainAttribute attr;
- SecKeychainAttributeList attrList;
- UInt32 length;
- void *outData;
-
- attr.tag = kSecAccountItemAttr;
- attr.length = 0;
- attr.data = NULL;
-
- attrList.count = 1;
- attrList.attr = &attr;
-
- if (SecKeychainItemCopyContent(itemRef, NULL, &attrList, &length, &outData) == noErr) {
- username = QString::fromUtf8((const char*)attr.data, attr.length);
- password = QString::fromUtf8((const char*)outData, length);
- SecKeychainItemFreeContent(&attrList,outData);
- retValue = true;
- }
- CFRelease(itemRef);
+
+ QCFType<CFMutableDictionaryRef> query(CFDictionaryCreateMutable(kCFAllocatorDefault,
+ 0, nullptr, nullptr));
+ Q_ASSERT(query);
+
+ CFDictionaryAddValue(query, kSecClass, kSecClassInternetPassword);
+ CFDictionaryAddValue(query, kSecAttrProtocol, protocolType);
+
+ QCFType<CFStringRef> serverName; // Note the scope.
+ if (proxyHostname.size()) {
+ serverName = proxyHostname.toCFString();
+ CFDictionaryAddValue(query, kSecAttrServer, serverName);
+ }
+
+ // This is to get the user name in the result:
+ CFDictionaryAddValue(query, kSecReturnAttributes, kCFBooleanTrue);
+ // This one to get the password:
+ CFDictionaryAddValue(query, kSecReturnData, kCFBooleanTrue);
+
+ // The default for kSecMatchLimit key is 1 (the first match only), which is fine,
+ // so don't set this value explicitly.
+
+ QCFType<CFTypeRef> replyData;
+ if (SecItemCopyMatching(query, &replyData) != errSecSuccess) {
+ qCWarning(lcQnam, "Failed to extract user name and password from the keychain.");
+ return false;
}
- return retValue;
+
+ if (!replyData || CFDictionaryGetTypeID() != CFGetTypeID(replyData)) {
+ qCWarning(lcQnam, "Query returned data in unexpected format.");
+ return false;
+ }
+
+ CFDictionaryRef accountData = replyData.as<CFDictionaryRef>();
+ const void *value = CFDictionaryGetValue(accountData, kSecAttrAccount);
+ if (!value || CFGetTypeID(value) != CFStringGetTypeID()) {
+ qCWarning(lcQnam, "Cannot find user name or its format is unknown.");
+ return false;
+ }
+ username = QString::fromCFString(static_cast<CFStringRef>(value));
+
+ value = CFDictionaryGetValue(accountData, kSecValueData);
+ if (!value || CFGetTypeID(value) != CFDataGetTypeID()) {
+ qCWarning(lcQnam, "Cannot find password or its format is unknown.");
+ return false;
+ }
+ const CFDataRef passData = static_cast<const CFDataRef>(value);
+ password = QString::fromLocal8Bit(reinterpret_cast<const char *>(CFDataGetBytePtr(passData)),
+ qsizetype(CFDataGetLength(passData)));
+ return true;
}
-#endif
+#endif // Q_OS_MACOS