]> code.communitydata.science - nu-vpn-proxy.git/blobdiff - gp-saml-gui.py
this script should live here
[nu-vpn-proxy.git] / gp-saml-gui.py
index 1f2b1b58663cf53aaea1f254eebe290ff9b5cd71..2d29d6204bc4c0d7bd2bce410ec6bbbd81eebbdb 100755 (executable)
@@ -7,7 +7,9 @@ import urllib
 import requests
 import xml.etree.ElementTree as ET
 import os
+import ssl
 
+from shlex import quote
 from sys import stderr
 from binascii import a2b_base64, b2a_base64
 
@@ -18,15 +20,18 @@ gi.require_version('WebKit2', '4.0')
 from gi.repository import WebKit2
 
 class SAMLLoginView:
-    def __init__(self, uri, html=None, verbose=False, cookies=None):
+    def __init__(self, uri, html=None, verbose=False, cookies=None, verify=True):
         window = Gtk.Window()
 
         # API reference: https://lazka.github.io/pgi-docs/#WebKit2-4.0
 
         self.success = False
+        self.saml_result = {}
         self.verbose = verbose
 
         self.ctx = WebKit2.WebContext.get_default()
+        if not args.verify:
+            self.ctx.set_tls_errors_policy(WebKit2.TLSErrorsPolicy.IGNORE)
         self.cookies = self.ctx.get_cookie_manager()
         if args.cookies:
             self.cookies.set_accept_policy(WebKit2.CookieAcceptPolicy.ALWAYS)
@@ -65,10 +70,13 @@ class SAMLLoginView:
                 if (name.startswith('saml-') or name in ('prelogin-cookie', 'portal-userauthcookie')):
                     t.append((name, value))
             h.foreach(listify)
-            self.saml_result = d = dict(l)
-            if d:
-                if self.verbose:
-                    print("Got SAML relevant headers, done: %r" % d, file=stderr)
+            d = dict(l)
+            if d and self.verbose:
+                print("Got SAML result headers: %r" % d, file=stderr)
+            d = self.saml_result
+            d.update(dict(l))
+            if 'saml-username' in d and ('prelogin-cookie' in d or 'portal-userauthcookie' in d):
+                print("Got all required SAML headers, done.", file=stderr)
                 self.success = True
                 Gtk.main_quit()
 
@@ -119,7 +127,23 @@ if __name__ == "__main__":
         sam, uri, html = 'URI', args.server, None
     else:
         endpoint = 'https://{}/{}/prelogin.esp'.format(args.server, ('global-protect' if args.portal else 'ssl-vpn'))
-        res = s.post(endpoint, verify=args.verify, data=args.extra)
+        print("Looking for SAML auth tags in response to %s..." % endpoint, file=stderr)
+        try:
+            res = s.post(endpoint, verify=args.verify, data=args.extra)
+        except Exception as ex:
+            rootex = ex
+            while True:
+                if isinstance(rootex, ssl.SSLError):
+                    break
+                elif not rootex.__cause__ and not rootex.__context__:
+                    break
+                rootex = rootex.__cause__ or rootex.__context__
+            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)
+            else:
+                raise
         xml = ET.fromstring(res.content)
         sam = xml.find('saml-auth-method')
         sr = xml.find('saml-request')
@@ -146,7 +170,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)
+    slv = SAMLLoginView(uri, html, verbose=args.verbose, cookies=args.cookies, verify=args.verify)
     Gtk.main()
     if not slv.success:
         p.error('''Login window closed without producing SAML cookie''')
@@ -160,9 +184,15 @@ if __name__ == "__main__":
     else:
         cn = None
 
+    fullpath = ('/global-protect/getconfig.esp' if args.portal else '/ssl-vpn/login.esp')
+    shortpath = ('portal' if args.portal else 'gateway')
     if args.verbose:
         print('''\n\nSAML response converted to OpenConnect command line invocation:\n''', file=stderr)
-        print('''    echo {!r} |\n        openconnect --protocol=gp --user={!r} --usergroup={}:{} --passwd-on-stdin {}\n'''.format(
-            cv, un, ('portal' if args.portal else 'gateway'), cn, args.server), file=stderr)
-
-    print("HOST={!r}\nUSER={!r}\nCOOKIE={!r}".format('https://%s/%s:%s' % (args.server, ('portal' if args.portal else 'gateway'), cn), un, cv))
+        print('''    echo {} |\n        openconnect --protocol=gp --user={} --usergroup={}:{} --passwd-on-stdin {}\n'''.format(
+            quote(cv), quote(un), quote(shortpath), quote(cn), quote(args.server)), file=stderr)
+
+    varvals = {
+        'HOST': quote('https://%s/%s:%s' % (args.server, shortpath, cn)),
+        'USER': quote(un), 'COOKIE': quote(cv),
+    }
+    print('\n'.join('%s=%s' % pair for pair in varvals.items()))

Community Data Science Collective || Want to submit a patch?