17
0

updated to new version fo gp-saml-gui and new api

Apparently new versions of GP hav changed the SAML API some. The
openconnect command now requires --gateway so this has been added.

I haven't tested the general and http scripts but I assume they
work. Someone else should verify.
This commit is contained in:
Benjamin Mako Hill 2023-06-28 11:59:51 -07:00
parent 4bb6708dc1
commit 2970f2c702
5 changed files with 283 additions and 66 deletions

View File

@ -1,18 +1,45 @@
[![Build Status](https://api.travis-ci.org/dlenski/gp-saml-gui.png)](https://travis-ci.org/dlenski/gp-saml-gui)
gp-saml-gui
===========
[![Test Workflow Status](https://github.com/dlenski/gp-saml-gui/workflows/build/badge.svg)](https://github.com/dlenski/gp-saml-gui/actions/workflows/test.yml)
Table of Contents
=================
* [Introduction](#introduction)
* [Installation](#installation)
* [First, non-Python Dependencies](#first-non-python-dependencies)
* [Second, gp-saml-gui itself](#second-gp-saml-gui-itself)
* [How to use](#how-to-use)
* [Extra arguments to OpenConnect](#extra-arguments-to-openconnect)
* [License](#license)
Introduction
============
This is a helper script to allow you to interactively login to a GlobalProtect VPN
that uses SAML authentication.
that uses [SAML](https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language)
authentication, so that you can subsequently connect with [OpenConnect](https://www.infradead.org/openconnect).
(The GlobalProtect protocol is supported in OpenConnect v8.0 or newer; v8.06+ is recommended.)
Interactive login is, unfortunately, sometimes a necessary alternative to automated
login via scripts such as
[zdave/openconnect-gp-okta](https://github.com/zdave/openconnect-gp-okta).
This script is known to work with many GlobalProtect VPNs using the major single-sign-on (SSO) providers:
- Okta (sign-in URLs typically `https://<company>.okta.com/login/*`)
- Microsoft (sign-in URLs typically `https://login.microsoftonline.com/*`)
Please search and file [issues](https://github.com/dlenski/gp-saml-gui/issues) if you can report success
or failure with other SSO SAML providers.
Installation
============
First, non-Python Dependencies
------------------------------
gp-saml-gui uses GTK, which requires Python 3 bindings.
On Debian / Ubuntu, these are packaged as `python3-gi`, `gir1.2-gtk-3.0`, and
@ -22,13 +49,34 @@ On Debian / Ubuntu, these are packaged as `python3-gi`, `gir1.2-gtk-3.0`, and
$ sudo apt install python3-gi gir1.2-gtk-3.0 gir1.2-webkit2-4.0
```
Then, set up a virtual environment that can access these system packages,
activate it, and install the Python dependencies:
On Fedora (and possibly RHEL/CentOS) the matching libraries are packaged in
`python3-gobject`, `gtk3-devel`, and `webkit2gtk3-devel`:
```
$ virtualenv --python=python3 --system-site-packages venv
$ . venv/bin/activate
$ pip install requests
$ sudo dnf install python3-gobject gtk3-devel webkit2gtk3-devel
```
On Arch Linux, the libraries are packaged in `gtk3`, `gobject-introspection`
and `webkit2gtk`:
```
$ sudo pacman -S gtk3 gobject-introspection webkit2gtk
```
Second, gp-saml-gui itself
--------------------------
Install gp-saml-gui itself using `pip`:
```
$ pip3 install https://github.com/dlenski/gp-saml-gui/archive/master.zip
...
$ gp-saml-gui
usage: gp-saml-gui [-h] [--no-verify] [-C COOKIES | -K] [-p | -g] [-c CERT]
[--key KEY] [-v | -q] [-x | -P | -S] [-u]
[--clientos {Windows,Linux,Mac}] [-f EXTRA]
server [openconnect_extra [openconnect_extra ...]]
gp-saml-gui: error: the following arguments are required: server, openconnect_extra
```
How to use
@ -39,14 +87,15 @@ arguments, such as `--clientos=Windows` (because many GlobalProtect
servers don't require SAML login, but apparently omit it in their configuration
for OSes other than Windows).
This script will pop up a [GTK WebKit2 WebView](https://webkitgtk.org/) window.
After you succesfully complete the SAML login via web forms, the script will output
This script will pop up a [GTK WebKit2 WebView](https://webkitgtk.org/) window
alongside your terminal window (see this [screenshot](screenshot.png)).
After you successfully complete the SAML login via web forms, the script will output
`HOST`, `USER`, `COOKIE`, and `OS` variables in a form that can be used by
[OpenConnect](http://www.infradead.org/openconnect/juniper.html)
(similar to the output of `openconnect --authenticate`):
```sh
$ eval $( gp-saml-gui.py --clientos=Windows vpn.company.com )
$ eval $( gp-saml-gui --gateway --clientos=Windows vpn.company.com )
Got SAML POST content, opening browser...
Finished loading about:blank...
Finished loading https://company.okta.com/app/panw_globalprotect/deadbeefFOOBARba1234/sso/saml...
@ -57,7 +106,7 @@ Got SAML relevant headers, done: {'prelogin-cookie': 'blahblahblah', 'saml-usern
SAML response converted to OpenConnect command line invocation:
echo 'blahblahblah' |
openconnect --protocol=gp --user='foo12345@corp.company.com' --os=win --usergroup=prelogin-cookie:gateway --passwd-on-stdin vpn.company.com
openconnect --protocol=gp --user='foo12345@corp.company.com' --os=win --usergroup=gateway:prelogin-cookie --passwd-on-stdin vpn.company.com
$ echo $HOST; echo $USER; echo $COOKIE; echo $OS
https://vpn.company.com/gateway:prelogin-cookie
@ -68,10 +117,24 @@ win
$ echo "$COOKIE" | openconnect --protocol=gp -u "$USER" --os="$OS" --passwd-on-stdin "$HOST"
```
TODO
====
If you specify either the `-P`/`--pkexec-openconnect` or `-S`/`--sudo-openconnect` options, the script
will automatically invoke OpenConnect as described, using either [`pkexec` from Polkit](https://www.freedesktop.org/software/polkit/docs/0.106/polkit.8.html)
or [`sudo`](https://www.sudo.ws/), as specified.
* Packaging
# Extra Arguments to OpenConnect
Extra arguments needed for OpenConnect can be specified by adding ` -- ` to the command line, and then
appending these. For example:
```sh
$ gp-saml-gui -P --gateway --clientos=Windows vpn.company.com -- --csd-wrapper=hip-report.sh
Launching OpenConnect with pkexec, equivalent to:
echo blahblahblahlongrandomcookievalue |
sudo openconnect --protocol=gp --user=foo12345@corp.company.com --os=win --usergroup=gateway:prelogin-cookie --passwd-on-stdin vpn.company.com
<pkexec authentication dialog pops up>
<openconnect runs>
```
License
=======

View File

@ -2,34 +2,51 @@
try:
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk, WebKit2, GLib
except ImportError:
try:
import pgi as gi
gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0')
from pgi.repository import Gtk, WebKit2, GLib
except ImportError:
gi = None
if gi is None:
raise ImportError("Either gi (PyGObject) or pgi module is required.")
import argparse
import pprint
import urllib
import urllib3
import requests
import xml.etree.ElementTree as ET
import ssl
import tempfile
from operator import setitem
from os import path
from os import path, dup2, execvp
from shlex import quote
from sys import stderr, platform
from binascii import a2b_base64, b2a_base64
from urllib.parse import urlparse, urlencode
from html.parser import HTMLParser
class CommentHtmlParser(HTMLParser):
def __init__(self):
super().__init__()
self.comments = []
def handle_comment(self, data: str) -> None:
self.comments.append(data)
COOKIE_FIELDS = ('prelogin-cookie', 'portal-userauthcookie')
gi.require_version('Gtk', '3.0')
gi.require_version('WebKit2', '4.0')
from gi.repository import Gtk, WebKit2, GLib
class SAMLLoginView:
def __init__(self, uri, html=None, verbose=False, cookies=None, verify=True):
def __init__(self, uri, html=None, verbose=False, cookies=None, verify=True, user_agent=None):
Gtk.init(None)
window = Gtk.Window()
# API reference: https://lazka.github.io/pgi-docs/#WebKit2-4.0
@ -40,20 +57,26 @@ class SAMLLoginView:
self.verbose = verbose
self.ctx = WebKit2.WebContext.get_default()
if not args.verify:
if not verify:
self.ctx.set_tls_errors_policy(WebKit2.TLSErrorsPolicy.IGNORE)
self.cookies = self.ctx.get_cookie_manager()
if args.cookies:
if cookies:
self.cookies.set_accept_policy(WebKit2.CookieAcceptPolicy.ALWAYS)
self.cookies.set_persistent_storage(args.cookies, WebKit2.CookiePersistentStorage.TEXT)
self.cookies.set_persistent_storage(cookies, WebKit2.CookiePersistentStorage.TEXT)
self.wview = WebKit2.WebView()
if user_agent is None:
user_agent = 'PAN GlobalProtect'
settings = self.wview.get_settings()
settings.set_user_agent(user_agent)
self.wview.set_settings(settings)
window.resize(500, 500)
window.add(self.wview)
window.show_all()
window.set_title("SAML Login")
window.connect('delete-event', self.close)
self.wview.connect('load-changed', self.get_saml_headers)
self.wview.connect('load-changed', self.on_load_changed)
self.wview.connect('resource-load-started', self.log_resources)
if html:
@ -93,42 +116,111 @@ class SAMLLoginView:
if charset or content_type.startswith('text/'):
print(data.decode(charset or 'utf-8'), file=stderr)
def get_saml_headers(self, webview, event):
def on_load_changed(self, webview, event):
if event != WebKit2.LoadEvent.FINISHED:
return
mr = webview.get_main_resource()
uri = mr.get_uri()
rs = mr.get_response()
h = rs.get_http_headers()
h = rs.get_http_headers() if rs else None
ct = h.get_content_type()
if self.verbose:
print('[PAGE ] Finished loading page %s' % uri, file=stderr)
if not h:
return
# convert to normal dict
d = {}
h.foreach(lambda k, v: setitem(d, k, v))
h.foreach(lambda k, v: setitem(d, k.lower(), v))
# filter to interesting headers
fd = {name:v for name, v in d.items() if name.startswith('saml-') or name in ('prelogin-cookie', 'portal-userauthcookie')}
if fd and self.verbose:
print("[SAML ] Got SAML result headers: %r" % fd, file=stderr)
if self.verbose > 1:
# display everything we found
ct = h.get_content_type()
mr.get_data(None, self.log_resource_text, ct[0], ct.params.get('charset'), d)
fd = {name: v for name, v in d.items() if name.startswith('saml-') or name in COOKIE_FIELDS}
# check if we're done
self.saml_result.update(fd, server=urlparse(uri).netloc)
GLib.timeout_add(1000, self.check_done)
if fd:
if self.verbose:
print("[SAML ] Got SAML result headers: %r" % fd, file=stderr)
if self.verbose > 1:
# display everything we found
mr.get_data(None, self.log_resource_text, ct[0], ct.params.get('charset'), d)
self.saml_result.update(fd, server=urlparse(uri).netloc)
self.check_done()
if not self.success:
if self.verbose > 1:
print("[SAML ] No headers in response, searching body for xml comments", file=stderr)
# asynchronous call to fetch body content, continue processing in callback:
mr.get_data(None, self.response_callback, ct)
def response_callback(self, resource, result, ct):
data = resource.get_data_finish(result)
content = data.decode(ct.params.get("charset") or "utf-8")
html_parser = CommentHtmlParser()
html_parser.feed(content)
fd = {}
for comment in html_parser.comments:
if self.verbose > 1:
print("[SAML ] Found comment in response body: '%s'" % comment, file=stderr)
try:
# xml parser requires valid xml with a single root tag, but our expected content
# is just a list of data tags, so we need to improvise
xmlroot = ET.fromstring("<fakexmlroot>%s</fakexmlroot>" % comment)
# search for any valid first level xml tags (inside our fake root) that could contain SAML data
for elem in xmlroot:
if elem.tag.startswith("saml-") or elem.tag in COOKIE_FIELDS:
fd[elem.tag] = elem.text
except ET.ParseError:
pass # silently ignore any comments that don't contain valid xml
if self.verbose > 1:
print("[SAML ] Finished parsing response body for %s" % resource.get_uri(), file=stderr)
if fd:
if self.verbose:
print("[SAML ] Got SAML result tags: %s" % fd, file=stderr)
self.saml_result.update(fd, server=urlparse(resource.get_uri()).netloc)
if not self.check_done():
# Work around timing/race condition by retrying check_done after 1 second
GLib.timeout_add(1000, self.check_done)
def check_done(self):
d = self.saml_result
if 'saml-username' in d and ('prelogin-cookie' in d or 'portal-userauthcookie' in d):
if args.verbose:
if self.verbose:
print("[SAML ] Got all required SAML headers, done.", file=stderr)
self.success = True
Gtk.main_quit()
return True
class TLSAdapter(requests.adapters.HTTPAdapter):
'''Adapt to older TLS stacks that would raise errors otherwise.
We try to work around different issues:
* Enable weak ciphers such as 3DES or RC4, that have been disabled by default
in OpenSSL 3.0 or recent Linux distributions.
* Enable weak Diffie-Hellman key exchange sizes.
* Enable unsafe legacy renegotiation for servers without RFC 5746 support.
See Also
--------
https://github.com/psf/requests/issues/4775#issuecomment-478198879
Notes
-----
Python is missing an ssl.OP_LEGACY_SERVER_CONNECT constant.
We have extracted the relevant value from <openssl/ssl.h>.
'''
def init_poolmanager(self, connections, maxsize, block=False):
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_context.set_ciphers('DEFAULT:@SECLEVEL=1')
ssl_context.options |= 1<<2 # OP_LEGACY_SERVER_CONNECT
self.poolmanager = urllib3.PoolManager(
num_pools=connections,
maxsize=maxsize,
block=block,
ssl_context=ssl_context)
def parse_args(args = None):
pf2clientos = dict(linux='Linux', darwin='Mac', win32='Windows', cygwin='Windows')
@ -144,10 +236,10 @@ def parse_args(args = None):
x.add_argument('-K', '--no-cookies', dest='cookies', action='store_const', const=None,
help="Don't use or store cookies at all")
x = p.add_mutually_exclusive_group()
x.add_argument('-p','--portal', dest='interface', action='store_const', const='portal', default='gateway',
help='SAML auth to portal')
x.add_argument('-g','--gateway', dest='interface', action='store_const', const='gateway',
help='SAML auth to gateway (default)')
x.add_argument('-g','--gateway', dest='interface', action='store_const', const='gateway', default='portal',
help='SAML auth to gateway')
x.add_argument('-p','--portal', dest='interface', action='store_const', const='portal',
help='SAML auth to portal (default)')
g = p.add_argument_group('Client certificate')
g.add_argument('-c','--cert', help='PEM file containing client certificate (and optionally private key)')
g.add_argument('--key', help='PEM file containing client private key (if not included in same file as certificate)')
@ -155,11 +247,20 @@ def parse_args(args = None):
x = p.add_mutually_exclusive_group()
x.add_argument('-v','--verbose', default=1, action='count', help='Increase verbosity of explanatory output to stderr')
x.add_argument('-q','--quiet', dest='verbose', action='store_const', const=0, help='Reduce verbosity to a minimum')
g.add_argument('-x','--external', action='store_true', help='Launch external browser (for debugging)')
x = p.add_mutually_exclusive_group()
x.add_argument('-x','--external', action='store_true', help='Launch external browser (for debugging)')
x.add_argument('-P','--pkexec-openconnect', action='store_const', dest='exec', const='pkexec', help='Use PolicyKit to exec openconnect')
x.add_argument('-S','--sudo-openconnect', action='store_const', dest='exec', const='sudo', help='Use sudo to exec openconnect')
g.add_argument('-u','--uri', action='store_true', help='Treat server as the complete URI of the SAML entry point, rather than GlobalProtect server')
g.add_argument('--clientos', choices=set(pf2clientos.values()), default=default_clientos, help="clientos value to send (default is %(default)s)")
p.add_argument('extra', nargs='*', help='Extra form field(s) to pass to include in the login query string (e.g. "magic-cookie-value=deadbeef01234567")')
args = p.parse_args(args = None)
p.add_argument('-f','--field', dest='extra', action='append', default=[],
help='Extra form field(s) to pass to include in the login query string (e.g. "-f magic-cookie-value=deadbeef01234567")')
p.add_argument('--allow-insecure-crypto', dest='insecure', action='store_true',
help='Allow use of insecure renegotiation or ancient 3DES and RC4 ciphers')
p.add_argument('--user-agent', '--useragent', default='PAN GlobalProtect',
help='Use the provided string as the HTTP User-Agent header (default is %(default)r, as used by OpenConnect)')
p.add_argument('openconnect_extra', nargs='*', help="Extra arguments to include in output OpenConnect command-line")
args = p.parse_args(args)
args.ocos = clientos2ocos[args.clientos]
args.extra = dict(x.split('=', 1) for x in args.extra)
@ -178,11 +279,13 @@ def parse_args(args = None):
return p, args
if __name__ == "__main__":
p, args = parse_args()
def main(args = None):
p, args = parse_args(args)
s = requests.Session()
s.headers['User-Agent'] = 'PAN GlobalProtect'
if args.insecure:
s.mount('https://', TLSAdapter())
s.headers['User-Agent'] = 'PAN GlobalProtect' if args.user_agent is None else args.user_agent
s.cert = args.cert
if2prelogin = {'portal':'global-protect/prelogin.esp','gateway':'ssl-vpn/prelogin.esp'}
@ -193,7 +296,7 @@ if __name__ == "__main__":
sam, uri, html = 'URI', args.server, None
else:
endpoint = 'https://{}/{}'.format(args.server, if2prelogin[args.interface])
data = {'tmp':'tmp', 'kerberos-support':'yes', 'ipv6-support':'no', 'clientVer':4100, 'clientos':args.clientos, **args.extra}
data = {'tmp':'tmp', 'kerberos-support':'yes', 'ipv6-support':'yes', 'clientVer':4100, 'clientos':args.clientos, **args.extra}
if args.verbose:
print("Looking for SAML auth tags in response to %s..." % endpoint, file=stderr)
try:
@ -209,12 +312,20 @@ if __name__ == "__main__":
if isinstance(rootex, ssl.CertificateError):
p.error("SSL certificate error (try --no-verify to ignore): %s" % rootex)
elif isinstance(rootex, ssl.SSLError):
p.error("SSL error: %s" % rootex)
p.error("SSL error (try --allow-insecure-crypto to ignore): %s" % rootex)
else:
raise
xml = ET.fromstring(res.content)
if xml.tag != 'prelogin-response':
p.error("This does not appear to be a GlobalProtect prelogin response\nCheck in browser: {}?{}".format(endpoint, urlencode(data)))
status = xml.find('status')
if status != None and status.text != 'Success':
msg = xml.find('msg')
if msg != None and msg.text == 'GlobalProtect {} does not exist'.format(args.interface):
p.error("{} interface does not exist; specify {} instead".format(
args.interface.title(), '--portal' if args.interface=='gateway' else '--gateway'))
else:
p.error("Error in {} prelogin response: {}".format(args.interface, msg.text))
sam = xml.find('saml-auth-method')
sr = xml.find('saml-request')
if sam is None or sr is None:
@ -243,7 +354,7 @@ if __name__ == "__main__":
# spawn WebKit view to do SAML interactive login
if args.verbose:
print("Got SAML %s, opening browser..." % sam, file=stderr)
slv = SAMLLoginView(uri, html, verbose=args.verbose, cookies=args.cookies, verify=args.verify)
slv = SAMLLoginView(uri, html, verbose=args.verbose, cookies=args.cookies, verify=args.verify, user_agent=args.user_agent)
Gtk.main()
if slv.closed:
print("Login window closed by user.", file=stderr)
@ -263,6 +374,29 @@ if __name__ == "__main__":
cn = ifh = None
p.error("Didn't get an expected cookie. Something went wrong.")
urlpath = args.interface + ":" + cn
openconnect_args = [
"--protocol=gp",
"--user="+un,
"--os="+args.ocos,
"--usergroup="+urlpath,
"--passwd-on-stdin",
server
] + args.openconnect_extra
if args.insecure:
openconnect_args.insert(1, "--allow-insecure-crypto")
if args.user_agent:
openconnect_args.insert(1, "--useragent="+args.user_agent)
if args.cert:
cert, key = args.cert
if key:
openconnect_args.insert(1, "--sslkey="+key)
openconnect_args.insert(1, "--certificate="+cert)
openconnect_command = ''' echo {} |\n sudo openconnect {}'''.format(
quote(cv), " ".join(map(quote, openconnect_args)))
if args.verbose:
# Warn about ambiguities
if server != args.server and not args.uri:
@ -274,14 +408,33 @@ if __name__ == "__main__":
'''that's often associated with the {} interface. You should probably try both.\n'''.format(args.interface, ifh),
file=stderr)
print('''\nSAML response converted to OpenConnect command line invocation:\n''', file=stderr)
print(''' echo {} |\n openconnect --protocol=gp --user={} --os={} --usergroup={}:{} --passwd-on-stdin {}'''.format(
quote(cv), quote(un), quote(args.ocos), quote(args.interface), quote(cn), quote(server)), file=stderr)
print(openconnect_command, file=stderr)
print('''\nSAML response converted to test-globalprotect-login.py invocation:\n''', file=stderr)
print(''' test-globalprotect-login.py --user={} --clientos={} -p '' \\\n https://{}/{} {}={}\n'''.format(
quote(un), quote(args.clientos), quote(server), quote(if2auth[args.interface]), quote(cn), quote(cv)), file=stderr)
varvals = {
'HOST': quote('https://%s/%s:%s' % (server, if2auth[args.interface], cn)),
'USER': quote(un), 'COOKIE': quote(cv), 'OS': quote(args.ocos),
}
print('\n'.join('%s=%s' % pair for pair in varvals.items()))
if args.exec:
print('''Launching OpenConnect with {}, equivalent to:\n{}'''.format(args.exec, openconnect_command), file=stderr)
with tempfile.TemporaryFile('w+') as tf:
tf.write(cv)
tf.flush()
tf.seek(0)
# redirect stdin from this file, before it is closed by the context manager
# (it will remain accessible via the open file descriptor)
dup2(tf.fileno(), 0)
if args.exec == 'pkexec':
cmd = ["pkexec", "--user", "root", "openconnect"] + openconnect_args
elif args.exec == 'sudo':
cmd = ["sudo", "openconnect"] + openconnect_args
execvp(cmd[0], cmd)
else:
varvals = {
'HOST': quote('https://%s/%s' % (server, urlpath)),
'USER': quote(un), 'COOKIE': quote(cv), 'OS': quote(args.ocos),
}
print('\n'.join('%s=%s' % pair for pair in varvals.items()))
if __name__ == "__main__":
main()

View File

@ -4,7 +4,7 @@
cd ~/bin/nu-vpn-proxy
## do the authentication
eval $( ./gp-saml-gui.py -v --clientos=Linux vpn-connect2.northwestern.edu )
eval $( ./gp-saml-gui.py -v --gateway --clientos=Linux vpn-connect2.northwestern.edu )
echo "$COOKIE" | sudo openconnect --useragent="PAN GlobalConnect" --version-string='5.1.0-101' --protocol=gp -u "$USER" --os="$OS" --passwd-on-stdin "$HOST" --csd-wrapper="hipreport-modified.sh" --reconnect-timeout 60

View File

@ -9,7 +9,7 @@ exec > $LOG_FILE
cd ~/bin/nu-vpn-proxy
## do the authentication
eval $( ./gp-saml-gui.py -v --clientos=Linux vpn-connect2.northwestern.edu )
eval $( ./gp-saml-gui.py -v --gateway --clientos=Linux vpn-connect2.northwestern.edu )
echo "$COOKIE" | /usr/sbin/openconnect --verbose --useragent="PAN GlobalConnect" --version-string='5.1.0-101' --protocol=gp -u "$USER" --os="$OS" --passwd-on-stdin "$HOST" --csd-wrapper="hipreport-modified.sh" --reconnect-timeout 60 --script-tun --script "ocproxy -D 8181 --keepalive 5 --verbose" -b --pid-file "${PID_FILE}"

View File

@ -1,5 +1,6 @@
#!/bin/bash
#!/bin/bash -x
OS="linux"
LOG_FILE=/tmp/nu-globalprotect-saml.log
PID_FILE=/tmp/nu-vpn-openconnect.pid
@ -9,7 +10,7 @@ exec > $LOG_FILE
cd ~/bin/nu-vpn-proxy
## do the authentication
eval $( ./gp-saml-gui.py -v --clientos=Linux vpn-connect2.northwestern.edu )
eval $( ./gp-saml-gui.py -v --gateway --clientos=Linux vpn-connect2.northwestern.edu )
echo "$COOKIE" | /usr/sbin/openconnect --useragent="PAN GlobalConnect" --version-string='5.1.0-101' --protocol=gp -u "$USER" --os="$OS" --passwd-on-stdin "$HOST" --csd-wrapper="hipreport-modified.sh" --reconnect-timeout 60 --script-tun --script "ocproxy -D 9052" -b --pid-file "${PID_FILE}"