diff --git a/vpn/openconnect/CMakeLists.txt b/vpn/openconnect/CMakeLists.txt --- a/vpn/openconnect/CMakeLists.txt +++ b/vpn/openconnect/CMakeLists.txt @@ -39,7 +39,7 @@ openconnectauthworkerthread.cpp ) - ki18n_wrap_ui(openconnect_SRCS openconnectprop.ui openconnectauth.ui) + ki18n_wrap_ui(openconnect_SRCS openconnectprop.ui openconnectauth.ui openconnecttoken.ui) add_library(plasmanetworkmanagement_openconnectui ${openconnect_SRCS}) diff --git a/vpn/openconnect/nm-openconnect-service.h b/vpn/openconnect/nm-openconnect-service.h --- a/vpn/openconnect/nm-openconnect-service.h +++ b/vpn/openconnect/nm-openconnect-service.h @@ -38,10 +38,13 @@ #define NM_OPENCONNECT_KEY_PRIVKEY "userkey" #define NM_OPENCONNECT_KEY_MTU "mtu" #define NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID "pem_passphrase_fsid" +#define NM_OPENCONNECT_KEY_PREVENT_INVALID_CERT "prevent_invalid_cert" #define NM_OPENCONNECT_KEY_PROTOCOL "protocol" #define NM_OPENCONNECT_KEY_PROXY "proxy" #define NM_OPENCONNECT_KEY_CSD_ENABLE "enable_csd_trojan" #define NM_OPENCONNECT_KEY_CSD_WRAPPER "csd_wrapper" +#define NM_OPENCONNECT_KEY_TOKEN_MODE "stoken_source" +#define NM_OPENCONNECT_KEY_TOKEN_SECRET "stoken_string" #define NM_OPENCONNECT_USER "nm-openconnect" diff --git a/vpn/openconnect/openconnectauth.h b/vpn/openconnect/openconnectauth.h --- a/vpn/openconnect/openconnectauth.h +++ b/vpn/openconnect/openconnectauth.h @@ -62,6 +62,7 @@ void workerFinished(const int&); void viewServerLogToggled(bool); void connectHost(); + void initTokens(); }; #endif // OPENCONNECTAUTH_H diff --git a/vpn/openconnect/openconnectauth.cpp b/vpn/openconnect/openconnectauth.cpp --- a/vpn/openconnect/openconnectauth.cpp +++ b/vpn/openconnect/openconnectauth.cpp @@ -57,14 +57,31 @@ #include } +#if !OPENCONNECT_CHECK_VER(2,1) +#define __openconnect_set_token_mode(...) -EOPNOTSUPP +#elif !OPENCONNECT_CHECK_VER(2,2) +#define __openconnect_set_token_mode(vpninfo, mode, secret) openconnect_set_stoken_mode(vpninfo, 1, secret) +#else +#define __openconnect_set_token_mode openconnect_set_token_mode +#endif + +#if OPENCONNECT_CHECK_VER(3,4) + static int updateToken(void*, const char*); +#endif + // name/address: IP/domain name of the host (OpenConnect accepts both, so no difference here) // group: user group on the server typedef struct { QString name; QString group; QString address; } VPNHost; +typedef struct { + oc_token_mode_t tokenMode; + QByteArray tokenSecret; +} Token; + class OpenconnectAuthWidgetPrivate { public: @@ -82,6 +99,8 @@ int cancelPipes[2]; QList > serverLog; int passwordFormIndex; + QByteArray tokenMode; + Token token; enum LogLevels {Error = 0, Info, Debug, Trace}; }; @@ -122,10 +141,15 @@ connect(d->worker, &OpenconnectAuthWorkerThread::updateLog, this, &OpenconnectAuthWidget::updateLog); connect(d->worker, QOverload::of(&OpenconnectAuthWorkerThread::writeNewConfig), this, &OpenconnectAuthWidget::writeNewConfig); connect(d->worker, &OpenconnectAuthWorkerThread::cookieObtained, this, &OpenconnectAuthWidget::workerFinished); + connect(d->worker, &OpenconnectAuthWorkerThread::initTokens, this, &OpenconnectAuthWidget::initTokens); readConfig(); readSecrets(); +#if OPENCONNECT_CHECK_VER(3,4) + openconnect_set_token_callbacks(d->vpninfo, &d->secrets, NULL, &updateToken); +#endif + // This might be set by readSecrets() so don't connect it until now connect(d->ui.cmbHosts, QOverload::of(&QComboBox::currentIndexChanged), this, &OpenconnectAuthWidget::connectHost); @@ -196,6 +220,8 @@ const QString protocol = dataMap[NM_OPENCONNECT_KEY_PROTOCOL]; openconnect_set_protocol(d->vpninfo, OC3DUP(protocol == "juniper" ? "nc" : protocol.toUtf8().data())); } + + d->tokenMode = dataMap[NM_OPENCONNECT_KEY_TOKEN_MODE].toUtf8(); } void OpenconnectAuthWidget::readSecrets() @@ -248,6 +274,40 @@ if (d->secrets["save_passwords"] == "yes") { d->ui.chkStorePasswords->setChecked(true); } + + d->token.tokenMode = OC_TOKEN_MODE_NONE; + d->token.tokenSecret = nullptr; + + if (!d->tokenMode.isEmpty()) { + int ret = 0; + QByteArray tokenSecret = d->secrets[NM_OPENCONNECT_KEY_TOKEN_SECRET].toUtf8(); + + if (d->tokenMode == QStringLiteral("manual") && !tokenSecret.isEmpty()) { + ret = __openconnect_set_token_mode(d->vpninfo, OC_TOKEN_MODE_STOKEN, tokenSecret); + } else if (d->tokenMode ==QStringLiteral("stokenrc")) { + ret = __openconnect_set_token_mode(d->vpninfo, OC_TOKEN_MODE_STOKEN, NULL); + } else if (d->tokenMode == QStringLiteral("totp") && !tokenSecret.isEmpty()) { + ret = __openconnect_set_token_mode(d->vpninfo, OC_TOKEN_MODE_TOTP, tokenSecret); + } +#if OPENCONNECT_CHECK_VER(3,4) + else if (d->tokenMode == QStringLiteral("hotp") && !tokenSecret.isEmpty()) { + ret = __openconnect_set_token_mode(d->vpninfo, OC_TOKEN_MODE_HOTP, tokenSecret); + } +#endif +#if OPENCONNECT_CHECK_VER(5,0) + else if (d->tokenMode == "yubioath") { + /* This needs to be done from a thread because it can call back to + ask for the PIN */ + d->token.tokenMode = OC_TOKEN_MODE_YUBIOATH; + if (!tokenSecret.isEmpty()) { + d->token.tokenSecret = tokenSecret; + } + } +#endif + if (ret) { + addFormInfo(QLatin1String("dialog-error"), i18n("Failed to initialize software token: %1", ret)); + } + } } void OpenconnectAuthWidget::acceptDialog() @@ -269,6 +329,7 @@ void OpenconnectAuthWidget::connectHost() { Q_D(OpenconnectAuthWidget); + d->userQuit = true; if (write(d->cancelPipes[1], "x", 1)) { // not a lot we can do @@ -301,6 +362,15 @@ d->worker->start(); } +void OpenconnectAuthWidget::initTokens() +{ + Q_D(OpenconnectAuthWidget); + + if (d->token.tokenMode != OC_TOKEN_MODE_NONE) { + __openconnect_set_token_mode(d->vpninfo, d->token.tokenMode, d->token.tokenSecret); + } +} + QVariantMap OpenconnectAuthWidget::setting() const { Q_D(const OpenconnectAuthWidget); @@ -346,6 +416,15 @@ return secretData; } +#if OPENCONNECT_CHECK_VER(3,4) +static int updateToken(void *cbdata, const char *tok) +{ + NMStringMap *secrets = static_cast(cbdata); + secrets->insert(QLatin1String(NM_OPENCONNECT_KEY_TOKEN_SECRET), QLatin1String(tok)); + return 0; +} +#endif + void OpenconnectAuthWidget::writeNewConfig(const QString & buf) { Q_D(OpenconnectAuthWidget); @@ -355,6 +434,7 @@ void OpenconnectAuthWidget::updateLog(const QString &message, const int &level) { Q_D(OpenconnectAuthWidget); + QPair pair; pair.first = message; if (pair.first.endsWith(QLatin1String("\n"))) { @@ -401,6 +481,7 @@ void OpenconnectAuthWidget::addFormInfo(const QString &iconName, const QString &message) { Q_D(OpenconnectAuthWidget); + QHBoxLayout *layout = new QHBoxLayout(); QLabel *icon = new QLabel(this); QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); @@ -426,6 +507,7 @@ void OpenconnectAuthWidget::processAuthForm(struct oc_auth_form *form) { Q_D(OpenconnectAuthWidget); + deleteAllFromLayout(d->ui.loginBoxLayout); if (form->banner) { addFormInfo(QLatin1String("dialog-information"), form->banner); @@ -571,6 +653,10 @@ connect(buttons, &QDialogButtonBox::rejected, dialog.data(), &QDialog::reject); dialog->layout()->addWidget(widget); dialog->layout()->addWidget(buttons); + + const NMStringMap dataMap = d->setting->data(); + buttons->button(QDialogButtonBox::Ok)->setEnabled(dataMap[NM_OPENCONNECT_KEY_PREVENT_INVALID_CERT] != "yes"); + if(dialog.data()->exec() == QDialog::Accepted) { *accepted = true; } else { @@ -641,6 +727,7 @@ void OpenconnectAuthWidget::workerFinished(const int &ret) { Q_D(OpenconnectAuthWidget); + if (ret < 0) { QString message; QList >::const_iterator i; diff --git a/vpn/openconnect/openconnectauthworkerthread.h b/vpn/openconnect/openconnectauthworkerthread.h --- a/vpn/openconnect/openconnectauthworkerthread.h +++ b/vpn/openconnect/openconnectauthworkerthread.h @@ -91,7 +91,7 @@ void updateLog(const QString &, const int&); void writeNewConfig(const QString &); void cookieObtained(const int&); - + void initTokens(void); protected: void run() override; diff --git a/vpn/openconnect/openconnectauthworkerthread.cpp b/vpn/openconnect/openconnectauthworkerthread.cpp --- a/vpn/openconnect/openconnectauthworkerthread.cpp +++ b/vpn/openconnect/openconnectauthworkerthread.cpp @@ -116,6 +116,7 @@ void OpenconnectAuthWorkerThread::run() { openconnect_init_ssl(); + Q_EMIT initTokens(); int ret = openconnect_obtain_cookie(m_openconnectInfo); if (*m_userDecidedToQuit) { return; diff --git a/vpn/openconnect/openconnectprop.ui b/vpn/openconnect/openconnectprop.ui --- a/vpn/openconnect/openconnectprop.ui +++ b/vpn/openconnect/openconnectprop.ui @@ -6,14 +6,20 @@ 0 0 - 339 - 364 + 418 + 488 + + + 0 + 0 + + OpenConnect Settings - + @@ -94,6 +100,9 @@ VPN Protocol: + + cmbProtocol + @@ -125,9 +134,6 @@ Certificate Authentication - - 6 - @@ -138,6 +144,13 @@ + + + + *.pem *.crt *.key + + + @@ -148,13 +161,6 @@ - - - - *.pem *.crt *.key - - - @@ -169,6 +175,39 @@ + + + + Prevent user from manually accepting invalid certificates + + + + + + + + + + + + + Qt::Horizontal + + + + 278 + 20 + + + + + + + + Token Authentication + + + @@ -190,10 +229,13 @@ KUrlRequester - QWidget + QFrame
kurlrequester.h
+ + enableTokenSecret(int) + diff --git a/vpn/openconnect/openconnecttoken.ui b/vpn/openconnect/openconnecttoken.ui new file mode 100644 --- /dev/null +++ b/vpn/openconnect/openconnecttoken.ui @@ -0,0 +1,71 @@ + + + OpenConnectToken + + + + 0 + 0 + 500 + 191 + + + + OpenConnect OTP Tokens + + + + + + Software Token Authentication + + + + + + Token Mode: + + + cmbTokenMode + + + + + + + QComboBox::AdjustToContents + + + + + + + Token Secret: + + + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + PasswordField + QLineEdit +
passwordfield.h
+
+
+ + +
diff --git a/vpn/openconnect/openconnectwidget.h b/vpn/openconnect/openconnectwidget.h --- a/vpn/openconnect/openconnectwidget.h +++ b/vpn/openconnect/openconnectwidget.h @@ -31,13 +31,22 @@ class OpenconnectSettingWidget : public SettingWidget { Q_OBJECT + Q_DECLARE_PRIVATE(OpenconnectSettingWidget) public: explicit OpenconnectSettingWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget *parent = nullptr); ~OpenconnectSettingWidget() override; void loadConfig(const NetworkManager::Setting::Ptr &setting) override; + void loadSecrets(const NetworkManager::Setting::Ptr &setting) override; QVariantMap setting() const override; bool isValid() const override; + bool initTokenGroup(); + +private Q_SLOTS: + void showTokens(); + void handleTokenSecret(int index); + void saveTokens(); + void restoreTokens(); private: OpenconnectSettingWidgetPrivate *const d_ptr; diff --git a/vpn/openconnect/openconnectwidget.cpp b/vpn/openconnect/openconnectwidget.cpp --- a/vpn/openconnect/openconnectwidget.cpp +++ b/vpn/openconnect/openconnectwidget.cpp @@ -22,32 +22,83 @@ #include "openconnectwidget.h" #include #include +#include #include "ui_openconnectprop.h" +#include "ui_openconnecttoken.h" #include +#include #include "nm-openconnect-service.h" +#include +#ifndef OPENCONNECT_CHECK_VER +#define OPENCONNECT_CHECK_VER(x,y) 0 +#endif + +#if !OPENCONNECT_CHECK_VER(2,1) +#define openconnect_has_stoken_support() 0 +#endif +#if !OPENCONNECT_CHECK_VER(2,2) +#define openconnect_has_oath_support() 0 +#endif +#if !OPENCONNECT_CHECK_VER(5,0) +#define openconnect_has_yubioath_support() 0 +#endif + +typedef struct { + int tokenIndex; + QString tokenSecret; +} Token; + class OpenconnectSettingWidgetPrivate { public: Ui_OpenconnectProp ui; + Ui::OpenConnectToken tokenUi; NetworkManager::VpnSetting::Ptr setting; + QDialog *tokenDlg; + Token token; }; OpenconnectSettingWidget::OpenconnectSettingWidget(const NetworkManager::VpnSetting::Ptr &setting, QWidget * parent) : SettingWidget(setting, parent) , d_ptr(new OpenconnectSettingWidgetPrivate) { Q_D(OpenconnectSettingWidget); + d->ui.setupUi(this); d->setting = setting; + // Connect for validity check + connect(d->ui.leGateway, &QLineEdit::textChanged, this, &OpenconnectSettingWidget::slotWidgetChanged); + + connect(d->ui.buTokens, &QPushButton::clicked, this, &OpenconnectSettingWidget::showTokens); + + d->tokenDlg = new QDialog(this); + d->tokenUi.setupUi(d->tokenDlg); + d->tokenUi.leTokenSecret->setPasswordModeEnabled(true); + d->tokenUi.leTokenSecret->setPasswordOptionsEnabled(true); + QVBoxLayout * layout = new QVBoxLayout(d->tokenDlg); + layout->addWidget(d->tokenDlg); + d->tokenDlg->setLayout(layout); + connect(d->tokenUi.buttonBox, &QDialogButtonBox::accepted, d->tokenDlg, &QDialog::accept); + connect(d->tokenUi.buttonBox, &QDialogButtonBox::rejected, d->tokenDlg, &QDialog::reject); + connect(d->tokenDlg, &QDialog::rejected, this, &OpenconnectSettingWidget::restoreTokens); + connect(d->tokenDlg, &QDialog::accepted, this, &OpenconnectSettingWidget::saveTokens); + + connect(d->tokenUi.cmbTokenMode, QOverload::of(&QComboBox::currentIndexChanged), this, QOverload::of((&OpenconnectSettingWidget::handleTokenSecret))); + // Connect for setting check watchChangedSetting(); - // Connect for validity check - connect(d->ui.leGateway, &QLineEdit::textChanged, this, &OpenconnectSettingWidget::slotWidgetChanged); + // Remove these from setting check: + // Just popping up the tokenDlg changes nothing + disconnect(d->ui.buTokens, &QPushButton::clicked, this, &SettingWidget::settingChanged); + // User cancels means nothing should change here + disconnect(d->tokenUi.buttonBox->button(QDialogButtonBox::Cancel), &QPushButton::clicked, this, &SettingWidget::settingChanged); + + d->tokenUi.gbToken->setVisible(initTokenGroup()); KAcceleratorManager::manage(this); @@ -61,13 +112,76 @@ delete d_ptr; } +void OpenconnectSettingWidget::handleTokenSecret(int index) +{ + Q_D(const OpenconnectSettingWidget); + + QVariant mode = d->tokenUi.cmbTokenMode->itemData(index); + if (mode == QStringLiteral("disabled")) { + d->tokenUi.leTokenSecret->setEnabled(false); + d->tokenUi.leTokenSecret->setToolTip("No secrets needed."); + } else if (mode == QStringLiteral("stokenrc")) { + d->tokenUi.leTokenSecret->setEnabled(false); + d->tokenUi.leTokenSecret->setToolTip("No secrets needed; will read them from ~/.stokenrc."); + } else if (mode == QStringLiteral("manual")) { + d->tokenUi.leTokenSecret->setToolTip("Insert the secret here. See the openconnect documentation for syntax."); + d->tokenUi.leTokenSecret->setEnabled(true); + } else if (mode == QStringLiteral("totp")) { + d->tokenUi.leTokenSecret->setEnabled(true); + d->tokenUi.leTokenSecret->setToolTip("Insert the secret here, with a sha specification and a leading '0x' or 'base32:'. See the openconnect documentation for syntax."); + } else if (mode ==QStringLiteral("hotp")) { + d->tokenUi.leTokenSecret->setEnabled(true); + d->tokenUi.leTokenSecret->setToolTip("Insert the secret here, with a leading '0x' or 'base32:' and a trailing counter after a comma (','), See the openconnect documentation for syntax."); + } else if (mode == QStringLiteral("yubioath")) { + d->tokenUi.leTokenSecret->setEnabled(true); + d->tokenUi.leTokenSecret->setToolTip("Insert the token Id here, in the form company:username. Make sure to set your Yubikey in CCID mode"); + } else { // Not really needed now, but who knows? + d->tokenUi.leTokenSecret->setEnabled(false); + d->tokenUi.leTokenSecret->setToolTip(""); + } +} + +bool OpenconnectSettingWidget::initTokenGroup() +{ + Q_D(const OpenconnectSettingWidget); + + int validRows = 0; + QStringList tokenLabelList = QStringList() << "Disabled" << "RSA SecurID — read from ~/.stokenrc" << "RSA SecurID — manually entered" << "TOTP — manually entered" << "HOTP — manually entered" << "Yubikey"; + QStringList tokenModeList = QStringList() << "disabled" << "stokenrc" << "manual" << "totp" << "hotp" << "yubioath"; + QComboBox *combo = d->tokenUi.cmbTokenMode; + + combo->addItem(tokenLabelList[validRows]); + combo->setItemData(validRows, tokenModeList[validRows], Qt::UserRole); + validRows++; + if (openconnect_has_stoken_support ()) { + for ( ; validRows < 3; validRows++) { + combo->addItem(tokenLabelList[validRows]); + combo->setItemData(validRows, tokenModeList[validRows], Qt::UserRole); + } + } + if (openconnect_has_oath_support ()) { + combo->addItem(tokenLabelList[validRows]); + combo->setItemData(validRows, tokenModeList[validRows], Qt::UserRole); + validRows++; + if (OPENCONNECT_CHECK_VER(3,4)) { + combo->addItem(tokenLabelList[validRows]); + combo->setItemData(validRows, tokenModeList[validRows], Qt::UserRole); + validRows++; + } + } + if (openconnect_has_yubioath_support ()) { + combo->addItem(tokenLabelList[validRows]); + combo->setItemData(validRows, tokenModeList[validRows], Qt::UserRole); + } + return validRows > 0; +} + void OpenconnectSettingWidget::loadConfig(const NetworkManager::Setting::Ptr &setting) { Q_D(OpenconnectSettingWidget); - Q_UNUSED(setting) // General settings - const NMStringMap dataMap = d->setting->data(); + const NMStringMap dataMap = setting.staticCast()->data(); d->ui.cmbProtocol->setCurrentIndex(dataMap[NM_OPENCONNECT_KEY_PROTOCOL] != QLatin1String("anyconnect")); d->ui.leGateway->setText(dataMap[NM_OPENCONNECT_KEY_GATEWAY]); @@ -78,6 +192,40 @@ d->ui.leUserCert->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENCONNECT_KEY_USERCERT])); d->ui.leUserPrivateKey->setUrl(QUrl::fromLocalFile(dataMap[NM_OPENCONNECT_KEY_PRIVKEY])); d->ui.chkUseFsid->setChecked(dataMap[NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID] == "yes"); + d->ui.preventInvalidCert->setChecked(dataMap[NM_OPENCONNECT_KEY_PREVENT_INVALID_CERT] == "yes"); + + // Token settings + const NetworkManager::Setting::SecretFlags tokenSecretFlag = static_cast(dataMap.value(NM_OPENCONNECT_KEY_TOKEN_SECRET"-flags").toInt()); + if (tokenSecretFlag == NetworkManager::Setting::None) { + d->tokenUi.leTokenSecret->setPasswordOption(PasswordField::StoreForAllUsers); + } else if (tokenSecretFlag == NetworkManager::Setting::AgentOwned) { + d->tokenUi.leTokenSecret->setPasswordOption(PasswordField::StoreForUser); + } else { + d->tokenUi.leTokenSecret->setPasswordOption(PasswordField::AlwaysAsk); + } + for (int index = 0; index < d->tokenUi.cmbTokenMode->count(); index++) { + if (d->tokenUi.cmbTokenMode->itemData(index, Qt::UserRole) == dataMap[NM_OPENCONNECT_KEY_TOKEN_MODE]) { + d->tokenUi.cmbTokenMode->setCurrentIndex(index); + d->token.tokenIndex = index; + if (index > 1) { + loadSecrets(d->setting); + } + break; + } + } +} + +void OpenconnectSettingWidget::loadSecrets(const NetworkManager::Setting::Ptr &setting) +{ + Q_D(OpenconnectSettingWidget); + + NetworkManager::VpnSetting::Ptr vpnSetting = setting.staticCast(); + + if (vpnSetting) { + const NMStringMap secrets = vpnSetting->secrets(); + d->tokenUi.leTokenSecret->setText(secrets.value(NM_OPENCONNECT_KEY_TOKEN_SECRET)); + d->token.tokenSecret = secrets.value(NM_OPENCONNECT_KEY_TOKEN_SECRET); + } } QVariantMap OpenconnectSettingWidget::setting() const @@ -88,6 +236,7 @@ setting.setServiceType(QLatin1String(NM_DBUS_SERVICE_OPENCONNECT)); NMStringMap data; + NMStringMap secrets; data.insert(NM_OPENCONNECT_KEY_PROTOCOL, d->ui.cmbProtocol->currentIndex() ? QLatin1String("nc") : QLatin1String("anyconnect")); data.insert(QLatin1String(NM_OPENCONNECT_KEY_GATEWAY), d->ui.leGateway->text()); @@ -108,27 +257,64 @@ data.insert(QLatin1String(NM_OPENCONNECT_KEY_PRIVKEY), d->ui.leUserPrivateKey->url().toLocalFile()); } data.insert(QLatin1String(NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID), d->ui.chkUseFsid->isChecked() ? "yes" : "no"); + data.insert(QLatin1String(NM_OPENCONNECT_KEY_PREVENT_INVALID_CERT), d->ui.preventInvalidCert->isChecked() ? "yes" : "no"); + + int index = d->tokenUi.cmbTokenMode->currentIndex(); + data.insert(QLatin1String(NM_OPENCONNECT_KEY_TOKEN_MODE), d->tokenUi.cmbTokenMode->itemData(index, Qt::UserRole).toString()); + secrets.insert(QLatin1String(NM_OPENCONNECT_KEY_TOKEN_SECRET), d->tokenUi.leTokenSecret->text()); // Restore previous flags, this is necessary for keeping secrets stored in KWallet for (const QString &key : d->setting->data().keys()) { if (key.contains(QLatin1String("-flags"))) { data.insert(key, d->setting->data().value(key)); } } + if (d->tokenUi.leTokenSecret->passwordOption() == PasswordField::StoreForAllUsers) { + data.insert(NM_OPENCONNECT_KEY_TOKEN_SECRET"-flags", QString::number(NetworkManager::Setting::None)); + } else if (d->tokenUi.leTokenSecret->passwordOption() == PasswordField::StoreForUser) { + data.insert(NM_OPENCONNECT_KEY_TOKEN_SECRET"-flags", QString::number(NetworkManager::Setting::AgentOwned)); + } else { + data.insert(NM_OPENCONNECT_KEY_TOKEN_SECRET"-flags", QString::number(NetworkManager::Setting::NotSaved)); + } + /* These are different for every login session, and should not be stored */ data.insert(QLatin1String(NM_OPENCONNECT_KEY_COOKIE"-flags"), QString::number(NetworkManager::Setting::NotSaved)); data.insert(QLatin1String(NM_OPENCONNECT_KEY_GWCERT"-flags"), QString::number(NetworkManager::Setting::NotSaved)); data.insert(QLatin1String(NM_OPENCONNECT_KEY_GATEWAY"-flags"), QString::number(NetworkManager::Setting::NotSaved)); setting.setData(data); - setting.setSecrets(d->setting->secrets()); + setting.setSecrets(secrets); return setting.toMap(); } +void OpenconnectSettingWidget::restoreTokens() +{ + Q_D(const OpenconnectSettingWidget); + + d->tokenUi.cmbTokenMode->setCurrentIndex(d->token.tokenIndex); + d->tokenUi.leTokenSecret->setText(d->token.tokenSecret); +} + +void OpenconnectSettingWidget::saveTokens() +{ + Q_D(OpenconnectSettingWidget); + + d->token.tokenIndex = d->tokenUi.cmbTokenMode->currentIndex(); + d->token.tokenSecret = d->tokenUi.leTokenSecret->text(); +} + +void OpenconnectSettingWidget::showTokens() +{ + Q_D(OpenconnectSettingWidget); + + d->tokenDlg->show(); +} + bool OpenconnectSettingWidget::isValid() const { Q_D(const OpenconnectSettingWidget); + return !d->ui.leGateway->text().isEmpty(); }