andrew-bibb / cmst

QT GUI for Connman
174 stars 37 forks source link

Add option to auto-create OpenConnect-cookie when connecting to VPN #194

Open EarthlingX opened 6 years ago

EarthlingX commented 6 years ago

When using a OpenConnect VPN-connection, many VPN servers request user authentication via cookie. This cookie has to be generated before connecting to the VPN and should be stored into /var/lib/connman-vpn/vpnname.config, otherwise the connection can not be established successfully.

To do so, every time you want to connect to the VPN you have to execute a little shell command that will do the job for you. This command is generating the cookie and writes this new cookie into the VPN provisioning file /var/lib/connman-vpn/vpnname.config:

sed -i "s/^OpenConnect.Cookie =.*$/$( echo '<YOUR-VPN-PASSWORD>' | openconnect --csd-wrapper=/home/user/.cisco/csd-wrapper.sh --authenticate --user=<USERNAME> --authgroup="<YOURGROUP>" --passwd-on-stdin <VPN-HOST-DOMAIN> | grep 'COOKIE=' | sed "s/COOKIE='//; s/'//g; s/^/OpenConnect.Cookie = /")/" <EXTERNAL-FILENAME>

Afterwards, in CMST you can click on Connect and connect to the VPN successfully. Unfortunately it is a bit annoying to run this command by hand every time you want to connect.


Would it be possible to add some function into CMST that will execute the command first of all when clicking on Connect?

For example:

You can have a look at the more detailed description from a user on StackExchange:

https://unix.stackexchange.com/questions/449174/connman-how-to-set-up-openconnect-vpn-with-csd-wrapper-correctly

It seems that NetworkManager can handle those recreations of the user cookie by himself. In CMST that is not possible yet , but it would be a nice feature.

I would appreciate such a feature! Thanks a lot for your efforts!

andrew-bibb commented 6 years ago

On the surface this seems like something I should be able to so something like this. Option 2 will not happen as that file is created by ConnMan and all entries are defined by them. Option 1 seems possible. We already have a similar feature or option to execute a user defined command after connect. Should be able to put one in to do before connect.

May be a bit though, I have a note on the front page here explaining why.

EarthlingX commented 6 years ago

"Option 1 seems possible. We already have a similar feature or option to execute a user defined command after connect. Should be able to put one in to do before connect."

That sounds great, thanks a lot for your kind efforts! :-)

Just two small annotations:

  1. In my case the mentioned command has to be executed as root¹. Do you think implementation for execution as root would cause big trouble?

    ¹ Because the VPN provisioning files are stored in /var/lib/connman-vpn/vpnname.config.

  2. When talking about pre/post-commands - how do you want to implement such a feature: Individually and independent from each other for every single VPN-connection, or would it be a global definition (e.g. one single pre/post-command valid for all existing VPN-connections)? I fear global pre/post-commands would not make much sense, because not all possible VPN-connections will require the same commands...

    Therefore only individually and independent commands (based on individual connection names) would bring success I think - what is your opinion?

andrew-bibb commented 6 years ago

Running as root is not a problem, the current vpn provisioning editor does that. Speaking of which, does the current editor do what you want? I haven't actually looked but when I wrote the editor I thought I put in every command allowed by Connman, and one of them is OpenConnect.cookie. You need the "Advanced" options checked to see this control (in the preferences tab, left side about half way down).

The ConnMan docs do say that since the cookie lifetime is limited it usually does not make sense to store it. Docs also say that the vpn agent is supposed to prompt for this cookie if it is needed and not present. I did implement an agent, so if that is not working I will need to research why. May not be my problem, but likely is.

EarthlingX commented 6 years ago

Once again - thank you so much for your great support and your efforts!

"[...] when I wrote the editor I thought I put in every command allowed by Connman, and one of them is OpenConnect.cookie."

Yes, you are completely right! VPN Editor provides the option to add OpenConnect.Cookie as well. After selecting, there is a prompt asking for "Read cookie from standard input?" - I am not completely sure about what this prompt means?

Anyway, I used the VPN Editor and created the provisioning file vpn-name.config with it (which is working fantastic). Also the VPN-connection works great (well, after obtaining the cookie from the server and adding it into the provisioning file). Already at this point a huge THANK YOU to you!!

As I mentioned above: The only eyesore is that I have to regenerate the cookie manually by hand every time I want to connect again (what is a bit annoying). Therefore an option to auto-recreate the cookie when clicking on Connect and auto-put it into the vpn-name.config-file would be a great option. This is what the command in my first posting does - currently I just have to run it manually before clicking on Connect.

