QGIS API Documentation  2.18.3-Las Palmas (77b8c3d)
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();
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( "*authmethod.so" ) );
64 #endif
65 
66  QgsDebugMsg( QString( "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( QString( "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( QString( "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( QString( "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( QString( "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( QString( "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  QgsDebugMsg( QString( "cleanup: %1" ).arg( it->first ) );
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  QString const & authMethodKey )
179 {
180  QgsAuthMethodRegistry::AuthMethods::const_iterator i =
181  metaData.find( authMethodKey );
182 
183  if ( i != metaData.end() )
184  {
185  return i->second;
186  }
187 
188  return nullptr;
189 } // findMetadata_
190 
191 
192 QString QgsAuthMethodRegistry::library( const QString &authMethodKey ) const
193 {
194  QgsAuthMethodMetadata * md = findMetadata_( mAuthMethods, authMethodKey );
195 
196  if ( md )
197  {
198  return md->library();
199  }
200 
201  return QString();
202 }
203 
205 {
206  AuthMethods::const_iterator it = mAuthMethods.begin();
207 
208  if ( mAuthMethods.empty() )
209  {
210  return QObject::tr( "No authentication method plugins are available." );
211  }
212 
213  QString list;
214 
215  if ( asHtml )
216  {
217  list += "<ol>";
218  }
219 
220  while ( it != mAuthMethods.end() )
221  {
222  if ( asHtml )
223  {
224  list += "<li>";
225  }
226 
227  list += it->second->description();
228 
229  if ( asHtml )
230  {
231  list + "<br></li>";
232  }
233  else
234  {
235  list += '\n';
236  }
237 
238  ++it;
239  }
240 
241  if ( asHtml )
242  {
243  list += "</ol>";
244  }
245 
246  return list;
247 }
248 
250 {
251  return mLibraryDirectory;
252 }
253 
255 {
256  mLibraryDirectory = path;
257 }
258 
259 
260 // typedef for the QgsDataProvider class factory
262 
264 {
265  // load the plugin
266  QString lib = library( authMethodKey );
267 
268 #ifdef TESTAUTHMETHODLIB
269  const char *cLib = lib.toUtf8();
270 
271  // test code to help debug auth method plugin loading problems
272  // void *handle = dlopen(cLib, RTLD_LAZY);
273  void *handle = dlopen( cOgrLib, RTLD_LAZY | RTLD_GLOBAL );
274  if ( !handle )
275  {
276  QgsLogger::warning( "Error in dlopen" );
277  }
278  else
279  {
280  QgsDebugMsg( "dlopen succeeded" );
281  dlclose( handle );
282  }
283 
284 #endif
285  // load the auth method
286  QLibrary myLib( lib );
287 
288  QgsDebugMsg( "Auth method library name is " + myLib.fileName() );
289  if ( !myLib.load() )
290  {
291  QgsMessageLog::logMessage( QObject::tr( "Failed to load %1: %2" ).arg( lib, myLib.errorString() ) );
292  return nullptr;
293  }
294 
295  classFactoryFunction_t *classFactory = reinterpret_cast< classFactoryFunction_t * >( cast_to_fptr( myLib.resolve( "classFactory" ) ) );
296  if ( !classFactory )
297  {
298  QgsDebugMsg( QString( "Failed to load %1: no classFactory method" ).arg( lib ) );
299  return nullptr;
300  }
301 
302  QgsAuthMethod *authMethod = classFactory();
303  if ( !authMethod )
304  {
305  QgsMessageLog::logMessage( QObject::tr( "Unable to instantiate the auth method plugin %1" ).arg( lib ) );
306  myLib.unload();
307  return nullptr;
308  }
309 
310  QgsDebugMsg( QString( "Instantiated the auth method plugin: %1" ).arg( authMethod->key() ) );
311  return authMethod;
312 }
313 
314 typedef QWidget * editFactoryFunction_t( QWidget * parent );
315 
316 QWidget *QgsAuthMethodRegistry::editWidget( const QString &authMethodKey, QWidget *parent )
317 {
318  editFactoryFunction_t * editFactory =
319  reinterpret_cast< editFactoryFunction_t * >( cast_to_fptr( function( authMethodKey, "editWidget" ) ) );
320 
321  if ( !editFactory )
322  return nullptr;
323 
324  return editFactory( parent );
325 }
326 
327 #if QT_VERSION >= 0x050000
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.toAscii().data() );
338  }
339  else
340  {
341  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
342  return 0;
343  }
344 }
345 #else
346 void *QgsAuthMethodRegistry::function( QString const & authMethodKey,
347  QString const & functionName )
348 {
349  QLibrary myLib( library( authMethodKey ) );
350 
351  QgsDebugMsg( "Library name is " + myLib.fileName() );
352 
353  if ( myLib.load() )
354  {
355  return myLib.resolve( functionName.toAscii().data() );
356  }
357  else
358  {
359  QgsDebugMsg( "Cannot load library: " + myLib.errorString() );
360  return nullptr;
361  }
362 }
363 #endif
364 
366 {
367  QLibrary *myLib = new QLibrary( library( authMethodKey ) );
368 
369  QgsDebugMsg( "Library name is " + myLib->fileName() );
370 
371  if ( myLib->load() )
372  return myLib;
373 
374  QgsDebugMsg( "Cannot load library: " + myLib->errorString() );
375 
376  delete myLib;
377 
378  return nullptr;
379 }
380 
382 {
383  QStringList lst;
384  for ( AuthMethods::const_iterator it = mAuthMethods.begin(); it != mAuthMethods.end(); ++it )
385  {
386  lst.append( it->first );
387  }
388  return lst;
389 }
390 
392 {
393  return findMetadata_( mAuthMethods, authMethodKey );
394 }
QStringList authMethodList() const
Return list of available auth methods by their keys.
int findRev(QChar c, int i, bool cs) const
bool isEmpty() const
virtual void setTitle(const QString &title)=0
set title for the messages
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
static void warning(const QString &msg)
Goes to qWarning.
Definition: qgslogger.cpp:124
void * function(const QString &authMethodKey, const QString &functionName)
Get pointer to auth method function.
Holds data auth method key, description, and associated shared library file information.
QgsAuthMethod * authMethod(const QString &authMethodKey)
Create an instance of the auth method.
static QgsMessageOutput * createMessageOutput()
function that returns new class derived from QgsMessageOutput (don&#39;t forget to delete it then if show...
bool unload()
const QgsAuthMethodMetadata * authMethodMetadata(const QString &authMethodKey) const
Return metadata of the auth method or nullptr if not found.
QString tr(const char *sourceText, const char *disambiguation, int n)
A registry / canonical manager of authentication methods.
void setPattern(const QString &pattern)
int indexIn(const QString &str, int offset, CaretMode caretMode) const
void append(const T &value)
QLibrary * authMethodLibrary(const QString &authMethodKey) const
Return the library object associated with an auth method key.
QWidget * editWidget(const QString &authMethodKey, QWidget *parent=nullptr)
Return the auth method capabilities.
bool isEmpty() const
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
virtual void setMessage(const QString &message, MessageType msgType)=0
set message, it won&#39;t be displayed until
const QDir & libraryDirectory() const
Return library directory where plugins are found.
QString methodkey_t()
QString library(const QString &authMethodKey) const
Return path for the library of the auth method.
bool isLoaded() const
QString library() const
This returns the library file name.
bool load()
std::map< QString, QgsAuthMethodMetadata * > AuthMethods
Type for auth method metadata associative container.
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:33
QString pluginList(bool asHtml=false) const
Return list of auth method plugins found.
void * resolve(const char *symbol)
int count() const
void setLibraryDirectory(const QDir &path)
Set library directory where to search for plugins.
static QgsAuthMethodMetadata * findMetadata_(QgsAuthMethodRegistry::AuthMethods const &metaData, QString const &authMethodKey)
Convenience function for finding any existing auth methods that match "authMethodKey".
virtual QString key() const =0
A non-translated short name representing the auth method.
char * data()
QString left(int n) const
QgsAuthMethod * classFactoryFunction_t()
QWidget * editFactoryFunction_t(QWidget *parent)
void(*)() cast_to_fptr(void *p)
Definition: qgis.h:272
Interface for showing messages from QGIS in GUI independent way.
static QgsAuthMethodRegistry * instance(const QString &pluginPath=QString::null)
Means of accessing canonical single instance.
virtual ~QgsAuthMethodRegistry()
Virtual dectructor.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
QString description_t()
bool isauthmethod_t()
QByteArray toAscii() const
QString errorString() const
QByteArray toUtf8() const