QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 #include "qgsapplication.h"
24 
25 #include <QPushButton>
26 #include <QThread>
27 
28 static QString invalidStyle_( const QString &selector = QStringLiteral( "QLineEdit" ) )
29 {
30  return QStringLiteral( "%1{color: rgb(200, 0, 0);}" ).arg( selector );
31 }
32 
33 QgsCredentialDialog::QgsCredentialDialog( QWidget *parent, Qt::WindowFlags fl )
34  : QDialog( parent, fl )
35 
36 {
37  setupUi( this );
38  connect( leMasterPass, &QgsPasswordLineEdit::textChanged, this, &QgsCredentialDialog::leMasterPass_textChanged );
39  connect( leMasterPassVerify, &QgsPasswordLineEdit::textChanged, this, &QgsCredentialDialog::leMasterPassVerify_textChanged );
40  connect( chkbxEraseAuthDb, &QCheckBox::toggled, this, &QgsCredentialDialog::chkbxEraseAuthDb_toggled );
41  setInstance( this );
43  this, &QgsCredentialDialog::requestCredentials,
44  Qt::BlockingQueuedConnection );
46  this, &QgsCredentialDialog::requestCredentialsMasterPassword,
47  Qt::BlockingQueuedConnection );
48  mOkButton = buttonBox->button( QDialogButtonBox::Ok );
49  leMasterPass->setPlaceholderText( tr( "Required" ) );
50  chkbxPasswordHelperEnable->setText( tr( "Store/update the master password in your %1" )
52  leUsername->setFocus();
53 }
54 
55 bool QgsCredentialDialog::request( const QString &realm, QString &username, QString &password, const QString &message )
56 {
57  bool ok;
58  if ( qApp->thread() != QThread::currentThread() )
59  {
60  QgsDebugMsg( QStringLiteral( "emitting signal" ) );
61  emit credentialsRequested( realm, &username, &password, message, &ok );
62  QgsDebugMsg( QStringLiteral( "signal returned %1 (username=%2)" ).arg( ok ? "true" : "false", username ) );
63  }
64  else
65  {
66  requestCredentials( realm, &username, &password, message, &ok );
67  }
68  return ok;
69 }
70 
71 void QgsCredentialDialog::requestCredentials( const QString &realm, QString *username, QString *password, const QString &message, bool *ok )
72 {
73  Q_ASSERT( qApp->thread() == thread() && thread() == QThread::currentThread() );
74  QgsDebugMsg( QStringLiteral( "Entering." ) );
75  stackedWidget->setCurrentIndex( 0 );
76 
77  chkbxPasswordHelperEnable->setChecked( QgsApplication::authManager()->passwordHelperEnabled() );
78  labelRealm->setText( realm );
79  leUsername->setText( *username );
80  lePassword->setText( *password );
81  labelMessage->setText( message );
82  labelMessage->setHidden( message.isEmpty() );
83 
84  if ( leUsername->text().isEmpty() )
85  leUsername->setFocus();
86  else
87  lePassword->setFocus();
88 
89  QWidget *activeWindow = qApp->activeWindow();
90 
91  QApplication::setOverrideCursor( Qt::ArrowCursor );
92 
93  QgsDebugMsg( QStringLiteral( "exec()" ) );
94  *ok = exec() == QDialog::Accepted;
95  QgsDebugMsg( QStringLiteral( "exec(): %1" ).arg( *ok ? "true" : "false" ) );
96 
97  QApplication::restoreOverrideCursor();
98 
99  if ( activeWindow )
100  activeWindow->raise();
101 
102  if ( *ok )
103  {
104  *username = leUsername->text();
105  *password = lePassword->text();
106  }
107 }
108 
109 bool QgsCredentialDialog::requestMasterPassword( QString &password, bool stored )
110 {
111  bool ok;
112  if ( qApp->thread() != QThread::currentThread() )
113  {
114  QgsDebugMsg( QStringLiteral( "emitting signal" ) );
115  emit credentialsRequestedMasterPassword( &password, stored, &ok );
116  }
117  else
118  {
119  requestCredentialsMasterPassword( &password, stored, &ok );
120  }
121  return ok;
122 }
123 
124 void QgsCredentialDialog::requestCredentialsMasterPassword( QString *password, bool stored, bool *ok )
125 {
126  QgsDebugMsg( QStringLiteral( "Entering." ) );
127  stackedWidget->setCurrentIndex( 1 );
128  leMasterPass->setFocus();
129 
130  QString titletxt( stored ? tr( "Enter CURRENT master authentication password" ) : tr( "Set NEW master authentication password" ) );
131  lblPasswordTitle->setText( titletxt );
132 
133  chkbxPasswordHelperEnable->setChecked( QgsApplication::authManager()->passwordHelperEnabled() );
134 
135  leMasterPassVerify->setVisible( !stored );
136  lblDontForget->setVisible( !stored );
137 
138  QApplication::setOverrideCursor( Qt::ArrowCursor );
139 
140  grpbxPassAttempts->setVisible( false );
141  int passfailed = 0;
142  while ( true )
143  {
144  mOkButton->setEnabled( false );
145  // TODO: have the number of attempted passwords configurable in auth settings?
146  if ( passfailed >= 3 )
147  {
148  lblSavedForSession->setVisible( false );
149  grpbxPassAttempts->setTitle( tr( "Password attempts: %1" ).arg( passfailed ) );
150  grpbxPassAttempts->setVisible( true );
151  }
152 
153  // resize vertically to fit contents
154  QSize s = sizeHint();
155  s.setWidth( width() );
156  resize( s );
157 
158  QgsDebugMsg( QStringLiteral( "exec()" ) );
159  *ok = exec() == QDialog::Accepted;
160  QgsDebugMsg( QStringLiteral( "exec(): %1" ).arg( *ok ? "true" : "false" ) );
161 
162  if ( *ok )
163  {
164  bool passok = !leMasterPass->text().isEmpty();
165  if ( passok && stored && !chkbxEraseAuthDb->isChecked() )
166  {
167  passok = QgsApplication::authManager()->verifyMasterPassword( leMasterPass->text() );
168  }
169 
170  if ( passok && !stored )
171  {
172  passok = ( leMasterPass->text() == leMasterPassVerify->text() );
173  }
174 
175  if ( passok || chkbxEraseAuthDb->isChecked() )
176  {
177  if ( stored && chkbxEraseAuthDb->isChecked() )
178  {
180  }
181  else
182  {
183  *password = leMasterPass->text();
184  // Let's store user's preferences to use the password helper
185  if ( chkbxPasswordHelperEnable->isChecked() != QgsApplication::authManager()->passwordHelperEnabled() )
186  {
187  QgsApplication::authManager()->setPasswordHelperEnabled( chkbxPasswordHelperEnable->isChecked() );
188  }
189  }
190  break;
191  }
192  else
193  {
194  if ( stored )
195  ++passfailed;
196 
197  leMasterPass->setStyleSheet( invalidStyle_() );
198  if ( leMasterPassVerify->isVisible() )
199  {
200  leMasterPassVerify->setStyleSheet( invalidStyle_() );
201  }
202  }
203  }
204  else
205  {
206  break;
207  }
208 
209  if ( passfailed >= 5 )
210  {
211  break;
212  }
213  }
214 
215  // don't leave master password in singleton's text field, or the ability to show it
216  leMasterPass->clear();
217  leMasterPassVerify->clear();
218 
219  chkbxEraseAuthDb->setChecked( false );
220  lblSavedForSession->setVisible( true );
221 
222  // re-enable OK button or non-master-password requests will be blocked
223  // needs to come after leMasterPass->clear() or textChanged auto-slot with disable it again
224  mOkButton->setEnabled( true );
225 
226  QApplication::restoreOverrideCursor();
227 
228  if ( passfailed >= 5 )
229  {
230  close();
231  }
232 }
233 
234 void QgsCredentialDialog::leMasterPass_textChanged( const QString &pass )
235 {
236  leMasterPass->setStyleSheet( QString() );
237  bool passok = !pass.isEmpty(); // regardless of new or comparing existing, empty password disallowed
238  if ( leMasterPassVerify->isVisible() )
239  {
240  leMasterPassVerify->setStyleSheet( QString() );
241  passok = passok && ( leMasterPass->text() == leMasterPassVerify->text() );
242  }
243  mOkButton->setEnabled( passok );
244 
245  if ( leMasterPassVerify->isVisible() && !passok )
246  {
247  leMasterPass->setStyleSheet( invalidStyle_() );
248  leMasterPassVerify->setStyleSheet( invalidStyle_() );
249  }
250 }
251 
252 void QgsCredentialDialog::leMasterPassVerify_textChanged( const QString &pass )
253 {
254  if ( leMasterPassVerify->isVisible() )
255  {
256  leMasterPass->setStyleSheet( QString() );
257  leMasterPassVerify->setStyleSheet( QString() );
258 
259  // empty password disallowed
260  bool passok = !pass.isEmpty() && ( leMasterPass->text() == leMasterPassVerify->text() );
261  mOkButton->setEnabled( passok );
262  if ( !passok )
263  {
264  leMasterPass->setStyleSheet( invalidStyle_() );
265  leMasterPassVerify->setStyleSheet( invalidStyle_() );
266  }
267  }
268 }
269 
270 void QgsCredentialDialog::chkbxEraseAuthDb_toggled( bool checked )
271 {
272  if ( checked )
273  mOkButton->setEnabled( true );
274 }
275 
bool passwordHelperEnabled() const
Password helper enabled getter.
void setScheduledAuthDatabaseErase(bool scheduleErase)
Schedule an optional erase of authentication database, starting when mutex is lockable.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
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 *)
static QgsAuthManager * authManager()
Returns the application&#39;s authentication manager instance.
bool request(const QString &realm, QString &username, QString &password, const QString &message=QString()) override
request a password
void setPasswordHelperEnabled(bool enabled)
Password helper enabled setter.
QgsCredentialDialog(QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
QgsCredentialDialog constructor.
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.