QGIS API Documentation  3.21.0-Master (5b68dc587e)
qgsauthconfigedit.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsauthconfigedit.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 "qgsauthconfigedit.h"
18 
19 #include <QPushButton>
20 
21 #include "qgsauthmethodmetadata.h"
22 #include "qgsauthconfig.h"
23 #include "qgsauthconfigidedit.h"
24 #include "qgsauthmanager.h"
25 #include "qgsauthmethodedit.h"
26 #include "qgslogger.h"
27 #include "qgsapplication.h"
28 #include "qgsgui.h"
29 
30 QgsAuthConfigEdit::QgsAuthConfigEdit( QWidget *parent, const QString &authcfg, const QString &dataprovider )
31  : QDialog( parent )
32  , mAuthCfg( authcfg )
33  , mDataProvider( dataprovider )
34 
35 {
36  const bool disabled = QgsApplication::authManager()->isDisabled();
37  bool idok = true;
38 
39  if ( !disabled && !authcfg.isEmpty() )
40  {
41  idok = QgsApplication::authManager()->configIds().contains( authcfg );
42  }
43 
44  if ( disabled || !idok )
45  {
46  mAuthNotifyLayout = new QVBoxLayout;
47  this->setLayout( mAuthNotifyLayout );
48 
49  QString msg( disabled ? QgsApplication::authManager()->disabledMessage() : QString() );
50  if ( !authcfg.isEmpty() )
51  {
52  msg += "\n\n" + tr( "Authentication config id not loaded: %1" ).arg( authcfg );
53  }
54  mAuthNotify = new QLabel( msg, this );
55  mAuthNotifyLayout->addWidget( mAuthNotify );
56 
57  mAuthCfg.clear(); // otherwise will continue to try authenticate (and fail) after save
58  buttonBox->button( QDialogButtonBox::Save )->setEnabled( false );
59  }
60  else
61  {
62  setupUi( this );
63  connect( btnClear, &QToolButton::clicked, this, &QgsAuthConfigEdit::btnClear_clicked );
64  connect( leName, &QLineEdit::textChanged, this, &QgsAuthConfigEdit::leName_textChanged );
65  connect( buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close );
66  connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsAuthConfigEdit::saveConfig );
67  connect( buttonBox->button( QDialogButtonBox::Reset ), &QAbstractButton::clicked, this, &QgsAuthConfigEdit::resetConfig );
68 
69  populateAuthMethods();
70 
71  connect( cmbAuthMethods, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ),
72  stkwAuthMethods, &QStackedWidget::setCurrentIndex );
73  connect( cmbAuthMethods, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ),
74  this, [ = ] { validateAuth(); } );
75 
76  connect( authCfgEdit, &QgsAuthConfigIdEdit::validityChanged, this, &QgsAuthConfigEdit::validateAuth );
77 
78  // needed (if only combobox is ever changed)?
79  // connect( stkwAuthMethods, SIGNAL( currentChanged( int ) ),
80  // cmbAuthMethods, SLOT( setCurrentIndex( int ) ) );
81 
82  // connect( stkwAuthMethods, SIGNAL( currentChanged( int ) ),
83  // this, SLOT( validateAuth() ) );
84 
85  if ( cmbAuthMethods->count() > 0 )
86  {
87  cmbAuthMethods->setCurrentIndex( 0 );
88  stkwAuthMethods->setCurrentIndex( 0 );
89  }
90 
91  loadConfig();
92  validateAuth();
93 
94  leName->setFocus();
95  }
96 
98 }
99 
100 void QgsAuthConfigEdit::populateAuthMethods()
101 {
102  const QStringList authMethodKeys = QgsApplication::authManager()->authMethodsKeys( mDataProvider );
103 
104  // sort by auth method description attribute, then populate
105  QMap<QString, const QgsAuthMethodMetadata *> descmap;
106  const auto constAuthMethodKeys = authMethodKeys;
107  for ( const QString &authMethodKey : constAuthMethodKeys )
108  {
109  const QgsAuthMethodMetadata *meta = QgsApplication::authManager()->authMethodMetadata( authMethodKey );
110  if ( !meta )
111  {
112  QgsDebugMsg( QStringLiteral( "Load auth method instance FAILED for auth method key (%1)" ).arg( authMethodKey ) );
113  continue;
114  }
115  descmap.insert( meta->description(), meta );
116  }
117 
118  QMap<QString, const QgsAuthMethodMetadata *>::iterator it = descmap.begin();
119  for ( it = descmap.begin(); it != descmap.end(); ++it )
120  {
121  QgsAuthMethodEdit *editWidget = qobject_cast<QgsAuthMethodEdit *>(
122  QgsApplication::authManager()->authMethodEditWidget( it.value()->key(), this ) );
123  if ( !editWidget )
124  {
125  QgsDebugMsg( QStringLiteral( "Load auth method edit widget FAILED for auth method key (%1)" ).arg( it.value()->key() ) );
126  continue;
127  }
128  connect( editWidget, &QgsAuthMethodEdit::validityChanged, this, &QgsAuthConfigEdit::validateAuth );
129 
130  cmbAuthMethods->addItem( it.key(), QVariant( it.value()->key() ) );
131  stkwAuthMethods->addWidget( editWidget );
132  }
133 }
134 
135 void QgsAuthConfigEdit::loadConfig()
136 {
137  const bool emptyAuthCfg = mAuthCfg.isEmpty();
138  authCfgEdit->setAllowEmptyId( emptyAuthCfg );
139  if ( emptyAuthCfg )
140  {
141  return;
142  }
143 
144  // edit mode requires master password to have been set and verified against auth db
145  if ( !QgsApplication::authManager()->setMasterPassword( true ) )
146  {
147  mAuthCfg.clear();
148  return;
149  }
150 
151  QgsAuthMethodConfig mconfig;
152  if ( !QgsApplication::authManager()->loadAuthenticationConfig( mAuthCfg, mconfig, true ) )
153  {
154  QgsDebugMsg( QStringLiteral( "Loading FAILED for authcfg: %1" ).arg( mAuthCfg ) );
155  return;
156  }
157 
158  if ( !mconfig.isValid( true ) )
159  {
160  QgsDebugMsg( QStringLiteral( "Loading FAILED for authcfg (%1): invalid config" ).arg( mAuthCfg ) );
161  return;
162  }
163 
164  // load basic info
165  leName->setText( mconfig.name() );
166  leResource->setText( mconfig.uri() );
167  authCfgEdit->setAuthConfigId( mconfig.id() );
168 
169  const QString authMethodKey = QgsApplication::authManager()->configAuthMethodKey( mAuthCfg );
170 
171  QgsDebugMsgLevel( QStringLiteral( "Loading authcfg: %1" ).arg( mAuthCfg ), 2 );
172  QgsDebugMsgLevel( QStringLiteral( "Loading auth method: %1" ).arg( authMethodKey ), 2 );
173 
174  if ( authMethodKey.isEmpty() )
175  {
176  QgsDebugMsg( QStringLiteral( "Loading FAILED for authcfg (%1): no auth method found" ).arg( mAuthCfg ) );
177  return;
178  }
179 
180  if ( mconfig.method() != authMethodKey )
181  {
182  QgsDebugMsg( QStringLiteral( "Loading FAILED for authcfg (%1): auth method and key mismatch" ).arg( mAuthCfg ) );
183  return;
184  }
185 
186  const int indx = authMethodIndex( authMethodKey );
187  if ( indx == -1 )
188  {
189  QgsDebugMsg( QStringLiteral( "Loading FAILED for authcfg (%1): no edit widget loaded for auth method '%2'" )
190  .arg( mAuthCfg, authMethodKey ) );
191  if ( cmbAuthMethods->count() > 0 )
192  {
193  cmbAuthMethods->setCurrentIndex( 0 );
194  stkwAuthMethods->setCurrentIndex( 0 );
195  }
196  return;
197  }
198 
199  cmbAuthMethods->setCurrentIndex( indx );
200  stkwAuthMethods->setCurrentIndex( indx );
201 
202  QgsAuthMethodEdit *editWidget = currentEditWidget();
203  if ( !editWidget )
204  {
205  QgsDebugMsg( QStringLiteral( "Cast to edit widget FAILED for authcfg (%1) and auth method key (%2)" )
206  .arg( mAuthCfg, authMethodKey ) );
207  return;
208  }
209 
210  editWidget->loadConfig( mconfig.configMap() );
211 }
212 
213 void QgsAuthConfigEdit::resetConfig()
214 {
215  clearAll();
216  loadConfig();
217  validateAuth();
218 }
219 
220 void QgsAuthConfigEdit::saveConfig()
221 {
222  if ( !QgsApplication::authManager()->setMasterPassword( true ) )
223  return;
224 
225  const QString authMethodKey = cmbAuthMethods->currentData().toString();
226 
227  QgsAuthMethodEdit *editWidget = currentEditWidget();
228  if ( !editWidget )
229  {
230  QgsDebugMsg( QStringLiteral( "Cast to edit widget FAILED)" ) );
231  return;
232  }
233 
234  QgsAuthMethod *authmethod = QgsApplication::authManager()->authMethod( authMethodKey );
235  if ( !authmethod )
236  {
237  QgsDebugMsg( QStringLiteral( "Save auth config FAILED when loading auth method instance from key (%1)" ).arg( authMethodKey ) );
238  return;
239  }
240 
241  QgsAuthMethodConfig mconfig;
242  mconfig.setName( leName->text() );
243  mconfig.setUri( leResource->text() );
244  mconfig.setMethod( authMethodKey );
245  mconfig.setVersion( authmethod->version() );
246  mconfig.setConfigMap( editWidget->configMap() );
247 
248  if ( !mconfig.isValid() )
249  {
250  QgsDebugMsg( QStringLiteral( "Save auth config FAILED: config invalid" ) );
251  return;
252  }
253 
254  const QString authCfgId( authCfgEdit->configId() );
255  if ( !mAuthCfg.isEmpty() )
256  {
257  if ( authCfgId == mAuthCfg ) // update
258  {
259  mconfig.setId( mAuthCfg );
260  if ( QgsApplication::authManager()->updateAuthenticationConfig( mconfig ) )
261  {
262  emit authenticationConfigUpdated( mAuthCfg );
263  }
264  else
265  {
266  QgsDebugMsg( QStringLiteral( "Updating auth config FAILED for authcfg: %1" ).arg( mAuthCfg ) );
267  }
268  }
269  else // store new with unique ID, then delete previous
270  {
271  mconfig.setId( authCfgId );
272  if ( QgsApplication::authManager()->storeAuthenticationConfig( mconfig ) )
273  {
274  emit authenticationConfigStored( authCfgId );
275  if ( !QgsApplication::authManager()->removeAuthenticationConfig( mAuthCfg ) )
276  {
277  QgsDebugMsg( QStringLiteral( "Removal of older auth config FAILED" ) );
278  }
279  mAuthCfg = authCfgId;
280  }
281  else
282  {
283  QgsDebugMsg( QStringLiteral( "Storing new auth config with user-created unique ID FAILED" ) );
284  }
285  }
286  }
287  else if ( mAuthCfg.isEmpty() )
288  {
289  if ( authCfgId.isEmpty() ) // create new with generated ID
290  {
291  if ( QgsApplication::authManager()->storeAuthenticationConfig( mconfig ) )
292  {
293  mAuthCfg = mconfig.id();
294  emit authenticationConfigStored( mAuthCfg );
295  }
296  else
297  {
298  QgsDebugMsg( QStringLiteral( "Storing new auth config FAILED" ) );
299  }
300  }
301  else // create new with user-created unique ID
302  {
303  mconfig.setId( authCfgId );
304  if ( QgsApplication::authManager()->storeAuthenticationConfig( mconfig ) )
305  {
306  mAuthCfg = authCfgId;
307  emit authenticationConfigStored( mAuthCfg );
308  }
309  else
310  {
311  QgsDebugMsg( QStringLiteral( "Storing new auth config with user-created unique ID FAILED" ) );
312  }
313  }
314  }
315 
316  this->accept();
317 }
318 
319 void QgsAuthConfigEdit::btnClear_clicked()
320 {
321  QgsAuthMethodEdit *editWidget = currentEditWidget();
322  if ( !editWidget )
323  {
324  QgsDebugMsg( QStringLiteral( "Cast to edit widget FAILED)" ) );
325  return;
326  }
327 
328  editWidget->clearConfig();
329 
330  validateAuth();
331 }
332 
333 void QgsAuthConfigEdit::clearAll()
334 {
335  leName->clear();
336  leResource->clear();
337  authCfgEdit->clear();
338 
339  for ( int i = 0; i < stkwAuthMethods->count(); i++ )
340  {
341  QgsAuthMethodEdit *editWidget = qobject_cast<QgsAuthMethodEdit *>( stkwAuthMethods->widget( i ) );
342  if ( editWidget )
343  {
344  editWidget->clearConfig();
345  }
346  }
347 
348  validateAuth();
349 }
350 
351 void QgsAuthConfigEdit::validateAuth()
352 {
353  bool authok = !leName->text().isEmpty();
354 
355  QgsAuthMethodEdit *editWidget = currentEditWidget();
356  if ( !editWidget )
357  {
358  QgsDebugMsg( QStringLiteral( "Cast to edit widget FAILED" ) );
359  }
360  else
361  {
362  authok = authok && editWidget->validateConfig();
363  }
364  authok = authok && authCfgEdit->validate();
365 
366  buttonBox->button( QDialogButtonBox::Save )->setEnabled( authok );
367 }
368 
369 void QgsAuthConfigEdit::leName_textChanged( const QString &txt )
370 {
371  Q_UNUSED( txt )
372  validateAuth();
373 }
374 
375 int QgsAuthConfigEdit::authMethodIndex( const QString &authMethodKey )
376 {
377  return cmbAuthMethods->findData( QVariant( authMethodKey ) );
378 }
379 
380 QgsAuthMethodEdit *QgsAuthConfigEdit::currentEditWidget()
381 {
382  return qobject_cast<QgsAuthMethodEdit *>( stkwAuthMethods->currentWidget() );
383 }
static QgsAuthManager * authManager()
Returns the application's authentication manager instance.
void authenticationConfigStored(const QString &authcfg)
Emit generated id when a new config is saved to auth database.
void authenticationConfigUpdated(const QString &authcfg)
Emit current id when an existing config is updated in auth database.
QgsAuthConfigEdit(QWidget *parent=nullptr, const QString &authcfg=QString(), const QString &dataprovider=QString())
Create a dialog for editing an authentication configuration.
void validityChanged(bool valid)
Validity of the ID has changed.
bool isDisabled() const
Whether QCA has the qca-ossl plugin, which a base run-time requirement.
QStringList configIds() const
Gets list of authentication ids from database.
QgsAuthMethod * authMethod(const QString &authMethodKey)
Gets authentication method from the config/provider cache via its key.
QStringList authMethodsKeys(const QString &dataprovider=QString())
Gets keys of supported authentication methods.
const QgsAuthMethodMetadata * authMethodMetadata(const QString &authMethodKey)
Gets authentication method metadata via its key.
QString configAuthMethodKey(const QString &authcfg) const
Gets key of authentication method associated with config ID.
Configuration storage class for authentication method configurations.
Definition: qgsauthconfig.h:42
bool isValid(bool validateid=false) const
Whether the configuration is valid.
QString method() const
Textual key of the associated authentication method.
Definition: qgsauthconfig.h:78
const QString uri() const
A URI to auto-select a config when connecting to a resource.
Definition: qgsauthconfig.h:74
void setName(const QString &name)
Sets name of configuration.
Definition: qgsauthconfig.h:71
void setConfigMap(const QgsStringMap &map)
Set extended configuration map.
void setVersion(int version)
Sets version of the configuration.
Definition: qgsauthconfig.h:84
const QString name() const
Gets name of configuration.
Definition: qgsauthconfig.h:69
const QString id() const
Gets 'authcfg' 7-character alphanumeric ID of the config.
Definition: qgsauthconfig.h:64
QgsStringMap configMap() const
Gets extended configuration, mapped to key/value pairs of QStrings.
void setMethod(const QString &method)
Definition: qgsauthconfig.h:79
void setUri(const QString &uri)
Definition: qgsauthconfig.h:75
void setId(const QString &id)
Sets auth config ID.
Definition: qgsauthconfig.h:66
Abstract base class for the edit widget of authentication method plugins.
virtual bool validateConfig()=0
Validate the configuration of subclasses.
void validityChanged(bool valid)
Emitted when the configuration validatity changes.
virtual void clearConfig()=0
Clear GUI controls in subclassed widget.
virtual QgsStringMap configMap() const =0
The configuration key-vale map of subclasses.
virtual void loadConfig(const QgsStringMap &configmap)=0
Load an existing config map into subclassed widget.
Holds data auth method key, description, and associated shared library file information.
QString description() const
Returns descriptive text for the method.
Abstract base class for authentication method plugins.
Definition: qgsauthmethod.h:43
int version() const
Increment this if method is significantly updated, allow updater code to be written for previously st...
Definition: qgsauthmethod.h:78
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:168
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38