mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-04-02 18:31:50 -04:00
Add support to switch gateway
This commit is contained in:
parent
e22bb8e1b7
commit
599ff3668f
@ -140,18 +140,16 @@ void GatewayAuthenticator::samlAuth(QString samlMethod, QString samlRequest, QSt
|
|||||||
{
|
{
|
||||||
PLOGI << "Trying to perform SAML login with saml-method " << samlMethod;
|
PLOGI << "Trying to perform SAML login with saml-method " << samlMethod;
|
||||||
|
|
||||||
SAMLLoginWindow *loginWindow = samlLogin(samlMethod, samlRequest, preloginUrl);
|
SAMLLoginWindow *loginWindow = new SAMLLoginWindow;
|
||||||
|
|
||||||
if (!loginWindow) {
|
connect(loginWindow, &SAMLLoginWindow::success, this, &GatewayAuthenticator::onSAMLLoginSuccess);
|
||||||
openMessageBox("SAML Login failed for gateway");
|
connect(loginWindow, &SAMLLoginWindow::fail, this, &GatewayAuthenticator::onSAMLLoginFail);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(loginWindow, &SAMLLoginWindow::success, this, &GatewayAuthenticator::onSAMLLoginFinished);
|
|
||||||
connect(loginWindow, &SAMLLoginWindow::rejected, this, &GatewayAuthenticator::onLoginWindowRejected);
|
connect(loginWindow, &SAMLLoginWindow::rejected, this, &GatewayAuthenticator::onLoginWindowRejected);
|
||||||
|
|
||||||
|
loginWindow->login(samlMethod, samlRequest, preloginUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GatewayAuthenticator::onSAMLLoginFinished(const QMap<QString, QString> &samlResult)
|
void GatewayAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> &samlResult)
|
||||||
{
|
{
|
||||||
PLOGI << "SAML login succeeded, got the prelogin cookie " << samlResult.value("preloginCookie");
|
PLOGI << "SAML login succeeded, got the prelogin cookie " << samlResult.value("preloginCookie");
|
||||||
|
|
||||||
@ -161,3 +159,8 @@ void GatewayAuthenticator::onSAMLLoginFinished(const QMap<QString, QString> &sam
|
|||||||
|
|
||||||
login(params);
|
login(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GatewayAuthenticator::onSAMLLoginFail(const QString msg)
|
||||||
|
{
|
||||||
|
emit fail(msg);
|
||||||
|
}
|
||||||
|
@ -25,7 +25,8 @@ private slots:
|
|||||||
void onPerformNormalLogin(const QString &username, const QString &password);
|
void onPerformNormalLogin(const QString &username, const QString &password);
|
||||||
void onLoginWindowRejected();
|
void onLoginWindowRejected();
|
||||||
void onLoginWindowFinished();
|
void onLoginWindowFinished();
|
||||||
void onSAMLLoginFinished(const QMap<QString, QString> &samlResult);
|
void onSAMLLoginSuccess(const QMap<QString, QString> &samlResult);
|
||||||
|
void onSAMLLoginFail(const QString msg);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString gateway;
|
QString gateway;
|
||||||
@ -34,7 +35,7 @@ private:
|
|||||||
|
|
||||||
const PortalConfigResponse& portalConfig;
|
const PortalConfigResponse& portalConfig;
|
||||||
|
|
||||||
NormalLoginWindow *normalLoginWindow{nullptr};
|
NormalLoginWindow *normalLoginWindow{ nullptr };
|
||||||
|
|
||||||
void login(const LoginParams& params);
|
void login(const LoginParams& params);
|
||||||
void doAuth();
|
void doAuth();
|
||||||
|
@ -12,8 +12,6 @@ using namespace gpclient::helper;
|
|||||||
GPClient::GPClient(QWidget *parent)
|
GPClient::GPClient(QWidget *parent)
|
||||||
: QMainWindow(parent)
|
: QMainWindow(parent)
|
||||||
, ui(new Ui::GPClient)
|
, ui(new Ui::GPClient)
|
||||||
, systemTrayIcon(new QSystemTrayIcon(parent))
|
|
||||||
, contextMenu(new QMenu("GlobalProtect", parent))
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setWindowTitle("GlobalProtect");
|
setWindowTitle("GlobalProtect");
|
||||||
@ -29,29 +27,15 @@ GPClient::GPClient(QWidget *parent)
|
|||||||
connect(vpn, &com::yuezk::qt::GPService::disconnected, this, &GPClient::onVPNDisconnected);
|
connect(vpn, &com::yuezk::qt::GPService::disconnected, this, &GPClient::onVPNDisconnected);
|
||||||
connect(vpn, &com::yuezk::qt::GPService::logAvailable, this, &GPClient::onVPNLogAvailable);
|
connect(vpn, &com::yuezk::qt::GPService::logAvailable, this, &GPClient::onVPNLogAvailable);
|
||||||
|
|
||||||
connect(systemTrayIcon, &QSystemTrayIcon::activated, this, &GPClient::onSystemTrayActivated);
|
|
||||||
|
|
||||||
// Initiallize the context menu of system tray.
|
// Initiallize the context menu of system tray.
|
||||||
openAction = contextMenu->addAction(QIcon::fromTheme("system-run"), "Open", this, &GPClient::activiate);
|
initSystemTrayIcon();
|
||||||
connectAction = contextMenu->addAction(QIcon::fromTheme("preferences-system-network"), "Connect", this, &GPClient::doConnect);
|
|
||||||
contextMenu->addSeparator();
|
|
||||||
quitAction = contextMenu->addAction(QIcon::fromTheme("application-exit"), "Quit", this, &GPClient::quit);
|
|
||||||
systemTrayIcon->setContextMenu(contextMenu);
|
|
||||||
systemTrayIcon->setToolTip("GlobalProtect");
|
|
||||||
|
|
||||||
initVpnStatus();
|
initVpnStatus();
|
||||||
systemTrayIcon->show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GPClient::~GPClient()
|
GPClient::~GPClient()
|
||||||
{
|
{
|
||||||
delete ui;
|
delete ui;
|
||||||
delete vpn;
|
delete vpn;
|
||||||
delete systemTrayIcon;
|
|
||||||
delete openAction;
|
|
||||||
delete connectAction;
|
|
||||||
delete quitAction;
|
|
||||||
delete contextMenu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPClient::on_connectButton_clicked()
|
void GPClient::on_connectButton_clicked()
|
||||||
@ -64,85 +48,35 @@ void GPClient::on_portalInput_returnPressed()
|
|||||||
doConnect();
|
doConnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPClient::updateConnectionStatus(const GPClient::VpnStatus &status)
|
void GPClient::on_portalInput_editingFinished()
|
||||||
{
|
{
|
||||||
switch (status) {
|
populateGatewayMenu();
|
||||||
case VpnStatus::disconnected:
|
|
||||||
ui->statusLabel->setText("Not Connected");
|
|
||||||
ui->statusImage->setStyleSheet("image: url(:/images/not_connected.png); padding: 15;");
|
|
||||||
ui->connectButton->setText("Connect");
|
|
||||||
ui->connectButton->setDisabled(false);
|
|
||||||
ui->portalInput->setReadOnly(false);
|
|
||||||
|
|
||||||
systemTrayIcon->setIcon(QIcon{ ":/images/not_connected.png" });
|
|
||||||
connectAction->setEnabled(true);
|
|
||||||
connectAction->setText("Connect");
|
|
||||||
break;
|
|
||||||
case VpnStatus::pending:
|
|
||||||
ui->statusImage->setStyleSheet("image: url(:/images/pending.png); padding: 15;");
|
|
||||||
ui->connectButton->setDisabled(true);
|
|
||||||
ui->portalInput->setReadOnly(true);
|
|
||||||
|
|
||||||
systemTrayIcon->setIcon(QIcon{ ":/images/pending.png" });
|
|
||||||
connectAction->setEnabled(false);
|
|
||||||
break;
|
|
||||||
case VpnStatus::connected:
|
|
||||||
ui->statusLabel->setText("Connected");
|
|
||||||
ui->statusImage->setStyleSheet("image: url(:/images/connected.png); padding: 15;");
|
|
||||||
ui->connectButton->setText("Disconnect");
|
|
||||||
ui->connectButton->setDisabled(false);
|
|
||||||
ui->portalInput->setReadOnly(true);
|
|
||||||
|
|
||||||
systemTrayIcon->setIcon(QIcon{ ":/images/connected.png" });
|
|
||||||
connectAction->setEnabled(true);
|
|
||||||
connectAction->setText("Disconnect");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPClient::onVPNConnected()
|
void GPClient::initSystemTrayIcon()
|
||||||
{
|
{
|
||||||
updateConnectionStatus(VpnStatus::connected);
|
systemTrayIcon = new QSystemTrayIcon(this);
|
||||||
}
|
contextMenu = new QMenu("GlobalProtect", this);
|
||||||
|
|
||||||
void GPClient::onVPNDisconnected()
|
gatewaySwitchMenu = new QMenu("Switch Gateway", this);
|
||||||
{
|
gatewaySwitchMenu->setIcon(QIcon::fromTheme("network-workgroup"));
|
||||||
updateConnectionStatus(VpnStatus::disconnected);
|
populateGatewayMenu();
|
||||||
}
|
|
||||||
|
|
||||||
void GPClient::onVPNLogAvailable(QString log)
|
systemTrayIcon->setIcon(QIcon(":/images/not_connected.png"));
|
||||||
{
|
systemTrayIcon->setToolTip("GlobalProtect");
|
||||||
PLOGI << log;
|
systemTrayIcon->setContextMenu(contextMenu);
|
||||||
}
|
|
||||||
|
|
||||||
void GPClient::onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason)
|
connect(systemTrayIcon, &QSystemTrayIcon::activated, this, &GPClient::onSystemTrayActivated);
|
||||||
{
|
connect(gatewaySwitchMenu, &QMenu::triggered, this, &GPClient::onGatewayChanged);
|
||||||
switch (reason) {
|
|
||||||
case QSystemTrayIcon::Trigger:
|
|
||||||
case QSystemTrayIcon::DoubleClick:
|
|
||||||
this->activiate();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPClient::activiate()
|
openAction = contextMenu->addAction(QIcon::fromTheme("window-new"), "Open", this, &GPClient::activiate);
|
||||||
{
|
connectAction = contextMenu->addAction(QIcon::fromTheme("preferences-system-network"), "Connect", this, &GPClient::doConnect);
|
||||||
activateWindow();
|
contextMenu->addMenu(gatewaySwitchMenu);
|
||||||
showNormal();
|
contextMenu->addSeparator();
|
||||||
}
|
clearAction = contextMenu->addAction(QIcon::fromTheme("edit-clear"), "Reset Settings", this, &GPClient::clearSettings);
|
||||||
|
quitAction = contextMenu->addAction(QIcon::fromTheme("application-exit"), "Quit", this, &GPClient::quit);
|
||||||
|
|
||||||
QString GPClient::portal() const
|
systemTrayIcon->show();
|
||||||
{
|
|
||||||
const QString input = ui->portalInput->text().trimmed();
|
|
||||||
|
|
||||||
if (input.startsWith("http")) {
|
|
||||||
return QUrl(input).authority();
|
|
||||||
}
|
|
||||||
return input;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPClient::initVpnStatus() {
|
void GPClient::initVpnStatus() {
|
||||||
@ -161,11 +95,115 @@ void GPClient::initVpnStatus() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPClient::populateGatewayMenu()
|
||||||
|
{
|
||||||
|
const QList<GPGateway> gateways = allGateways();
|
||||||
|
gatewaySwitchMenu->clear();
|
||||||
|
|
||||||
|
if (gateways.isEmpty()) {
|
||||||
|
gatewaySwitchMenu->addAction("<None>")->setData(-1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString currentGatewayName = currentGateway().name();
|
||||||
|
for (int i = 0; i < gateways.length(); i++) {
|
||||||
|
const GPGateway g = gateways.at(i);
|
||||||
|
QString iconImage = ":/images/radio_unselected.png";
|
||||||
|
if (g.name() == currentGatewayName) {
|
||||||
|
iconImage = ":/images/radio_selected.png";
|
||||||
|
}
|
||||||
|
gatewaySwitchMenu->addAction(QIcon(iconImage), g.name())->setData(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::updateConnectionStatus(const GPClient::VpnStatus &status)
|
||||||
|
{
|
||||||
|
switch (status) {
|
||||||
|
case VpnStatus::disconnected:
|
||||||
|
ui->statusLabel->setText("Not Connected");
|
||||||
|
ui->statusImage->setStyleSheet("image: url(:/images/not_connected.png); padding: 15;");
|
||||||
|
ui->connectButton->setText("Connect");
|
||||||
|
ui->connectButton->setDisabled(false);
|
||||||
|
ui->portalInput->setReadOnly(false);
|
||||||
|
|
||||||
|
systemTrayIcon->setIcon(QIcon{ ":/images/not_connected.png" });
|
||||||
|
connectAction->setEnabled(true);
|
||||||
|
connectAction->setText("Connect");
|
||||||
|
gatewaySwitchMenu->setEnabled(true);
|
||||||
|
clearAction->setEnabled(true);
|
||||||
|
break;
|
||||||
|
case VpnStatus::pending:
|
||||||
|
ui->statusImage->setStyleSheet("image: url(:/images/pending.png); padding: 15;");
|
||||||
|
ui->connectButton->setDisabled(true);
|
||||||
|
ui->portalInput->setReadOnly(true);
|
||||||
|
|
||||||
|
systemTrayIcon->setIcon(QIcon{ ":/images/pending.png" });
|
||||||
|
connectAction->setEnabled(false);
|
||||||
|
gatewaySwitchMenu->setEnabled(false);
|
||||||
|
clearAction->setEnabled(false);
|
||||||
|
break;
|
||||||
|
case VpnStatus::connected:
|
||||||
|
ui->statusLabel->setText("Connected");
|
||||||
|
ui->statusImage->setStyleSheet("image: url(:/images/connected.png); padding: 15;");
|
||||||
|
ui->connectButton->setText("Disconnect");
|
||||||
|
ui->connectButton->setDisabled(false);
|
||||||
|
ui->portalInput->setReadOnly(true);
|
||||||
|
|
||||||
|
systemTrayIcon->setIcon(QIcon{ ":/images/connected.png" });
|
||||||
|
connectAction->setEnabled(true);
|
||||||
|
connectAction->setText("Disconnect");
|
||||||
|
gatewaySwitchMenu->setEnabled(true);
|
||||||
|
clearAction->setEnabled(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason)
|
||||||
|
{
|
||||||
|
switch (reason) {
|
||||||
|
case QSystemTrayIcon::Trigger:
|
||||||
|
case QSystemTrayIcon::DoubleClick:
|
||||||
|
this->activiate();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::onGatewayChanged(QAction *action)
|
||||||
|
{
|
||||||
|
const int index = action->data().toInt();
|
||||||
|
|
||||||
|
if (index == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GPGateway g = allGateways().at(index);
|
||||||
|
|
||||||
|
// If the selected gateway is the same as the current gateway
|
||||||
|
if (g.name() == currentGateway().name()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCurrentGateway(g);
|
||||||
|
|
||||||
|
if (connected()) {
|
||||||
|
ui->statusLabel->setText("Switching Gateway...");
|
||||||
|
ui->connectButton->setEnabled(false);
|
||||||
|
|
||||||
|
vpn->disconnect();
|
||||||
|
isSwitchingGateway = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GPClient::doConnect()
|
void GPClient::doConnect()
|
||||||
{
|
{
|
||||||
const QString btnText = ui->connectButton->text();
|
const QString btnText = ui->connectButton->text();
|
||||||
const QString portal = this->portal();
|
const QString portal = this->portal();
|
||||||
|
|
||||||
|
// Display the main window if portal is empty
|
||||||
if (portal.isEmpty()) {
|
if (portal.isEmpty()) {
|
||||||
activiate();
|
activiate();
|
||||||
return;
|
return;
|
||||||
@ -173,11 +211,15 @@ void GPClient::doConnect()
|
|||||||
|
|
||||||
if (btnText.endsWith("Connect")) {
|
if (btnText.endsWith("Connect")) {
|
||||||
settings::save("portal", portal);
|
settings::save("portal", portal);
|
||||||
ui->statusLabel->setText("Authenticating...");
|
|
||||||
updateConnectionStatus(VpnStatus::pending);
|
|
||||||
|
|
||||||
// Perform the portal login
|
// Login to the previously saved gateway
|
||||||
portalLogin(portal);
|
if (!currentGateway().name().isEmpty()) {
|
||||||
|
isQuickConnect = true;
|
||||||
|
gatewayLogin();
|
||||||
|
} else {
|
||||||
|
// Perform the portal login
|
||||||
|
portalLogin();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ui->statusLabel->setText("Disconnecting...");
|
ui->statusLabel->setText("Disconnecting...");
|
||||||
updateConnectionStatus(VpnStatus::pending);
|
updateConnectionStatus(VpnStatus::pending);
|
||||||
@ -187,9 +229,9 @@ void GPClient::doConnect()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login to the portal interface to get the portal config and preferred gateway
|
// Login to the portal interface to get the portal config and preferred gateway
|
||||||
void GPClient::portalLogin(const QString& portal)
|
void GPClient::portalLogin()
|
||||||
{
|
{
|
||||||
PortalAuthenticator *portalAuth = new PortalAuthenticator(portal);
|
PortalAuthenticator *portalAuth = new PortalAuthenticator(portal());
|
||||||
|
|
||||||
connect(portalAuth, &PortalAuthenticator::success, this, &GPClient::onPortalSuccess);
|
connect(portalAuth, &PortalAuthenticator::success, this, &GPClient::onPortalSuccess);
|
||||||
// Prelogin failed on the portal interface, try to treat the portal as a gateway interface
|
// Prelogin failed on the portal interface, try to treat the portal as a gateway interface
|
||||||
@ -197,13 +239,16 @@ void GPClient::portalLogin(const QString& portal)
|
|||||||
// Portal login failed
|
// Portal login failed
|
||||||
connect(portalAuth, &PortalAuthenticator::fail, this, &GPClient::onPortalFail);
|
connect(portalAuth, &PortalAuthenticator::fail, this, &GPClient::onPortalFail);
|
||||||
|
|
||||||
|
ui->statusLabel->setText("Authenticating...");
|
||||||
|
updateConnectionStatus(VpnStatus::pending);
|
||||||
portalAuth->authenticate();
|
portalAuth->authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPClient::onPortalSuccess(const PortalConfigResponse &portalConfig, const GPGateway &gateway)
|
void GPClient::onPortalSuccess(const PortalConfigResponse portalConfig, const GPGateway gateway, QList<GPGateway> allGateways)
|
||||||
{
|
{
|
||||||
this->portalConfig = portalConfig;
|
this->portalConfig = portalConfig;
|
||||||
this->gateway = gateway;
|
setAllGateways(allGateways);
|
||||||
|
setCurrentGateway(gateway);
|
||||||
|
|
||||||
gatewayLogin();
|
gatewayLogin();
|
||||||
}
|
}
|
||||||
@ -212,8 +257,17 @@ void GPClient::onPortalPreloginFail()
|
|||||||
{
|
{
|
||||||
PLOGI << "Portal prelogin failed, try to preform login on the the gateway interface...";
|
PLOGI << "Portal prelogin failed, try to preform login on the the gateway interface...";
|
||||||
|
|
||||||
// Set the gateway address to portal input
|
// Treat the portal input as the gateway address
|
||||||
gateway.setAddress(portal());
|
GPGateway g;
|
||||||
|
g.setName(portal());
|
||||||
|
g.setAddress(portal());
|
||||||
|
|
||||||
|
QList<GPGateway> gateways;
|
||||||
|
gateways.append(g);
|
||||||
|
|
||||||
|
setAllGateways(gateways);
|
||||||
|
setCurrentGateway(g);
|
||||||
|
|
||||||
gatewayLogin();
|
gatewayLogin();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,36 +281,126 @@ void GPClient::onPortalFail(const QString &msg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Login to the gateway
|
// Login to the gateway
|
||||||
void GPClient::gatewayLogin() const
|
void GPClient::gatewayLogin()
|
||||||
{
|
{
|
||||||
GatewayAuthenticator *gatewayAuth = new GatewayAuthenticator(gateway.address(), portalConfig);
|
GatewayAuthenticator *gatewayAuth = new GatewayAuthenticator(currentGateway().address(), portalConfig);
|
||||||
|
|
||||||
connect(gatewayAuth, &GatewayAuthenticator::success, this, &GPClient::onGatewaySuccess);
|
connect(gatewayAuth, &GatewayAuthenticator::success, this, &GPClient::onGatewaySuccess);
|
||||||
connect(gatewayAuth, &GatewayAuthenticator::fail, this, &GPClient::onGatewayFail);
|
connect(gatewayAuth, &GatewayAuthenticator::fail, this, &GPClient::onGatewayFail);
|
||||||
|
|
||||||
|
ui->statusLabel->setText("Authenticating...");
|
||||||
|
updateConnectionStatus(VpnStatus::pending);
|
||||||
gatewayAuth->authenticate();
|
gatewayAuth->authenticate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GPClient::onGatewaySuccess(const QString &authCookie)
|
||||||
|
{
|
||||||
|
PLOGI << "Gateway login succeeded, got the cookie " << authCookie;
|
||||||
|
|
||||||
|
isQuickConnect = false;
|
||||||
|
vpn->connect(currentGateway().address(), portalConfig.username(), authCookie);
|
||||||
|
ui->statusLabel->setText("Connecting...");
|
||||||
|
updateConnectionStatus(VpnStatus::pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::onGatewayFail(const QString &msg)
|
||||||
|
{
|
||||||
|
// If the quick connect on gateway failed, perform the portal login
|
||||||
|
if (isQuickConnect && !msg.isEmpty()) {
|
||||||
|
isQuickConnect = false;
|
||||||
|
portalLogin();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!msg.isEmpty()) {
|
||||||
|
openMessageBox("Gateway authentication failed.", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConnectionStatus(VpnStatus::disconnected);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::activiate()
|
||||||
|
{
|
||||||
|
activateWindow();
|
||||||
|
showNormal();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GPClient::portal() const
|
||||||
|
{
|
||||||
|
const QString input = ui->portalInput->text().trimmed();
|
||||||
|
|
||||||
|
if (input.startsWith("http")) {
|
||||||
|
return QUrl(input).authority();
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GPClient::connected() const
|
||||||
|
{
|
||||||
|
const QString statusText = ui->statusLabel->text();
|
||||||
|
return statusText.contains("Connected") && !statusText.contains("Not");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QList<GPGateway> GPClient::allGateways() const
|
||||||
|
{
|
||||||
|
const QString gatewaysJson = settings::get(portal() + "_gateways").toString();
|
||||||
|
return GPGateway::fromJson(gatewaysJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::setAllGateways(QList<GPGateway> gateways)
|
||||||
|
{
|
||||||
|
settings::save(portal() + "_gateways", GPGateway::serialize(gateways));
|
||||||
|
populateGatewayMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
GPGateway GPClient::currentGateway() const
|
||||||
|
{
|
||||||
|
const QString selectedGateway = settings::get(portal() + "_selectedGateway").toString();
|
||||||
|
|
||||||
|
for (auto g : allGateways()) {
|
||||||
|
if (g.name() == selectedGateway) {
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return GPGateway{};
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::setCurrentGateway(const GPGateway gateway)
|
||||||
|
{
|
||||||
|
settings::save(portal() + "_selectedGateway", gateway.name());
|
||||||
|
populateGatewayMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::clearSettings()
|
||||||
|
{
|
||||||
|
settings::clear();
|
||||||
|
populateGatewayMenu();
|
||||||
|
ui->portalInput->clear();
|
||||||
|
}
|
||||||
|
|
||||||
void GPClient::quit()
|
void GPClient::quit()
|
||||||
{
|
{
|
||||||
vpn->disconnect();
|
vpn->disconnect();
|
||||||
QApplication::quit();
|
QApplication::quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPClient::onGatewaySuccess(const QString &authCookie)
|
void GPClient::onVPNConnected()
|
||||||
{
|
{
|
||||||
PLOGI << "Gateway login succeeded, got the cookie " << authCookie;
|
updateConnectionStatus(VpnStatus::connected);
|
||||||
|
|
||||||
vpn->connect(gateway.address(), portalConfig.username(), authCookie);
|
|
||||||
ui->statusLabel->setText("Connecting...");
|
|
||||||
updateConnectionStatus(VpnStatus::pending);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPClient::onGatewayFail(const QString &msg)
|
void GPClient::onVPNDisconnected()
|
||||||
{
|
{
|
||||||
if (!msg.isEmpty()) {
|
|
||||||
openMessageBox("Portal authentication failed.", msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
updateConnectionStatus(VpnStatus::disconnected);
|
updateConnectionStatus(VpnStatus::disconnected);
|
||||||
|
|
||||||
|
if (isSwitchingGateway) {
|
||||||
|
gatewayLogin();
|
||||||
|
isSwitchingGateway = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPClient::onVPNLogAvailable(QString log)
|
||||||
|
{
|
||||||
|
PLOGI << log;
|
||||||
}
|
}
|
||||||
|
@ -19,15 +19,21 @@ class GPClient : public QMainWindow
|
|||||||
public:
|
public:
|
||||||
GPClient(QWidget *parent = nullptr);
|
GPClient(QWidget *parent = nullptr);
|
||||||
~GPClient();
|
~GPClient();
|
||||||
|
|
||||||
void activiate();
|
void activiate();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_connectButton_clicked();
|
void on_connectButton_clicked();
|
||||||
void on_portalInput_returnPressed();
|
void on_portalInput_returnPressed();
|
||||||
|
void on_portalInput_editingFinished();
|
||||||
|
|
||||||
void onPortalSuccess(const PortalConfigResponse &portalConfig, const GPGateway &gateway);
|
void onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason);
|
||||||
|
void onGatewayChanged(QAction *action);
|
||||||
|
|
||||||
|
void onPortalSuccess(const PortalConfigResponse portalConfig, const GPGateway gateway, QList<GPGateway> allGateways);
|
||||||
void onPortalPreloginFail();
|
void onPortalPreloginFail();
|
||||||
void onPortalFail(const QString &msg);
|
void onPortalFail(const QString &msg);
|
||||||
|
|
||||||
void onGatewaySuccess(const QString &authCookie);
|
void onGatewaySuccess(const QString &authCookie);
|
||||||
void onGatewayFail(const QString &msg);
|
void onGatewayFail(const QString &msg);
|
||||||
|
|
||||||
@ -35,8 +41,6 @@ private slots:
|
|||||||
void onVPNDisconnected();
|
void onVPNDisconnected();
|
||||||
void onVPNLogAvailable(QString log);
|
void onVPNLogAvailable(QString log);
|
||||||
|
|
||||||
void onSystemTrayActivated(QSystemTrayIcon::ActivationReason reason);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class VpnStatus
|
enum class VpnStatus
|
||||||
{
|
{
|
||||||
@ -52,20 +56,34 @@ private:
|
|||||||
QMenu *contextMenu;
|
QMenu *contextMenu;
|
||||||
QAction *openAction;
|
QAction *openAction;
|
||||||
QAction *connectAction;
|
QAction *connectAction;
|
||||||
|
|
||||||
|
QMenu *gatewaySwitchMenu;
|
||||||
|
QAction *clearAction;
|
||||||
QAction *quitAction;
|
QAction *quitAction;
|
||||||
|
|
||||||
GPGateway gateway;
|
bool isQuickConnect { false };
|
||||||
|
bool isSwitchingGateway { false };
|
||||||
PortalConfigResponse portalConfig;
|
PortalConfigResponse portalConfig;
|
||||||
|
|
||||||
QString portal() const;
|
void initSystemTrayIcon();
|
||||||
|
|
||||||
void initVpnStatus();
|
void initVpnStatus();
|
||||||
void doConnect();
|
void populateGatewayMenu();
|
||||||
void updateConnectionStatus(const VpnStatus &status);
|
void updateConnectionStatus(const VpnStatus &status);
|
||||||
|
|
||||||
void portalLogin(const QString& portal);
|
void doConnect();
|
||||||
void gatewayLogin() const;
|
void portalLogin();
|
||||||
|
void gatewayLogin();
|
||||||
|
|
||||||
|
QString portal() const;
|
||||||
|
bool connected() const;
|
||||||
|
|
||||||
|
QList<GPGateway> allGateways() const;
|
||||||
|
void setAllGateways(QList<GPGateway> gateways);
|
||||||
|
|
||||||
|
GPGateway currentGateway() const;
|
||||||
|
void setCurrentGateway(const GPGateway gateway);
|
||||||
|
|
||||||
|
void clearSettings();
|
||||||
void quit();
|
void quit();
|
||||||
};
|
};
|
||||||
#endif // GPCLIENT_H
|
#endif // GPCLIENT_H
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
#include "gpgateway.h"
|
#include "gpgateway.h"
|
||||||
|
|
||||||
|
#include <QJsonObject>
|
||||||
|
#include <QJsonDocument>
|
||||||
|
#include <QJsonArray>
|
||||||
|
|
||||||
GPGateway::GPGateway()
|
GPGateway::GPGateway()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -36,3 +40,58 @@ int GPGateway::priorityOf(QString ruleName) const
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject GPGateway::toJsonObject() const
|
||||||
|
{
|
||||||
|
QJsonObject obj;
|
||||||
|
obj.insert("name", name());
|
||||||
|
obj.insert("address", address());
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GPGateway::toString() const
|
||||||
|
{
|
||||||
|
QJsonDocument jsonDoc{ toJsonObject() };
|
||||||
|
return QString::fromUtf8(jsonDoc.toJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString GPGateway::serialize(QList<GPGateway> &gateways)
|
||||||
|
{
|
||||||
|
QJsonArray arr;
|
||||||
|
|
||||||
|
for (auto g : gateways) {
|
||||||
|
arr.append(g.toJsonObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc{ arr };
|
||||||
|
return QString::fromUtf8(jsonDoc.toJson());
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<GPGateway> GPGateway::fromJson(const QString &jsonString)
|
||||||
|
{
|
||||||
|
QList<GPGateway> gateways;
|
||||||
|
|
||||||
|
if (jsonString.isEmpty()) {
|
||||||
|
return gateways;
|
||||||
|
}
|
||||||
|
|
||||||
|
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonString.toUtf8());
|
||||||
|
|
||||||
|
for (auto item : jsonDoc.array()) {
|
||||||
|
GPGateway g = GPGateway::fromJsonObject(item.toObject());
|
||||||
|
gateways.append(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
return gateways;
|
||||||
|
}
|
||||||
|
|
||||||
|
GPGateway GPGateway::fromJsonObject(const QJsonObject &jsonObj)
|
||||||
|
{
|
||||||
|
GPGateway g;
|
||||||
|
|
||||||
|
g.setName(jsonObj.value("name").toString());
|
||||||
|
g.setAddress(jsonObj.value("address").toString());
|
||||||
|
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
#include <QJsonObject>
|
||||||
|
|
||||||
class GPGateway
|
class GPGateway
|
||||||
{
|
{
|
||||||
@ -16,6 +17,12 @@ public:
|
|||||||
void setAddress(const QString &address);
|
void setAddress(const QString &address);
|
||||||
void setPriorityRules(const QMap<QString, int> &priorityRules);
|
void setPriorityRules(const QMap<QString, int> &priorityRules);
|
||||||
int priorityOf(QString ruleName) const;
|
int priorityOf(QString ruleName) const;
|
||||||
|
QJsonObject toJsonObject() const;
|
||||||
|
QString toString() const;
|
||||||
|
|
||||||
|
static QString serialize(QList<GPGateway> &gateways);
|
||||||
|
static QList<GPGateway> fromJson(const QString &jsonString);
|
||||||
|
static GPGateway fromJsonObject(const QJsonObject &jsonObj);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QString _name;
|
QString _name;
|
||||||
|
@ -21,27 +21,11 @@ QNetworkReply* gpclient::helper::createRequest(QString url, QByteArray params)
|
|||||||
return networkManager->post(request, params);
|
return networkManager->post(request, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
SAMLLoginWindow* gpclient::helper::samlLogin(QString samlMethod, QString samlRequest, QString preloginUrl)
|
GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> gateways, const QString ruleName)
|
||||||
{
|
{
|
||||||
SAMLLoginWindow *loginWindow = new SAMLLoginWindow;
|
GPGateway gateway = gateways.first();
|
||||||
|
|
||||||
if (samlMethod == "POST") {
|
for (GPGateway g : gateways) {
|
||||||
loginWindow->login(preloginUrl, samlRequest);
|
|
||||||
} else if (samlMethod == "REDIRECT") {
|
|
||||||
loginWindow->login(samlRequest);
|
|
||||||
} else {
|
|
||||||
PLOGE << "Unknown saml-auth-method expected POST or REDIRECT, got " << samlMethod;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return loginWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> *gateways, const QString ruleName)
|
|
||||||
{
|
|
||||||
GPGateway gateway = gateways->first();
|
|
||||||
|
|
||||||
for (GPGateway g : *gateways) {
|
|
||||||
if (g.priorityOf(ruleName) > gateway.priorityOf(ruleName)) {
|
if (g.priorityOf(ruleName) > gateway.priorityOf(ruleName)) {
|
||||||
gateway = g;
|
gateway = g;
|
||||||
}
|
}
|
||||||
@ -76,7 +60,7 @@ QUrlQuery gpclient::helper::parseGatewayResponse(const QByteArray &xml)
|
|||||||
void gpclient::helper::openMessageBox(const QString &message, const QString& informativeText)
|
void gpclient::helper::openMessageBox(const QString &message, const QString& informativeText)
|
||||||
{
|
{
|
||||||
QMessageBox msgBox;
|
QMessageBox msgBox;
|
||||||
msgBox.setWindowTitle("GlobalProtect");
|
msgBox.setWindowTitle("Notice");
|
||||||
msgBox.setText(message);
|
msgBox.setText(message);
|
||||||
msgBox.setFixedWidth(500);
|
msgBox.setFixedWidth(500);
|
||||||
msgBox.setStyleSheet("QLabel{min-width: 250px}");
|
msgBox.setStyleSheet("QLabel{min-width: 250px}");
|
||||||
@ -117,3 +101,8 @@ void gpclient::helper::settings::save(const QString &key, const QVariant &value)
|
|||||||
{
|
{
|
||||||
_settings->setValue(key, value);
|
_settings->setValue(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gpclient::helper::settings::clear()
|
||||||
|
{
|
||||||
|
_settings->clear();
|
||||||
|
}
|
||||||
|
@ -20,9 +20,7 @@ namespace gpclient {
|
|||||||
|
|
||||||
QNetworkReply* createRequest(QString url, QByteArray params = nullptr);
|
QNetworkReply* createRequest(QString url, QByteArray params = nullptr);
|
||||||
|
|
||||||
SAMLLoginWindow *samlLogin(QString samlMethod, QString samlRequest, QString preloginUrl);
|
GPGateway filterPreferredGateway(QList<GPGateway> gateways, const QString ruleName);
|
||||||
|
|
||||||
GPGateway filterPreferredGateway(QList<GPGateway> *gateways, const QString ruleName);
|
|
||||||
|
|
||||||
QUrlQuery parseGatewayResponse(const QByteArray& xml);
|
QUrlQuery parseGatewayResponse(const QByteArray& xml);
|
||||||
|
|
||||||
@ -36,6 +34,7 @@ namespace gpclient {
|
|||||||
|
|
||||||
QVariant get(const QString &key, const QVariant &defaultValue = QVariant());
|
QVariant get(const QString &key, const QVariant &defaultValue = QVariant());
|
||||||
void save(const QString &key, const QVariant &value);
|
void save(const QString &key, const QVariant &value);
|
||||||
|
void clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -113,24 +113,27 @@ void PortalAuthenticator::samlAuth()
|
|||||||
{
|
{
|
||||||
PLOGI << "Trying to perform SAML login with saml-method " << preloginResponse.samlMethod();
|
PLOGI << "Trying to perform SAML login with saml-method " << preloginResponse.samlMethod();
|
||||||
|
|
||||||
SAMLLoginWindow *loginWindow = samlLogin(preloginResponse.samlMethod(), preloginResponse.samlRequest(), preloginUrl);
|
SAMLLoginWindow *loginWindow = new SAMLLoginWindow;
|
||||||
|
|
||||||
if (!loginWindow) {
|
|
||||||
openMessageBox("SAML Login failed for portal");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(loginWindow, &SAMLLoginWindow::success, this, &PortalAuthenticator::onSAMLLoginSuccess);
|
connect(loginWindow, &SAMLLoginWindow::success, this, &PortalAuthenticator::onSAMLLoginSuccess);
|
||||||
|
connect(loginWindow, &SAMLLoginWindow::fail, this, &PortalAuthenticator::onSAMLLoginFail);
|
||||||
connect(loginWindow, &SAMLLoginWindow::rejected, this, &PortalAuthenticator::onLoginWindowRejected);
|
connect(loginWindow, &SAMLLoginWindow::rejected, this, &PortalAuthenticator::onLoginWindowRejected);
|
||||||
|
|
||||||
|
loginWindow->login(preloginResponse.samlMethod(), preloginResponse.samlRequest(), preloginUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> &samlResult)
|
void PortalAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> samlResult)
|
||||||
{
|
{
|
||||||
PLOGI << "SAML login succeeded, got the prelogin cookie " << samlResult.value("preloginCookie");
|
PLOGI << "SAML login succeeded, got the prelogin cookie " << samlResult.value("preloginCookie");
|
||||||
|
|
||||||
fetchConfig(samlResult.value("username"), "", samlResult.value("preloginCookie"));
|
fetchConfig(samlResult.value("username"), "", samlResult.value("preloginCookie"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PortalAuthenticator::onSAMLLoginFail(const QString msg)
|
||||||
|
{
|
||||||
|
emitFail(msg);
|
||||||
|
}
|
||||||
|
|
||||||
void PortalAuthenticator::fetchConfig(QString username, QString password, QString preloginCookie)
|
void PortalAuthenticator::fetchConfig(QString username, QString password, QString preloginCookie)
|
||||||
{
|
{
|
||||||
LoginParams params;
|
LoginParams params;
|
||||||
@ -146,7 +149,6 @@ void PortalAuthenticator::fetchConfig(QString username, QString password, QStrin
|
|||||||
PLOGI << "Fetching the portal config from " << configUrl << " for user: " << username;
|
PLOGI << "Fetching the portal config from " << configUrl << " for user: " << username;
|
||||||
|
|
||||||
QNetworkReply *reply = createRequest(configUrl, params.toUtf8());
|
QNetworkReply *reply = createRequest(configUrl, params.toUtf8());
|
||||||
|
|
||||||
connect(reply, &QNetworkReply::finished, this, &PortalAuthenticator::onFetchConfigFinished);
|
connect(reply, &QNetworkReply::finished, this, &PortalAuthenticator::onFetchConfigFinished);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +187,7 @@ void PortalAuthenticator::onFetchConfigFinished()
|
|||||||
normalLoginWindow->close();
|
normalLoginWindow->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
emit success(response, filterPreferredGateway(response.allGateways(), preloginResponse.region()));
|
emit success(response, filterPreferredGateway(response.allGateways(), preloginResponse.region()), response.allGateways());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalAuthenticator::emitFail(const QString& msg)
|
void PortalAuthenticator::emitFail(const QString& msg)
|
||||||
|
@ -18,7 +18,7 @@ public:
|
|||||||
void authenticate();
|
void authenticate();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void success(const PortalConfigResponse&, const GPGateway&);
|
void success(const PortalConfigResponse, const GPGateway, QList<GPGateway> allGateways);
|
||||||
void fail(const QString& msg);
|
void fail(const QString& msg);
|
||||||
void preloginFailed(const QString& msg);
|
void preloginFailed(const QString& msg);
|
||||||
|
|
||||||
@ -27,7 +27,8 @@ private slots:
|
|||||||
void onPerformNormalLogin(const QString &username, const QString &password);
|
void onPerformNormalLogin(const QString &username, const QString &password);
|
||||||
void onLoginWindowRejected();
|
void onLoginWindowRejected();
|
||||||
void onLoginWindowFinished();
|
void onLoginWindowFinished();
|
||||||
void onSAMLLoginSuccess(const QMap<QString, QString> &samlResult);
|
void onSAMLLoginSuccess(const QMap<QString, QString> samlResult);
|
||||||
|
void onSAMLLoginFail(const QString msg);
|
||||||
void onFetchConfigFinished();
|
void onFetchConfigFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -8,13 +8,11 @@ QString PortalConfigResponse::xmlPrelogonUserAuthCookie = "portal-prelogonuserau
|
|||||||
QString PortalConfigResponse::xmlGateways = "gateways";
|
QString PortalConfigResponse::xmlGateways = "gateways";
|
||||||
|
|
||||||
PortalConfigResponse::PortalConfigResponse()
|
PortalConfigResponse::PortalConfigResponse()
|
||||||
: _gateways(new QList<GPGateway>)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PortalConfigResponse::~PortalConfigResponse()
|
PortalConfigResponse::~PortalConfigResponse()
|
||||||
{
|
{
|
||||||
delete _gateways;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PortalConfigResponse PortalConfigResponse::parse(const QByteArray& xml)
|
PortalConfigResponse PortalConfigResponse::parse(const QByteArray& xml)
|
||||||
@ -33,7 +31,7 @@ PortalConfigResponse PortalConfigResponse::parse(const QByteArray& xml)
|
|||||||
} else if (name == xmlPrelogonUserAuthCookie) {
|
} else if (name == xmlPrelogonUserAuthCookie) {
|
||||||
response.setPrelogonUserAuthCookie(xmlReader.readElementText());
|
response.setPrelogonUserAuthCookie(xmlReader.readElementText());
|
||||||
} else if (name == xmlGateways) {
|
} else if (name == xmlGateways) {
|
||||||
parseGateways(xmlReader, response.allGateways());
|
response.setAllGateways(parseGateways(xmlReader));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,20 +53,23 @@ QString PortalConfigResponse::password() const
|
|||||||
return _password;
|
return _password;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader, QList<GPGateway> *gateways)
|
QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader)
|
||||||
{
|
{
|
||||||
|
QList<GPGateway> gateways;
|
||||||
|
|
||||||
while (xmlReader.name() != xmlGateways || !xmlReader.isEndElement()) {
|
while (xmlReader.name() != xmlGateways || !xmlReader.isEndElement()) {
|
||||||
xmlReader.readNext();
|
xmlReader.readNext();
|
||||||
// Parse the gateways -> external -> list -> entry
|
// Parse the gateways -> external -> list -> entry
|
||||||
if (xmlReader.name() == "entry" && xmlReader.isStartElement()) {
|
if (xmlReader.name() == "entry" && xmlReader.isStartElement()) {
|
||||||
GPGateway gateway;
|
GPGateway g;
|
||||||
QString address = xmlReader.attributes().value("name").toString();
|
QString address = xmlReader.attributes().value("name").toString();
|
||||||
gateway.setAddress(address);
|
g.setAddress(address);
|
||||||
gateway.setPriorityRules(parsePriorityRules(xmlReader));
|
g.setPriorityRules(parsePriorityRules(xmlReader));
|
||||||
gateway.setName(parseGatewayName(xmlReader));
|
g.setName(parseGatewayName(xmlReader));
|
||||||
gateways->append(gateway);
|
gateways.append(g);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return gateways;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<QString, int> PortalConfigResponse::parsePriorityRules(QXmlStreamReader &xmlReader)
|
QMap<QString, int> PortalConfigResponse::parsePriorityRules(QXmlStreamReader &xmlReader)
|
||||||
@ -112,11 +113,16 @@ QString PortalConfigResponse::prelogonUserAuthCookie() const
|
|||||||
return _prelogonAuthCookie;
|
return _prelogonAuthCookie;
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<GPGateway>* PortalConfigResponse::allGateways()
|
QList<GPGateway> PortalConfigResponse::allGateways()
|
||||||
{
|
{
|
||||||
return _gateways;
|
return _gateways;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PortalConfigResponse::setAllGateways(QList<GPGateway> gateways)
|
||||||
|
{
|
||||||
|
_gateways = gateways;
|
||||||
|
}
|
||||||
|
|
||||||
void PortalConfigResponse::setRawResponse(const QByteArray &response)
|
void PortalConfigResponse::setRawResponse(const QByteArray &response)
|
||||||
{
|
{
|
||||||
_rawResponse = response;
|
_rawResponse = response;
|
||||||
|
@ -20,7 +20,8 @@ public:
|
|||||||
QString password() const;
|
QString password() const;
|
||||||
QString userAuthCookie() const;
|
QString userAuthCookie() const;
|
||||||
QString prelogonUserAuthCookie() const;
|
QString prelogonUserAuthCookie() const;
|
||||||
QList<GPGateway>* allGateways();
|
QList<GPGateway> allGateways();
|
||||||
|
void setAllGateways(QList<GPGateway> gateways);
|
||||||
|
|
||||||
void setUsername(const QString& username);
|
void setUsername(const QString& username);
|
||||||
void setPassword(const QString& password);
|
void setPassword(const QString& password);
|
||||||
@ -36,13 +37,13 @@ private:
|
|||||||
QString _userAuthCookie;
|
QString _userAuthCookie;
|
||||||
QString _prelogonAuthCookie;
|
QString _prelogonAuthCookie;
|
||||||
|
|
||||||
QList<GPGateway> *_gateways;
|
QList<GPGateway> _gateways;
|
||||||
|
|
||||||
void setRawResponse(const QByteArray& response);
|
void setRawResponse(const QByteArray& response);
|
||||||
void setUserAuthCookie(const QString& cookie);
|
void setUserAuthCookie(const QString& cookie);
|
||||||
void setPrelogonUserAuthCookie(const QString& cookie);
|
void setPrelogonUserAuthCookie(const QString& cookie);
|
||||||
|
|
||||||
static void parseGateways(QXmlStreamReader &xmlReader, QList<GPGateway> *gateways);
|
static QList<GPGateway> parseGateways(QXmlStreamReader &xmlReader);
|
||||||
static QMap<QString, int> parsePriorityRules(QXmlStreamReader &xmlReader);
|
static QMap<QString, int> parsePriorityRules(QXmlStreamReader &xmlReader);
|
||||||
static QString parseGatewayName(QXmlStreamReader &xmlReader);
|
static QString parseGatewayName(QXmlStreamReader &xmlReader);
|
||||||
};
|
};
|
||||||
|
BIN
GPClient/radio_selected.png
Normal file
BIN
GPClient/radio_selected.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
GPClient/radio_unselected.png
Normal file
BIN
GPClient/radio_unselected.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 993 B |
@ -4,5 +4,7 @@
|
|||||||
<file>connected.png</file>
|
<file>connected.png</file>
|
||||||
<file>pending.png</file>
|
<file>pending.png</file>
|
||||||
<file>not_connected.png</file>
|
<file>not_connected.png</file>
|
||||||
|
<file>radio_unselected.png</file>
|
||||||
|
<file>radio_selected.png</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@ -3,16 +3,17 @@
|
|||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <plog/Log.h>
|
#include <plog/Log.h>
|
||||||
#include <QWebEngineProfile>
|
#include <QWebEngineProfile>
|
||||||
|
#include <QWebEngineView>
|
||||||
|
|
||||||
SAMLLoginWindow::SAMLLoginWindow(QWidget *parent)
|
SAMLLoginWindow::SAMLLoginWindow(QWidget *parent)
|
||||||
: QDialog(parent)
|
: QDialog(parent)
|
||||||
|
, webView(new EnhancedWebView(this))
|
||||||
{
|
{
|
||||||
setWindowTitle("GlobalProtect SAML Login");
|
setWindowTitle("GlobalProtect SAML Login");
|
||||||
setModal(true);
|
setModal(true);
|
||||||
resize(700, 550);
|
resize(700, 550);
|
||||||
|
|
||||||
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
|
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
|
||||||
webView = new EnhancedWebView(this);
|
|
||||||
webView->setUrl(QUrl("about:blank"));
|
webView->setUrl(QUrl("about:blank"));
|
||||||
// webView->page()->profile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
|
// webView->page()->profile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
|
||||||
verticalLayout->addWidget(webView);
|
verticalLayout->addWidget(webView);
|
||||||
@ -33,12 +34,15 @@ void SAMLLoginWindow::closeEvent(QCloseEvent *event)
|
|||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SAMLLoginWindow::login(QString url, QString html)
|
void SAMLLoginWindow::login(const QString samlMethod, const QString samlRequest, const QString preloingUrl)
|
||||||
{
|
{
|
||||||
if (html.isEmpty()) {
|
if (samlMethod == "POST") {
|
||||||
webView->load(QUrl(url));
|
webView->setHtml(samlRequest, preloingUrl);
|
||||||
|
} else if (samlMethod == "REDIRECT") {
|
||||||
|
webView->load(samlRequest);
|
||||||
} else {
|
} else {
|
||||||
webView->setHtml(html, url);
|
PLOGE << "Unknown saml-auth-method expected POST or REDIRECT, got " << samlMethod;
|
||||||
|
emit fail("Unknown saml-auth-method, got " + samlMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,10 +15,11 @@ public:
|
|||||||
explicit SAMLLoginWindow(QWidget *parent = nullptr);
|
explicit SAMLLoginWindow(QWidget *parent = nullptr);
|
||||||
~SAMLLoginWindow();
|
~SAMLLoginWindow();
|
||||||
|
|
||||||
void login(QString url, QString html = "");
|
void login(const QString samlMethod, const QString samlRequest, const QString preloingUrl);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void success(QMap<QString, QString> samlResult);
|
void success(QMap<QString, QString> samlResult);
|
||||||
|
void fail(const QString msg);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onResponseReceived(QJsonObject params);
|
void onResponseReceived(QJsonObject params);
|
||||||
|
@ -1,55 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file was generated by qdbusxml2cpp version 0.8
|
|
||||||
* Command line was: qdbusxml2cpp -i gpservice_adaptor.h -a :gpservice_adaptor.cpp gpservice.xml
|
|
||||||
*
|
|
||||||
* qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd.
|
|
||||||
*
|
|
||||||
* This is an auto-generated file.
|
|
||||||
* Do not edit! All changes made to it will be lost.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "gpservice_adaptor.h"
|
|
||||||
#include <QtCore/QMetaObject>
|
|
||||||
#include <QtCore/QByteArray>
|
|
||||||
#include <QtCore/QList>
|
|
||||||
#include <QtCore/QMap>
|
|
||||||
#include <QtCore/QString>
|
|
||||||
#include <QtCore/QStringList>
|
|
||||||
#include <QtCore/QVariant>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Implementation of adaptor class GPServiceAdaptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
GPServiceAdaptor::GPServiceAdaptor(QObject *parent)
|
|
||||||
: QDBusAbstractAdaptor(parent)
|
|
||||||
{
|
|
||||||
// constructor
|
|
||||||
setAutoRelaySignals(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
GPServiceAdaptor::~GPServiceAdaptor()
|
|
||||||
{
|
|
||||||
// destructor
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPServiceAdaptor::connect(const QString &server, const QString &username, const QString &passwd)
|
|
||||||
{
|
|
||||||
// handle method call com.yuezk.qt.GPService.connect
|
|
||||||
QMetaObject::invokeMethod(parent(), "connect", Q_ARG(QString, server), Q_ARG(QString, username), Q_ARG(QString, passwd));
|
|
||||||
}
|
|
||||||
|
|
||||||
void GPServiceAdaptor::disconnect()
|
|
||||||
{
|
|
||||||
// handle method call com.yuezk.qt.GPService.disconnect
|
|
||||||
QMetaObject::invokeMethod(parent(), "disconnect");
|
|
||||||
}
|
|
||||||
|
|
||||||
int GPServiceAdaptor::status()
|
|
||||||
{
|
|
||||||
// handle method call com.yuezk.qt.GPService.status
|
|
||||||
int out0;
|
|
||||||
QMetaObject::invokeMethod(parent(), "status", Q_RETURN_ARG(int, out0));
|
|
||||||
return out0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file was generated by qdbusxml2cpp version 0.8
|
|
||||||
* Command line was: qdbusxml2cpp -a gpservice_adaptor.h: gpservice.xml
|
|
||||||
*
|
|
||||||
* qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd.
|
|
||||||
*
|
|
||||||
* This is an auto-generated file.
|
|
||||||
* This file may have been hand-edited. Look for HAND-EDIT comments
|
|
||||||
* before re-generating it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GPSERVICE_ADAPTOR_H
|
|
||||||
#define GPSERVICE_ADAPTOR_H
|
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
|
||||||
#include <QtDBus/QtDBus>
|
|
||||||
QT_BEGIN_NAMESPACE
|
|
||||||
class QByteArray;
|
|
||||||
template<class T> class QList;
|
|
||||||
template<class Key, class Value> class QMap;
|
|
||||||
class QString;
|
|
||||||
class QStringList;
|
|
||||||
class QVariant;
|
|
||||||
QT_END_NAMESPACE
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Adaptor class for interface com.yuezk.qt.GPService
|
|
||||||
*/
|
|
||||||
class GPServiceAdaptor: public QDBusAbstractAdaptor
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
Q_CLASSINFO("D-Bus Interface", "com.yuezk.qt.GPService")
|
|
||||||
Q_CLASSINFO("D-Bus Introspection", ""
|
|
||||||
" <interface name=\"com.yuezk.qt.GPService\">\n"
|
|
||||||
" <signal name=\"connected\"/>\n"
|
|
||||||
" <signal name=\"disconnected\"/>\n"
|
|
||||||
" <signal name=\"logAvailable\">\n"
|
|
||||||
" <arg type=\"s\" name=\"log\"/>\n"
|
|
||||||
" </signal>\n"
|
|
||||||
" <method name=\"connect\">\n"
|
|
||||||
" <arg direction=\"in\" type=\"s\" name=\"server\"/>\n"
|
|
||||||
" <arg direction=\"in\" type=\"s\" name=\"username\"/>\n"
|
|
||||||
" <arg direction=\"in\" type=\"s\" name=\"passwd\"/>\n"
|
|
||||||
" </method>\n"
|
|
||||||
" <method name=\"disconnect\"/>\n"
|
|
||||||
" <method name=\"status\">\n"
|
|
||||||
" <arg direction=\"out\" type=\"i\"/>\n"
|
|
||||||
" </method>\n"
|
|
||||||
" </interface>\n"
|
|
||||||
"")
|
|
||||||
public:
|
|
||||||
GPServiceAdaptor(QObject *parent);
|
|
||||||
virtual ~GPServiceAdaptor();
|
|
||||||
|
|
||||||
public: // PROPERTIES
|
|
||||||
public Q_SLOTS: // METHODS
|
|
||||||
void connect(const QString &server, const QString &username, const QString &passwd);
|
|
||||||
void disconnect();
|
|
||||||
int status();
|
|
||||||
Q_SIGNALS: // SIGNALS
|
|
||||||
void connected();
|
|
||||||
void disconnected();
|
|
||||||
void logAvailable(const QString &log);
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
@ -7,9 +7,10 @@ A GlobalProtect VPN client (GUI) for Linux based on Openconnect and built with Q
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Supports both SAML and non-SAML authentication modes.
|
|
||||||
- Supports automatically select the preferred gateway from the multiple gateways.
|
|
||||||
- Similar user experience as the offical client in macOS.
|
- Similar user experience as the offical client in macOS.
|
||||||
|
- Supports both SAML and non-SAML authentication modes.
|
||||||
|
- Supports automatically selecting the preferred gateway from the multiple gateways.
|
||||||
|
- Supports switching gateway manually.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user