Skip to content

Repository files navigation

NetworkManager GlobalProtect VPN Plugin

NetworkManager VPN plugin for GlobalProtect (Palo Alto Networks) with SAML/SSO authentication support. image image

image image

Features

  • NetworkManager integration - manage VPN like any other connection
  • SAML/2FA authentication via browser (Edge, Firefox, Chrome)
  • Standard login & RSA token portals - interactive username/password/OTP prompts via desktop dialogs (see docs/INTERACTIVE_AUTH.md)
  • Desktop support - GNOME Settings (GTK3/GTK4) and KDE Plasma
  • Routing control - configure which traffic goes through VPN
  • Systemd service - automatic VPN service management via D-Bus

Installation

Add the apt repository and install - dependencies, upgrades and the GNOME/Plasma choice are handled by apt:

curl -fsSL https://wmp.github.io/GlobalProtect-SAML-NetworkManager/gpclient-archive-keyring.gpg \
  | sudo tee /usr/share/keyrings/gpclient-archive-keyring.gpg > /dev/null

echo "deb [arch=amd64 signed-by=/usr/share/keyrings/gpclient-archive-keyring.gpg] https://wmp.github.io/GlobalProtect-SAML-NetworkManager $(lsb_release -cs) main" \
  | sudo tee /etc/apt/sources.list.d/gpclient.list

sudo apt update
sudo apt install network-manager-gpclient-gnome    # GNOME, MATE, Cinnamon, XFCE
# or
sudo apt install network-manager-gpclient-plasma   # KDE Plasma

Supported: Ubuntu 22.04, 24.04 and 26.04, amd64. Details, deb822 format and removal instructions: docs/APT_REPO.md.

Ubuntu 22.04 only: python3-sdbus is not in apt, install it with pip first:

pip3 install sdbus
Alternative: individual .deb files

Download the packages for your Ubuntu version from GitHub Releases. You need network-manager-gpclient plus either network-manager-gpclient-gnome or network-manager-gpclient-plasma, and the GUI package requires exactly the same version of the core package - so install them in one go and let apt sort out the dependencies:

sudo apt install ./network-manager-gpclient_*.deb ./network-manager-gpclient-gnome_*.deb

dpkg -i on a single file fails on purpose here; use apt install ./file.deb (or the repository above).

Migrating from globalprotect-openconnect

If you previously had the globalprotect-openconnect package installed, remove it first — our package declares a Conflicts: against it and dpkg -i will otherwise refuse to install:

sudo apt remove globalprotect-openconnect
sudo apt autoremove

Installing from the apt repository pulls the runtime prerequisites (openconnect, python3-sdbus, vpnc-scripts) in by itself. On Ubuntu 22.04 python3-sdbus is not in apt — use the pip3 install sdbus step shown above instead.

