1 /***************************************************************************
2 qgsauthconfigselect.cpp
3 ---------------------
4 begin : October 5, 2014
5 copyright : (C) 2014 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 "qgsauthconfigselect.h"
18 #include "ui_qgsauthconfigselect.h"
19
20 #include "qgsauthconfig.h"
21 #include "qgsauthguiutils.h"
22 #include "qgsauthmanager.h"
23 #include "qgsauthconfigedit.h"
24 #include "qgslogger.h"
25 #include "qgsapplication.h"
26 #include "qgsauthmethodmetadata.h"
27
28 #include <QHash>
29 #include <QMessageBox>
30 #include <QTimer>
31 #include <QRegularExpression>
32
33
QgsAuthConfigSelect(QWidget * parent,const QString & dataprovider)34 QgsAuthConfigSelect::QgsAuthConfigSelect( QWidget *parent, const QString &dataprovider )
35 : QWidget( parent )
36 , mDataProvider( dataprovider )
37 {
38 if ( QgsApplication::authManager()->isDisabled() )
39 {
40 mDisabled = true;
41 mAuthNotifyLayout = new QVBoxLayout;
42 this->setLayout( mAuthNotifyLayout );
43 mAuthNotify = new QLabel( QgsApplication::authManager()->disabledMessage(), this );
44 mAuthNotifyLayout->addWidget( mAuthNotify );
45 }
46 else
47 {
48 setupUi( this );
49 connect( cmbConfigSelect, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsAuthConfigSelect::cmbConfigSelect_currentIndexChanged );
50 connect( btnConfigAdd, &QToolButton::clicked, this, &QgsAuthConfigSelect::btnConfigAdd_clicked );
51 connect( btnConfigEdit, &QToolButton::clicked, this, &QgsAuthConfigSelect::btnConfigEdit_clicked );
52 connect( btnConfigRemove, &QToolButton::clicked, this, &QgsAuthConfigSelect::btnConfigRemove_clicked );
53 connect( btnConfigMsgClear, &QToolButton::clicked, this, &QgsAuthConfigSelect::btnConfigMsgClear_clicked );
54
55 // Set icons and remove texts
56 btnConfigAdd->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
57 btnConfigRemove->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyRemove.svg" ) ) );
58 btnConfigEdit->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionToggleEditing.svg" ) ) );
59 btnConfigMsgClear->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mIconClose.svg" ) ) );
60
61 btnConfigAdd->setText( QString() );
62 btnConfigRemove->setText( QString() );
63 btnConfigEdit->setText( QString() );
64 btnConfigMsgClear->setText( QString() );
65
66 leConfigMsg->setStyleSheet( QStringLiteral( "QLineEdit{background-color: %1}" )
67 .arg( QgsAuthGuiUtils::yellowColor().name() ) );
68
69 clearConfig();
70 clearMessage();
71 populateConfigSelector();
72 }
73 }
74
setConfigId(const QString & authcfg)75 void QgsAuthConfigSelect::setConfigId( const QString &authcfg )
76 {
77 if ( mDisabled && mAuthNotify )
78 {
79 mAuthNotify->setText( QgsApplication::authManager()->disabledMessage() + "\n\n" +
80 tr( "Authentication config id not loaded: %1" ).arg( authcfg ) );
81 }
82 else
83 {
84 if ( mAuthCfg != authcfg )
85 {
86 mAuthCfg = authcfg;
87 }
88 // avoid duplicate call to loadConfig(), which may potentially be triggered by combo box index changes in the
89 // call to populateConfigSelector(). We *always* call loadConfig() after this, so we don't want to do it twice.
90 mTemporarilyBlockLoad = true;
91 populateConfigSelector();
92 mTemporarilyBlockLoad = false;
93 loadConfig();
94 }
95 }
96
setDataProviderKey(const QString & key)97 void QgsAuthConfigSelect::setDataProviderKey( const QString &key )
98 {
99 if ( mDisabled )
100 {
101 return;
102 }
103
104 mDataProvider = key;
105 populateConfigSelector();
106 }
107
loadConfig()108 void QgsAuthConfigSelect::loadConfig()
109 {
110 clearConfig();
111 if ( !mAuthCfg.isEmpty() && mConfigs.contains( mAuthCfg ) )
112 {
113 const QgsAuthMethodConfig config = mConfigs.value( mAuthCfg );
114 const QString authMethodKey = QgsApplication::authManager()->configAuthMethodKey( mAuthCfg );
115 QString methoddesc = tr( "Missing authentication method description" );
116 const QgsAuthMethodMetadata *meta = QgsApplication::authManager()->authMethodMetadata( authMethodKey );
117 if ( meta )
118 {
119 methoddesc = meta->description();
120 }
121 cmbConfigSelect->setToolTip( tr( "<ul><li><b>Method type:</b> %1</li>"
122 "<li><b>Configuration ID:</b> %2</li></ul>" ).arg( methoddesc, config.id( ) ) );
123 btnConfigEdit->setEnabled( true );
124 btnConfigRemove->setEnabled( true );
125 }
126 emit selectedConfigIdChanged( mAuthCfg );
127 }
128
clearConfig()129 void QgsAuthConfigSelect::clearConfig()
130 {
131 cmbConfigSelect->setToolTip( QString() );
132 btnConfigEdit->setEnabled( false );
133 btnConfigRemove->setEnabled( false );
134 }
135
validateConfig()136 void QgsAuthConfigSelect::validateConfig()
137 {
138 if ( !mAuthCfg.isEmpty() && !mConfigs.contains( mAuthCfg ) )
139 {
140 showMessage( tr( "Configuration '%1' not in database" ).arg( mAuthCfg ) );
141 mAuthCfg.clear();
142 }
143 }
144
populateConfigSelector()145 void QgsAuthConfigSelect::populateConfigSelector()
146 {
147 loadAvailableConfigs();
148 validateConfig();
149
150 cmbConfigSelect->blockSignals( true );
151 cmbConfigSelect->clear();
152 cmbConfigSelect->addItem( tr( "No Authentication" ), "0" );
153
154 QgsStringMap sortmap;
155 QgsAuthMethodConfigsMap::const_iterator cit = mConfigs.constBegin();
156 for ( cit = mConfigs.constBegin(); cit != mConfigs.constEnd(); ++cit )
157 {
158 const QgsAuthMethodConfig config = cit.value();
159 sortmap.insert( QStringLiteral( "%1 (%2)" ).arg( config.name(), config.method() ), cit.key() );
160 }
161
162 QgsStringMap::const_iterator sm = sortmap.constBegin();
163 for ( sm = sortmap.constBegin(); sm != sortmap.constEnd(); ++sm )
164 {
165 cmbConfigSelect->addItem( sm.key(), sm.value() );
166 }
167 cmbConfigSelect->blockSignals( false );
168
169 int indx = 0;
170 if ( !mAuthCfg.isEmpty() )
171 {
172 indx = cmbConfigSelect->findData( mAuthCfg );
173 }
174 cmbConfigSelect->setCurrentIndex( indx > 0 ? indx : 0 );
175 }
176
showMessage(const QString & msg)177 void QgsAuthConfigSelect::showMessage( const QString &msg )
178 {
179 if ( mDisabled )
180 {
181 return;
182 }
183 leConfigMsg->setText( msg );
184 frConfigMsg->setVisible( true );
185 }
186
clearMessage()187 void QgsAuthConfigSelect::clearMessage()
188 {
189 if ( mDisabled )
190 {
191 return;
192 }
193 leConfigMsg->clear();
194 frConfigMsg->setVisible( false );
195 }
196
loadAvailableConfigs()197 void QgsAuthConfigSelect::loadAvailableConfigs()
198 {
199 mConfigs.clear();
200 mConfigs = QgsApplication::authManager()->availableAuthMethodConfigs( mDataProvider );
201 }
202
cmbConfigSelect_currentIndexChanged(int index)203 void QgsAuthConfigSelect::cmbConfigSelect_currentIndexChanged( int index )
204 {
205 const QString authcfg = cmbConfigSelect->itemData( index ).toString();
206 mAuthCfg = ( !authcfg.isEmpty() && authcfg != QLatin1String( "0" ) ) ? authcfg : QString();
207 if ( !mTemporarilyBlockLoad )
208 loadConfig();
209 }
210
btnConfigAdd_clicked()211 void QgsAuthConfigSelect::btnConfigAdd_clicked()
212 {
213 if ( !QgsApplication::authManager()->setMasterPassword( true ) )
214 return;
215
216 QgsAuthConfigEdit *ace = new QgsAuthConfigEdit( this, QString(), mDataProvider );
217 ace->setWindowModality( Qt::WindowModal );
218 if ( ace->exec() )
219 {
220 setConfigId( ace->configId() );
221 }
222 ace->deleteLater();
223 }
224
btnConfigEdit_clicked()225 void QgsAuthConfigSelect::btnConfigEdit_clicked()
226 {
227 if ( !QgsApplication::authManager()->setMasterPassword( true ) )
228 return;
229
230 QgsAuthConfigEdit *ace = new QgsAuthConfigEdit( this, mAuthCfg, mDataProvider );
231 ace->setWindowModality( Qt::WindowModal );
232 if ( ace->exec() )
233 {
234 //qDebug( "Edit returned config Id: %s", ace->configId().toLatin1().constData() );
235 setConfigId( ace->configId() );
236 }
237 ace->deleteLater();
238 }
239
btnConfigRemove_clicked()240 void QgsAuthConfigSelect::btnConfigRemove_clicked()
241 {
242 if ( QMessageBox::warning( this, tr( "Remove Authentication" ),
243 tr( "Are you sure that you want to permanently remove this configuration right now?\n\n"
244 "Operation can NOT be undone!" ),
245 QMessageBox::Ok | QMessageBox::Cancel,
246 QMessageBox::Cancel ) == QMessageBox::Cancel )
247 {
248 return;
249 }
250
251 if ( QgsApplication::authManager()->removeAuthenticationConfig( mAuthCfg ) )
252 {
253 emit selectedConfigIdRemoved( mAuthCfg );
254 setConfigId( QString() );
255 }
256 }
257
btnConfigMsgClear_clicked()258 void QgsAuthConfigSelect::btnConfigMsgClear_clicked()
259 {
260 clearMessage();
261 }
262
263
264 //////////////// Embed in dialog ///////////////////
265
266 #include <QPushButton>
267
QgsAuthConfigUriEdit(QWidget * parent,const QString & datauri,const QString & dataprovider)268 QgsAuthConfigUriEdit::QgsAuthConfigUriEdit( QWidget *parent, const QString &datauri, const QString &dataprovider )
269 : QDialog( parent )
270 {
271 if ( QgsApplication::authManager()->isDisabled() )
272 {
273 mDisabled = true;
274 mAuthNotifyLayout = new QVBoxLayout;
275 this->setLayout( mAuthNotifyLayout );
276 mAuthNotify = new QLabel( QgsApplication::authManager()->disabledMessage(), this );
277 mAuthNotifyLayout->addWidget( mAuthNotify );
278 }
279 else
280 {
281 setupUi( this );
282
283 setWindowTitle( tr( "Authentication Config ID String Editor" ) );
284
285 buttonBox->button( QDialogButtonBox::Close )->setDefault( true );
286 connect( buttonBox, &QDialogButtonBox::rejected, this, &QWidget::close );
287 connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsAuthConfigUriEdit::saveChanges );
288
289 connect( buttonBox->button( QDialogButtonBox::Reset ), &QAbstractButton::clicked, this, &QgsAuthConfigUriEdit::resetChanges );
290
291 connect( wdgtAuthSelect, &QgsAuthConfigSelect::selectedConfigIdChanged, this, &QgsAuthConfigUriEdit::authCfgUpdated );
292 connect( wdgtAuthSelect, &QgsAuthConfigSelect::selectedConfigIdRemoved, this, &QgsAuthConfigUriEdit::authCfgRemoved );
293
294 wdgtAuthSelect->setDataProviderKey( dataprovider );
295 setDataSourceUri( datauri );
296 }
297 }
298
setDataSourceUri(const QString & datauri)299 void QgsAuthConfigUriEdit::setDataSourceUri( const QString &datauri )
300 {
301 if ( mDisabled )
302 {
303 return;
304 }
305 if ( datauri.isEmpty() )
306 return;
307
308 mDataUri = mDataUriOrig = datauri;
309
310 teDataUri->setPlainText( mDataUri );
311
312 if ( authCfgIndex() == -1 )
313 {
314 wdgtAuthSelect->showMessage( tr( "No authcfg in Data Source URI" ) );
315 return;
316 }
317
318 selectAuthCfgInUri();
319
320 mAuthCfg = authCfgFromUri();
321
322 QgsDebugMsg( QStringLiteral( "Parsed authcfg ID: %1" ).arg( mAuthCfg ) );
323
324 wdgtAuthSelect->blockSignals( true );
325 wdgtAuthSelect->setConfigId( mAuthCfg );
326 wdgtAuthSelect->blockSignals( false );
327 }
328
dataSourceUri()329 QString QgsAuthConfigUriEdit::dataSourceUri()
330 {
331 if ( mDisabled )
332 {
333 return QString();
334 }
335 return mDataUri;
336 }
337
hasConfigId(const QString & txt)338 bool QgsAuthConfigUriEdit::hasConfigId( const QString &txt )
339 {
340 if ( QgsApplication::authManager()->isDisabled() )
341 {
342 return false;
343 }
344 return QgsApplication::authManager()->hasConfigId( txt );
345 }
346
saveChanges()347 void QgsAuthConfigUriEdit::saveChanges()
348 {
349 this->accept();
350 }
351
resetChanges()352 void QgsAuthConfigUriEdit::resetChanges()
353 {
354 wdgtAuthSelect->clearMessage();
355 setDataSourceUri( mDataUriOrig );
356 }
357
authCfgUpdated(const QString & authcfg)358 void QgsAuthConfigUriEdit::authCfgUpdated( const QString &authcfg )
359 {
360 mAuthCfg = authcfg;
361
362 if ( mAuthCfg.size() != 7 )
363 {
364 mAuthCfg.clear();
365 removeAuthCfgFromUri();
366 }
367 else
368 {
369 updateUriWithAuthCfg();
370 }
371 teDataUri->clear();
372 teDataUri->setPlainText( mDataUri );
373 selectAuthCfgInUri();
374 }
375
authCfgRemoved(const QString & authcfg)376 void QgsAuthConfigUriEdit::authCfgRemoved( const QString &authcfg )
377 {
378 if ( authCfgFromUri() == authcfg )
379 {
380 removeAuthCfgFromUri();
381 }
382 }
383
authCfgIndex()384 int QgsAuthConfigUriEdit::authCfgIndex()
385 {
386 return mDataUri.indexOf( QRegularExpression( QgsApplication::authManager()->configIdRegex() ) );
387 }
388
authCfgFromUri()389 QString QgsAuthConfigUriEdit::authCfgFromUri()
390 {
391 const int startindex = authCfgIndex();
392 if ( startindex == -1 )
393 return QString();
394
395 return mDataUri.mid( startindex + 8, 7 );
396 }
397
selectAuthCfgInUri()398 void QgsAuthConfigUriEdit::selectAuthCfgInUri()
399 {
400 const int startindex = authCfgIndex();
401 if ( startindex == -1 )
402 return;
403
404 // authcfg=.{7} will always be 15 chars
405 QTextCursor tc = teDataUri->textCursor();
406 tc.setPosition( startindex );
407 tc.setPosition( startindex + 15, QTextCursor::KeepAnchor );
408 teDataUri->setTextCursor( tc );
409 teDataUri->setFocus();
410 }
411
updateUriWithAuthCfg()412 void QgsAuthConfigUriEdit::updateUriWithAuthCfg()
413 {
414 const int startindex = authCfgIndex();
415 if ( startindex == -1 )
416 {
417 if ( mAuthCfg.size() == 7 )
418 {
419 wdgtAuthSelect->showMessage( tr( "Adding authcfg to URI not supported" ) );
420 }
421 return;
422 }
423
424 mDataUri = mDataUri.replace( startindex + 8, 7, mAuthCfg );
425 }
426
removeAuthCfgFromUri()427 void QgsAuthConfigUriEdit::removeAuthCfgFromUri()
428 {
429 int startindex = authCfgIndex();
430 if ( startindex == -1 )
431 return;
432
433 // add any preceding space so two spaces will not result after removal
434 int rmvlen = 15;
435 if ( startindex - 1 >= 0
436 && ( mDataUri.at( startindex - 1 ).isSpace()
437 || mDataUri.at( startindex - 1 ) == QChar( '&' ) ) )
438 {
439 startindex -= 1;
440 rmvlen += 1;
441 }
442
443 // trim any leftover spaces or & from ends
444 mDataUri = mDataUri.remove( startindex, rmvlen ).trimmed();
445 if ( mDataUri.at( 0 ) == QChar( '&' ) )
446 mDataUri = mDataUri.remove( 0, 1 );
447
448 // trim any & from
449
450 mAuthCfg.clear();
451 }
452
453