QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsauthmethodregistry.cpp
Go to the documentation of this file.
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 
39 {
40  static QgsAuthMethodRegistry *sInstance( new QgsAuthMethodRegistry( pluginPath ) );
41  return sInstance;
42 }
43 
44 QgsAuthMethodRegistry::QgsAuthMethodRegistry( const QString &pluginPath )
45 {
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  mLibraryDirectory = pluginPath;
57  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
58  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
59 
60 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
61  mLibraryDirectory.setNameFilters( QStringList( "*authmethod.dll" ) );
62 #else
63  mLibraryDirectory.setNameFilters( QStringList( QStringLiteral( "*authmethod.so" ) ) );
64 #endif
65 
66  QgsDebugMsg( QStringLiteral( "Checking for auth method plugins in: %1" ).arg( mLibraryDirectory.path() ) );
67 
68  if ( mLibraryDirectory.count() == 0 )
69  {
70  QString msg = QObject::tr( "No QGIS auth method plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() );
71  msg += QObject::tr( "No authentication methods can be used. Check your QGIS installation" );
72 
74  output->setTitle( QObject::tr( "No Authentication Methods" ) );
76  output->showMessage();
77  return;
78  }
79 
80  // auth method file regex pattern, only files matching the pattern are loaded if the variable is defined
81  QString filePattern = getenv( "QGIS_AUTHMETHOD_FILE" );
82  QRegExp fileRegexp;
83  if ( !filePattern.isEmpty() )
84  {
85  fileRegexp.setPattern( filePattern );
86  }
87 
88  QListIterator<QFileInfo> it( mLibraryDirectory.entryInfoList() );
89  while ( it.hasNext() )
90  {
91  QFileInfo fi( it.next() );
92 
93  if ( !fileRegexp.isEmpty() )
94  {
95  if ( fileRegexp.indexIn( fi.fileName() ) == -1 )
96  {
97  QgsDebugMsg( "auth method " + fi.fileName() + " skipped because doesn't match pattern " + filePattern );
98  continue;
99  }
100  }
101 
102  QLibrary myLib( fi.filePath() );
103  if ( !myLib.load() )
104  {
105  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName(), myLib.errorString() ) );
106  continue;
107  }
108 
109  // get the description and the key for the auth method plugin
110  isauthmethod_t *isAuthMethod = reinterpret_cast< isauthmethod_t * >( cast_to_fptr( myLib.resolve( "isAuthMethod" ) ) );
111  if ( !isAuthMethod )
112  {
113  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (no isAuthMethod method)" ).arg( myLib.fileName() ) );
114  continue;
115  }
116 
117  // check to see if this is an auth method plugin
118  if ( !isAuthMethod() )
119  {
120  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (not an auth method)" ).arg( myLib.fileName() ) );
121  continue;
122  }
123 
124  // looks like an auth method plugin. get the key and description
125  description_t *pDesc = reinterpret_cast< description_t * >( cast_to_fptr( myLib.resolve( "description" ) ) );
126  if ( !pDesc )
127  {
128  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (no description method)" ).arg( myLib.fileName() ) );
129  continue;
130  }
131 
132  methodkey_t *pKey = reinterpret_cast< methodkey_t * >( cast_to_fptr( myLib.resolve( "authMethodKey" ) ) );
133  if ( !pKey )
134  {
135  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (no authMethodKey method)" ).arg( myLib.fileName() ) );
136  continue;
137  }
138 
139  // add this auth method to the method map
140  mAuthMethods[pKey()] = new QgsAuthMethodMetadata( pKey(), pDesc(), myLib.fileName() );
141 
142  }
143 }
144 
145 // typedef for the unload auth method function
146 typedef void cleanupAuthMethod_t();
147 
149 {
150  AuthMethods::const_iterator it = mAuthMethods.begin();
151 
152  while ( it != mAuthMethods.end() )
153  {
154  QgsDebugMsgLevel( QStringLiteral( "cleanup: %1" ).arg( it->first ), 5 );
155  QString lib = it->second->library();
156  QLibrary myLib( lib );
157  if ( myLib.isLoaded() )
158  {
159  cleanupAuthMethod_t *cleanupFunc = reinterpret_cast< cleanupAuthMethod_t * >( cast_to_fptr( myLib.resolve( "cleanupAuthMethod" ) ) );
160  if ( cleanupFunc )
161  cleanupFunc();
162  }
163  // clear cached QgsAuthMethodMetadata *
164  delete it->second;
165  ++it;
166  }
167 }
168 
169 
178 static QgsAuthMethodMetadata *findMetadata_( QgsAuthMethodRegistry::AuthMethods const &metaData,
179  QString const &authMethodKey )
180 {
181  QgsAuthMethodRegistry::AuthMethods::const_iterator i =
182  metaData.find( authMethodKey );
183 
184  if ( i != metaData.end() )
185  {
186  return i->second;
187  }
188 
189  return nullptr;
190 } // findMetadata_
191 
192 
193 QString QgsAuthMethodRegistry::library( const QString &authMethodKey ) const
194 {
195  QgsAuthMethodMetadata *md = findMetadata_( mAuthMethods, authMethodKey );
196 
197  if ( md )
198  {
199  return md->library();
200  }
201 
202  return QString();
203 }
204 
205 QString QgsAuthMethodRegistry::pluginList( bool asHtml ) const
206 {
207  AuthMethods::const_iterator it = mAuthMethods.begin();
208 
209  if ( mAuthMethods.empty() )
210  {
211  return QObject::tr( "No authentication method plugins are available." );
212  }
213 
214  QString list;
215 
216  if ( asHtml )
217  {
218  list += QLatin1String( "<ol>" );
219  }
220 
221  while ( it != mAuthMethods.end() )
222  {
223  if ( asHtml )
224  {
225  list += QLatin1String( "<li>" );
226  }
227 
228  list += it->second->description();
229 
230  if ( asHtml )
231  {
232  list += QLatin1String( "<br></li>" );
233  }
234  else
235  {
236  list += '\n';
237  }
238 
239  ++it;
240  }
241 
242  if ( asHtml )
243  {
244  list += QLatin1String( "</ol>" );
245  }
246 
247  return list;
248 }
249 
251 {
252  return mLibraryDirectory;
253 }
254 
256 {
257  mLibraryDirectory = path;
258 }
259 
260 
261 // typedef for the QgsDataProvider class factory
263 
264 std::unique_ptr<QgsAuthMethod> QgsAuthMethodRegistry::authMethod( const QString &authMethodKey )
265 {
266  // load the plugin
267  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  QLibrary myLib( lib );
288 
289  QgsDebugMsg( "Auth method library name is " + myLib.fileName() );
290  if ( !myLib.load() )
291  {
292  QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib, myLib.errorString() ) );
293  return nullptr;
294  }
295 
296  classFactoryFunction_t *classFactory = reinterpret_cast< classFactoryFunction_t * >( cast_to_fptr( myLib.resolve( "classFactory" ) ) );
297  if ( !classFactory )
298  {
299  QgsDebugMsg( QStringLiteral( "Failed to load %1: no classFactory method" ).arg( lib ) );
300  return nullptr;
301  }
302 
303  std::unique_ptr< QgsAuthMethod > authMethod( classFactory() );
304  if ( !authMethod )
305  {
306  QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the auth method plugin %1" ).arg( lib ) );
307  myLib.unload();
308  return nullptr;
309  }
310 
311  QgsDebugMsg( QStringLiteral( "Instantiated the auth method plugin: %1" ).arg( authMethod->key() ) );
312  return authMethod;
313 }
314 
315 typedef QWidget *editFactoryFunction_t( QWidget *parent );
316 
317 QWidget *QgsAuthMethodRegistry::editWidget( const QString &authMethodKey, QWidget *parent )
318 {
319  editFactoryFunction_t *editFactory =
320  reinterpret_cast< editFactoryFunction_t * >( cast_to_fptr( function( authMethodKey, QStringLiteral( "editWidget" ) ) ) );
321 
322  if ( !editFactory )
323  return nullptr;
324 
325  return editFactory( parent );
326 }
327 
328 QFunctionPointer QgsAuthMethodRegistry::function( QString const &authMethodKey,
329  QString const &functionName )
330 {
331  QLibrary myLib( library( authMethodKey ) );
332 
333  QgsDebugMsg( "Library name is " + myLib.fileName() );
334 
335  if ( myLib.load() )
336  {
337  return myLib.resolve( functionName.toLatin1().data() );
338  }
339  else
340  {
341  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
342  return nullptr;
343  }
344 }
345 
346 std::unique_ptr<QLibrary> QgsAuthMethodRegistry::authMethodLibrary( const QString &authMethodKey ) const
347 {
348  std::unique_ptr< QLibrary > myLib( new QLibrary( library( authMethodKey ) ) );
349 
350  QgsDebugMsg( "Library name is " + myLib->fileName() );
351 
352  if ( myLib->load() )
353  return myLib;
354 
355  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
356  return nullptr;
357 }
358 
360 {
361  QStringList lst;
362  for ( AuthMethods::const_iterator it = mAuthMethods.begin(); it != mAuthMethods.end(); ++it )
363  {
364  lst.append( it->first );
365  }
366  return lst;
367 }
368 
369 const QgsAuthMethodMetadata *QgsAuthMethodRegistry::authMethodMetadata( const QString &authMethodKey ) const
370 {
371  return findMetadata_( mAuthMethods, authMethodKey );
372 }
virtual void setTitle(const QString &title)=0
Sets title for the messages.
QStringList authMethodList() const
Returns list of available auth methods by their keys.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:121
Holds data auth method key, description, and associated shared library file information.
static QgsMessageOutput * createMessageOutput()
function that returns new class derived from QgsMessageOutput (don&#39;t forget to delete it then if show...
std::unique_ptr< QgsAuthMethod > authMethod(const QString &authMethodKey)
Create an instance of the auth method.
A registry / canonical manager of authentication methods.
QFunctionPointer function(const QString &authMethodKey, const QString &functionName)
Gets pointer to auth method function.
QWidget * editWidget(const QString &authMethodKey, QWidget *parent=nullptr)
Returns the auth method capabilities.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QString pluginList(bool asHtml=false) const
Returns list of auth method plugins found.
virtual void setMessage(const QString &message, MessageType msgType)=0
Sets message, it won&#39;t be displayed until.
std::map< QString, QgsAuthMethodMetadata * > AuthMethods
Type for auth method metadata associative container.
QString methodkey_t()
#define cast_to_fptr(f)
Definition: qgis.h:158
QString library() const
This returns the library file name.
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
void cleanupAuthMethod_t()
Abstract base class for authentication method plugins.
Definition: qgsauthmethod.h:36
const QgsAuthMethodMetadata * authMethodMetadata(const QString &authMethodKey) const
Returns metadata of the auth method or nullptr if not found.
void setLibraryDirectory(const QDir &path)
Sets library directory where to search for plugins.
QString library(const QString &authMethodKey) const
Returns path for the library of the auth method.
QgsAuthMethod * classFactoryFunction_t()
QWidget * editFactoryFunction_t(QWidget *parent)
Interface for showing messages from QGIS in GUI independent way.
static QgsAuthMethodRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
virtual ~QgsAuthMethodRegistry()
Virtual dectructor.
QString description_t()
bool isauthmethod_t()
QDir libraryDirectory() const
Returns library directory where plugins are found.
std::unique_ptr< QLibrary > authMethodLibrary(const QString &authMethodKey) const
Returns the library object associated with an auth method key.