Including such a automated command as an option in CMST when clicking on Connect would be awesome. :-)

As you said: Possible solutions could be optional pre/post-commands which are executed when clicking on Connect. We just have to ensure that those pre/post-commands are specific and exclusively getting used for the belonging VPN-connection names, but not globally used for all saved VPN-connections.

For example, a OpenVPN-connection does not require a OpenConnect-cookie - this would cause errors en masse. :-)

I hope that I am not disturbing you with this... Anyway, I am very happy to hear from you! :-)

andrew-bibb commented 5 years ago

No problem answering questions. About all I can do until I recover some sort of development computer.

On the read cookie input, it may be right or maybe something I misinterpreted I just read the ConnMan docs and tried to provide what they needed. I've been wrong several times, but once somebody finds those mistakes we can correct it. For this option below is the sum total of what I had go on from the docs:

OpenConnect.Cookie --cookie-on-stdin Cookie received as a result of the web authentication. As the cookie lifetime can be very limited, it does not usually make sense to add it into the configuration file

From your description it sounds like maybe it is working, but if not let me know what you think I may need to do to fix it. Maybe they are saying it does not make sense, but you can. Sometimes hard to interpret.

It sounds to me that ConnMan is not going to store the cookie in the configuration file, but that does not mean we can't provide an option for the pre connect command. I'm careful not to stray too far from what they do, but this sounds along the lines of the execute on connect option we already implemented.

EarthlingX commented 5 years ago

Thanks again for your great efforts! :-)

There is a nice explanation on StackExchange about what the OpenConnect-Cookie actually does:

https://unix.stackexchange.com/questions/449174/connman-how-to-set-up-openconnect-vpn-with-csd-wrapper-correctly

As far as I understand, the process is like that:

The OpenConnect-command itself is just necessary to obtain the required server cert and cookie. Afterwards you don't need this command anymore.

So, my current workflow is that:

  1. Obtaining a cookie by running the OpenConnect-command
  2. Putting that cookie into the provisioning file (vpn-name.config)
  3. Using the provisioning file with the current data to connect to the server

But: Your idea is great and maybe I misunderstand something big: Maybe ConnMan is seriously able to obtain the cookie by himself. But in this case, I am not sure where I can provide all additional information like username, password, group, etc. for ConnMan?

Let's assume that ConnMan does not write the cookie into the provisioning file, so maybe he stores it temporarily into a cache and does only use it for the connection process.

So: What would happen if we add the part...

echo '<YOUR-VPN-PASSWORD>' | openconnect --csd-wrapper=/home/user/.cisco/csd-wrapper.sh --authenticate --user=<USERNAME> --authgroup="<YOURGROUP>" --passwd-on-stdin <VPN-HOST-DOMAIN>

... behind the line OpenConnect.Cookie = into the provisioning file?

Maybe ConnMan can already execute the command by himself and takes out all necessary information?

I am wondering what kind of input the ConnMan-developers expect for the line OpenConnect.Cookie =? Should there be a executable command pasted to obtain the cookie? Or just a simple yes/no or similar?


The ConnMan-description is seriously difficult to understand... :-)

progandy commented 5 years ago

If "OpenConnect.Cookie" is missing from the VPN configuration file, then connman should ask the vpn agent (cmst) for the value it should use. (using the RequestInput method in net.connman.vpn.Agent)

In a very basic implementation, cmst now asks for the cookie, you create it in a terminal without root permissions and copy/paste it in the request. cmst sends the triplet Cookie, ServerCert, VPNHost to connman. In a more elaborate configuration, cmst has the command configured, the password is retrieved from storage or interactively requested. Then the command is executed and Cookie, ServerCert, VPNHost are sent to connman.

EarthlingX commented 5 years ago
  • In a very basic implementation, cmst now asks for the cookie, you create it in a terminal without root permissions and copy/paste it in the request. cmst sends the triplet Cookie, ServerCert, VPNHost to connman.
  • In a more elaborate configuration, cmst has the command configured, the password is retrieved from storage or interactively requested. Then the command is executed and Cookie, ServerCert, VPNHost are sent to connman.

This sounds very great! :+1:

The first option would be a nice and helpful workaround, the second option would be a mercedes. :-)

progandy commented 5 years ago

The first option should already work I think. If you remove the cookie line from your configuration, then cmst opens a window where you have to enter Cookie, ServerCert, and VPNHost.

