New Upstream Snapshot - gp-saml-gui

Ready changes

Summary

Merged new upstream version: 0.0~git20221031 (was: 0.0~git20220831).

Diff

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
deleted file mode 100644
index dd8edca..0000000
--- a/.github/workflows/test.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
-# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
-
-name: build
-
-on: [ push, pull_request]
-
-jobs:
-  build:
-
-    runs-on: ubuntu-latest
-    strategy:
-      matrix:
-        python-version: ['3.5', '3.6', '3.7', '3.8']
-
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
-      with:
-        python-version: ${{ matrix.python-version }}
-    - name: Install dependencies
-      run: |
-        sudo apt install -y libgirepository1.0-dev
-        python -m pip install --upgrade pip
-        python -m pip install flake8 pytest
-        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
-    - name: Lint with flake8
-      run: |
-        # stop the build if there are Python syntax errors or undefined names
-        flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
-        # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
-        flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
-    - name: Verify successful compilation
-      run: |
-        python -m py_compile gp_saml_gui.py
-        python -m py_compile test-globalprotect-login.py
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..e504a31
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,153 @@
+Metadata-Version: 2.1
+Name: gp-saml-gui
+Version: 0.1
+Summary: Interactively authenticate to GlobalProtect VPNs that require SAML
+Home-page: https://github.com/dlenski/gp-saml-gui
+Author: Daniel Lenski
+Author-email: dlenski@gmail.com
+License: GPL v3 or later
+Description-Content-Type: text/markdown
+License-File: LICENSE
+
+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?query=workflow%3Abuild)
+
+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](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
+`gir1.2-webkit2-4.0`:
+
+```
+$ sudo apt install python3-gi gir1.2-gtk-3.0 gir1.2-webkit2-4.0
+```
+
+On Fedora (and possibly RHEL/CentOS) the matching libraries are packaged in
+`python3-gobject`, `gtk3-devel`, and `webkit2gtk3-devel`:
+
+```
+$ 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
+==========
+
+Specify the GlobalProtect server URL (portal or gateway) and optional
+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
+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 --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...
+Finished loading https://company.okta.com/login/sessionCookieRedirect...
+Finished loading https://vpn.qorvo.com/SAML20/SP/ACS...
+Got SAML relevant headers, done: {'prelogin-cookie': 'blahblahblah', 'saml-username': 'foo12345@corp.company.com', 'saml-slo': 'no', 'saml-auth-status': '1'}
+
+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
+
+$ echo $HOST; echo $USER; echo $COOKIE; echo $OS
+https://vpn.company.com/gateway:prelogin-cookie
+foo12345@corp.company.com
+blahblahblah
+win
+
+$ echo "$COOKIE" | openconnect --protocol=gp -u "$USER" --os="$OS" --passwd-on-stdin "$HOST"
+```
+
+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.
+
+# 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
+=======
+
+GPLv3 or newer
diff --git a/README.md b/README.md
index da8d300..a5b4613 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,7 @@ Table of Contents
     * [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
@@ -118,7 +119,11 @@ $ echo "$COOKIE" | openconnect --protocol=gp -u "$USER" --os="$OS" --passwd-on-s
 
 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. Extra arguments needed for OpenConnect can be specified by adding ` -- ` to the command line, and then
+or [`sudo`](https://www.sudo.ws/), as specified.
+
+# 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
diff --git a/debian/changelog b/debian/changelog
index 1806d60..98d165a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,9 +1,10 @@
-gp-saml-gui (0.0~git20220831-2) UNRELEASED; urgency=medium
+gp-saml-gui (0.0~git20221031-1) UNRELEASED; urgency=medium
 
   * Remove constraints unnecessary since buster (oldstable):
     + Build-Depends: Drop versioned constraint on python3.
+  * New upstream snapshot.
 
- -- Debian Janitor <janitor@jelmer.uk>  Sat, 15 Oct 2022 19:09:42 -0000
+ -- Debian Janitor <janitor@jelmer.uk>  Sun, 26 Feb 2023 22:30:51 -0000
 
 gp-saml-gui (0.0~git20220831-1) unstable; urgency=medium
 
diff --git a/gp_saml_gui.egg-info/PKG-INFO b/gp_saml_gui.egg-info/PKG-INFO
new file mode 100644
index 0000000..e504a31
--- /dev/null
+++ b/gp_saml_gui.egg-info/PKG-INFO
@@ -0,0 +1,153 @@
+Metadata-Version: 2.1
+Name: gp-saml-gui
+Version: 0.1
+Summary: Interactively authenticate to GlobalProtect VPNs that require SAML
+Home-page: https://github.com/dlenski/gp-saml-gui
+Author: Daniel Lenski
+Author-email: dlenski@gmail.com
+License: GPL v3 or later
+Description-Content-Type: text/markdown
+License-File: LICENSE
+
+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?query=workflow%3Abuild)
+
+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](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
+`gir1.2-webkit2-4.0`:
+
+```
+$ sudo apt install python3-gi gir1.2-gtk-3.0 gir1.2-webkit2-4.0
+```
+
+On Fedora (and possibly RHEL/CentOS) the matching libraries are packaged in
+`python3-gobject`, `gtk3-devel`, and `webkit2gtk3-devel`:
+
+```
+$ 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
+==========
+
+Specify the GlobalProtect server URL (portal or gateway) and optional
+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
+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 --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...
+Finished loading https://company.okta.com/login/sessionCookieRedirect...
+Finished loading https://vpn.qorvo.com/SAML20/SP/ACS...
+Got SAML relevant headers, done: {'prelogin-cookie': 'blahblahblah', 'saml-username': 'foo12345@corp.company.com', 'saml-slo': 'no', 'saml-auth-status': '1'}
+
+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
+
+$ echo $HOST; echo $USER; echo $COOKIE; echo $OS
+https://vpn.company.com/gateway:prelogin-cookie
+foo12345@corp.company.com
+blahblahblah
+win
+
+$ echo "$COOKIE" | openconnect --protocol=gp -u "$USER" --os="$OS" --passwd-on-stdin "$HOST"
+```
+
+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.
+
+# 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
+=======
+
+GPLv3 or newer
diff --git a/gp_saml_gui.egg-info/SOURCES.txt b/gp_saml_gui.egg-info/SOURCES.txt
new file mode 100644
index 0000000..4837193
--- /dev/null
+++ b/gp_saml_gui.egg-info/SOURCES.txt
@@ -0,0 +1,11 @@
+LICENSE
+README.md
+gp-saml-gui.8
+gp_saml_gui.py
+setup.py
+gp_saml_gui.egg-info/PKG-INFO
+gp_saml_gui.egg-info/SOURCES.txt
+gp_saml_gui.egg-info/dependency_links.txt
+gp_saml_gui.egg-info/entry_points.txt
+gp_saml_gui.egg-info/requires.txt
+gp_saml_gui.egg-info/top_level.txt
\ No newline at end of file
diff --git a/gp_saml_gui.egg-info/dependency_links.txt b/gp_saml_gui.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/gp_saml_gui.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/gp_saml_gui.egg-info/entry_points.txt b/gp_saml_gui.egg-info/entry_points.txt
new file mode 100644
index 0000000..c7c5f2e
--- /dev/null
+++ b/gp_saml_gui.egg-info/entry_points.txt
@@ -0,0 +1,2 @@
+[console_scripts]
+gp-saml-gui = gp_saml_gui:main
diff --git a/requirements.txt b/gp_saml_gui.egg-info/requires.txt
similarity index 100%
rename from requirements.txt
rename to gp_saml_gui.egg-info/requires.txt
index 80ea7da..7d50fef 100644
--- a/requirements.txt
+++ b/gp_saml_gui.egg-info/requires.txt
@@ -1,2 +1,2 @@
-requests
 pygobject
+requests
diff --git a/gp_saml_gui.egg-info/top_level.txt b/gp_saml_gui.egg-info/top_level.txt
new file mode 100644
index 0000000..e89fd45
--- /dev/null
+++ b/gp_saml_gui.egg-info/top_level.txt
@@ -0,0 +1 @@
+gp_saml_gui
diff --git a/screenshot.png b/screenshot.png
deleted file mode 100644
index ee7f858..0000000
Binary files a/screenshot.png and /dev/null differ
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..8bfd5a1
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,4 @@
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff --git a/setup.py b/setup.py
index 2429606..08171f1 100755
--- a/setup.py
+++ b/setup.py
@@ -15,7 +15,7 @@ setup(
     name="gp-saml-gui",
     version='0.1',
     description="Interactively authenticate to GlobalProtect VPNs that require SAML",
-    long_description=open("README.md").read(),
+    long_description=open("README.md", encoding="utf-8").read(),
     long_description_content_type='text/markdown',
     author="Daniel Lenski",
     author_email="dlenski@gmail.com",
diff --git a/test-globalprotect-login.py b/test-globalprotect-login.py
deleted file mode 100755
index 74a8605..0000000
--- a/test-globalprotect-login.py
+++ /dev/null
@@ -1,164 +0,0 @@
-#!/usr/bin/python3
-
-from __future__ import print_function
-from sys import stderr, version_info, platform
-if (version_info >= (3, 0)):
-    from urllib.parse import urlparse, urlencode
-    raw_input = input
-else:
-    from urlparse import urlparse
-    from urllib import urlencode
-import requests
-import argparse
-import getpass
-import os
-import xml.etree.ElementTree as ET
-import posixpath
-from binascii import a2b_base64
-from tempfile import NamedTemporaryFile
-from shlex import quote
-from itertools import chain
-
-clientos_map = dict(linux='Linux', darwin='Mac', win32='Windows', cygwin='Windows')
-default_clientos = clientos_map.get(platform, 'Windows')
-
-p = argparse.ArgumentParser()
-p.add_argument('-v','--verbose', default=0, action='count')
-p.add_argument('endpoint', help='GlobalProtect server; can append /ssl-vpn/login.esp (default) or /global-protect/getconfig.esp or /{ssl-vpn,global-protect}/prelogin.esp')
-p.add_argument('extra', nargs='*', help='Extra field to pass to include in the login query string (e.g. "portal-userauthcookie=deadbeef01234567")')
-g = p.add_argument_group('Login credentials')
-g.add_argument('-u','--user', help='Username (will prompt if unspecified)')
-g.add_argument('-p','--password', help='Password (will prompt if unspecified)')
-g.add_argument('-c','--cert', help='PEM file containing client certificate (and optionally private key)')
-g.add_argument('--computer', default=os.uname()[1], help="Computer name (default is `hostname`)")
-g.add_argument('--clientos', choices=set(clientos_map.values()), default=default_clientos, help="clientos value to send (default is %(default)s)")
-g.add_argument('-k','--key', help='PEM file containing client private key (if not included in same file as certificate)')
-p.add_argument('-b','--browse', action='store_true', help='Automatically spawn browser for SAML')
-p.add_argument('--no-verify', dest='verify', action='store_false', default=True, help='Ignore invalid server certificate')
-args = p.parse_args()
-
-extra = dict(x.split('=', 1) for x in args.extra)
-endpoint = urlparse(('https://' if '//' not in args.endpoint else '') + args.endpoint, 'https:')
-if not endpoint.path:
-    print("Endpoint path unspecified: defaulting to /ssl-vpn/login.esp", file=stderr)
-    endpoint = endpoint._replace(path = '/ssl-vpn/login.esp')
-prelogin = (posixpath.split(endpoint.path)[-1] == 'prelogin.esp')
-
-if args.cert and args.key:
-    cert = (args.cert, args.key)
-elif args.cert:
-    cert = (args.cert, None)
-elif args.key:
-    p.error('--key specified without --cert')
-else:
-    cert = None
-
-s = requests.Session()
-s.headers['User-Agent'] = 'PAN GlobalProtect'
-s.cert = cert
-
-if prelogin:
-    data={
-        # sent by many clients but not known to have any effect
-        'tmp': 'tmp', 'clientVer': 4100, 'kerberos-support': 'yes', 'ipv6-support': 'yes',
-        # affects some clients' behavior (https://github.com/dlenski/gp-saml-gui/issues/6#issuecomment-599743060)
-        'clientos': args.clientos,
-        **extra
-    }
-else:
-    # same request params work for /global-protect/getconfig.esp as for /ssl-vpn/login.esp
-    if args.user == None:
-        args.user = raw_input('Username: ')
-    if args.password == None:
-        args.password = getpass.getpass('Password: ')
-    data=dict(user=args.user, passwd=args.password,
-              # required
-              jnlpReady='jnlpReady', ok='Login', direct='yes',
-              # optional but might affect behavior
-              clientVer=4100, server=endpoint.netloc, prot='https:',
-              computer=args.computer,
-              **extra)
-res = s.post(endpoint.geturl(), verify=args.verify, data=data)
-
-if args.verbose:
-    print("Request body:\n", res.request.body, file=stderr)
-
-res.raise_for_status()
-
-# build openconnect "cookie" if the result is a <jnlp>
-
-try:
-    xml = ET.fromstring(res.text)
-except Exception:
-    xml = None
-
-if cert:
-    cert_and_key = '\\\n        ' + ' '.join('%s "%s"' % (opt, quote(fn)) for opt, fn in zip(('-c','-k'), cert) if fn) + ' \\\n'
-else:
-    cert_and_key = ''
-
-if xml is not None and xml.tag == 'jnlp':
-    arguments = [(t.text or '') for t in xml.iter('argument')]
-    arguments += [''] * (16-len(arguments))
-    cookie = urlencode({'authcookie': arguments[1], 'portal': arguments[3], 'user': arguments[4], 'domain': arguments[7],
-                        'computer': args.computer, 'preferred-ip': arguments[15]})
-
-    print('''
-
-Extracted connection cookie from <jnlp>. Use this to connect:
-
-    openconnect --protocol=gp --usergroup=gateway %s \\
-        --cookie %s%s
-''' % (quote(endpoint.netloc), quote(cookie), cert_and_key), file=stderr)
-
-# do SAML request if the result is <prelogin-response><saml...>
-
-elif xml is not None and xml.tag == 'prelogin-response' and None not in (xml.find('saml-auth-method'), xml.find('saml-request')):
-    import webbrowser
-    sam = xml.find('saml-auth-method').text
-    sr = a2b_base64(xml.find('saml-request').text)
-    if sam == 'POST':
-        with NamedTemporaryFile(delete=False, suffix='.html') as tf:
-            tf.write(sr)
-        if args.browse:
-            print("Got SAML POST, browsing to %s" % tf.name)
-            webbrowser.open('file://' + tf.name)
-        else:
-            print("Got SAML POST, saved to:\n\t%s" % tf.name)
-    elif sam == 'REDIRECT':
-        sr = a2b_base64(sr)
-        if args.browse:
-            print("Got SAML REDIRECT, browsing to %s" % sr)
-            webbrowser.open(sr)
-        else:
-            print("Got SAML REDIRECT to:\n\t%s" % sr)
-
-# if it's a portal config response, pass along to gateway
-
-elif xml is not None and xml.tag == 'policy':
-
-    uemail = xml.find('user-email')
-    if uemail: uemail = uemail.text
-    cookies = [(cn, xml.find(cn).text) for cn in ('portal-prelogonuserauthcookie', 'portal-userauthcookie')]
-    gateways = [(e.find('description').text, e.get('name')) for e in set(chain(xml.findall('gateways/external/list/entry'), xml.findall('gateways6/external/list/entry')))]
-
-    print('''\nPortal config response response converted to new test-globalprotect-login.py invocation for gateway login:\n'''
-          '''    test-globalprotect-login.py --user={} --clientos={} -p {} {}\\\n'''
-          '''        https://{}/ssl-vpn/login.esp \\\n'''
-          '''        {}\n'''.format(
-              quote(args.user), quote(args.clientos), quote(args.password), cert_and_key, quote(gateways[0][1]),
-              ' '.join(cn+'='+quote(cv) for cn, cv in cookies),
-              file=stderr))
-
-    if uemail and uemail != args.user:
-        print('''IMPORTANT: Portal config contained different username. You might need to try\n'''
-              '''{} instead.\n'''.format(uemail))
-    if len(gateways)>1:
-        print('''Received multiple gateways. Options include:\n    {}\n'''.format('\n    '.join('%s => %s' % (desc, host) for desc, host in gateways)))
-
-# Just print the result
-
-else:
-    if args.verbose:
-        print(res.headers, file=stderr)
-    print(res.text)

More details

Full run details

Historical runs