yuezk / GlobalProtect-openconnect

A GlobalProtect VPN client for Linux, written in Rust, based on OpenConnect and Tauri, supports SSO with MFA, Yubikey, and client certificate authentication, etc.
GNU General Public License v3.0
1.3k stars 150 forks source link

Allow to use default browser for SAML auth window #98

Closed anatol closed 8 months ago

anatol commented 2 years ago

I use GlobalProtect-openconnect for my VPN and it works great.

Though current login flow has one inconvenience. When I login to my VPN it opens SAML login page in a separate window. I type the login. Then I open my browser to get into internal resources (like JIRA bug tracker) and now I need to type the password and use Yubikey for authentication one more time.

It would be great if the authentication information reused both for VPN application and the browser session. Some other clients (like proprietary GlobalProtect) open SAML in the default browser and once I authenticate there it starts working both for VPN itself and browser. Could you please similar functionality to GlobalProtect-openconnect as well?

yuezk commented 2 years ago

It's a good suggestion, but it's not that easy to implement on the Linux system. The primary problem is the client couldn't communicate with the default browser to get the authentication token, even though I could launch the default browser.

anatol commented 2 years ago

I think proprietary client is able to use the default browser to share session with SAML login. So communication with browser part should be doable.

I know there are technologies like selenium that allow to start a browser, manage window state, modify/read DOM. Here is a client for c++ https://github.com/sekogan/webdriverxx

yuezk commented 2 years ago

@anatol Thanks. I have some knowledge of browser drivers and had used Protractor to perform the E2E testing. I will take your advice and see if the solution is feasible. Thanks.

sudoforge commented 2 years ago

The proprietary client works with an external browser by providing a callback URI to the SAML provider; something like globalprotect://<foo>. I think this works because the proprietary client is integrated with the specific SAML provider, however, it should be noted that the user would need to ensure that the specific URI is configured to open the application on their system (using an external browser with the proprietary client doesn't work by default for me, for example).

denilsonsa commented 2 years ago

As an alternative, this project could start up a temporary HTTP server listening to a specific port on localhost. That way, after the authentication process, the browser would connect to the local server to finish up sending the required data back to the daemon.

MozWire project implements this flow. It is a non-official client to the MozillaVPN service, and it also requires a browser authentication.

If this idea gets implemented here, I'd suggest to also display the URL that it tries to open in the browser, just in case launching the browser fails, or if it opens the wrong browser/profile.

BrendanBall commented 1 year ago

If anyone wants to implement this, here is how you need to do it (at least based on my config):

  1. include default-browser=1 as a query parameter in the prelogin request.
  2. save the saml-request html from the prelogin response somewhere that the default browser can access (either /tmp/ or $XDG_CACHE_HOME).
  3. run xdg-open <path to saml-request.html> to open in your default browser.
  4. Perform login as necessary, redirects happen
  5. The browser requests to open the GlobalProtect application. It does this by making a request with the uri globalprotectcallback:<data>. The browser makes use of xdg-open to decide which application to open
  6. To complete 5. you need to have a desktop entry which specifies MimeType=x-scheme-handler/globalprotectcallback;
  7. The application specified in the desktop entry gets executed with the uri as an argument.
  8. use the data in the uri to complete the auth with openconnect.

I don't think we can use an http server since as users we're not able to configure how the GlobalProtect server behaves.

kudos commented 1 year ago

@BrendanBall any chance you could share the script you're using to do all those things? I'm not expecting it to be anything I could use directly, but would help a lot when writing my own. Any maybe someone can evolve it into something more general :)

BrendanBall commented 1 year ago

I don't have a script that does all of this, but the flow is mostly the same as is currently implemented. You just need to add the default-browser=1 query parameter to the prelogin url. Then instead of using an embedded webview you save the saml request and use xdg-open. The browser callback makes it a bit difficult to just implement a script to do this because you need an app registered to be used with xdg-open, but if you manage to do that, you could have it pass the callback data to your waiting script by either listening on localhost or using dbus.

I wanted to try integrate it with NetworkManager, but turns out NetworkManager vpn plugins are not that straightforward and lacks a lot of documentation and I'm not a C programmer, so it would just take too much time to figure out.

If you actually have a GlobalProtect account to test against, it shouldn't be too difficult to figure out. The missing query parameter was the big missing piece, because without it, the server doesn't end up doing the callback, which is why people are using embedded webviews/doing weird things with selenium.

kudos commented 1 year ago

@BrendanBall Gotcha, thanks for the clarification!

janbrummer commented 11 months ago

I wanted to try integrate it with NetworkManager, but turns out NetworkManager vpn plugins are not that straightforward and lacks a lot of documentation and I'm not a C programmer, so it would just take too much time to figure out.

I've just pushed a draft version for openconnect. So there is no need to change NM-openconnect.

yuezk commented 8 months ago

Supported in 2.0.0-beta5, you can enable this option in settings. Closing.

Mirro888 commented 5 months ago

@BredanBall: the browser returns something like:

globalprotectcallback:cas-as=1&un=user@xyz.com&token=very_long_string

How shall I use the token in the openconnect client?

Thank you,

Mirro

yuezk commented 5 months ago

@Mirro888 Let's move to #339 to continue the discussion.