andrew-bibb commented 5 years ago

I have been somewhat remiss in following up on this, however I wanted to comment that in the past two weeks there has been a flurry of activity at the ConnMan end regarding VPN. There is one patch I saw go by that if I am reading it right adds a custom callback function that I think could be used for this. Next version of ConnMan I think there will be a lot to do to bring CMST up to date, there seems to have been a lot of features added the past month or so, with VPN occupying a lot of the last two weeks.

andrew-bibb commented 4 years ago

Connman now supports openconnect.cookie and CMST as of our most recent release have it in the VPN provisioning editor. Going to close this now

EarthlingX commented 4 years ago

Thank you very much for your efforts!

That means that Connman and CMST can execute the OpenConnect authentication request to obtain server certificate (FINGERPRINT) and COOKIE by themselves now?

Or do we still have to obtain both of these manually but now have the option to paste them into the GUI?

andrew-bibb commented 4 years ago

Here is a link to a document that explains which OpenConnect options Connman supports:

https://git.kernel.org/pub/scm/network/connman/connman.git/tree/doc/vpn-config-format.txt

Even if I don't have all of the sub options in the VPN configuration editor the editor works as a conventional text editor so you could put in the ones I don't have a helper for. If you find one I need as a helper would you kindly open a new issue for it and explain what I need to do. I read this documentation but I sometimes don't quite understand it all. One thing I've discovered about ConnMan is that the documentation is sometimes a bit sparse on detail.

progandy commented 4 years ago

I believe EarthlingX asks if there is a way to execute a custom command when OpenConnect.Cookie is requested by connman with a dbus call to net.connman.Agent.RequestInput. Cookies are shortlived and have to be recreated for each connection attempt.

EarthlingX commented 4 years ago

I believe EarthlingX asks if there is a way to execute a custom command when OpenConnect.Cookie is requested by connman with a dbus call to net.connman.Agent.RequestInput. Cookies are shortlived and have to be recreated for each connection attempt.

Exactly, that's the core of my question. Thank you very much! :+1:

Even with those input options in CMST, I would have to execute some additional command in CLI to obtain FINGERPRINT and COOKIE and afterwards paste them manually into the mentioned CMST input fields.

It would be great if such a CLI-command could be executed while clicking on "connect". Maybe we can introduce some input field to insert the mentioned code that has to be executed each time when connecting?

progandy commented 4 years ago

Maybe it could be a global command that runs on each call to RequestInput regardless of the connection type?

andrew-bibb commented 4 years ago

Sorry, brain dead here. We have an option to execute a command after a connection is made, sounds like you want one after the connect button is pressed. I should be able to do that. Right now the connect button signals Connman via DBUS to initiate a connection. Should be a simple thing to put in an intermediate function first.

Need to change out snow tires on wifey's car tomorrow, but other than that I have the weekend free. I've been doing a lot of touch up to some (occasionally embarrassing) things that didn't work after the release to support 1.38. This will give me something meaty to add to add to that.

andrew-bibb commented 4 years ago

This might also allow me to address the issue for OpenVPN connections that require input during the connect via stdin. That one should be addressed at the Connman end, but does not sound like anybody cares enough to take it on. Might give me a work around.

EarthlingX commented 4 years ago

Nice to hear from you guys, thanks a lot! :+1:

At least for OpenConnect-based connections the required solution in CMST could be quite simple:

I have written a small bash script that, when executing, will request the values FINGERPRINT and COOKIE from the server. Afterwards the bash script will automatically paste the results into the lines FINGERPRINT = blablabla and COOKIE = blablabla within the vpn_name.config provisioning file. After finishing execution of this script I can access the VPN immediately.

By this means, CMST would just need one additional input field (run as root) where I can put this bash script code into (in best case it should be made storable, so I do not need to copy & paste it each time). Now, when clicking on "Connect", CMST will run the bash script quickly (which updates the provisioning file) and then could connect to the server.

screen

Here you can have a look at the mentioned bash script:

#!/bin/bash

USER='my-username' PASSWD='my-password' DOMAIN='https://vpngate.mycompany.com' TARGETFILE=/var/lib/connman-vpn/vpn_mycompany.config

