]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Bugfix F5 'plain' login form
authorDaniel Lenski <dlenski@gmail.com>
Fri, 19 Nov 2021 19:26:59 +0000 (11:26 -0800)
committerDaniel Lenski <dlenski@gmail.com>
Fri, 19 Nov 2021 20:25:27 +0000 (12:25 -0800)
Fixes #351.

It turns out that the "plain auth form" for F5 has been broken since
0b47ea1882346fdedfcd8a315f51aeb39e13459e.  (This form is used as a stand-in
when the server fails to provide a real HTML login form, and only gives a
JavaScript mess that dynamically creates a form.)

DW probably didn't notice this when making that commit, because
a07bbbcd711c6fc4ef20fd9719e0e5da40f141f9 had previously fixed the other
places where a form with no `auth_id` could be created.

This ensures that the "plain auth form" has its `auth_id` set, and adds test
coverage of this form to `f5-auth-and-config`.

Signed-off-by: Daniel Lenski <dlenski@gmail.com>
f5.c
tests/f5-auth-and-config
tests/fake-f5-server.py

diff --git a/f5.c b/f5.c
index 953d3301696e3d1564377233f429f2179ca9f125..818abc529f795b53fdf3d0a281fa2e897e2b1f02 100644 (file)
--- a/f5.c
+++ b/f5.c
 
 #define XCAST(x) ((const xmlChar *)(x))
 
+/* XX: some F5 VPNs simply do not have a static HTML form to parse, but
+ * only a mess of JavaScript which creates a dynamic form that's
+ * functionally equivalent to the following:
+ *
+ * <form id="auth_form" method="post">
+ *   <input type="text" name="username"/>
+ *   <input type="password" name="password"/>
+ * </form>
+ */
 static struct oc_auth_form *plain_auth_form(void)
 {
        struct oc_auth_form *form;
@@ -49,6 +58,9 @@ static struct oc_auth_form *plain_auth_form(void)
                free_auth_form(form);
                return NULL;
        }
+       if ((form->auth_id = strdup("auth_form")) == NULL)
+               goto nomem;
+
        opt = form->opts = calloc(1, sizeof(*opt));
        if (!opt)
                goto nomem;
index 52e743dd1e14cd472b69f6670c22aa0d50a320f1..5a6c4eccd7ce0e2c7e265e6b4a712473f6fbe88f 100755 (executable)
@@ -35,6 +35,12 @@ launch_simple_sr_server $ADDRESS 443 $CERT $KEY > /dev/null 2>&1
 PID=$!
 wait_server $PID 1
 
+echo -n "Authenticating with username/password in the absence of an HTML login form... "
+( echo "test" | LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT --protocol=f5 -q $ADDRESS:443/?no_html_login_form=1 -u test $FINGERPRINT --cookieonly >/dev/null 2>&1) ||
+    fail $PID "Could not receive cookie from fake F5 server"
+
+echo ok
+
 echo -n "Authenticating with username/password... "
 ( echo "test" | LD_PRELOAD=libsocket_wrapper.so $OPENCONNECT --protocol=f5 -q $ADDRESS:443 -u test $FINGERPRINT --cookieonly >/dev/null 2>&1) ||
     fail $PID "Could not receive cookie from fake F5 server"
index c4ef53af981847b6b21102a7933af10bb8a4d62c..569fb955e99e06bf494fbc61938f2eb6438f6078 100755 (executable)
@@ -84,9 +84,12 @@ def check_form_against_session(*fields, use_query=False):
 # [Save list of domains/authgroups in the session for use later]
 @app.route('/')
 def root():
-    domains, mock_dtls = request.args.get('domains'), request.args.get('mock_dtls')
+    domains, mock_dtls, no_html_login_form = request.args.get('domains'), request.args.get('mock_dtls'), request.args.get('no_html_login_form')
+    assert not (domains and no_html_login_form), \
+        f'combination of domains and no_html_login_form is not allow specified'
     session.update(step='initial-GET', domains=domains and domains.split(','),
-                   mock_dtls=mock_dtls and bool(mock_dtls))
+                   mock_dtls=mock_dtls and bool(mock_dtls),
+                   no_html_login_form = no_html_login_form and bool(no_html_login_form))
     # print(session)
     return redirect(url_for('get_policy'))
 
@@ -95,6 +98,10 @@ def root():
 @app.route('/my.policy')
 def get_policy():
     session.update(step='GET-login-form')
+    no_html_login_form = session.get('no_html_login_form')
+    if no_html_login_form:
+        return '''<html><body>It would be nice if F5 login pages consistently used actual HTML forms</body></html>'''
+
     domains = session.get('domains')
     sel = ''
     if domains: