1 /***************************************************************************
2 qgsauthpkipathsedit.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 "qgsauthpkipathsedit.h"
18 #include "ui_qgsauthpkipathsedit.h"
19
20 #include <QDateTime>
21 #include <QFile>
22 #include <QFileInfo>
23 #include <QSslCertificate>
24 #include <QSslKey>
25
26 #include "qgsapplication.h"
27 #include "qgsauthcertutils.h"
28 #include "qgsauthmanager.h"
29 #include "qgsauthguiutils.h"
30 #include "qgslogger.h"
31
32
QgsAuthPkiPathsEdit(QWidget * parent)33 QgsAuthPkiPathsEdit::QgsAuthPkiPathsEdit( QWidget *parent )
34 : QgsAuthMethodEdit( parent )
35 {
36 setupUi( this );
37 connect( chkPkiPathsPassShow, &QCheckBox::stateChanged, this, &QgsAuthPkiPathsEdit::chkPkiPathsPassShow_stateChanged );
38 connect( btnPkiPathsCert, &QToolButton::clicked, this, &QgsAuthPkiPathsEdit::btnPkiPathsCert_clicked );
39 connect( btnPkiPathsKey, &QToolButton::clicked, this, &QgsAuthPkiPathsEdit::btnPkiPathsKey_clicked );
40 connect( cbAddCas, &QCheckBox::stateChanged, this, [ = ]( int state ) { cbAddRootCa->setEnabled( state == Qt::Checked ); } );
41 lblCas->hide();
42 twCas->hide();
43 cbAddCas->hide();
44 cbAddRootCa->hide();
45 }
46
validateConfig()47 bool QgsAuthPkiPathsEdit::validateConfig()
48 {
49 // required components
50 const QString certpath( lePkiPathsCert->text() );
51 const QString keypath( lePkiPathsKey->text() );
52
53 const bool certfound = QFile::exists( certpath );
54 const bool keyfound = QFile::exists( keypath );
55
56 QgsAuthGuiUtils::fileFound( certpath.isEmpty() || certfound, lePkiPathsCert );
57 QgsAuthGuiUtils::fileFound( keypath.isEmpty() || keyfound, lePkiPathsKey );
58
59 if ( !certfound || !keyfound )
60 {
61 writePkiMessage( lePkiPathsMsg, tr( "Missing components" ), Invalid );
62 return validityChange( false );
63 }
64
65 // check for issue date validity, then notify status
66 const QSslCertificate cert( QgsAuthCertUtils::certFromFile( certpath ) );
67
68 if ( cert.isNull() )
69 {
70 writePkiMessage( lePkiPathsMsg, tr( "Failed to load certificate from file" ), Invalid );
71 return validityChange( false );
72 }
73
74 const QDateTime startdate( cert.effectiveDate() );
75 const QDateTime enddate( cert.expiryDate() );
76
77 writePkiMessage( lePkiPathsMsg,
78 tr( "%1 thru %2" ).arg( startdate.toString(), enddate.toString() ),
79 ( QgsAuthCertUtils::certIsCurrent( cert ) ? Valid : Invalid ) );
80
81 const bool certviable = QgsAuthCertUtils::certIsViable( cert );
82 const bool showCas( certviable && populateCas() );
83 lblCas->setVisible( showCas );
84 twCas->setVisible( showCas );
85 cbAddCas->setVisible( showCas );
86 cbAddRootCa->setVisible( showCas );
87
88 return validityChange( certviable );
89 }
90
configMap() const91 QgsStringMap QgsAuthPkiPathsEdit::configMap() const
92 {
93 QgsStringMap config;
94 config.insert( QStringLiteral( "certpath" ), lePkiPathsCert->text() );
95 config.insert( QStringLiteral( "keypath" ), lePkiPathsKey->text() );
96 config.insert( QStringLiteral( "keypass" ), lePkiPathsKeyPass->text() );
97 config.insert( QStringLiteral( "addcas" ), cbAddCas->isChecked() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
98 config.insert( QStringLiteral( "addrootca" ), cbAddRootCa->isChecked() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
99
100 return config;
101 }
102
loadConfig(const QgsStringMap & configmap)103 void QgsAuthPkiPathsEdit::loadConfig( const QgsStringMap &configmap )
104 {
105 clearConfig();
106
107 mConfigMap = configmap;
108 lePkiPathsCert->setText( configmap.value( QStringLiteral( "certpath" ) ) );
109 lePkiPathsKey->setText( configmap.value( QStringLiteral( "keypath" ) ) );
110 lePkiPathsKeyPass->setText( configmap.value( QStringLiteral( "keypass" ) ) );
111 cbAddCas->setChecked( configmap.value( QStringLiteral( "addcas" ), QStringLiteral( "false " ) ) == QLatin1String( "true" ) );
112 cbAddRootCa->setChecked( configmap.value( QStringLiteral( "addrootca" ), QStringLiteral( "false " ) ) == QLatin1String( "true" ) );
113
114 validateConfig();
115 }
116
resetConfig()117 void QgsAuthPkiPathsEdit::resetConfig()
118 {
119 loadConfig( mConfigMap );
120 }
121
clearConfig()122 void QgsAuthPkiPathsEdit::clearConfig()
123 {
124 clearPkiPathsCertPath();
125 clearPkiPathsKeyPath();
126 clearPkiPathsKeyPass();
127
128 clearPkiMessage( lePkiPathsMsg );
129 validateConfig();
130 }
131
clearPkiMessage(QLineEdit * lineedit)132 void QgsAuthPkiPathsEdit::clearPkiMessage( QLineEdit *lineedit )
133 {
134 lineedit->clear();
135 lineedit->setStyleSheet( QString() );
136 }
137
writePkiMessage(QLineEdit * lineedit,const QString & msg,Validity valid)138 void QgsAuthPkiPathsEdit::writePkiMessage( QLineEdit *lineedit, const QString &msg, Validity valid )
139 {
140 QString ss;
141 QString txt( msg );
142 switch ( valid )
143 {
144 case Valid:
145 ss = QgsAuthGuiUtils::greenTextStyleSheet( QStringLiteral( "QLineEdit" ) );
146 txt = tr( "Valid: %1" ).arg( msg );
147 break;
148 case Invalid:
149 ss = QgsAuthGuiUtils::redTextStyleSheet( QStringLiteral( "QLineEdit" ) );
150 txt = tr( "Invalid: %1" ).arg( msg );
151 break;
152 case Unknown:
153 break;
154 }
155 lineedit->setStyleSheet( ss );
156 lineedit->setText( txt );
157 lineedit->setCursorPosition( 0 );
158 }
159
clearPkiPathsCertPath()160 void QgsAuthPkiPathsEdit::clearPkiPathsCertPath()
161 {
162 lePkiPathsCert->clear();
163 lePkiPathsCert->setStyleSheet( QString() );
164 }
165
clearPkiPathsKeyPath()166 void QgsAuthPkiPathsEdit::clearPkiPathsKeyPath()
167 {
168 lePkiPathsKey->clear();
169 lePkiPathsKey->setStyleSheet( QString() );
170 }
171
172
clearPkiPathsKeyPass()173 void QgsAuthPkiPathsEdit::clearPkiPathsKeyPass()
174 {
175 lePkiPathsKeyPass->clear();
176 lePkiPathsKeyPass->setStyleSheet( QString() );
177 chkPkiPathsPassShow->setChecked( false );
178 }
179
chkPkiPathsPassShow_stateChanged(int state)180 void QgsAuthPkiPathsEdit::chkPkiPathsPassShow_stateChanged( int state )
181 {
182 lePkiPathsKeyPass->setEchoMode( ( state > 0 ) ? QLineEdit::Normal : QLineEdit::Password );
183 }
184
btnPkiPathsCert_clicked()185 void QgsAuthPkiPathsEdit::btnPkiPathsCert_clicked()
186 {
187 const QString &fn = QgsAuthGuiUtils::getOpenFileName( this, tr( "Open Client Certificate File" ),
188 tr( "All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
189 if ( !fn.isEmpty() )
190 {
191 lePkiPathsCert->setText( fn );
192 validateConfig();
193 }
194 }
195
btnPkiPathsKey_clicked()196 void QgsAuthPkiPathsEdit::btnPkiPathsKey_clicked()
197 {
198 const QString &fn = QgsAuthGuiUtils::getOpenFileName( this, tr( "Open Private Key File" ),
199 tr( "All files (*.*);;PEM (*.pem);;DER (*.der)" ) );
200 if ( !fn.isEmpty() )
201 {
202 lePkiPathsKey->setText( fn );
203 validateConfig();
204 }
205 }
206
validityChange(bool curvalid)207 bool QgsAuthPkiPathsEdit::validityChange( bool curvalid )
208 {
209 if ( mValid != curvalid )
210 {
211 mValid = curvalid;
212 emit validityChanged( curvalid );
213 }
214 return curvalid;
215 }
216
217
populateCas()218 bool QgsAuthPkiPathsEdit::populateCas()
219 {
220 twCas->clear();
221 const QList<QSslCertificate> cas( QgsAuthCertUtils::casFromFile( lePkiPathsCert->text() ) );
222 if ( cas.isEmpty() )
223 {
224 return false;
225 }
226
227 QTreeWidgetItem *prevItem( nullptr );
228 QList<QSslCertificate>::const_iterator it( cas.constEnd() );
229 while ( it != cas.constBegin() )
230 {
231 --it;
232 const QSslCertificate cert = static_cast<QSslCertificate>( *it );
233 QTreeWidgetItem *item;
234
235 if ( prevItem && cert.issuerInfo( QSslCertificate::SubjectInfo::CommonName ).contains( prevItem->text( 0 ) ) )
236 {
237 item = new QTreeWidgetItem( QStringList( cert.subjectInfo( QSslCertificate::SubjectInfo::CommonName ) ) );
238 prevItem->addChild( item );
239 }
240 else
241 {
242 item = new QTreeWidgetItem( twCas, QStringList( cert.subjectInfo( QSslCertificate::SubjectInfo::CommonName ) ) );
243 }
244 item->setIcon( 0, QgsApplication::getThemeIcon( QStringLiteral( "/mIconCertificate.svg" ) ) );
245 item->setToolTip( 0, tr( "<ul><li>Serial #: %1</li><li>Expiry date: %2</li></ul>" ).arg( cert.serialNumber( ), cert.expiryDate().toString( Qt::TextDate ) ) );
246 prevItem = item;
247 }
248 twCas->expandAll();
249
250 return true;
251 }
252