sed -i "s/^Host =.*$/$( echo "$PASSWD" | openconnect --authenticate --user="$USER" --passwd-on-stdin "$DOMAIN" | grep 'HOST=' | sed "s/HOST='//; s/'//g; s/^/Host = /")/" $TARGETFILE sed -i "s/^OpenConnect.ServerCert =.*$/$( echo "$PASSWD" | openconnect --authenticate --user="$USER" --passwd-on-stdin "$DOMAIN" | grep 'FINGERPRINT=' | sed "s/FINGERPRINT='//; s/'//g; s/^/OpenConnect.ServerCert = /")/" $TARGETFILE sed -i "s/^OpenConnect.Cookie =.*$/$( echo "$PASSWD" | openconnect --authenticate --user="$USER" --passwd-on-stdin "$DOMAIN" | grep 'COOKIE=' | sed "s/COOKIE='//; s/'//g; s/^/OpenConnect.Cookie = /")/" $TARGETFILE

Need to change out snow tires on wifey's car tomorrow

Haha, wifey's things go first! :-))

andrew-bibb commented 4 years ago

So there is a very preliminary version to implement this uploaded here to the master branch. Few things you need to know. To set the programs to run before connect you need to have the Advanced options checkbox in the Preferences tab checked. With that checked you'll see a bunch of new lines in the lower right of that dialog. Hopefully they are self explanatory (at least for now) but there are some "whats this" text for each.

Getting a program to execute before connecting was easy. What has taken the time has been limiting what can be done with elevated privileges and making sure that whatever process is specified has actually completed before we try the connect. That last part is not quite working yet, but if your script is fast you can get away with it. For the elevated privileges part we only allow CMST to edit (create, delete) files in /var/lib/connman or /var/lib/connman-vpn that have a file extension of .cmst.config. Be advised of that.

What I have done is when the Modify Services Box is checked in preferences we read all of the output from whatever program is in the Execute Box. The output is then used to modify the specified .cmst.config file. No need for the sed lines in your script. I have been testing with a script that just has a series of "echo" lines in it. Whatever you echo will replace the corresponding line in the .cmst.config file if there is one, or will append it if there is no corresponding line.

If you would like to start testing I'd appreciate it. Still a ton of cleanup I need to do at this end. Once this is settled I want to look at Progandy's idea but I think this is more or less how it is going to have to work.

EarthlingX commented 4 years ago

Thank you very much Andrew, also for your nice explanation! :-)

I have settled up a virtual machine and compiled the new CMST which works fine with the basic functions.

VPN:

My provisioning-file has the file name my_company.cmst.config - nevertheless, I run into some permission error when connecting the VPN.

screen

Can I call the bash script externally (e. g. so that CMST will execute sh /home/user/script.sh), or is it mandatory to insert the the whole script into the mentioned field?

Running the script externally by hand (in terminal) works fine - I just need to get CMST starting it by himself.

Update:

Also running CMST as root does not help. I am able to avoid the error message with this, but the VPN cannot be connected successfully. I guess my script is too slow and taking too much time - maybe we need some adjustable delay option (1 second to 5 seconds adjustable) before igniting the connection process? :-)

andrew-bibb commented 4 years ago

Thanks for trying this. I just updated the code to not call the dbus connect method until the external program has finished. That async stuff has been driving me nuts (I am only self taught - not a professional), but I found a way to do it. It may actually even be the correct way.

andrew-bibb commented 4 years ago

I looked again at the error you were getting plus read your update and I don't think it was from calling the connect function before your script finished. The error is on the initial read which occurs before your script would even be called. My guess is it is permissions. The built in roothelper will only allow you to edit files if you (the logged in user) are in the appropriate network group for your distro. CMST default is "network" because I work in Arch, in Slackware it is "netdev". This pretty much explains why you connect as root. The timing issue should have been fixed with my upload last night.

EarthlingX commented 4 years ago

Thanks a lot for your update! Nice to hear the timing issue has been fixed now. :+1:

Anyhow, also with the new version I still receive the error message as seen above - probably (as you said) I need to add my user to the network group (Debian-based distro).

So can I recall my bash script as an external file (via sh /home/user/bash-script.sh), or does it have to be pasted into the CMST-field completely?

andrew-bibb commented 4 years ago

Been a couple of very difficult days here. Moved what I could from my office to home as we're locked down for the next 3 weeks, plus had to let a few of my employees know that their best bet for continued income was to file for unemployment. Been an all around dandy few days.

Anyway, I am not sure where or what version you have or where we left this. The box in CMST for your script must be the full path starting with /. Path only, don't paste the entire script. Latest version I have here is working fine with a test bash script, either modifying the .cmst.config file or just running as a separate process. That last is determined by the checkbox in Preferences for modify service file