Support login SAML
Hi, I see that openfortivpn supported 2FA but no supports SAML. Can you implement this feature?
Best regards, Severus
Any update on this from dev? Is it hard to implement?
This would be a great feature
While I probably won't have time myself, pull requests are welcome.
Should we use a library that implements SAML? It looks Lasso is or used to be the de facto standard for C programs, but as far as I can understand it's for writing service providers (SP) such as a FortiGate, not clients.
Some FortiGate documentation: Technical Tip: Configuring SAML SSO login for FortiGate administrators with Azure AD acting as SAML IdP
This might be of interest: gp-saml-gui
It would help to have screen captures of what SAML authentication looks like with FortiCLient.
My guess is that the cookie is retrieved by a possibly independent process, then fed to the VPN client which does not need to re-authenticate. If so, the question is, how do we retrieve the cookie? Can you describe the FortiClient workflow (with screen captures) or at least the expected workflow?
I can provide some screenshots:

You get a popup that is asking for you microsoft credentials:

Hi, interested in helping to get this implemented. I can help with screenshots and I can see if I can provide some logs or run a sample session with mitmproxy to get request & responses (sanitized ofc). What kind of info would be helpful?
I am also willing to help with this feature. Official client supports it. Would be wonderful if openfortivpn does it too.
Patches are welcome 😀
Perhaps you can have a look at openconnect. I am not certain it supports SAML yet, but it might be worth trying. If it does not, I suggest you open an issue there too. Perhaps they will have the resources to implement it more rapidly.
Perhaps you can have a look at openconnect. I am not certain it supports SAML yet, but it might be worth trying. If it does not, I suggest you open an issue there too. Perhaps they will have the resources to implement it more rapidly.
openconnet does not support SAML but other project like https://github.com/yuezk/GlobalProtect-openconnect did it.
I think they have a branch in the works - not the master branch. Perhaps support for SAML will be available after openconnect 9.0 is released.
Honestly, at this point and for lack of resources, I probably won't be able to write anything for openfortivpn before they do...
Hi,
The company I work for will enable the SAML authentication. I'm not a C developer and thus I can not really help to implement the feature. But if you need some help for testing I would be glad to help you!
~~The bad thing is that I tested the official client on Gnome and KDE (Fedora and Arch) to help my IT team to validate the client on Linux, and it works fine, but I use i3 and I did not manage to get a working connection with it. When I try to connect the client opens the authentication form of the SSO platform used in my company (Okta), I fill my credentials but the client never completes the auth process. Of course nothing in my logs or in the output when I run the app from my terminal... I thought about some polkit or PAM issues but I could not find anything.~~
Does somebody have some tricks about that to help me waiting for a SAML implementation on openfortivpn ?
PS: Thank you very much for creating openfortivpn, it allowed me to not use the bloated and buggy official client for so long!
Edit: I managed to make the official client working on my system. It was both a polkit issue on my machine and a certificate mistake. But I'm still OK if you need some tests on an openfortivpn SAML implementation :wink:
I don't code in C but I might be able to fill in some of the gaps in case someone wants to take this up. I enabled ssl debug logging on a fortigate a connected with the windows client and I saw the following requests. I don't think you need any kind of saml library just a browser and a way to extract part of the response. The official client uses electronjs to display the login.
- /remote/info
- contains remoteauthtimeout in seconds. this while not needed is important as the user can take a long time to login but the fortigate will timeout the session.
- /remote/saml/start
- redirects to the saml idp login page
- /remote/saml/login
- redirected here from the IDP. a cookie gets set here
- /sslvpn/portal.html
- /remote/fortisslvpn
- looks like it sets a cookie via javascript
<script> var cookie_str='pc2QKF5dD...8pgsU9zoYJbwP0H8='; </script>
- /remote/licensecheck
- I don't know if this is required. I don't have ems but 🤷♂️
- /remote/fortisslvpn_xml
- this looks like the list of routes/dns/etc
- /remote/sslvpn-tunnel?uuid=[HEX]
I'm not a developer either, but I can help test any patch or new version.
The company enabled yesterday, of course, without testing ignoring Linux users (they only support those who use Windows), and in my case with Arch, not even the official client (version 7.0.0.18) is working, but a colleague with Ubuntu didn't work either .
I did a clean install, to test the crap of the manufacturer's official client.
The packages you installed from installing the forticlient package were:
Packages to install (from repository https://repo.fortinet.com/repo/7.0/centos/8/os/x86_64): forticlient
Below, the installed dependencies:
libXScrnSaver
m4
mailx
make
ncurses-compat-libs
nss-tools
patch
postfix
redhat-lsb-core
redhat-lsb-submod-security
spax
yum-utils
After that, I called the binary from a terminal, to log what would be done. Configured the VPN portal (just put the address and the SAML option).
Below, I put the output of the process (I decharacterized so I don't have problems):
[infra@teste-fortinet ~]$ forticlient
Platform detected: fedora
[ '/opt/forticlient/gui/FortiClient-linux-x64/FortiClient' ]
Saml - init
did-finish-load
renderer ready - IPC_RENDERER_REQUEST.FETCH_INVITATION_CODE 2021-08-19T20:04:02.768Z
this.inviteCode=null
IPC_RENDERER_REQUEST.LOADED
Events - processArgv
[ '/opt/forticlient/gui/FortiClient-linux-x64/FortiClient' ]
certificate-error url=https://vpn.address.com/remote/info
saml-login https://vpn.address.com:443/remote/saml/start
Saml - doSamlAuth
{ authTimeout: '600',
ignoreCert: false,
type: 1,
url: 'https://vpn.address.com:443/remote/saml/start' }
Saml - loadUrlWithType type=1 url=https://vpn.address.com:443/remote/saml/start
samlReq.url = https://vpn.address.com:443/remote/saml/start
samlReq.type = 1
beginUrl.href = https://vpn.address.com/remote/saml/start
certificate-error url=https://vpn.address.com/remote/saml/start
Gtk-Message: 17:05:22.632: GtkDialog mapped without a transient parent. This is discouraged.
continue-error-certificate https://vpn.address.com/gateway-realm:443/remote/saml/start
Saml - reloadWindow authTimeout = 600
Saml - loadUrlWithType type=1 url=https://vpn.address.com/gateway-realm:443/remote/saml/start
certificate-error url=https://vpn.address.com/gateway-realm:443/remote/saml/start
FortiSAMLInstance.IgnoreCertificate url=https://vpn.address.com/gateway-realm:443/remote/saml/start
samlType=1 logDomainCookies - https://vpn.address.com
certificate-error url=https://vpn.address.com/sslvpn/css/ssl_style.css
FortiSAMLInstance.IgnoreCertificate url=https://vpn.address.com/sslvpn/css/ssl_style.css
samlType=1 logDomainCookies - https://vpn.address.com
certificate-error url=https://vpn.address.com/sslvpn/css/ssl_style.css
FortiSAMLInstance.IgnoreCertificate url=https://vpn.address.com/sslvpn/css/ssl_style.css
samlType=1 logDomainCookies - https://vpn.address.com
Saml - 'did-finish-load'
Saml - currentPath=https://vpn.address.com/gateway-realm:443/remote/saml/start
samlType=1 logDomainCookies - https://vpn.address.com
SAML - current path: https://vpn.address.com/gateway-realm:443/remote/saml/start
Saml - handleRedirect url=https://vpn.address.com/gateway-realm:443/remote/saml/start
Saml will-nativgate newUrl=https://vpn.address.com/remote/login
Saml - handleRedirect url=https://vpn.address.com/remote/login
Saml will-redirect url=https://vpn.address.com/remote/login?lang=en
certificate-error url=https://vpn.address.com/sslvpn/js/login.js?q=17551d5deba7dad25bffcfacc62cb666
FortiSAMLInstance.IgnoreCertificate url=https://vpn.address.com/sslvpn/js/login.js?q=17551d5deba7dad25bffcfacc62cb666
samlType=1 logDomainCookies - https://vpn.address.com
certificate-error url=https://vpn.address.com/remote/fgt_lang?lang=en
FortiSAMLInstance.IgnoreCertificate url=https://vpn.address.com/remote/fgt_lang?lang=en
samlType=1 logDomainCookies - https://vpn.address.com
certificate-error url=https://vpn.address.com/remote/fgt_lang?lang=en
FortiSAMLInstance.IgnoreCertificate url=https://vpn.address.com/remote/fgt_lang?lang=en
samlType=1 logDomainCookies - https://vpn.address.com
Saml - 'did-finish-load'
Saml - currentPath=https://vpn.address.com/remote/login?lang=en
samlType=1 logDomainCookies - https://vpn.address.com
SAML - current path: https://vpn.address.com/remote/login?lang=en
Saml - handleRedirect url=https://vpn.address.com/remote/login?lang=en
Saml - 'close' state=4
cancelAndExit state=4 currentWindow=[object BrowserWindow]
closeServer
Saml - 'closed' state=4
Can't offer any help, but also affected by the SAML issue. Bought a raspberry pi last year to use as a thin client, and been unable to do so since work added the SAML requirement (again, like other posters, non-windows is not really considered) - as far as I can tell, openfortivpn is the only way to use fortinet vpn on an arm device - so really hope this is possible!
For what it's worth, the @master branch of OpenConnect does support Fortinet SSL VPNs, but I think it doesn't support SAML yet, either.
Not sure of anybody is working on this. Using 1.17.1, instead of "/remote/login" - it goes to "/remote/saml/start". However, the redirect to "https://login.microsoftonline.com/" this part, I have no idea how to handle it. Any suggestions are welcome. Thanks.
Not sure of anybody is working on this. Using 1.17.1, instead of "/remote/login" - it goes to "/remote/saml/start". However, the redirect to "https://login.microsoftonline.com/" this part, I have no idea how to handle it. Any suggestions are welcome. Thanks.
I can see a few solutions, each has their pros and cons.
- Show the URL to the user, ask the user to proceed in a real web browser, and eventually copy & paste the result back. The Linux OneOrive client does this. It works, but I personally do not like the solution, because it requires extra user interactions.
- Run a headless web browser and performs the necessary steps inside the browser. This allows non-interactive use, but may break if Microsoft changes their login page. Some people may also have a distaste of the added overhead of a headless web browser.
- Dealing with the HTTP GET/POST requests in the code, and parse the HTML / JavaScript responses. This is the lightweight and non-interactive solution, but does require a bit of extra effort and may break if Microsoft changes their login page.
- Let an external program handles it, pass the URL to the external program and expect the result back from it. User may choose to use any of the above methods to implement the external program, everyone is happy.
I expect there are multiple different SAML providers following a certain standard, I had to use Forticlient recently with SAML, there was no trace of anything Microsoft related.
I expect there are multiple different SAML providers following a certain standard, I had to use Forticlient recently with SAML, there was no trace of anything Microsoft related.
Hmm, in that case, I can only see two ways out of this - interactive authentication in a web browser or an external program.
I personally prefer the later with some reference implementations, and one of them is the interactive authentication. The user should be able to use the reference implementation out of box if they prefer, or implement their own non-interactive version for their SAML provider.
My company has just started requiring SAML. After battling a bit with the official Forticlient, which keeps dropping the connection soon after creating the tunnel, I decided to look into ways to get the VPN working with openfortivpn.
This is the result: https://github.com/gm-vm/openfortivpn/tree/saml
The solution is far from ideal, it requires you to login from a browser, grab the SVPNCOOKIE and paste it in the console, but it's good enough for me for now.
Thinking about this a bit more, I don't think there is too much room for improvement here.
One way to make things better is that of having a standardized way to launch an external application to deal with the authentication and have the SVPNCOOKIE passed back.
I think that supporting every SAML provider reliably in a generic way without a browser is probably close to impossible. In my case, for example, I have to use Cisco's Duo, which does more than requiring username and password.
Thank you @gm-vm!
I don't know if I made a mistake but I tried to add saml = 1 in the config file and the program returns WARN: Bad key in configuration file: "saml".
However using the flag --saml works fine, I just had to take the port into account for the login URL because my IT team set up another port.
@MartialGeek thank you for the fixes.
Meanwhile I wrote a tiny Qt application to grab SVPNCOOKIE more easily. It is basically a QtWebEngine that opens the SAML page and prints the SVPNCOOKIE to stdout as soon as it is set.
This is the application: https://github.com/gm-vm/openfortivpn-webview
My idea was that of passing the path to this program to openfortivpn through some command line argument and have it run it as needed. It was too late when I remembered that openfortivpn must run as root and I definitely do not want to run a browser as root. I could get that to work the way I wanted with a combination of sudo --preserve-env, fork() and setuid(), but I did not really like how it ended up looking.
I therefore decided to change approach and have SVPNCOOKIE passed as argument. I have also made it possible to pass it through stdin, so that I can do something like this:
openfortivpn-webview my_host 2>/dev/null | sudo openfortivpn my_host --svpn-cookie -
I have created a new branch here: https://github.com/gm-vm/openfortivpn/tree/svpn_cookie
As I mentioned in my previous message, I really doubt I can get this working reliably without a browser.
This is for example an overview of the steps needed when using Duo. The overview omits the required steps for the setup of the mobile application: https://duo.com/docs/sso#saml-identity-provider
I think it is OK to use a browser as a first step. It is also OK to launch the browser before openfortivpn as a first step.
Note the ongoing effort to implement SAML in OpenConnect too. You might want to have a look, see for example https://gitlab.com/search?group_id=500944&project_id=2335175&scope=issues&search=SAML.
If the browser window is NOT lunched by the VPN software, how is reconnecting going to be handled?
Keep in mind the SVPNCOOKIE cookie may have fairly short expiry time or is limited to single use only, but other cookies for keeping track of the user login status may have much longer validity and can be used to get the short lived cookie again when needed.
For example, with the FortiClient VPN, it pops up the login window when reconnecting, and closes it in a few seconds without requiring any user interaction if the user is already logged in. The whole process is just a lots of HTTP redirection with the "set-cookie" headers.
Automatic reconnection with --persistent doesn't work well anyway, it resends the same password, which of course cannot work with SAML. I was against this option, the same can be achieved with an encapsulating script or proper init/systemd parameters, or by the NetworkManager plugin.
Indeed the proper way would be to attempt to reconnect with a cookie first, then re-enter new credentials. But you're right that reconnection with a cookie doesn't seem to work that well in Fortinet products anyway, see discussion about this somewhere in the OpenConnect issues or merge requests.
I definitely do not want to run a browser as root
I think it is a wise decision!
If the browser window is NOT lunched by the VPN software, how is reconnecting going to be handled?
We may need to watch the status of openfortivpn? I mean if the program that runs the browser acts as a daemon, it could monitor the openfortivpn process and re-lunch a login window under certain circumstance (some status code for example)?