Compare commits

..

6 Commits

Author SHA1 Message Date
Kevin Yue
3a790cdc63 Release v1.2.3 2020-05-30 23:00:38 +08:00
Kevin Yue
73925fd1e2 Add more logs to debug the portal login (#16) 2020-05-30 22:58:58 +08:00
Kevin Yue
e12613d9a4 Try to fix saml hang (#14)
* Try to fix saml login hang

* Add more logs

* Add version number
2020-05-30 11:22:05 +08:00
Kevin Yue
86ad51b0ad Add extra parameters to prelogin request 2020-05-29 23:44:02 +08:00
Kevin Yue
1e2322b938 Fix saml login for portal-userauthcookie (#12) 2020-05-29 23:38:51 +08:00
Kevin Yue
4313b9d0e7 Update README.md 2020-05-25 10:05:11 +08:00
14 changed files with 144 additions and 60 deletions

View File

@@ -10,7 +10,7 @@ using namespace gpclient::helper;
GatewayAuthenticator::GatewayAuthenticator(const QString& gateway, const PortalConfigResponse& portalConfig) GatewayAuthenticator::GatewayAuthenticator(const QString& gateway, const PortalConfigResponse& portalConfig)
: QObject() : QObject()
, preloginUrl("https://" + gateway + "/ssl-vpn/prelogin.esp") , preloginUrl("https://" + gateway + "/ssl-vpn/prelogin.esp?tmp=tmp&kerberos-support=yes&ipv6-support=yes&clientVer=4100&clientos=Linux")
, loginUrl("https://" + gateway + "/ssl-vpn/login.esp") , loginUrl("https://" + gateway + "/ssl-vpn/login.esp")
, portalConfig(portalConfig) , portalConfig(portalConfig)
{ {
@@ -23,6 +23,8 @@ GatewayAuthenticator::~GatewayAuthenticator()
void GatewayAuthenticator::authenticate() void GatewayAuthenticator::authenticate()
{ {
PLOGI << "Start gateway authentication...";
LoginParams params; LoginParams params;
params.setUser(portalConfig.username()); params.setUser(portalConfig.username());
params.setPassword(portalConfig.password()); params.setPassword(portalConfig.password());
@@ -118,6 +120,8 @@ void GatewayAuthenticator::normalAuth(QString labelUsername, QString labelPasswo
void GatewayAuthenticator::onPerformNormalLogin(const QString &username, const QString &password) void GatewayAuthenticator::onPerformNormalLogin(const QString &username, const QString &password)
{ {
PLOGI << "Start to perform normal login...";
normalLoginWindow->setProcessing(true); normalLoginWindow->setProcessing(true);
LoginParams params; LoginParams params;
params.setUser(username); params.setUser(username);
@@ -151,11 +155,16 @@ void GatewayAuthenticator::samlAuth(QString samlMethod, QString samlRequest, QSt
void GatewayAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> &samlResult) void GatewayAuthenticator::onSAMLLoginSuccess(const QMap<QString, QString> &samlResult)
{ {
PLOGI << "SAML login succeeded, got the prelogin cookie " << samlResult.value("preloginCookie"); if (samlResult.contains("preloginCookie")) {
PLOGI << "SAML login succeeded, got the prelogin-cookie " << samlResult.value("preloginCookie");
} else {
PLOGI << "SAML login succeeded, got the portal-userauthcookie " << samlResult.value("userAuthCookie");
}
LoginParams params; LoginParams params;
params.setUser(samlResult.value("username")); params.setUser(samlResult.value("username"));
params.setPreloginCookie(samlResult.value("preloginCookie")); params.setPreloginCookie(samlResult.value("preloginCookie"));
params.setUserAuthCookie(samlResult.value("userAuthCookie"));
login(params); login(params);
} }

View File

@@ -97,6 +97,8 @@ void GPClient::initVpnStatus() {
void GPClient::populateGatewayMenu() void GPClient::populateGatewayMenu()
{ {
PLOGI << "Populating the Switch Gateway menu...";
const QList<GPGateway> gateways = allGateways(); const QList<GPGateway> gateways = allGateways();
gatewaySwitchMenu->clear(); gatewaySwitchMenu->clear();
@@ -200,6 +202,8 @@ void GPClient::onGatewayChanged(QAction *action)
void GPClient::doConnect() void GPClient::doConnect()
{ {
PLOGI << "Start connecting...";
const QString btnText = ui->connectButton->text(); const QString btnText = ui->connectButton->text();
const QString portal = this->portal(); const QString portal = this->portal();
@@ -214,16 +218,19 @@ void GPClient::doConnect()
// Login to the previously saved gateway // Login to the previously saved gateway
if (!currentGateway().name().isEmpty()) { if (!currentGateway().name().isEmpty()) {
PLOGI << "Start gateway login using the previously saved gateway...";
isQuickConnect = true; isQuickConnect = true;
gatewayLogin(); gatewayLogin();
} else { } else {
// Perform the portal login // Perform the portal login
PLOGI << "Start portal login...";
portalLogin(); portalLogin();
} }
} else { } else {
PLOGI << "Start disconnecting the VPN...";
ui->statusLabel->setText("Disconnecting..."); ui->statusLabel->setText("Disconnecting...");
updateConnectionStatus(VpnStatus::pending); updateConnectionStatus(VpnStatus::pending);
vpn->disconnect(); vpn->disconnect();
} }
} }
@@ -246,7 +253,10 @@ void GPClient::portalLogin()
void GPClient::onPortalSuccess(const PortalConfigResponse portalConfig, const GPGateway gateway, QList<GPGateway> allGateways) void GPClient::onPortalSuccess(const PortalConfigResponse portalConfig, const GPGateway gateway, QList<GPGateway> allGateways)
{ {
PLOGI << "Portal authentication succeeded.";
this->portalConfig = portalConfig; this->portalConfig = portalConfig;
setAllGateways(allGateways); setAllGateways(allGateways);
setCurrentGateway(gateway); setCurrentGateway(gateway);
@@ -283,6 +293,8 @@ void GPClient::onPortalFail(const QString &msg)
// Login to the gateway // Login to the gateway
void GPClient::gatewayLogin() void GPClient::gatewayLogin()
{ {
PLOGI << "Performing gateway login...";
GatewayAuthenticator *gatewayAuth = new GatewayAuthenticator(currentGateway().address(), portalConfig); GatewayAuthenticator *gatewayAuth = new GatewayAuthenticator(currentGateway().address(), portalConfig);
connect(gatewayAuth, &GatewayAuthenticator::success, this, &GPClient::onGatewaySuccess); connect(gatewayAuth, &GatewayAuthenticator::success, this, &GPClient::onGatewaySuccess);
@@ -341,7 +353,6 @@ bool GPClient::connected() const
return statusText.contains("Connected") && !statusText.contains("Not"); return statusText.contains("Connected") && !statusText.contains("Not");
} }
QList<GPGateway> GPClient::allGateways() const QList<GPGateway> GPClient::allGateways() const
{ {
const QString gatewaysJson = settings::get(portal() + "_gateways").toString(); const QString gatewaysJson = settings::get(portal() + "_gateways").toString();
@@ -350,6 +361,8 @@ QList<GPGateway> GPClient::allGateways() const
void GPClient::setAllGateways(QList<GPGateway> gateways) void GPClient::setAllGateways(QList<GPGateway> gateways)
{ {
PLOGI << "Updating all the gateways...";
settings::save(portal() + "_gateways", GPGateway::serialize(gateways)); settings::save(portal() + "_gateways", GPGateway::serialize(gateways));
populateGatewayMenu(); populateGatewayMenu();
} }
@@ -368,6 +381,8 @@ GPGateway GPClient::currentGateway() const
void GPClient::setCurrentGateway(const GPGateway gateway) void GPClient::setCurrentGateway(const GPGateway gateway)
{ {
PLOGI << "Updating the current gateway to " << gateway.name();
settings::save(portal() + "_selectedGateway", gateway.name()); settings::save(portal() + "_selectedGateway", gateway.name());
populateGatewayMenu(); populateGatewayMenu();
} }

View File

@@ -23,10 +23,13 @@ QNetworkReply* gpclient::helper::createRequest(QString url, QByteArray params)
GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> gateways, const QString ruleName) GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> gateways, const QString ruleName)
{ {
PLOGI << gateways.size() << " gateway(s) avaiable, filter the gateways with rule: " << ruleName;
GPGateway gateway = gateways.first(); GPGateway gateway = gateways.first();
for (GPGateway g : gateways) { for (GPGateway g : gateways) {
if (g.priorityOf(ruleName) > gateway.priorityOf(ruleName)) { if (g.priorityOf(ruleName) > gateway.priorityOf(ruleName)) {
PLOGI << "Find a preferred gateway: " << g.name();
gateway = g; gateway = g;
} }
} }
@@ -36,6 +39,8 @@ GPGateway gpclient::helper::filterPreferredGateway(QList<GPGateway> gateways, co
QUrlQuery gpclient::helper::parseGatewayResponse(const QByteArray &xml) QUrlQuery gpclient::helper::parseGatewayResponse(const QByteArray &xml)
{ {
PLOGI << "Start parsing the gateway response...";
QXmlStreamReader xmlReader{xml}; QXmlStreamReader xmlReader{xml};
QList<QString> args; QList<QString> args;

View File

@@ -26,32 +26,32 @@ LoginParams::~LoginParams()
{ {
} }
void LoginParams::setUser(const QString &user) void LoginParams::setUser(const QString user)
{ {
updateQueryItem("user", user); updateQueryItem("user", user);
} }
void LoginParams::setServer(const QString &server) void LoginParams::setServer(const QString server)
{ {
updateQueryItem("server", server); updateQueryItem("server", server);
} }
void LoginParams::setPassword(const QString &password) void LoginParams::setPassword(const QString password)
{ {
updateQueryItem("passwd", password); updateQueryItem("passwd", password);
} }
void LoginParams::setUserAuthCookie(const QString &cookie) void LoginParams::setUserAuthCookie(const QString cookie)
{ {
updateQueryItem("portal-userauthcookie", cookie); updateQueryItem("portal-userauthcookie", cookie);
} }
void LoginParams::setPrelogonAuthCookie(const QString &cookie) void LoginParams::setPrelogonAuthCookie(const QString cookie)
{ {
updateQueryItem("portal-prelogonuserauthcookie", cookie); updateQueryItem("portal-prelogonuserauthcookie", cookie);
} }
void LoginParams::setPreloginCookie(const QString &cookie) void LoginParams::setPreloginCookie(const QString cookie)
{ {
updateQueryItem("prelogin-cookie", cookie); updateQueryItem("prelogin-cookie", cookie);
} }
@@ -61,7 +61,7 @@ QByteArray LoginParams::toUtf8() const
return params.toString().toUtf8(); return params.toString().toUtf8();
} }
void LoginParams::updateQueryItem(const QString &key, const QString &value) void LoginParams::updateQueryItem(const QString key, const QString value)
{ {
if (params.hasQueryItem(key)) { if (params.hasQueryItem(key)) {
params.removeQueryItem(key); params.removeQueryItem(key);

View File

@@ -9,19 +9,19 @@ public:
LoginParams(); LoginParams();
~LoginParams(); ~LoginParams();
void setUser(const QString &user); void setUser(const QString user);
void setServer(const QString &server); void setServer(const QString server);
void setPassword(const QString &password); void setPassword(const QString password);
void setUserAuthCookie(const QString &cookie); void setUserAuthCookie(const QString cookie);
void setPrelogonAuthCookie(const QString &cookie); void setPrelogonAuthCookie(const QString cookie);
void setPreloginCookie(const QString &cookie); void setPreloginCookie(const QString cookie);
QByteArray toUtf8() const; QByteArray toUtf8() const;
private: private:
QUrlQuery params; QUrlQuery params;
void updateQueryItem(const QString &key, const QString &value); void updateQueryItem(const QString key, const QString value);
}; };
#endif // LOGINPARAMS_H #endif // LOGINPARAMS_H

View File

@@ -6,6 +6,8 @@
#include <plog/Log.h> #include <plog/Log.h>
#include <plog/Appenders/ColorConsoleAppender.h> #include <plog/Appenders/ColorConsoleAppender.h>
static const QString version = "v1.2.3";
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const QDir path = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/GlobalProtect-openconnect"; const QDir path = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/GlobalProtect-openconnect";
@@ -17,6 +19,8 @@ int main(int argc, char *argv[])
static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender; static plog::ColorConsoleAppender<plog::TxtFormatter> consoleAppender;
plog::init(plog::debug, logFile.toUtf8()).addAppender(&consoleAppender); plog::init(plog::debug, logFile.toUtf8()).addAppender(&consoleAppender);
PLOGI << "GlobalProtect started, version: " << version;
QString port = QString::fromLocal8Bit(qgetenv(ENV_CDP_PORT)); QString port = QString::fromLocal8Bit(qgetenv(ENV_CDP_PORT));
if (port == "") { if (port == "") {

View File

@@ -14,7 +14,7 @@ using namespace gpclient::helper;
PortalAuthenticator::PortalAuthenticator(const QString& portal) : QObject() PortalAuthenticator::PortalAuthenticator(const QString& portal) : QObject()
, portal(portal) , portal(portal)
, preloginUrl("https://" + portal + "/global-protect/prelogin.esp") , preloginUrl("https://" + portal + "/global-protect/prelogin.esp?tmp=tmp&kerberos-support=yes&ipv6-support=yes&clientVer=4100&clientos=Linux")
, configUrl("https://" + portal + "/global-protect/getconfig.esp") , configUrl("https://" + portal + "/global-protect/getconfig.esp")
{ {
} }
@@ -46,6 +46,9 @@ void PortalAuthenticator::onPreloginFinished()
PLOGI << "Portal prelogin succeeded."; PLOGI << "Portal prelogin succeeded.";
preloginResponse = PreloginResponse::parse(reply->readAll()); preloginResponse = PreloginResponse::parse(reply->readAll());
PLOGI << "Finished parsing the prelogin response. The region field is: " << preloginResponse.region();
if (preloginResponse.hasSamlAuthFields()) { if (preloginResponse.hasSamlAuthFields()) {
// Do SAML authentication // Do SAML authentication
samlAuth(); samlAuth();
@@ -124,9 +127,13 @@ void PortalAuthenticator::samlAuth()
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"); if (samlResult.contains("preloginCookie")) {
PLOGI << "SAML login succeeded, got the prelogin-cookie " << samlResult.value("preloginCookie");
} else {
PLOGI << "SAML login succeeded, got the portal-userauthcookie " << samlResult.value("userAuthCookie");
}
fetchConfig(samlResult.value("username"), "", samlResult.value("preloginCookie")); fetchConfig(samlResult.value("username"), "", samlResult.value("preloginCookie"), samlResult.value("userAuthCookie"));
} }
void PortalAuthenticator::onSAMLLoginFail(const QString msg) void PortalAuthenticator::onSAMLLoginFail(const QString msg)
@@ -134,13 +141,14 @@ void PortalAuthenticator::onSAMLLoginFail(const QString msg)
emitFail(msg); emitFail(msg);
} }
void PortalAuthenticator::fetchConfig(QString username, QString password, QString preloginCookie) void PortalAuthenticator::fetchConfig(QString username, QString password, QString preloginCookie, QString userAuthCookie)
{ {
LoginParams params; LoginParams params;
params.setServer(portal); params.setServer(portal);
params.setUser(username); params.setUser(username);
params.setPassword(password); params.setPassword(password);
params.setPreloginCookie(preloginCookie); params.setPreloginCookie(preloginCookie);
params.setUserAuthCookie(userAuthCookie);
// Save the username and password for future use. // Save the username and password for future use.
this->username = username; this->username = username;
@@ -173,14 +181,16 @@ void PortalAuthenticator::onFetchConfigFinished()
} }
PLOGI << "Fetch the portal config succeeded."; PLOGI << "Fetch the portal config succeeded.";
PortalConfigResponse response = PortalConfigResponse::parse(reply->readAll()); PortalConfigResponse response = PortalConfigResponse::parse(reply->readAll());
// Add the username & password to the response object // Add the username & password to the response object
response.setUsername(username); response.setUsername(username);
response.setPassword(password); response.setPassword(password);
// Close the login window // Close the login window
if (normalLoginWindow) { if (normalLoginWindow) {
PLOGI << "Closing the NormalLoginWindow...";
// Save the credentials for reuse // Save the credentials for reuse
settings::save("username", username); settings::save("username", username);
settings::save("password", password); settings::save("password", password);

View File

@@ -47,7 +47,7 @@ private:
void tryAutoLogin(); void tryAutoLogin();
void normalAuth(); void normalAuth();
void samlAuth(); void samlAuth();
void fetchConfig(QString username, QString password, QString preloginCookie = ""); void fetchConfig(QString username, QString password, QString preloginCookie = "", QString userAuthCookie = "");
void emitFail(const QString& msg = ""); void emitFail(const QString& msg = "");
}; };

View File

@@ -15,8 +15,10 @@ PortalConfigResponse::~PortalConfigResponse()
{ {
} }
PortalConfigResponse PortalConfigResponse::parse(const QByteArray& xml) PortalConfigResponse PortalConfigResponse::parse(const QByteArray xml)
{ {
PLOGI << "Start parsing the portal configuration...";
QXmlStreamReader xmlReader(xml); QXmlStreamReader xmlReader(xml);
PortalConfigResponse response; PortalConfigResponse response;
response.setRawResponse(xml); response.setRawResponse(xml);
@@ -27,18 +29,22 @@ PortalConfigResponse PortalConfigResponse::parse(const QByteArray& xml)
QString name = xmlReader.name().toString(); QString name = xmlReader.name().toString();
if (name == xmlUserAuthCookie) { if (name == xmlUserAuthCookie) {
PLOGI << "Start reading " << name;
response.setUserAuthCookie(xmlReader.readElementText()); response.setUserAuthCookie(xmlReader.readElementText());
} else if (name == xmlPrelogonUserAuthCookie) { } else if (name == xmlPrelogonUserAuthCookie) {
PLOGI << "Start reading " << name;
response.setPrelogonUserAuthCookie(xmlReader.readElementText()); response.setPrelogonUserAuthCookie(xmlReader.readElementText());
} else if (name == xmlGateways) { } else if (name == xmlGateways) {
response.setAllGateways(parseGateways(xmlReader)); response.setAllGateways(parseGateways(xmlReader));
} }
} }
PLOGI << "Finished parsing portal configuration.";
return response; return response;
} }
const QByteArray& PortalConfigResponse::rawResponse() const const QByteArray PortalConfigResponse::rawResponse() const
{ {
return _rawResponse; return _rawResponse;
} }
@@ -55,6 +61,8 @@ QString PortalConfigResponse::password() const
QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader) QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader)
{ {
PLOGI << "Start parsing the gateways from portal configuration...";
QList<GPGateway> gateways; QList<GPGateway> gateways;
while (xmlReader.name() != xmlGateways || !xmlReader.isEndElement()) { while (xmlReader.name() != xmlGateways || !xmlReader.isEndElement()) {
@@ -69,11 +77,16 @@ QList<GPGateway> PortalConfigResponse::parseGateways(QXmlStreamReader &xmlReader
gateways.append(g); gateways.append(g);
} }
} }
PLOGI << "Finished parsing the gateways.";
return gateways; return gateways;
} }
QMap<QString, int> PortalConfigResponse::parsePriorityRules(QXmlStreamReader &xmlReader) QMap<QString, int> PortalConfigResponse::parsePriorityRules(QXmlStreamReader &xmlReader)
{ {
PLOGI << "Start parsing the priority rules...";
QMap<QString, int> priorityRules; QMap<QString, int> priorityRules;
while (xmlReader.name() != "priority-rule" || !xmlReader.isEndElement()) { while (xmlReader.name() != "priority-rule" || !xmlReader.isEndElement()) {
@@ -87,20 +100,26 @@ QMap<QString, int> PortalConfigResponse::parsePriorityRules(QXmlStreamReader &xm
priorityRules.insert(ruleName, ruleValue); priorityRules.insert(ruleName, ruleValue);
} }
} }
PLOGI << "Finished parsing the priority rules.";
return priorityRules; return priorityRules;
} }
QString PortalConfigResponse::parseGatewayName(QXmlStreamReader &xmlReader) QString PortalConfigResponse::parseGatewayName(QXmlStreamReader &xmlReader)
{ {
while (xmlReader.name() != "description" || !xmlReader.isEndElement()) { PLOGI << "Start parsing the gateway name...";
xmlReader.readNext();
if (xmlReader.name() == "description" && xmlReader.tokenType() == xmlReader.StartElement) {
return xmlReader.readElementText();
}
}
PLOGE << "Error: <description> tag not found"; while (xmlReader.name() != "description" || !xmlReader.isEndElement()) {
return ""; xmlReader.readNext();
if (xmlReader.name() == "description" && xmlReader.tokenType() == xmlReader.StartElement) {
PLOGI << "Finished parsing the gateway name";
return xmlReader.readElementText();
}
}
PLOGE << "Error: <description> tag not found";
return "";
} }
QString PortalConfigResponse::userAuthCookie() const QString PortalConfigResponse::userAuthCookie() const
@@ -123,27 +142,27 @@ void PortalConfigResponse::setAllGateways(QList<GPGateway> gateways)
_gateways = gateways; _gateways = gateways;
} }
void PortalConfigResponse::setRawResponse(const QByteArray &response) void PortalConfigResponse::setRawResponse(const QByteArray response)
{ {
_rawResponse = response; _rawResponse = response;
} }
void PortalConfigResponse::setUsername(const QString& username) void PortalConfigResponse::setUsername(const QString username)
{ {
_username = username; _username = username;
} }
void PortalConfigResponse::setPassword(const QString& password) void PortalConfigResponse::setPassword(const QString password)
{ {
_password = password; _password = password;
} }
void PortalConfigResponse::setUserAuthCookie(const QString &cookie) void PortalConfigResponse::setUserAuthCookie(const QString cookie)
{ {
_userAuthCookie = cookie; _userAuthCookie = cookie;
} }
void PortalConfigResponse::setPrelogonUserAuthCookie(const QString &cookie) void PortalConfigResponse::setPrelogonUserAuthCookie(const QString cookie)
{ {
_prelogonAuthCookie = cookie; _prelogonAuthCookie = cookie;
} }

View File

@@ -13,9 +13,9 @@ public:
PortalConfigResponse(); PortalConfigResponse();
~PortalConfigResponse(); ~PortalConfigResponse();
static PortalConfigResponse parse(const QByteArray& xml); static PortalConfigResponse parse(const QByteArray xml);
const QByteArray& rawResponse() const; const QByteArray rawResponse() const;
QString username() const; QString username() const;
QString password() const; QString password() const;
QString userAuthCookie() const; QString userAuthCookie() const;
@@ -23,8 +23,8 @@ public:
QList<GPGateway> allGateways(); QList<GPGateway> allGateways();
void setAllGateways(QList<GPGateway> gateways); 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);
private: private:
static QString xmlUserAuthCookie; static QString xmlUserAuthCookie;
@@ -39,9 +39,9 @@ private:
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 QList<GPGateway> parseGateways(QXmlStreamReader &xmlReader); static QList<GPGateway> parseGateways(QXmlStreamReader &xmlReader);
static QMap<QString, int> parsePriorityRules(QXmlStreamReader &xmlReader); static QMap<QString, int> parsePriorityRules(QXmlStreamReader &xmlReader);

View File

@@ -2,6 +2,7 @@
#include <QXmlStreamReader> #include <QXmlStreamReader>
#include <QMap> #include <QMap>
#include <plog/Log.h>
QString PreloginResponse::xmlAuthMessage = "authentication-message"; QString PreloginResponse::xmlAuthMessage = "authentication-message";
QString PreloginResponse::xmlLabelUsername = "username-label"; QString PreloginResponse::xmlLabelUsername = "username-label";
@@ -22,6 +23,8 @@ PreloginResponse::PreloginResponse()
PreloginResponse PreloginResponse::parse(const QByteArray& xml) PreloginResponse PreloginResponse::parse(const QByteArray& xml)
{ {
PLOGI << "Start parsing the prelogin response...";
QXmlStreamReader xmlReader(xml); QXmlStreamReader xmlReader(xml);
PreloginResponse response; PreloginResponse response;
response.setRawResponse(xml); response.setRawResponse(xml);
@@ -81,17 +84,17 @@ bool PreloginResponse::hasNormalAuthFields() const
return !labelUsername().isEmpty() && !labelPassword().isEmpty(); return !labelUsername().isEmpty() && !labelPassword().isEmpty();
} }
void PreloginResponse::setRawResponse(const QByteArray &response) void PreloginResponse::setRawResponse(const QByteArray response)
{ {
_rawResponse = response; _rawResponse = response;
} }
bool PreloginResponse::has(const QString &name) const bool PreloginResponse::has(const QString name) const
{ {
return resultMap.contains(name); return resultMap.contains(name);
} }
void PreloginResponse::add(const QString &name, const QString &value) void PreloginResponse::add(const QString name, const QString value)
{ {
resultMap.insert(name, value); resultMap.insert(name, value);
} }

View File

@@ -33,9 +33,9 @@ private:
QMap<QString, QString> resultMap; QMap<QString, QString> resultMap;
QByteArray _rawResponse; QByteArray _rawResponse;
void setRawResponse(const QByteArray &response); void setRawResponse(const QByteArray response);
void add(const QString &name, const QString &value); void add(const QString name, const QString value);
bool has(const QString &name) const; bool has(const QString name) const;
}; };
#endif // PRELOGINRESPONSE_H #endif // PRELOGINRESPONSE_H

View File

@@ -59,22 +59,41 @@ void SAMLLoginWindow::onResponseReceived(QJsonObject params)
const QString username = headers.value("saml-username").toString(); const QString username = headers.value("saml-username").toString();
const QString preloginCookie = headers.value("prelogin-cookie").toString(); const QString preloginCookie = headers.value("prelogin-cookie").toString();
const QString userAuthCookie = headers.value("portal-userauthcookie").toString();
if (!username.isEmpty() && !preloginCookie.isEmpty()) { LOGI << "Response received from " << response.value("url").toString();
if (!username.isEmpty()) {
LOGI << "Got username from SAML response headers " << username;
samlResult.insert("username", username); samlResult.insert("username", username);
}
if (!preloginCookie.isEmpty()) {
LOGI << "Got prelogin-cookie from SAML response headers " << preloginCookie;
samlResult.insert("preloginCookie", preloginCookie); samlResult.insert("preloginCookie", preloginCookie);
} }
}
void SAMLLoginWindow::onLoadFinished() if (!userAuthCookie.isEmpty()) {
{ LOGI << "Got portal-userauthcookie from SAML response headers " << userAuthCookie;
LOGI << "Load finished " << this->webView->page()->url().toString(); samlResult.insert("userAuthCookie", userAuthCookie);
}
// Check the SAML result // Check the SAML result
if (!samlResult.value("username").isEmpty() && !samlResult.value("preloginCookie").isEmpty()) { if (samlResult.contains("username")
&& (samlResult.contains("preloginCookie") || samlResult.contains("userAuthCookie"))) {
LOGI << "Got the SAML authentication information successfully. "
<< "username: " << samlResult.value("username")
<< ", preloginCookie: " << samlResult.value("preloginCookie")
<< ", userAuthCookie: " << samlResult.value("userAuthCookie");
emit success(samlResult); emit success(samlResult);
accept(); accept();
} else { } else {
this->show(); this->show();
} }
} }
void SAMLLoginWindow::onLoadFinished()
{
LOGI << "Load finished " << this->webView->page()->url().toString();
}

View File

@@ -7,10 +7,10 @@ A GlobalProtect VPN client (GUI) for Linux based on Openconnect and built with Q
## Features ## Features
- Similar user experience as the offical client in macOS. - Similar user experience as the official client in macOS.
- Supports both SAML and non-SAML authentication modes. - Supports both SAML and non-SAML authentication modes.
- Supports automatically selecting the preferred gateway from the multiple gateways. - Supports automatically selecting the preferred gateway from the multiple gateways.
- Supports switching gateway manually. - Supports switching gateway from the system tray menu manually.
## Prerequisites ## Prerequisites