Automatically query for Mac Proxy Server credentials

Add support for automatically searching the Mac System Preferences
for proxy server username/password. If a user has put credentials
in the SystemPreferences->Network->Interface->Proxies area, we
will now look in the KeyChain for those files. This will
automatically pop up a Permissions dialog from the OS if valid
credentials were found which match the server we are trying to
access.

Task-Number: QTBUG-22033

Change-Id: Ic7952afab4d16a65a87bb2f97a928c1c91167fe7
Reviewed-by: Shane Kearns <shane.kearns@accenture.com>
bb10
Aron Rosenberg 2012-04-04 16:41:27 -07:00 committed by Qt by Nokia
parent c524bbbb8a
commit 90520cd834
2 changed files with 72 additions and 0 deletions

View File

@ -65,3 +65,5 @@ SOURCES += \
access/qhttpmultipart.cpp
include($$PWD/../../3rdparty/zlib_dependency.pri)
mac:LIBS_PRIVATE += -framework Security

View File

@ -82,6 +82,64 @@ Q_GLOBAL_STATIC(QNetworkAccessFtpBackendFactory, ftpBackend)
Q_GLOBAL_STATIC(QNetworkAccessDebugPipeBackendFactory, debugpipeBackend)
#endif
#ifdef Q_OS_MAC
#include <CoreServices/CoreServices.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <Security/SecKeychain.h>
bool getProxyAuth(const QString& proxyHostname, const QString &scheme, QString& username, QString& password)
{
OSStatus err;
SecKeychainItemRef itemRef;
bool retValue = false;
SecProtocolType protocolType = kSecProtocolTypeAny;
if (scheme.compare(QLatin1String("ftp"),Qt::CaseInsensitive)==0) {
protocolType = kSecProtocolTypeFTP;
} else if (scheme.compare(QLatin1String("http"),Qt::CaseInsensitive)==0) {
protocolType = kSecProtocolTypeHTTP;
} else if (scheme.compare(QLatin1String("https"),Qt::CaseInsensitive)==0) {
protocolType = kSecProtocolTypeHTTPS;
}
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);
}
return retValue;
}
#endif
static void ensureInitialized()
{
#ifndef QT_NO_FTP
@ -1117,6 +1175,18 @@ void QNetworkAccessManagerPrivate::authenticationRequired(QAuthenticator *authen
return;
}
}
#ifdef Q_OS_MAC
//now we try to get the username and password from keychain
//if not successful signal will be emitted
QString username;
QString password;
if (getProxyAuth(proxy.hostName(),reply->request().url().scheme(),username,password)) {
authenticator->setUser(username);
authenticator->setPassword(password);
authenticationManager->cacheProxyCredentials(proxy, authenticator);
return;
}
#endif
// if we emit a signal here in synchronous mode, the user might spin
// an event loop, which might recurse and lead to problems