11#include <config-libkleo.h>
13#include "editdirectoryservicedialog.h"
15#include <libkleo/algorithm.h>
16#include <libkleo/gnupg.h>
17#include <libkleo/keyserverconfig.h>
19#include <KCollapsibleGroupBox>
20#include <KColorScheme>
21#include <KConfigGroup>
23#include <KLocalizedString>
24#include <KPasswordLineEdit>
25#include <KSharedConfig>
26#include <KStandardGuiItem>
28#include <QButtonGroup>
30#include <QDialogButtonBox>
36#include <QRadioButton>
44int defaultPort(KeyserverConnection connection)
46 return connection == KeyserverConnection::TunnelThroughTLS ? 636 : 389;
50class EditDirectoryServiceDialog::Private
52 EditDirectoryServiceDialog *
const q;
55 QLineEdit *hostEdit =
nullptr;
56 QSpinBox *portSpinBox =
nullptr;
57 QCheckBox *useDefaultPortCheckBox =
nullptr;
58 QButtonGroup *authenticationGroup =
nullptr;
59 QLineEdit *userEdit =
nullptr;
60 KPasswordLineEdit *passwordEdit =
nullptr;
61 QButtonGroup *connectionGroup =
nullptr;
62 KCollapsibleGroupBox *advancedSettings =
nullptr;
63 QLineEdit *baseDnEdit =
nullptr;
64 QLineEdit *additionalFlagsEdit =
nullptr;
65 QDialogButtonBox *buttonBox =
nullptr;
66 QLabel *invalidHostLabel =
nullptr;
69 : hostEdit{new QLineEdit{
parent}}
70 , portSpinBox{new QSpinBox{
parent}}
71 , useDefaultPortCheckBox{new QCheckBox{
parent}}
72 , authenticationGroup{new QButtonGroup{
parent}}
73 , userEdit{new QLineEdit{
parent}}
74 , passwordEdit{new KPasswordLineEdit{
parent}}
75 , connectionGroup{new QButtonGroup{
parent}}
76 , advancedSettings{new KCollapsibleGroupBox{
parent}}
77 , baseDnEdit{new QLineEdit{
parent}}
78 , additionalFlagsEdit{new QLineEdit{
parent}}
79 , buttonBox{new QDialogButtonBox{
parent}}
80 , invalidHostLabel{new QLabel{
parent}}
82#define SET_OBJECT_NAME(x) x->setObjectName(QStringLiteral(#x));
83 SET_OBJECT_NAME(hostEdit)
84 SET_OBJECT_NAME(portSpinBox)
85 SET_OBJECT_NAME(useDefaultPortCheckBox)
86 SET_OBJECT_NAME(authenticationGroup)
87 SET_OBJECT_NAME(userEdit)
88 SET_OBJECT_NAME(passwordEdit)
89 SET_OBJECT_NAME(connectionGroup)
90 SET_OBJECT_NAME(advancedSettings)
91 SET_OBJECT_NAME(baseDnEdit)
92 SET_OBJECT_NAME(additionalFlagsEdit)
93 SET_OBJECT_NAME(buttonBox)
95 auto mainLayout =
new QVBoxLayout{
parent};
99 auto layout =
new QGridLayout{serverWidget};
100 layout->setColumnStretch(2, 1);
103 hostEdit->setToolTip(
i18nc(
"@info:tooltip",
"Enter the name or IP address of the server hosting the directory service."));
104 hostEdit->setClearButtonEnabled(
true);
111 invalidHostLabel->setPalette(
palette);
112 invalidHostLabel->setText(
i18nc(
"@info:label",
"Error: Enter a hostname in the correct format, like ldap.example.com."));
113 invalidHostLabel->setVisible(
false);
117 portSpinBox->setRange(1, USHRT_MAX);
118 portSpinBox->setToolTip(
i18nc(
"@info:tooltip",
119 "<b>(Optional, the default is fine in most cases)</b> "
120 "Pick the port number the directory service is listening on."));
122 useDefaultPortCheckBox->setText(
i18n(
"Use default"));
123 useDefaultPortCheckBox->setChecked(
true);
126 mainLayout->addWidget(serverWidget);
128 auto authenticationWidget =
new QGroupBox{
i18n(
"Authentication"),
parent};
130 auto layout =
new QVBoxLayout{authenticationWidget};
132 auto radioButton =
new QRadioButton{
i18n(
"Anonymous")};
133 radioButton->setToolTip(
i18nc(
"@info:tooltip",
"Use an anonymous LDAP server that does not require authentication."));
134 radioButton->setChecked(
true);
135 authenticationGroup->addButton(radioButton,
static_cast<int>(KeyserverAuthentication::Anonymous));
139 auto radioButton =
new QRadioButton{
i18n(
"Authenticate via Active Directory")};
140 if (!engineIsVersion(2, 2, 28, GpgME::GpgSMEngine)) {
141 radioButton->setText(
i18n(
"Authenticate via Active Directory (requires GnuPG 2.2.28 or later)"));
143 radioButton->setToolTip(
144 i18nc(
"@info:tooltip",
"On Windows, authenticate to the LDAP server using the Active Directory with the current user."));
145 authenticationGroup->addButton(radioButton,
static_cast<int>(KeyserverAuthentication::ActiveDirectory));
149 auto radioButton =
new QRadioButton{
i18n(
"Authenticate with user and password")};
150 radioButton->setToolTip(
i18nc(
"@info:tooltip",
"Authenticate to the LDAP server with your LDAP credentials."));
151 authenticationGroup->addButton(radioButton,
static_cast<int>(KeyserverAuthentication::Password));
157 auto layout =
new QGridLayout{credentialsWidget};
158 layout->setColumnStretch(1, 1);
161 userEdit->setToolTip(
i18nc(
"@info:tooltip",
"Enter your LDAP user resp. Bind DN for authenticating to the LDAP server."));
162 userEdit->setClearButtonEnabled(
true);
166 passwordEdit->setToolTip(
xi18nc(
"@info:tooltip",
167 "Enter your password for authenticating to the LDAP server.<nl/>"
168 "<warning>The password will be saved in the clear "
169 "in a configuration file in your home directory.</warning>"));
170 passwordEdit->setClearButtonEnabled(
true);
175 mainLayout->addWidget(authenticationWidget);
177 auto securityWidget =
new QGroupBox{
i18n(
"Connection Security"),
parent};
178 if (!engineIsVersion(2, 2, 28, GpgME::GpgSMEngine)) {
179 securityWidget->setTitle(
i18n(
"Connection Security (requires GnuPG 2.2.28 or later)"));
182 auto layout =
new QVBoxLayout{securityWidget};
184 auto radioButton =
new QRadioButton{
i18n(
"Use default connection (probably not TLS secured)")};
185 radioButton->setToolTip(
i18nc(
"@info:tooltip",
186 "Use GnuPG's default to connect to the LDAP server. "
187 "By default, GnuPG 2.3 and earlier use a plain, not TLS secured connection. "
188 "<b>(Not recommended)</b>"));
189 radioButton->setChecked(
true);
190 connectionGroup->addButton(radioButton,
static_cast<int>(KeyserverConnection::Default));
194 auto radioButton =
new QRadioButton{
i18n(
"Do not use a TLS secured connection")};
195 radioButton->setToolTip(
i18nc(
"@info:tooltip",
196 "Use a plain, not TLS secured connection to connect to the LDAP server. "
197 "<b>(Not recommended)</b>"));
198 connectionGroup->addButton(radioButton,
static_cast<int>(KeyserverConnection::Plain));
202 auto radioButton =
new QRadioButton{
i18n(
"Use TLS secured connection")};
203 radioButton->setToolTip(
i18nc(
"@info:tooltip",
204 "Use a standard TLS secured connection (initiated with STARTTLS) "
205 "to connect to the LDAP server. "
206 "<b>(Recommended)</b>"));
207 connectionGroup->addButton(radioButton,
static_cast<int>(KeyserverConnection::UseSTARTTLS));
211 auto radioButton =
new QRadioButton{
i18n(
"Tunnel LDAP through a TLS connection")};
212 radioButton->setToolTip(
i18nc(
"@info:tooltip",
213 "Use a TLS secured connection through which the connection to the "
214 "LDAP server is tunneled. "
215 "<b>(Not recommended)</b>"));
216 connectionGroup->addButton(radioButton,
static_cast<int>(KeyserverConnection::TunnelThroughTLS));
220 mainLayout->addWidget(securityWidget);
222 advancedSettings->setTitle(
i18n(
"Advanced Settings"));
224 auto layout =
new QGridLayout{advancedSettings};
225 layout->setColumnStretch(1, 1);
228 baseDnEdit->setToolTip(
i18nc(
"@info:tooltip",
229 "<b>(Optional, can usually be left empty)</b> "
230 "Enter the base DN for this LDAP server to limit searches "
231 "to only that subtree of the directory."));
232 baseDnEdit->setClearButtonEnabled(
true);
236 additionalFlagsEdit->setToolTip(
i18nc(
"@info:tooltip",
237 "Here you can enter additional flags that are not yet (or no longer) "
238 "supported by Kleopatra. For example, older versions of GnuPG use "
239 "<code>ldaps</code> to request a TLS secured connection."));
240 additionalFlagsEdit->setClearButtonEnabled(
true);
243 mainLayout->addWidget(advancedSettings);
245 mainLayout->addStretch(1);
251 mainLayout->addWidget(buttonBox);
257 return ui.hostEdit->text().trimmed();
262 return ui.useDefaultPortCheckBox->isChecked() ? -1 : ui.portSpinBox->value();
265 KeyserverAuthentication authentication()
const
267 return KeyserverAuthentication{ui.authenticationGroup->checkedId()};
272 return ui.userEdit->text().trimmed();
275 QString password()
const
277 return ui.passwordEdit->password();
280 KeyserverConnection connection()
const
282 return KeyserverConnection{ui.connectionGroup->checkedId()};
285 QString baseDn()
const
287 return ui.baseDnEdit->text().trimmed();
290 QStringList additionalFlags()
const
292 return transformInPlace(ui.additionalFlagsEdit->text().split(QLatin1Char{
','},
Qt::SkipEmptyParts), [](
const auto &flag) {
293 return flag.trimmed();
297 bool inputIsAcceptable()
const
299 const bool hostIsSet = !host().isEmpty();
302 ui.invalidHostLabel->setVisible(!url.
isValid());
303 const bool requiredCredentialsAreSet = authentication() != KeyserverAuthentication::Password || (!user().isEmpty() && !password().isEmpty());
304 return hostIsSet && requiredCredentialsAreSet && url.
isValid();
309 ui.portSpinBox->setEnabled(!ui.useDefaultPortCheckBox->isChecked());
310 if (ui.useDefaultPortCheckBox->isChecked()) {
311 ui.portSpinBox->setValue(defaultPort(connection()));
314 ui.userEdit->setEnabled(authentication() == KeyserverAuthentication::Password);
315 ui.passwordEdit->setEnabled(authentication() == KeyserverAuthentication::Password);
321 Private(EditDirectoryServiceDialog *q)
337 connect(ui.passwordEdit, &KPasswordLineEdit::passwordChanged, q, [
this]() {
357 void setKeyserver(
const KeyserverConfig &keyserver)
359 ui.hostEdit->setText(keyserver.host());
360 ui.useDefaultPortCheckBox->setChecked(keyserver.port() == -1);
361 ui.portSpinBox->setValue(keyserver.port() == -1 ? defaultPort(keyserver.connection()) : keyserver.port());
362 ui.authenticationGroup->button(
static_cast<int>(keyserver.authentication()))->setChecked(
true);
363 ui.userEdit->setText(keyserver.user());
364 ui.passwordEdit->setPassword(keyserver.password());
365 ui.connectionGroup->button(
static_cast<int>(keyserver.connection()))->setChecked(
true);
366 ui.baseDnEdit->setText(keyserver.ldapBaseDn());
367 ui.additionalFlagsEdit->setText(keyserver.additionalFlags().join(QLatin1Char{
','}));
369 ui.advancedSettings->setExpanded(!keyserver.ldapBaseDn().isEmpty() || !keyserver.additionalFlags().empty());
373 KeyserverConfig keyserver()
const
375 KeyserverConfig keyserver;
376 keyserver.setHost(host());
377 keyserver.setPort(port());
378 keyserver.setAuthentication(authentication());
379 keyserver.setUser(user());
380 keyserver.setPassword(password());
381 keyserver.setConnection(connection());
382 keyserver.setLdapBaseDn(baseDn());
383 keyserver.setAdditionalFlags(additionalFlags());
392 configGroup.writeEntry(
"Size", q->size());
399 const auto size = configGroup.readEntry(
"Size", QSize{});
400 if (
size.isValid()) {
408 , d{std::make_unique<Private>(this)}
410 setWindowTitle(
i18nc(
"@title:window",
"Edit Directory Service"));
413EditDirectoryServiceDialog::~EditDirectoryServiceDialog() =
default;
415void EditDirectoryServiceDialog::setKeyserver(
const KeyserverConfig &keyserver)
417 d->setKeyserver(keyserver);
420KeyserverConfig EditDirectoryServiceDialog::keyserver()
const
422 return d->keyserver();
425#include "moc_editdirectoryservicedialog.cpp"
static void assign(QPushButton *button, const KGuiItem &item)
static KSharedConfig::Ptr openStateConfig(const QString &fileName=QString())
QString xi18nc(const char *context, const char *text, const TYPE &arg...)
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
void textEdited(const QString &text)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
bool isValid() const const
void setHost(const QString &host, ParsingMode mode)