Thanks to @ottuzzi for the writeup (#3).

Usage

  1. Open GNOME Settings → Network or KDE Network Settings
  2. Add VPN → GlobalProtect
  3. Enter the portal address (e.g. vpn.example.com)
  4. Connect - a browser opens for SAML authentication

If your organisation gave you a gateway address rather than a portal address, also tick Address is a gateway (skip the portal).

When the portal offers several gateways, the first one it proposes is used automatically; after the first successful connection the full list appears in the Preferred gateway drop-down, so you can pin a different one.

Portals that use a standard login (username/password) or an RSA SecurID token instead of SAML are supported too - the plugin asks for the credentials in a dialog when gpclient needs them. See docs/INTERACTIVE_AUTH.md for details and for storing the username/password in the connection.

# Or via command line
nmcli connection up "GlobalProtect VPN"

Connection settings

Everything the editors show lives in the connection's vpn.data, so it can also be set with nmcli connection modify "My VPN" +vpn.data key=value:

Key Default Meaning
gateway (required) Portal address, or gateway address with as-gateway=true
as-gateway false The address is a gateway - skip the portal workflow
preferred-gateway (empty) Gateway to use; empty means the portal's first proposal. Falls back to the first proposal when the value is not offered
gateway-list (written by the service) Gateways seen during the last successful connection, ;-separated. Read by the editors to fill the drop-down
auth-mode saml saml = browser login, credentials = username/password collected upfront
username (empty) Username for portals that ask on the terminal
browser edge edge, firefox, chrome, chromium, default, or a path to your own wrapper (details)
fix-openssl auto Legacy TLS renegotiation for portals with an old TLS stack. auto retries once when the portal needs it and then stores true in the profile; true uses it from the start; false never does
hip true Send the HIP (Host Integrity Protection) report
dns (empty) Override VPN DNS servers, ;-separated. Empty keeps automatic split DNS
dns-domains (empty) Extra search domains, space-separated

The password for auth-mode=credentials is a secret, not data: nmcli connection modify "My VPN" +vpn.secrets password=...

Packages

Package Description
network-manager-gpclient Core VPN service (required)
network-manager-gpclient-gnome GNOME/GTK integration
network-manager-gpclient-plasma KDE Plasma integration

Architecture

┌─────────────────────────┐
│   GNOME Settings        │
│   KDE Plasma NM         │
│   nm-connection-editor  │
└───────────┬─────────────┘
            │ Configuration
            ▼
┌─────────────────────────┐
│   NetworkManager        │
└───────────┬─────────────┘
            │ D-Bus
            ▼
┌─────────────────────────┐
│ nm-gpclient-service     │  ← Python VPN Service (systemd)
└───────────┬─────────────┘
            │
            ▼
┌─────────────────────────┐
│   gpclient / gpauth     │  ← VPN connection + SAML auth
└─────────────────────────┘

Project Structure

├── service/                    # Python VPN service backend
│   └── nm-gpclient-service.py
├── plugins/
│   ├── gnome/                  # GNOME/GTK plugins (C)
│   └── plasma/                 # KDE Plasma plugin (C++/Qt)
├── config/                     # NetworkManager & systemd configuration
├── .github/
│   ├── scripts/                # build-apt-repo.sh (apt repository builder)
│   └── workflows/              # build/release and Pages publishing
├── scripts/                    # Helper scripts (browser-wrapper)
├── external/
│   └── GlobalProtect-openconnect/  # VPN client (submodule)
└── debian/                     # Debian packaging

Building from Source

Requirements

  • GNOME plugins: libglib2.0-dev, libnm-dev, libgtk-3-dev, libgtk-4-dev, libnma-dev
  • Plasma plugin: cmake, extra-cmake-modules, plasma-nm-dev, Qt5 libraries
  • VPN client: cargo (Rust), libssl-dev, libopenconnect-dev

Build

./build-all.sh          # Build for all Ubuntu versions (22.04, 24.04, 26.04)
./build-all.sh 24.04    # Build for Ubuntu 24.04 only
./build-all.sh 26.04    # Build for Ubuntu 26.04 only (Plasma 6 / Qt6 / KF6)

Notes for Ubuntu 26.04:

  • The Plasma plugin is built against Qt6/KF6 (plasma-nm/plasma-nm-dev, libkf6networkmanagerqt-dev, qt6-base-dev).
  • The Plasma plugin module installs into /usr/lib/x86_64-linux-gnu/qt6/plugins/ instead of the qt5/ path used on 22.04/24.04.

Build Individual Components

make gnome-plugins      # Build only GNOME plugins
cd plugins/plasma && ./build.sh  # Build only Plasma plugin

Why Microsoft Edge?

Microsoft Edge is the recommended browser for SAML authentication because:

  • Microsoft Intune compatibility - Edge integrates with Microsoft Entra ID (Azure AD) and Intune MDM, enabling seamless SSO authentication without additional password prompts
  • Keyless authentication - When enrolled in Intune, Edge can use device certificates and Windows Hello credentials stored in the system, eliminating manual credential entry
  • GlobalProtect callback handling - Edge properly handles the globalprotectcallback:// protocol used to pass authentication tokens back to the VPN client

The included edge-wrapper script handles:

  • Running Edge with correct Wayland/X11 display settings
  • Working around NetworkManager's sandbox (ProtectHome=read-only)
  • Auto-closing Edge window after successful authentication
  • Setting up Edge policies for automatic protocol handling

Security note: NetworkManager runs VPN services with ProtectHome=read-only, which prevents Edge from accessing its profile in ~/.config/microsoft-edge. The edge-wrapper creates a temporary profile in /tmp/edge-wrapper-$UID/ to work around this. This means your main Edge profile (with saved passwords, cookies) is not used for VPN authentication - each session starts fresh. While /tmp is world-readable, the wrapper creates per-user directories with restricted permissions.

Firefox and Chrome also work but may require manual credential entry for Intune-protected portals.

Troubleshooting

# Watch the service's own logs (preferred — this works while the
# service is auto-activated by NetworkManager/systemd)
sudo journalctl -u nm-gpclient -f

# Or filter NetworkManager logs for plugin activity
sudo journalctl -u NetworkManager -f | grep gpclient

# Verify installation
ls -l /usr/lib/NetworkManager/nm-gpclient-service
ls -l /usr/lib/x86_64-linux-gnu/NetworkManager/libnm-vpn-plugin-gpclient*.so

Running the service manually for debugging

The service is normally auto-started on demand by systemd / D-Bus the first time NetworkManager touches a GlobalProtect VPN connection — you do not need to start it by hand for normal use.

If you want to run it manually (for example with --debug), you have to stop the auto-started instance first, otherwise both processes try to claim the same D-Bus name and you get sd_bus_internals.SdBusRequestNameExistsError (see #1):

sudo systemctl stop nm-gpclient
sudo /usr/lib/NetworkManager/nm-gpclient-service --debug

That error on its own does not mean the VPN is broken — it just means the service is already running. The actual error from a failing VPN connect will be in journalctl -u nm-gpclient.

The VPN fails immediately with an SSL error

error:0A000152:SSL routines:final_renegotiate:unsafe legacy renegotiation disabled

The portal's TLS stack needs renegotiation that OpenSSL 3 refuses by default, so the connection dies before any browser can open. The service notices this, and retries once with gpclient's --fix-openssl workaround, then records it in the profile (Legacy TLS renegotiation: Always on in the editor) so the failed first attempt does not repeat. To set it up front, or to turn it off:

nmcli connection modify "My VPN" +vpn.data fix-openssl=true    # or false

Two browser windows open for one connection

gpclient tries the gateway with the portal's authentication cookie first and authenticates again when the gateway refuses it. If the address in your connection is itself one of the gateways in gateway-list, tick Address is a gateway (skip the portal) to get a single authentication. Details: docs/INTERACTIVE_AUTH.md.

The authentication window has a different size every time

The --window-size the wrapper passes only applies when it creates the window. If a browser is already running, the URL is handed to that instance, which ignores the flag and restores its own remembered geometry. Wayland gives no way to fix this from outside the browser - GNOME's compositor exposes no window control at all, and KWin ignores a geometry change while the window is still being mapped.

On KDE you can pin it down once with a window rule, which KWin applies during placement: System Settings → Window Management → Window Rules → Add New, then Window classSubstring match127.0.0.1 (the authentication window is an app-mode window whose class is derived from the local callback address, so this matches it and nothing else), and set Size to Apply Initially.

The authentication browser does not open, or closes too early

# The wrapper logs every launch and always says why it finished
grep -E "done:|WARNING|ERROR" /tmp/edge-wrapper-$(id -u).log

# Try the browser on its own - the window must open and stay open
GP_BROWSER=firefox /usr/libexec/gpclient/browser-wrapper "https://example.com"

The service log shows which session variables it found for the browser:

sudo journalctl -u nm-gpclient | grep "session keys"

More in docs/EDGE_WRAPPER.md.

Debug vpnc-script

The repository includes a modified vpnc-script (from Ubuntu 24.04 vpnc-scripts package) with added debug logging. This script is not installed by the package - you need to download it manually from the repository:

# Download and install debug vpnc-script
curl -o /tmp/vpnc-script https://raw.githubusercontent.com/WMP/GlobalProtect-SAML-NetworkManager/main/scripts/vpnc-script-debug
sudo cp /tmp/vpnc-script /usr/share/vpnc-scripts/vpnc-script

Debug logs are written to /tmp/vpnc-script2.log.

Documentation

License

See debian/copyright.

Credits

This project uses GlobalProtect-openconnect by yuezk as a submodule. From that project we build and include:

  • gpclient - VPN client binary that handles the actual VPN connection
  • gpauth - SAML authentication handler
  • gpservice - Background service for VPN management

The NetworkManager integration (plugins for GNOME/Plasma, Python service, D-Bus configuration) is original work in this repository.

Related Projects

About

NetworkManager VPN plugin for GlobalProtect with SAML/SSO authentication - supports GNOME and KDE Plasma

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages