From 32c08c5ae5c2b2def7c1a1cd7a7e6869c6ef60a5 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 24 Feb 2015 15:14:36 +0000 Subject: [PATCH] Support fallback from X-Support-HTTP-Auth If HTTP authentication fails against ocserv, it can offer us a form to try authentication the standard way. It can indicate that such is available by sending 'X-Support-HTTP-Auth: fallback' along with the 401 response. That way, we retry without 'X-Support-HTTP-Auth: true' in the request and we'll get the standard form. Signed-off-by: David Woodhouse --- cstp.c | 3 ++- http-auth.c | 12 ++++++++++++ http.c | 8 +++++--- library.c | 1 + openconnect-internal.h | 2 ++ 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/cstp.c b/cstp.c index 5130f40e..08888bc2 100644 --- a/cstp.c +++ b/cstp.c @@ -1148,7 +1148,8 @@ void cstp_common_headers(struct openconnect_info *vpninfo, struct oc_text_buf *b buf_append(buf, "X-AnyConnect-Platform: %s\r\n", vpninfo->platname); } - buf_append(buf, "X-Support-HTTP-Auth: true\r\n"); + if (vpninfo->try_http_auth) + buf_append(buf, "X-Support-HTTP-Auth: true\r\n"); append_mobile_headers(vpninfo, buf); } diff --git a/http-auth.c b/http-auth.c index 12954325..b4c2271d 100644 --- a/http-auth.c +++ b/http-auth.c @@ -247,6 +247,12 @@ int gen_authorization_hdr(struct openconnect_info *vpninfo, int proxy, } } vpn_progress(vpninfo, PRG_INFO, _("No more authentication methods to try\n")); + + if (vpninfo->retry_on_auth_fail) { + /* Try again without the X-Support-HTTP-Auth: header */ + vpninfo->try_http_auth = 0; + return 0; + } return -ENOENT; } @@ -305,6 +311,12 @@ int http_auth_hdrs(struct openconnect_info *vpninfo, char *hdr, char *val) { int i; + if (!strcasecmp(hdr, "X-HTTP-Auth-Support") && + !strcasecmp(val, "fallback")) { + vpninfo->retry_on_auth_fail = 1; + return 0; + } + if (strcasecmp(hdr, "WWW-Authenticate")) return 0; diff --git a/http.c b/http.c index 482ce2b0..b1e5a9fa 100644 --- a/http.c +++ b/http.c @@ -820,8 +820,6 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method, */ buf = buf_alloc(); buf_append(buf, "%s /%s HTTP/1.1\r\n", method, vpninfo->urlpath ?: ""); - if (vpninfo->proto.add_http_headers) - vpninfo->proto.add_http_headers(vpninfo, buf); if (auth) { result = gen_authorization_hdr(vpninfo, 0, buf); if (result) @@ -830,6 +828,8 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method, /* Forget existing challenges */ clear_auth_states(vpninfo, vpninfo->http_auth, 0); } + if (vpninfo->proto.add_http_headers) + vpninfo->proto.add_http_headers(vpninfo, buf); if (request_body_type) { rlen = request_body->pos; @@ -859,6 +859,8 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method, if (buf_error(buf)) return buf_free(buf); + vpninfo->retry_on_auth_fail = 0; + retry: if (openconnect_https_connected(vpninfo)) { /* The session is already connected. If we get a failure on @@ -899,7 +901,7 @@ int do_https_request(struct openconnect_info *vpninfo, const char *method, if (vpninfo->dump_http_traffic && buf->pos) dump_buf(vpninfo, '<', buf->data); - if (result == 401) { + if (result == 401 && vpninfo->try_http_auth) { auth = 1; goto redirected; } diff --git a/library.c b/library.c index fe256114..3198f091 100644 --- a/library.c +++ b/library.c @@ -83,6 +83,7 @@ struct openconnect_info *openconnect_vpninfo_new(const char *useragent, vpninfo->cbdata = privdata ? : vpninfo; vpninfo->xmlpost = 1; vpninfo->verbose = PRG_TRACE; + vpninfo->try_http_auth = 1; openconnect_set_reported_os(vpninfo, NULL); if (!vpninfo->localname || !vpninfo->useragent) diff --git a/openconnect-internal.h b/openconnect-internal.h index d5216e93..f0b7029a 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -374,6 +374,8 @@ struct openconnect_info { char *proxy_user; char *proxy_pass; int proxy_close_during_auth; + int retry_on_auth_fail; + int try_http_auth; struct http_auth_state http_auth[MAX_AUTH_TYPES]; struct http_auth_state proxy_auth[MAX_AUTH_TYPES]; int authmethods_set;