From 0d360d450aaf3172d23fb77d03f107d08a6ff6e3 Mon Sep 17 00:00:00 2001 From: "Juergen E. Fischer" Date: Sun, 22 Jun 2014 17:54:40 +0200 Subject: [PATCH] fix interactive network authentication --- python/core/qgscredentials.sip | 7 +++ src/app/qgisapp.cpp | 89 ++++++++++++++++++++++------ src/app/qgsidentifyresultsdialog.cpp | 9 ++- src/core/qgscredentials.cpp | 8 ++- src/core/qgscredentials.h | 7 +++ src/core/qgsnetworkaccessmanager.cpp | 11 ++-- src/providers/wms/qgswmsprovider.cpp | 2 +- 7 files changed, 106 insertions(+), 27 deletions(-) diff --git a/python/core/qgscredentials.sip b/python/core/qgscredentials.sip index b7182d3a238..90ebc79a6c8 100644 --- a/python/core/qgscredentials.sip +++ b/python/core/qgscredentials.sip @@ -21,12 +21,19 @@ class QgsCredentials * @note added in 2.4 */ void lock(); + /** * Unlock the instance after being locked. * @note added in 2.4 */ void unlock(); + /** + * Return pointer to mutex + * @note added in 2.4 + */ + QMutex *mutex(); + protected: QgsCredentials(); diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 3ba7037fe94..f09351d5bc4 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -9761,7 +9761,8 @@ void QgisApp::namSetup() connect( nam, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ), this, SLOT( namProxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ) ); - connect( nam, SIGNAL( requestTimedOut( QNetworkReply* ) ), this, SLOT( namRequestTimedOut( QNetworkReply* ) ) ); + connect( nam, SIGNAL( requestTimedOut( QNetworkReply* ) ), + this, SLOT( namRequestTimedOut( QNetworkReply* ) ) ); #ifndef QT_NO_OPENSSL connect( nam, SIGNAL( sslErrors( QNetworkReply *, const QList & ) ), @@ -9774,15 +9775,41 @@ void QgisApp::namAuthenticationRequired( QNetworkReply *reply, QAuthenticator *a QString username = auth->user(); QString password = auth->password(); - bool ok = QgsCredentials::instance()->get( - QString( "%1 at %2" ).arg( auth->realm() ).arg( reply->url().host() ), - username, password, - tr( "Authentication required" ) ); - if ( !ok ) - return; + QMutexLocker lock( QgsCredentials::instance()->mutex() ); - if ( reply->isFinished() ) - return; + do + { + bool ok = QgsCredentials::instance()->get( + QString( "%1 at %2" ).arg( auth->realm() ).arg( reply->url().host() ), + username, password, + tr( "Authentication required" ) ); + if ( !ok ) + return; + + if ( reply->isFinished() ) + return; + + if ( auth->user() == username && password == auth->password() ) + { + if ( !password.isNull() ) + { + // credentials didn't change - stored ones probably wrong? clear password and retry + QgsCredentials::instance()->put( + QString( "%1 at %2" ).arg( auth->realm() ).arg( reply->url().host() ), + username, QString::null ); + continue; + } + } + else + { + // save credentials + QgsCredentials::instance()->put( + QString( "%1 at %2" ).arg( auth->realm() ).arg( reply->url().host() ), + username, password + ); + } + } + while ( 0 ); auth->setUser( username ); auth->setPassword( password ); @@ -9801,12 +9828,37 @@ void QgisApp::namProxyAuthenticationRequired( const QNetworkProxy &proxy, QAuthe QString username = auth->user(); QString password = auth->password(); - bool ok = QgsCredentials::instance()->get( - QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), - username, password, - tr( "Proxy authentication required" ) ); - if ( !ok ) - return; + QMutexLocker lock( QgsCredentials::instance()->mutex() ); + + do + { + bool ok = QgsCredentials::instance()->get( + QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), + username, password, + tr( "Proxy authentication required" ) ); + if ( !ok ) + return; + + if ( auth->user() == username && password == auth->password() ) + { + if ( !password.isNull() ) + { + // credentials didn't change - stored ones probably wrong? clear password and retry + QgsCredentials::instance()->put( + QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), + username, QString::null ); + continue; + } + } + else + { + QgsCredentials::instance()->put( + QString( "proxy %1:%2 [%3]" ).arg( proxy.hostName() ).arg( proxy.port() ).arg( auth->realm() ), + username, password + ); + } + } + while ( 0 ); auth->setUser( username ); auth->setPassword( password ); @@ -9850,8 +9902,11 @@ void QgisApp::namSslErrors( QNetworkReply *reply, const QList &errors void QgisApp::namRequestTimedOut( QNetworkReply *reply ) { - QgsMessageLog::logMessage( tr( "The request '%1' timed out. Any data received is likely incomplete." ).arg( reply->url().toString() ), QString::null, QgsMessageLog::WARNING ); - messageBar()->pushMessage( tr( "Network request timeout" ), tr( "A network request timed out, any data received is likely incomplete." ), QgsMessageBar::WARNING, messageTimeout() ); + QLabel *msgLabel = new QLabel( tr( "A network request timed out, any data received is likely incomplete." ) + + tr( " Please check the message log for further info." ), messageBar() ); + msgLabel->setWordWrap( true ); + connect( msgLabel, SIGNAL( linkActivated( QString ) ), mLogDock, SLOT( show() ) ); + messageBar()->pushItem( new QgsMessageBarItem( msgLabel, QgsMessageBar::WARNING, messageTimeout() ) ); } void QgisApp::namUpdate() diff --git a/src/app/qgsidentifyresultsdialog.cpp b/src/app/qgsidentifyresultsdialog.cpp index 538d1d9bc85..e22be4cce62 100644 --- a/src/app/qgsidentifyresultsdialog.cpp +++ b/src/app/qgsidentifyresultsdialog.cpp @@ -738,7 +738,14 @@ void QgsIdentifyResultsDialog::addFeature( QgsRasterLayer *layer, { QgsIdentifyResultsWebViewItem *attrItem = new QgsIdentifyResultsWebViewItem( lstResults ); featItem->addChild( attrItem ); // before setHtml()! - attrItem->setContent( attributes.begin().value().toUtf8(), currentFormat == QgsRaster::IdentifyFormatHtml ? "text/html" : "text/plain" ); + if ( !attributes.isEmpty() ) + { + attrItem->setContent( attributes.begin().value().toUtf8(), currentFormat == QgsRaster::IdentifyFormatHtml ? "text/html" : "text/plain" ); + } + else + { + attrItem->setContent( tr( "No attributes." ).toUtf8(), "text/plain" ); + } } else { diff --git a/src/core/qgscredentials.cpp b/src/core/qgscredentials.cpp index b79ac99f5e3..60e3e863c51 100644 --- a/src/core/qgscredentials.cpp +++ b/src/core/qgscredentials.cpp @@ -54,9 +54,12 @@ bool QgsCredentials::get( QString realm, QString &username, QString &password, Q username = credentials.first; password = credentials.second; QgsDebugMsg( QString( "retrieved realm:%1 username:%2 password:%3" ).arg( realm ).arg( username ).arg( password ) ); - return true; + + if ( !password.isNull() ) + return true; } - else if ( request( realm, username, password, message ) ) + + if ( request( realm, username, password, message ) ) { QgsDebugMsg( QString( "requested realm:%1 username:%2 password:%3" ).arg( realm ).arg( username ).arg( password ) ); return true; @@ -74,7 +77,6 @@ void QgsCredentials::put( QString realm, QString username, QString password ) mCredentialCache.insert( realm, QPair( username, password ) ); } - void QgsCredentials::lock() { mMutex.lock(); diff --git a/src/core/qgscredentials.h b/src/core/qgscredentials.h index ec0f354eae3..2d9a48eeeba 100644 --- a/src/core/qgscredentials.h +++ b/src/core/qgscredentials.h @@ -53,12 +53,19 @@ class CORE_EXPORT QgsCredentials * @note added in 2.4 */ void lock(); + /** * Unlock the instance after being locked. * @note added in 2.4 */ void unlock(); + /** + * Return pointer to mutex + * @note added in 2.4 + */ + QMutex *mutex() { return &mMutex; } + protected: QgsCredentials(); diff --git a/src/core/qgsnetworkaccessmanager.cpp b/src/core/qgsnetworkaccessmanager.cpp index 86f9a0e8e06..f1edf25b2bd 100644 --- a/src/core/qgsnetworkaccessmanager.cpp +++ b/src/core/qgsnetworkaccessmanager.cpp @@ -246,22 +246,23 @@ void QgsNetworkAccessManager::setupDefaultProxyAndCache() if ( this != instance() ) { + Qt::ConnectionType connectionType = thread() == instance()->thread() ? Qt::AutoConnection : Qt::BlockingQueuedConnection; + connect( this, SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ), instance(), SIGNAL( authenticationRequired( QNetworkReply *, QAuthenticator * ) ), - Qt::BlockingQueuedConnection ); + connectionType ); connect( this, SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ), instance(), SIGNAL( proxyAuthenticationRequired( const QNetworkProxy &, QAuthenticator * ) ), - Qt::BlockingQueuedConnection ); + connectionType ); connect( this, SIGNAL( requestTimedOut( QNetworkReply* ) ), - instance(), SIGNAL( requestTimedOut( QNetworkReply* ) ), - Qt::BlockingQueuedConnection ); + instance(), SIGNAL( requestTimedOut( QNetworkReply* ) ) ); #ifndef QT_NO_OPENSSL connect( this, SIGNAL( sslErrors( QNetworkReply *, const QList & ) ), instance(), SIGNAL( sslErrors( QNetworkReply *, const QList & ) ), - Qt::BlockingQueuedConnection ); + connectionType ); #endif } diff --git a/src/providers/wms/qgswmsprovider.cpp b/src/providers/wms/qgswmsprovider.cpp index 247808d1c26..b17ba445a57 100644 --- a/src/providers/wms/qgswmsprovider.cpp +++ b/src/providers/wms/qgswmsprovider.cpp @@ -439,7 +439,7 @@ void QgsWmsProvider::setFormatQueryItem( QUrl &url ) setQueryItem( url, "FORMAT", mSettings.mImageMimeType ); } -QImage *QgsWmsProvider::draw( QgsRectangle const &viewExtent, int pixelWidth, int pixelHeight ) +QImage *QgsWmsProvider::draw( QgsRectangle const &viewExtent, int pixelWidth, int pixelHeight ) { QgsDebugMsg( "Entering." );