Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsauthmethodregistry.cpp 3 : : --------------------- 4 : : begin : September 1, 2015 5 : : copyright : (C) 2015 by Boundless Spatial, Inc. USA 6 : : author : Larry Shaffer 7 : : email : lshaffer at boundlessgeo dot com 8 : : *************************************************************************** 9 : : * * 10 : : * This program is free software; you can redistribute it and/or modify * 11 : : * it under the terms of the GNU General Public License as published by * 12 : : * the Free Software Foundation; either version 2 of the License, or * 13 : : * (at your option) any later version. * 14 : : * * 15 : : ***************************************************************************/ 16 : : 17 : : #include "qgsauthmethodregistry.h" 18 : : 19 : : #include <QString> 20 : : #include <QDir> 21 : : #include <QLibrary> 22 : : 23 : : #include "qgis.h" 24 : : #include "qgsauthconfig.h" 25 : : #include "qgsauthmethod.h" 26 : : #include "qgslogger.h" 27 : : #include "qgsmessageoutput.h" 28 : : #include "qgsmessagelog.h" 29 : : #include "qgsauthmethodmetadata.h" 30 : : 31 : : 32 : : // typedefs for auth method plugin functions of interest 33 : : typedef QString methodkey_t(); 34 : : typedef QString description_t(); 35 : : typedef bool isauthmethod_t(); 36 : : 37 : : 38 : 3 : QgsAuthMethodRegistry *QgsAuthMethodRegistry::instance( const QString &pluginPath ) 39 : : { 40 : 3 : static QgsAuthMethodRegistry *sInstance( new QgsAuthMethodRegistry( pluginPath ) ); 41 : 3 : return sInstance; 42 : 0 : } 43 : : 44 : 3 : QgsAuthMethodRegistry::QgsAuthMethodRegistry( const QString &pluginPath ) 45 : 3 : { 46 : : // At startup, examine the libs in the qgis/lib dir and store those that 47 : : // are an auth method shared lib 48 : : // check all libs in the current plugin directory and get name and descriptions 49 : : #if 0 50 : : char **argv = qApp->argv(); 51 : : QString appDir = argv[0]; 52 : : int bin = appDir.findRev( "/bin", -1, false ); 53 : : QString baseDir = appDir.left( bin ); 54 : : QString mLibraryDirectory = baseDir + "/lib"; 55 : : #endif 56 : 3 : mLibraryDirectory.setPath( pluginPath ); 57 : 3 : mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase ); 58 : 3 : mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks ); 59 : : 60 : : #if defined(Q_OS_WIN) || defined(__CYGWIN__) 61 : : mLibraryDirectory.setNameFilters( QStringList( "*authmethod.dll" ) ); 62 : : #else 63 : 6 : mLibraryDirectory.setNameFilters( QStringList( QStringLiteral( "*authmethod.so" ) ) ); 64 : : #endif 65 : : 66 : 3 : QgsDebugMsgLevel( QStringLiteral( "Checking for auth method plugins in: %1" ).arg( mLibraryDirectory.path() ), 2 ); 67 : : 68 : 3 : if ( mLibraryDirectory.count() == 0 ) 69 : : { 70 : 3 : QString msg = QObject::tr( "No QGIS auth method plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() ); 71 : 3 : msg += QObject::tr( "No authentication methods can be used. Check your QGIS installation" ); 72 : : 73 : 3 : QgsMessageOutput *output = QgsMessageOutput::createMessageOutput(); 74 : 3 : output->setTitle( QObject::tr( "No Authentication Methods" ) ); 75 : 3 : output->setMessage( msg, QgsMessageOutput::MessageText ); 76 : 3 : output->showMessage(); 77 : : return; 78 : 3 : } 79 : : 80 : : // auth method file regex pattern, only files matching the pattern are loaded if the variable is defined 81 : 0 : QString filePattern = getenv( "QGIS_AUTHMETHOD_FILE" ); 82 : 0 : QRegExp fileRegexp; 83 : 0 : if ( !filePattern.isEmpty() ) 84 : : { 85 : 0 : fileRegexp.setPattern( filePattern ); 86 : 0 : } 87 : : 88 : 0 : QListIterator<QFileInfo> it( mLibraryDirectory.entryInfoList() ); 89 : 0 : while ( it.hasNext() ) 90 : : { 91 : 0 : QFileInfo fi( it.next() ); 92 : : 93 : 0 : if ( !fileRegexp.isEmpty() ) 94 : : { 95 : 0 : if ( fileRegexp.indexIn( fi.fileName() ) == -1 ) 96 : : { 97 : 0 : QgsDebugMsg( "auth method " + fi.fileName() + " skipped because doesn't match pattern " + filePattern ); 98 : 0 : continue; 99 : : } 100 : 0 : } 101 : : 102 : 0 : QLibrary myLib( fi.filePath() ); 103 : 0 : if ( !myLib.load() ) 104 : : { 105 : 0 : QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName(), myLib.errorString() ) ); 106 : 0 : continue; 107 : : } 108 : : 109 : : // get the description and the key for the auth method plugin 110 : 0 : isauthmethod_t *isAuthMethod = reinterpret_cast< isauthmethod_t * >( cast_to_fptr( myLib.resolve( "isAuthMethod" ) ) ); 111 : 0 : if ( !isAuthMethod ) 112 : : { 113 : 0 : QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (no isAuthMethod method)" ).arg( myLib.fileName() ) ); 114 : 0 : continue; 115 : : } 116 : : 117 : : // check to see if this is an auth method plugin 118 : 0 : if ( !isAuthMethod() ) 119 : : { 120 : 0 : QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (not an auth method)" ).arg( myLib.fileName() ) ); 121 : 0 : continue; 122 : : } 123 : : 124 : : // looks like an auth method plugin. get the key and description 125 : 0 : description_t *pDesc = reinterpret_cast< description_t * >( cast_to_fptr( myLib.resolve( "description" ) ) ); 126 : 0 : if ( !pDesc ) 127 : : { 128 : 0 : QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (no description method)" ).arg( myLib.fileName() ) ); 129 : 0 : continue; 130 : : } 131 : : 132 : 0 : methodkey_t *pKey = reinterpret_cast< methodkey_t * >( cast_to_fptr( myLib.resolve( "authMethodKey" ) ) ); 133 : 0 : if ( !pKey ) 134 : : { 135 : 0 : QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (no authMethodKey method)" ).arg( myLib.fileName() ) ); 136 : 0 : continue; 137 : : } 138 : : 139 : : // add this auth method to the method map 140 : 0 : mAuthMethods[pKey()] = new QgsAuthMethodMetadata( pKey(), pDesc(), myLib.fileName() ); 141 : : 142 : 0 : } 143 : 3 : } 144 : : 145 : : // typedef for the unload auth method function 146 : : typedef void cleanupAuthMethod_t(); 147 : : 148 : 0 : QgsAuthMethodRegistry::~QgsAuthMethodRegistry() 149 : 0 : { 150 : 0 : AuthMethods::const_iterator it = mAuthMethods.begin(); 151 : : 152 : 0 : while ( it != mAuthMethods.end() ) 153 : : { 154 : 0 : QgsDebugMsgLevel( QStringLiteral( "cleanup: %1" ).arg( it->first ), 5 ); 155 : 0 : QString lib = it->second->library(); 156 : 0 : QLibrary myLib( lib ); 157 : 0 : if ( myLib.isLoaded() ) 158 : : { 159 : 0 : cleanupAuthMethod_t *cleanupFunc = reinterpret_cast< cleanupAuthMethod_t * >( cast_to_fptr( myLib.resolve( "cleanupAuthMethod" ) ) ); 160 : 0 : if ( cleanupFunc ) 161 : 0 : cleanupFunc(); 162 : 0 : } 163 : : // clear cached QgsAuthMethodMetadata * 164 : 0 : delete it->second; 165 : 0 : ++it; 166 : 0 : } 167 : 0 : } 168 : : 169 : : 170 : : /** 171 : : * Convenience function for finding any existing auth methods that match "authMethodKey" 172 : : 173 : : Necessary because [] map operator will create a QgsProviderMetadata 174 : : instance. Also you cannot use the map [] operator in const members for that 175 : : very reason. So there needs to be a convenient way to find an auth method 176 : : without accidentally adding a null meta data item to the metadata map. 177 : : */ 178 : 0 : static QgsAuthMethodMetadata *findMetadata_( QgsAuthMethodRegistry::AuthMethods const &metaData, 179 : : QString const &authMethodKey ) 180 : : { 181 : : QgsAuthMethodRegistry::AuthMethods::const_iterator i = 182 : 0 : metaData.find( authMethodKey ); 183 : : 184 : 0 : if ( i != metaData.end() ) 185 : : { 186 : 0 : return i->second; 187 : : } 188 : : 189 : 0 : return nullptr; 190 : 0 : } // findMetadata_ 191 : : 192 : : 193 : 0 : QString QgsAuthMethodRegistry::library( const QString &authMethodKey ) const 194 : : { 195 : 0 : QgsAuthMethodMetadata *md = findMetadata_( mAuthMethods, authMethodKey ); 196 : : 197 : 0 : if ( md ) 198 : : { 199 : 0 : return md->library(); 200 : : } 201 : : 202 : 0 : return QString(); 203 : 0 : } 204 : : 205 : 0 : QString QgsAuthMethodRegistry::pluginList( bool asHtml ) const 206 : : { 207 : 0 : AuthMethods::const_iterator it = mAuthMethods.begin(); 208 : : 209 : 0 : if ( mAuthMethods.empty() ) 210 : : { 211 : 0 : return QObject::tr( "No authentication method plugins are available." ); 212 : : } 213 : : 214 : 0 : QString list; 215 : : 216 : 0 : if ( asHtml ) 217 : : { 218 : 0 : list += QLatin1String( "<ol>" ); 219 : 0 : } 220 : : 221 : 0 : while ( it != mAuthMethods.end() ) 222 : : { 223 : 0 : if ( asHtml ) 224 : : { 225 : 0 : list += QLatin1String( "<li>" ); 226 : 0 : } 227 : : 228 : 0 : list += it->second->description(); 229 : : 230 : 0 : if ( asHtml ) 231 : : { 232 : 0 : list += QLatin1String( "<br></li>" ); 233 : 0 : } 234 : : else 235 : : { 236 : 0 : list += '\n'; 237 : : } 238 : : 239 : 0 : ++it; 240 : : } 241 : : 242 : 0 : if ( asHtml ) 243 : : { 244 : 0 : list += QLatin1String( "</ol>" ); 245 : 0 : } 246 : : 247 : 0 : return list; 248 : 0 : } 249 : : 250 : 0 : QDir QgsAuthMethodRegistry::libraryDirectory() const 251 : : { 252 : 0 : return mLibraryDirectory; 253 : : } 254 : : 255 : 0 : void QgsAuthMethodRegistry::setLibraryDirectory( const QDir &path ) 256 : : { 257 : 0 : mLibraryDirectory = path; 258 : 0 : } 259 : : 260 : : 261 : : // typedef for the QgsDataProvider class factory 262 : : typedef QgsAuthMethod *classFactoryFunction_t(); 263 : : 264 : 0 : std::unique_ptr<QgsAuthMethod> QgsAuthMethodRegistry::authMethod( const QString &authMethodKey ) 265 : : { 266 : : // load the plugin 267 : 0 : QString lib = library( authMethodKey ); 268 : : 269 : : #ifdef TESTAUTHMETHODLIB 270 : : const char *cLib = lib.toUtf8(); 271 : : 272 : : // test code to help debug auth method plugin loading problems 273 : : // void *handle = dlopen(cLib, RTLD_LAZY); 274 : : void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL ); 275 : : if ( !handle ) 276 : : { 277 : : QgsLogger::warning( "Error in dlopen" ); 278 : : } 279 : : else 280 : : { 281 : : QgsDebugMsg( QStringLiteral( "dlopen succeeded" ) ); 282 : : dlclose( handle ); 283 : : } 284 : : 285 : : #endif 286 : : // load the auth method 287 : 0 : QLibrary myLib( lib ); 288 : : 289 : 0 : QgsDebugMsgLevel( "Auth method library name is " + myLib.fileName(), 2 ); 290 : 0 : if ( !myLib.load() ) 291 : : { 292 : 0 : QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib, myLib.errorString() ) ); 293 : 0 : return nullptr; 294 : : } 295 : : 296 : 0 : classFactoryFunction_t *classFactory = reinterpret_cast< classFactoryFunction_t * >( cast_to_fptr( myLib.resolve( "classFactory" ) ) ); 297 : 0 : if ( !classFactory ) 298 : : { 299 : 0 : QgsDebugMsg( QStringLiteral( "Failed to load %1: no classFactory method" ).arg( lib ) ); 300 : 0 : return nullptr; 301 : : } 302 : : 303 : 0 : std::unique_ptr< QgsAuthMethod > authMethod( classFactory() ); 304 : 0 : if ( !authMethod ) 305 : : { 306 : 0 : QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the auth method plugin %1" ).arg( lib ) ); 307 : 0 : myLib.unload(); 308 : 0 : return nullptr; 309 : : } 310 : : 311 : 0 : QgsDebugMsgLevel( QStringLiteral( "Instantiated the auth method plugin: %1" ).arg( authMethod->key() ), 2 ); 312 : 0 : return authMethod; 313 : 0 : } 314 : : 315 : : typedef QWidget *editFactoryFunction_t( QWidget *parent ); 316 : : 317 : 0 : QWidget *QgsAuthMethodRegistry::editWidget( const QString &authMethodKey, QWidget *parent ) 318 : : { 319 : 0 : editFactoryFunction_t *editFactory = 320 : 0 : reinterpret_cast< editFactoryFunction_t * >( cast_to_fptr( function( authMethodKey, QStringLiteral( "editWidget" ) ) ) ); 321 : : 322 : 0 : if ( !editFactory ) 323 : 0 : return nullptr; 324 : : 325 : 0 : return editFactory( parent ); 326 : 0 : } 327 : : 328 : 0 : QFunctionPointer QgsAuthMethodRegistry::function( QString const &authMethodKey, 329 : : QString const &functionName ) 330 : : { 331 : 0 : QLibrary myLib( library( authMethodKey ) ); 332 : : 333 : 0 : QgsDebugMsgLevel( "Library name is " + myLib.fileName(), 2 ); 334 : : 335 : 0 : if ( myLib.load() ) 336 : : { 337 : 0 : return myLib.resolve( functionName.toLatin1().data() ); 338 : : } 339 : : else 340 : : { 341 : 0 : QgsDebugMsg( "Cannot load library: " + myLib.errorString() ); 342 : 0 : return nullptr; 343 : : } 344 : 0 : } 345 : : 346 : 0 : std::unique_ptr<QLibrary> QgsAuthMethodRegistry::authMethodLibrary( const QString &authMethodKey ) const 347 : : { 348 : 0 : std::unique_ptr< QLibrary > myLib( new QLibrary( library( authMethodKey ) ) ); 349 : : 350 : 0 : QgsDebugMsgLevel( "Library name is " + myLib->fileName(), 2 ); 351 : : 352 : 0 : if ( myLib->load() ) 353 : 0 : return myLib; 354 : : 355 : 0 : QgsDebugMsg( "Cannot load library: " + myLib->errorString() ); 356 : 0 : return nullptr; 357 : 0 : } 358 : : 359 : 3 : QStringList QgsAuthMethodRegistry::authMethodList() const 360 : : { 361 : 3 : QStringList lst; 362 : 3 : for ( AuthMethods::const_iterator it = mAuthMethods.begin(); it != mAuthMethods.end(); ++it ) 363 : : { 364 : 0 : lst.append( it->first ); 365 : 0 : } 366 : 3 : return lst; 367 : 3 : } 368 : : 369 : 0 : const QgsAuthMethodMetadata *QgsAuthMethodRegistry::authMethodMetadata( const QString &authMethodKey ) const 370 : : { 371 : 0 : return findMetadata_( mAuthMethods, authMethodKey ); 372 : : }