From patchwork Thu Jun 13 04:41:13 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arne Schwabe X-Patchwork-Id: 753 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director8.mail.ord1d.rsapps.net ([172.28.255.1]) by backend30.mail.ord1d.rsapps.net with LMTP id 2I2dFedgAl0QdgAAIUCqbw for ; Thu, 13 Jun 2019 10:42:47 -0400 Received: from proxy1.mail.ord1c.rsapps.net ([172.28.255.1]) by director8.mail.ord1d.rsapps.net with LMTP id WFFzFedgAl3WWwAAfY0hYg ; Thu, 13 Jun 2019 10:42:47 -0400 Received: from smtp19.gate.ord1c ([172.28.255.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy1.mail.ord1c.rsapps.net with LMTP id sJFYFedgAl0ADwAA2VeTtA ; Thu, 13 Jun 2019 10:42:47 -0400 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.105.38.7] Authentication-Results: smtp19.gate.ord1c.rsapps.net; iprev=pass policy.iprev="216.105.38.7"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=none (p=nil; dis=none) header.from=rfc2549.org X-Suspicious-Flag: YES X-Classification-ID: 81e84dae-8de9-11e9-8c05-bc305bf036e4-1-1 Received: from [216.105.38.7] ([216.105.38.7:40972] helo=lists.sourceforge.net) by smtp19.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.38.62370 r(:)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 18/57-21561-6E0620D5; Thu, 13 Jun 2019 10:42:46 -0400 Received: from [127.0.0.1] (helo=sfs-ml-2.v29.lw.sourceforge.com) by sfs-ml-2.v29.lw.sourceforge.com with esmtp (Exim 4.90_1) (envelope-from ) id 1hbQv2-0006zH-3Q; Thu, 13 Jun 2019 14:41:36 +0000 Received: from [172.30.20.202] (helo=mx.sourceforge.net) by sfs-ml-2.v29.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1hbQuz-0006yz-Ud for openvpn-devel@lists.sourceforge.net; Thu, 13 Jun 2019 14:41:33 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=References:In-Reply-To:Message-Id:Date:Subject:To: From:Sender:Reply-To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=ryWZTeV5Zwq4k3AQ6exkOL96YX+SP/VR/J8EEY99PEU=; b=j698ihOK441pIwKrmXlbpAA/Hh SfFbfkBcqgbdgBWQiRx3DK6hhABJa4ejKU2d3Xi5VD67VW38/L9dNt/8rUuPvSEBW9HxZW6Yd44zY gkSqVMjR0OR0Ith/f18yABidiM4pFXWVZ0p3Pvw9lfdc/PYKWwbk0zI7xzEbmDlPJJhc=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=References:In-Reply-To:Message-Id:Date:Subject:To:From:Sender:Reply-To:Cc :MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ryWZTeV5Zwq4k3AQ6exkOL96YX+SP/VR/J8EEY99PEU=; b=CQkTVI6IUZIww3u4CaiTX5O5Lp FRQcTNZT42tis11s0UAKGFnrZnYYJqdO6TCZoQ8KIJedhtyLX6yEIr3u7j26DDRFQJvuSPrIvuyaI a6s7VGy6jQlGhlv/6egC+33dYE58jvPJCh96g+Q5ieEEnWay6zNRJNtmYa3G4X3n4Pjc=; Received: from [192.26.174.232] (helo=mail.blinkt.de) by sfi-mx-3.v28.lw.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) id 1hbQuw-00C2Dc-JH for openvpn-devel@lists.sourceforge.net; Thu, 13 Jun 2019 14:41:34 +0000 Received: from kamera.blinkt.de ([2001:638:502:390:20c:29ff:fec8:535c]) by mail.blinkt.de with smtp (Exim 4.91 (FreeBSD)) (envelope-from ) id 1hbQug-000OBb-8Y for openvpn-devel@lists.sourceforge.net; Thu, 13 Jun 2019 16:41:14 +0200 Received: (nullmailer pid 6478 invoked by uid 10006); Thu, 13 Jun 2019 14:41:14 -0000 From: Arne Schwabe To: openvpn-devel@lists.sourceforge.net Date: Thu, 13 Jun 2019 16:41:13 +0200 Message-Id: <20190613144113.6418-6-arne@rfc2549.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190613144113.6418-1-arne@rfc2549.org> References: <20190613144113.6418-1-arne@rfc2549.org> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. 0.0 URIBL_BLOCKED ADMINISTRATOR NOTICE: The query to URIBL was blocked. See http://wiki.apache.org/spamassassin/DnsBlocklists#dnsbl-block for more information. [URIs: rfc2549.org] 0.2 HEADER_FROM_DIFFERENT_DOMAINS From and EnvelopeFrom 2nd level mail domains are different 0.0 SPF_NONE SPF: sender does not publish an SPF Record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record 1.0 RDNS_NONE Delivered to internal network by a host with no rDNS X-Headers-End: 1hbQuw-00C2Dc-JH Subject: [Openvpn-devel] [PATCH 5/5] Implement sending SSO challenge to clients X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox This implements sending AUTH_PENDING and INFO_PRE messages to clients that indicate that the clients should be continue authentication with a second factor. This can currently be out of band (openurl) or a normal challenge/response 2FA like TOTP (CR_TEXT). Note that this also sends a AUTH_PENDING message that signal the client to change its behaviour and continue polling with PUSH request. In OpenVPN2 this is already default behaviour, so we can ignore this message in OpenVPN2. Signed-off-by: Arne Schwabe --- doc/management-notes.txt | 47 ++++++++++++++++++++++++++++++++++++++++ src/openvpn/manage.c | 36 ++++++++++++++++++++++++++++++ src/openvpn/manage.h | 3 +++ src/openvpn/multi.c | 19 ++++++++++++++++ src/openvpn/push.c | 24 ++++++++++++++++++++ src/openvpn/push.h | 2 ++ 6 files changed, 131 insertions(+) diff --git a/doc/management-notes.txt b/doc/management-notes.txt index 29f2da75..a3c09b78 100644 --- a/doc/management-notes.txt +++ b/doc/management-notes.txt @@ -592,6 +592,53 @@ interface to approve client connections. CID,KID -- client ID and Key ID. See documentation for ">CLIENT:" notification for more info. +COMMAND -- client-sso-auth (OpenVPN 2.5 or higher) +---------------------------------------------------- + +Instruct OpenVPN server to send AUTH_PENDING and INFO_PRE signal +a single sign on url to the client. + + client-sso-auth {CID} {EXTRA} + +The server will send AUTH_PENDING and INFO_PRE,{EXTRA} to the client. +The client is expected to inform the user that authentication is pending and +display the extra information. +For the openurl SSO method EXTRA has the form OPEN_URL:url +and an example is: + + client-sso-auth 17 "OPENURL:https://examples.com/do_web_auth" + +and client should ask to the user to open the URL to continue. + +For the OpenVPN server this is stateless operation and needs to be +followed by a client-deny/client-auth[-nt] command (that is the result of the +out of band authentication). + +The other implemented method is challenge/response (crtext). This uses +the same format as the user and password bases challenge respsonse with +AUTH_FAILED but omits the session id and username. + + client-sso-auth 18 "CR_TEXT::" + +For exmaple: + + client-sso-auth 18 "CR_TEXT:R,E:Please enter token PIN" + +The client should present the user the challenge and follow up +with cr-response command. + +See the section >CLIENT,CR_RESPONSE for the client response. + +A client should announce its support for these methods with +the IV_SSO variable seperated by comma. E.g., in the configuration file + + setenv IV_SSO openurl,crtext + +A server should check wether these methods are supported by +examining IV_SSO and otherwise fall back to classic challenge +response protocol or sending a AUTH_FAILED message that points +out missing client support. + COMMAND -- client-deny (OpenVPN 2.1 or higher) ----------------------------------------------- diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c index 8ec90bb1..ffd48445 100644 --- a/src/openvpn/manage.c +++ b/src/openvpn/manage.c @@ -105,6 +105,8 @@ man_help(void) msg(M_CLIENT, "client-auth-nt CID KID : Authenticate client-id/key-id CID/KID"); msg(M_CLIENT, "client-deny CID KID R [CR] : Deny auth client-id/key-id CID/KID with log reason"); msg(M_CLIENT, " text R and optional client reason text CR"); + msg(M_CLIENT, "client-sso-auth CID MSG : Instruct OpenVPN to send AUTH_PENDING and INFO_PRE msg" + " to the client and wait for a final client-auth/client-deny"); msg(M_CLIENT, "client-kill CID [M] : Kill client instance CID with message M (def=RESTART)"); msg(M_CLIENT, "env-filter [level] : Set env-var filter level"); #ifdef MANAGEMENT_PF @@ -1000,6 +1002,33 @@ parse_kid(const char *str, unsigned int *kid) return false; } } +static void +man_client_sso_auth(struct management *man, const char *cid_str, const char *extra) +{ + unsigned long cid = 0; + if (parse_cid(cid_str, &cid)) + { + if (man->persist.callback.client_sso) + { + bool ret = (*man->persist.callback.client_sso) + (man->persist.callback.arg, cid, extra); + + if (ret) + { + msg(M_CLIENT, "SUCCESS: client-sso-auth command succeeded"); + } + else + { + msg(M_CLIENT, "SUCCESS: client-sso-auth command failed." + " Extra paramter might be too long"); + } + } + else + { + msg(M_CLIENT, "ERROR: The client-deny command is not supported by the current daemon mode"); + } + } +} static void man_client_auth(struct management *man, const char *cid_str, const char *kid_str, const bool extra) @@ -1539,6 +1568,13 @@ man_dispatch_command(struct management *man, struct status_output *so, const cha man_client_auth(man, p[1], p[2], true); } } + else if (streq(p[0], "client-sso-auth")) + { + if (man_need(man, p, 2, 0)) + { + man_client_sso_auth(man, p[1], p[2]); + } + } #ifdef MANAGEMENT_PF else if (streq(p[0], "client-pf")) { diff --git a/src/openvpn/manage.h b/src/openvpn/manage.h index 6a749725..ff6b6737 100644 --- a/src/openvpn/manage.h +++ b/src/openvpn/manage.h @@ -174,6 +174,9 @@ struct management_callback const char *reason, const char *client_reason, struct buffer_list *cc_config); /* ownership transferred */ + bool (*client_sso) (void *arg, + const unsigned long cid, + const char *url); char *(*get_peer_info) (void *arg, const unsigned long cid); #endif #ifdef MANAGEMENT_PF diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c index d1f9c72e..03e03aff 100644 --- a/src/openvpn/multi.c +++ b/src/openvpn/multi.c @@ -3253,6 +3253,24 @@ management_kill_by_cid(void *arg, const unsigned long cid, const char *kill_msg) } } +static bool +management_client_sso(void *arg, + const unsigned long cid, + const char *extra) +{ + struct multi_context *m = (struct multi_context *) arg; + struct multi_instance *mi = lookup_by_cid(m, cid); + if (mi) + { + /* sends INFO_PRE and AUTH_PENDING messages to client */ + bool ret = send_sso_messages(&mi->context, extra); + multi_schedule_context_wakeup(m, mi); + return ret; + } + return false; +} + + static bool management_client_auth(void *arg, const unsigned long cid, @@ -3360,6 +3378,7 @@ init_management_callback_multi(struct multi_context *m) #ifdef MANAGEMENT_DEF_AUTH cb.kill_by_cid = management_kill_by_cid; cb.client_auth = management_client_auth; + cb.client_sso = management_client_sso; cb.get_peer_info = management_get_peer_info; #endif #ifdef MANAGEMENT_PF diff --git a/src/openvpn/push.c b/src/openvpn/push.c index 3b568b9b..0cec692c 100644 --- a/src/openvpn/push.c +++ b/src/openvpn/push.c @@ -287,6 +287,30 @@ send_auth_failed(struct context *c, const char *client_reason) gc_free(&gc); } +bool +send_sso_messages(struct context *c, const char* extra) +{ + send_control_channel_string(c, "AUTH_PENDING", D_PUSH); + + static const char info_pre[] = "INFO_PRE,"; + + + size_t len = strlen(extra)+1 + sizeof(info_pre); + if (len > PUSH_BUNDLE_SIZE) + { + return false; + } + struct gc_arena gc = gc_new(); + + struct buffer buf = alloc_buf_gc(len, &gc); + buf_printf(&buf, info_pre); + buf_printf(&buf, "%s", extra); + send_control_channel_string(c, BSTR(&buf), D_PUSH); + + gc_free(&gc); + return true; +} + /* * Send restart message from server to client. */ diff --git a/src/openvpn/push.h b/src/openvpn/push.h index 3f5079f3..a15aa58c 100644 --- a/src/openvpn/push.h +++ b/src/openvpn/push.h @@ -72,6 +72,8 @@ void remove_iroutes_from_push_route_list(struct options *o); void send_auth_failed(struct context *c, const char *client_reason); +bool send_sso_messages(struct context *c, const char *url); + void send_restart(struct context *c, const char *kill_msg); #endif