QGIS API Documentation  2.99.0-Master (009e47e)
qgscredentialdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscredentialdialog.cpp - description
3  -------------------
4  begin : February 2010
5  copyright : (C) 2010 by Juergen E. Fischer
6  email : jef at norbit dot de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgscredentialdialog.h"
19 
20 #include "qgsauthmanager.h"
21 #include "qgslogger.h"
22 #include "qgssettings.h"
23 
24 #include <QPushButton>
25 #include <QThread>
26 
27 static QString invalidStyle_( const QString &selector = QStringLiteral( "QLineEdit" ) )
28 {
29  return QStringLiteral( "%1{color: rgb(200, 0, 0);}" ).arg( selector );
30 }
31 
32 QgsCredentialDialog::QgsCredentialDialog( QWidget *parent, Qt::WindowFlags fl )
33  : QDialog( parent, fl )
34  , mOkButton( nullptr )
35 {
36  setupUi( this );
37  setInstance( this );
39  this, &QgsCredentialDialog::requestCredentials,
40  Qt::BlockingQueuedConnection );
42  this, &QgsCredentialDialog::requestCredentialsMasterPassword,
43  Qt::BlockingQueuedConnection );
44  mOkButton = buttonBox->button( QDialogButtonBox::Ok );
45  leMasterPass->setPlaceholderText( tr( "Required" ) );
46  chkbxPasswordHelperEnable->setText( tr( "Store/update the master password in your %1" )
48  leUsername->setFocus();
49 }
50 
51 bool QgsCredentialDialog::request( const QString &realm, QString &username, QString &password, const QString &message )
52 {
53  bool ok;
54  if ( qApp->thread() != QThread::currentThread() )
55  {
56  QgsDebugMsg( "emitting signal" );
57  emit credentialsRequested( realm, &username, &password, message, &ok );
58  QgsDebugMsg( QString( "signal returned %1 (username=%2, password=%3)" ).arg( ok ? "true" : "false", username, password ) );
59  }
60  else
61  {
62  requestCredentials( realm, &username, &password, message, &ok );
63  }
64  return ok;
65 }
66 
67 void QgsCredentialDialog::requestCredentials( const QString &realm, QString *username, QString *password, const QString &message, bool *ok )
68 {
69  Q_ASSERT( qApp->thread() == thread() && thread() == QThread::currentThread() );
70  QgsDebugMsg( "Entering." );
71  stackedWidget->setCurrentIndex( 0 );
72 
73  chkbxPasswordHelperEnable->setChecked( QgsAuthManager::instance()->passwordHelperEnabled( ) );
74  labelRealm->setText( realm );
75  leUsername->setText( *username );
76  lePassword->setText( *password );
77  labelMessage->setText( message );
78  labelMessage->setHidden( message.isEmpty() );
79 
80  if ( !leUsername->text().isEmpty() )
81  lePassword->setFocus();
82 
83  QWidget *activeWindow = qApp->activeWindow();
84 
85  QApplication::setOverrideCursor( Qt::ArrowCursor );
86 
87  QgsDebugMsg( "exec()" );
88  *ok = exec() == QDialog::Accepted;
89  QgsDebugMsg( QString( "exec(): %1" ).arg( *ok ? "true" : "false" ) );
90 
91  QApplication::restoreOverrideCursor();
92 
93  if ( activeWindow )
94  activeWindow->raise();
95 
96  if ( *ok )
97  {
98  *username = leUsername->text();
99  *password = lePassword->text();
100  }
101 }
102 
103 bool QgsCredentialDialog::requestMasterPassword( QString &password, bool stored )
104 {
105  bool ok;
106  if ( qApp->thread() != QThread::currentThread() )
107  {
108  QgsDebugMsg( "emitting signal" );
109  emit credentialsRequestedMasterPassword( &password, stored, &ok );
110  }
111  else
112  {
113  requestCredentialsMasterPassword( &password, stored, &ok );
114  }
115  return ok;
116 }
117 
118 void QgsCredentialDialog::requestCredentialsMasterPassword( QString *password, bool stored, bool *ok )
119 {
120  QgsDebugMsg( "Entering." );
121  stackedWidget->setCurrentIndex( 1 );
122  leMasterPass->setFocus();
123 
124  QString titletxt( stored ? tr( "Enter CURRENT master authentication password" ) : tr( "Set NEW master authentication password" ) );
125  lblPasswordTitle->setText( titletxt );
126 
127  chkbxPasswordHelperEnable->setChecked( QgsAuthManager::instance()->passwordHelperEnabled( ) );
128 
129  leMasterPassVerify->setVisible( !stored );
130  lblDontForget->setVisible( !stored );
131 
132  QApplication::setOverrideCursor( Qt::ArrowCursor );
133 
134  grpbxPassAttempts->setVisible( false );
135  int passfailed = 0;
136  while ( true )
137  {
138  mOkButton->setEnabled( false );
139  // TODO: have the number of attempted passwords configurable in auth settings?
140  if ( passfailed >= 3 )
141  {
142  lblSavedForSession->setVisible( false );
143  grpbxPassAttempts->setTitle( tr( "Password attempts: %1" ).arg( passfailed ) );
144  grpbxPassAttempts->setVisible( true );
145  }
146 
147  // resize vertically to fit contents
148  QSize s = sizeHint();
149  s.setWidth( width() );
150  resize( s );
151 
152  QgsDebugMsg( "exec()" );
153  *ok = exec() == QDialog::Accepted;
154  QgsDebugMsg( QString( "exec(): %1" ).arg( *ok ? "true" : "false" ) );
155 
156  if ( *ok )
157  {
158  bool passok = !leMasterPass->text().isEmpty();
159  if ( passok && stored && !chkbxEraseAuthDb->isChecked() )
160  {
161  passok = QgsAuthManager::instance()->verifyMasterPassword( leMasterPass->text() );
162  }
163 
164  if ( passok && !stored )
165  {
166  passok = ( leMasterPass->text() == leMasterPassVerify->text() );
167  }
168 
169  if ( passok || chkbxEraseAuthDb->isChecked() )
170  {
171  if ( stored && chkbxEraseAuthDb->isChecked() )
172  {
174  }
175  else
176  {
177  *password = leMasterPass->text();
178  // Let's store user's preferences to use the password helper
179  if ( chkbxPasswordHelperEnable->isChecked() != QgsAuthManager::instance()->passwordHelperEnabled( ) )
180  {
181  QgsAuthManager::instance()->setPasswordHelperEnabled( chkbxPasswordHelperEnable->isChecked() );
182  }
183  }
184  break;
185  }
186  else
187  {
188  if ( stored )
189  ++passfailed;
190 
191  leMasterPass->setStyleSheet( invalidStyle_() );
192  if ( leMasterPassVerify->isVisible() )
193  {
194  leMasterPassVerify->setStyleSheet( invalidStyle_() );
195  }
196  }
197  }
198  else
199  {
200  break;
201  }
202 
203  if ( passfailed >= 5 )
204  {
205  break;
206  }
207  }
208 
209  // don't leave master password in singleton's text field, or the ability to show it
210  leMasterPass->clear();
211  leMasterPassVerify->clear();
212 
213  chkbxEraseAuthDb->setChecked( false );
214  lblSavedForSession->setVisible( true );
215 
216  // re-enable OK button or non-master-password requests will be blocked
217  // needs to come after leMasterPass->clear() or textChanged auto-slot with disable it again
218  mOkButton->setEnabled( true );
219 
220  QApplication::restoreOverrideCursor();
221 
222  if ( passfailed >= 5 )
223  {
224  close();
225  }
226 }
227 
228 void QgsCredentialDialog::on_leMasterPass_textChanged( const QString &pass )
229 {
230  leMasterPass->setStyleSheet( QLatin1String( "" ) );
231  bool passok = !pass.isEmpty(); // regardless of new or comparing existing, empty password disallowed
232  if ( leMasterPassVerify->isVisible() )
233  {
234  leMasterPassVerify->setStyleSheet( QLatin1String( "" ) );
235  passok = passok && ( leMasterPass->text() == leMasterPassVerify->text() );
236  }
237  mOkButton->setEnabled( passok );
238 
239  if ( leMasterPassVerify->isVisible() && !passok )
240  {
241  leMasterPass->setStyleSheet( invalidStyle_() );
242  leMasterPassVerify->setStyleSheet( invalidStyle_() );
243  }
244 }
245 
246 void QgsCredentialDialog::on_leMasterPassVerify_textChanged( const QString &pass )
247 {
248  if ( leMasterPassVerify->isVisible() )
249  {
250  leMasterPass->setStyleSheet( QLatin1String( "" ) );
251  leMasterPassVerify->setStyleSheet( QLatin1String( "" ) );
252 
253  // empty password disallowed
254  bool passok = !pass.isEmpty() && ( leMasterPass->text() == leMasterPassVerify->text() );
255  mOkButton->setEnabled( passok );
256  if ( !passok )
257  {
258  leMasterPass->setStyleSheet( invalidStyle_() );
259  leMasterPassVerify->setStyleSheet( invalidStyle_() );
260  }
261  }
262 }
263 
264 void QgsCredentialDialog::on_chkbxEraseAuthDb_toggled( bool checked )
265 {
266  if ( checked )
267  mOkButton->setEnabled( true );
268 }
269 
bool passwordHelperEnabled() const
Password helper enabled getter.
static QgsAuthManager * instance()
Enforce singleton pattern.
void setScheduledAuthDatabaseErase(bool scheduleErase)
Schedule an optional erase of authentication database, starting when mutex is lockable.
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
void setInstance(QgsCredentials *instance)
register instance
static const QString AUTH_PASSWORD_HELPER_DISPLAY_NAME
The display name of the password helper (platform dependent)
void credentialsRequested(const QString &, QString *, QString *, const QString &, bool *)
void setPasswordHelperEnabled(const bool enabled)
Password helper enabled setter.
virtual bool request(const QString &realm, QString &username, QString &password, const QString &message=QString()) override
request a password
QgsCredentialDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
QgsCredentialDialog constructor.
virtual bool requestMasterPassword(QString &password, bool stored=false) override
request a master password
void credentialsRequestedMasterPassword(QString *, bool, bool *)
bool verifyMasterPassword(const QString &compare=QString())
Verify the supplied master password against any existing hash in authentication database.