QGIS API Documentation  3.27.0-Master (aef1b1ec20)
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 "qgis.h"
20 #include "qgsauthconfig.h"
21 #include "qgsauthmethod.h"
22 #include "qgslogger.h"
23 #include "qgsmessageoutput.h"
24 #include "qgsmessagelog.h"
25 #include "qgsauthmethodmetadata.h"
26 
27 #ifdef HAVE_STATIC_PROVIDERS
28 #include "qgsauthbasicmethod.h"
29 #include "qgsauthesritokenmethod.h"
30 #include "qgsauthidentcertmethod.h"
31 #ifdef HAVE_OAUTH2_PLUGIN
32 #include "qgsauthoauth2method.h"
33 #endif
34 #include "qgsauthpkipathsmethod.h"
35 #include "qgsauthpkcs12method.h"
36 #endif
37 
38 #include <QString>
39 #include <QDir>
40 #include <QLibrary>
41 #include <QRegularExpression>
42 
43 
44 static QgsAuthMethodRegistry *sInstance = nullptr;
45 
46 
48 {
49  if ( !sInstance )
50  {
51  static QMutex sMutex;
52  const QMutexLocker locker( &sMutex );
53  if ( !sInstance )
54  {
55  sInstance = new QgsAuthMethodRegistry( pluginPath );
56  }
57  }
58  return sInstance;
59 }
60 
69 static QgsAuthMethodMetadata *findMetadata_( QgsAuthMethodRegistry::AuthMethods const &metaData,
70  QString const &authMethodKey )
71 {
72  const QgsAuthMethodRegistry::AuthMethods::const_iterator i =
73  metaData.find( authMethodKey );
74 
75  if ( i != metaData.end() )
76  {
77  return i->second;
78  }
79 
80  return nullptr;
81 }
82 
83 QgsAuthMethodRegistry::QgsAuthMethodRegistry( const QString &pluginPath )
84 {
85  // At startup, examine the libs in the qgis/lib dir and store those that
86  // are an auth method shared lib
87  // check all libs in the current plugin directory and get name and descriptions
88 #if 0
89  char **argv = qApp->argv();
90  QString appDir = argv[0];
91  int bin = appDir.findRev( "/bin", -1, false );
92  QString baseDir = appDir.left( bin );
93  QString mLibraryDirectory = baseDir + "/lib";
94 #endif
95  mLibraryDirectory.setPath( pluginPath );
96  mLibraryDirectory.setSorting( QDir::Name | QDir::IgnoreCase );
97  mLibraryDirectory.setFilter( QDir::Files | QDir::NoSymLinks );
98 
99  init();
100 }
101 
102 void QgsAuthMethodRegistry::init()
103 {
104 #ifdef HAVE_STATIC_PROVIDERS
105  mAuthMethods[ QgsAuthBasicMethod::AUTH_METHOD_KEY] = new QgsAuthBasicMethodMetadata();
106  mAuthMethods[ QgsAuthEsriTokenMethod::AUTH_METHOD_KEY] = new QgsAuthEsriTokenMethodMetadata();
107  mAuthMethods[ QgsAuthIdentCertMethod::AUTH_METHOD_KEY] = new QgsAuthIdentCertMethodMetadata();
108 #ifdef HAVE_OAUTH2_PLUGIN
109  mAuthMethods[ QgsAuthOAuth2Method::AUTH_METHOD_KEY] = new QgsAuthOAuth2MethodMetadata();
110 #endif
111  mAuthMethods[ QgsAuthPkiPathsMethod::AUTH_METHOD_KEY] = new QgsAuthPkiPathsMethodMetadata();
112  mAuthMethods[ QgsAuthPkcs12Method::AUTH_METHOD_KEY] = new QgsAuthPkcs12MethodMetadata();
113 #else
114  typedef QgsAuthMethodMetadata *factory_function( );
115 
116 #if defined(Q_OS_WIN) || defined(__CYGWIN__)
117  mLibraryDirectory.setNameFilters( QStringList( "*authmethod_*.dll" ) );
118 #else
119  mLibraryDirectory.setNameFilters( QStringList( QStringLiteral( "*authmethod_*.so" ) ) );
120 #endif
121  QgsDebugMsgLevel( QStringLiteral( "Checking for auth method plugins in: %1" ).arg( mLibraryDirectory.path() ), 2 );
122 
123  if ( mLibraryDirectory.count() == 0 )
124  {
125  QString msg = QObject::tr( "No QGIS auth method plugins found in:\n%1\n" ).arg( mLibraryDirectory.path() );
126  msg += QObject::tr( "No authentication methods can be used. Check your QGIS installation" );
127 
129  output->setTitle( QObject::tr( "No Authentication Methods" ) );
131  output->showMessage();
132  return;
133  }
134 
135  // auth method file regex pattern, only files matching the pattern are loaded if the variable is defined
136  const QString filePattern = getenv( "QGIS_AUTHMETHOD_FILE" );
137  QRegularExpression fileRegexp;
138  if ( !filePattern.isEmpty() )
139  {
140  fileRegexp.setPattern( filePattern );
141  }
142 
143  QListIterator<QFileInfo> it( mLibraryDirectory.entryInfoList() );
144  while ( it.hasNext() )
145  {
146  const QFileInfo fi( it.next() );
147 
148  if ( !filePattern.isEmpty() )
149  {
150  if ( fi.fileName().indexOf( fileRegexp ) == -1 )
151  {
152  QgsDebugMsg( "auth method " + fi.fileName() + " skipped because doesn't match pattern " + filePattern );
153  continue;
154  }
155  }
156 
157  QLibrary myLib( fi.filePath() );
158  if ( !myLib.load() )
159  {
160  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (lib not loadable): %2" ).arg( myLib.fileName(), myLib.errorString() ) );
161  continue;
162  }
163 
164  bool libraryLoaded { false };
165  QFunctionPointer func = myLib.resolve( QStringLiteral( "authMethodMetadataFactory" ).toLatin1().data() );
166  factory_function *function = reinterpret_cast< factory_function * >( cast_to_fptr( func ) );
167  if ( function )
168  {
169  QgsAuthMethodMetadata *meta = function();
170  if ( meta )
171  {
172  if ( findMetadata_( mAuthMethods, meta->key() ) )
173  {
174  QgsDebugMsg( QStringLiteral( "Checking %1: ...invalid (key %2 already registered)" ).arg( myLib.fileName() ).arg( meta->key() ) );
175  delete meta;
176  continue;
177  }
178  // add this method to the map
179  mAuthMethods[meta->key()] = meta;
180  libraryLoaded = true;
181  }
182  }
183  if ( ! libraryLoaded )
184  {
185  QgsDebugMsgLevel( QStringLiteral( "Checking %1: ...invalid (no authMethodMetadataFactory method)" ).arg( myLib.fileName() ), 2 );
186  }
187  }
188 #endif
189 }
190 
191 // typedef for the unload auth method function
192 typedef void cleanupAuthMethod_t();
193 
195 {
196  clean();
197  if ( sInstance == this )
198  sInstance = nullptr;
199 };
200 
201 void QgsAuthMethodRegistry::clean()
202 {
203  AuthMethods::const_iterator it = mAuthMethods.begin();
204 
205  while ( it != mAuthMethods.end() )
206  {
207  QgsDebugMsgLevel( QStringLiteral( "cleanup: %1" ).arg( it->first ), 5 );
208  const QString lib = it->second->library();
209  QLibrary myLib( lib );
210  if ( myLib.isLoaded() )
211  {
212  cleanupAuthMethod_t *cleanupFunc = reinterpret_cast< cleanupAuthMethod_t * >( cast_to_fptr( myLib.resolve( "cleanupAuthMethod" ) ) );
213  if ( cleanupFunc )
214  cleanupFunc();
215  }
216  // clear cached QgsAuthMethodMetadata *
217  delete it->second;
218  ++it;
219  }
220 }
221 
222 
223 QString QgsAuthMethodRegistry::library( const QString &authMethodKey ) const
224 {
225  QgsAuthMethodMetadata *md = findMetadata_( mAuthMethods, authMethodKey );
226 
227  if ( md )
228  {
230  return md->library();
232  }
233 
234  return QString();
235 }
236 
237 QString QgsAuthMethodRegistry::pluginList( bool asHtml ) const
238 {
239  AuthMethods::const_iterator it = mAuthMethods.begin();
240 
241  if ( mAuthMethods.empty() )
242  {
243  return QObject::tr( "No authentication method plugins are available." );
244  }
245 
246  QString list;
247 
248  if ( asHtml )
249  {
250  list += QLatin1String( "<ol>" );
251  }
252 
253  while ( it != mAuthMethods.end() )
254  {
255  if ( asHtml )
256  {
257  list += QLatin1String( "<li>" );
258  }
259 
260  list += it->second->description();
261 
262  if ( asHtml )
263  {
264  list += QLatin1String( "<br></li>" );
265  }
266  else
267  {
268  list += '\n';
269  }
270 
271  ++it;
272  }
273 
274  if ( asHtml )
275  {
276  list += QLatin1String( "</ol>" );
277  }
278 
279  return list;
280 }
281 
283 {
284  return mLibraryDirectory;
285 }
286 
288 {
289  mLibraryDirectory = path;
290 }
291 
292 
293 // typedef for the QgsAuthMethod class factory
295 
296 const QgsAuthMethodMetadata *QgsAuthMethodRegistry::authMethodMetadata( const QString &authMethodKey ) const
297 {
298  return findMetadata_( mAuthMethods, authMethodKey );
299 }
300 
302 {
303  QgsAuthMethodMetadata *metadata = findMetadata_( mAuthMethods, authMethodKey );
304  if ( !metadata )
305  {
306  QgsMessageLog::logMessage( QObject::tr( "Invalid auth method %1" ).arg( authMethodKey ) );
307  return nullptr;
308  }
309 
310  return metadata->createAuthMethod();
311 }
312 
314 {
315  QStringList lst;
316  for ( AuthMethods::const_iterator it = mAuthMethods.begin(); it != mAuthMethods.end(); ++it )
317  {
318  lst.append( it->first );
319  }
320  return lst;
321 }
322 
323 
Holds data auth method key, description, and associated shared library file information.
virtual QgsAuthMethod * createAuthMethod() const
Class factory to return a pointer to a newly created QgsDataProvider object.
QString key() const
Returns the unique key associated with the method.
QString library() const
Returns the library file name.
A registry / canonical manager of authentication methods.
const QgsAuthMethodMetadata * authMethodMetadata(const QString &authMethodKey) const
Returns metadata of the auth method or nullptr if not found.
static QgsAuthMethodRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString pluginList(bool asHtml=false) const
Returns list of auth method plugins found.
void setLibraryDirectory(const QDir &path)
Sets library directory where to search for plugins.
QDir libraryDirectory() const
Returns library directory where plugins are found.
virtual ~QgsAuthMethodRegistry()
Virtual dectructor.
Q_DECL_DEPRECATED QString library(const QString &authMethodKey) const
Returns path for the library of the auth method.
QStringList authMethodList() const
Returns list of available auth methods by their keys.
std::map< QString, QgsAuthMethodMetadata * > AuthMethods
Type for auth method metadata associative container.
QgsAuthMethod * createAuthMethod(const QString &authMethodKey)
Create an instance of the auth method.
Abstract base class for authentication method plugins.
Definition: qgsauthmethod.h:43
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Interface for showing messages from QGIS in GUI independent way.
virtual void showMessage(bool blocking=true)=0
display the message to the user and deletes itself
static QgsMessageOutput * createMessageOutput()
function that returns new class derived from QgsMessageOutput (don't forget to delete it then if show...
virtual void setMessage(const QString &message, MessageType msgType)=0
Sets message, it won't be displayed until.
virtual void setTitle(const QString &title)=0
Sets title for the messages.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2815
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2814
#define cast_to_fptr(f)
Definition: qgis.h:2132
void cleanupAuthMethod_t()
QgsAuthMethod * classFactoryFunction_t()
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38