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