summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViacheslav Hletenko <v.gletenko@vyos.io>2026-01-05 17:20:02 +0200
committerGitHub <noreply@github.com>2026-01-05 17:20:02 +0200
commit06945f0a7079b72ab3844bec77288aea208ac266 (patch)
tree2271fa220bfe6c90f7320ffdbc0d6bf8ebcf42af
parent2e9c1ffd20a8149842a71acae062a8f0822f95dc (diff)
parent381ae4a8ccddb524bca5951e27cc826eeef45453 (diff)
downloadvyos-1x-06945f0a7079b72ab3844bec77288aea208ac266.tar.gz
vyos-1x-06945f0a7079b72ab3844bec77288aea208ac266.zip
Merge pull request #4618 from giga1699/T7635
T7635: OpenConnect Certificate Authentication
-rw-r--r--data/templates/ocserv/ocserv_config.j29
-rw-r--r--interface-definitions/vpn_openconnect.xml.in31
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py15
3 files changed, 52 insertions, 3 deletions
diff --git a/data/templates/ocserv/ocserv_config.j2 b/data/templates/ocserv/ocserv_config.j2
index 81f777031..76d3e6e4e 100644
--- a/data/templates/ocserv/ocserv_config.j2
+++ b/data/templates/ocserv/ocserv_config.j2
@@ -30,6 +30,15 @@ auth = "plain[otp=/run/ocserv/users.oath]"
{% else %}
auth = "plain[/run/ocserv/ocpasswd]"
{% endif %}
+{% elif "certificate" in authentication.mode %}
+auth = "certificate"
+{% if authentication.mode.certificate.user_identifier_field == "cn" %}
+cert-user-oid = 2.5.4.3
+{% elif authentication.mode.certificate.user_identifier_field == "uid" %}
+cert-user-oid = 0.9.2342.19200300.100.1.1
+{% else %}
+cert-user-oid = {{ authentication.mode.certificate.user_identifier_field }}
+{% endif %}
{% else %}
auth = "plain[/run/ocserv/ocpasswd]"
{% endif %}
diff --git a/interface-definitions/vpn_openconnect.xml.in b/interface-definitions/vpn_openconnect.xml.in
index a2f040b2f..13e5142fd 100644
--- a/interface-definitions/vpn_openconnect.xml.in
+++ b/interface-definitions/vpn_openconnect.xml.in
@@ -69,6 +69,37 @@
<valueless/>
</properties>
</leafNode>
+ <node name="certificate">
+ <properties>
+ <help>Use certificate-based authentication</help>
+ </properties>
+ <children>
+ <leafNode name="user-identifier-field">
+ <properties>
+ <help>Certificate field to identify users by</help>
+ <valueHelp>
+ <format>cn</format>
+ <description>OID 2.5.4.3 - Common Name</description>
+ </valueHelp>
+ <valueHelp>
+ <format>uid</format>
+ <description>OID 0.9.2342.19200300.100.1.1 - UID</description>
+ </valueHelp>
+ <valueHelp>
+ <format>x.x.xx.xxx</format>
+ <description>Custom OID in dotted decimal format</description>
+ </valueHelp>
+ <constraint>
+ <regex>(^\d{1,5}(?:\.\d{1,5})*$|cn|uid)</regex>
+ </constraint>
+ <constraintErrorMessage>Invalid OID selection. Must be cn, uid, or a valid OID format.</constraintErrorMessage>
+ <completionHelp>
+ <list>cn uid x.x.xx.xxx</list>
+ </completionHelp>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
</children>
</node>
<node name="identity-based-config">
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 68cd363f0..bfc1d5269 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -105,11 +105,17 @@ def verify(ocserv):
if 'authentication' in ocserv:
if 'mode' in ocserv['authentication']:
if (
- 'local' in ocserv['authentication']['mode']
- and 'radius' in ocserv['authentication']['mode']
+ ('local' in ocserv['authentication']['mode']
+ and 'radius' in ocserv['authentication']['mode'])
+ or
+ ('local' in ocserv['authentication']['mode']
+ and 'certificate' in ocserv['authentication']['mode'])
+ or
+ ('radius' in ocserv['authentication']['mode']
+ and 'certificate' in ocserv['authentication']['mode'])
):
raise ConfigError(
- 'OpenConnect authentication modes are mutually-exclusive, remove either local or radius from your configuration'
+ 'OpenConnect authentication modes are mutually-exclusive. Use only one of local, radius, or certificate.'
)
if 'radius' in ocserv['authentication']['mode']:
if 'server' not in ocserv['authentication']['radius']:
@@ -203,6 +209,9 @@ def verify(ocserv):
raise ConfigError('SSL certificate missing on OpenConnect config!')
verify_pki_certificate(ocserv, ocserv['ssl']['certificate'])
+ if 'ca_certificate' not in ocserv['ssl'] and 'certificiate' in ocserv['authentication']['mode']:
+ raise ConfigError('CA certificate must be provided in certificate authentication mode!')
+
if 'ca_certificate' in ocserv['ssl']:
for ca_cert in ocserv['ssl']['ca_certificate']:
verify_pki_ca_certificate(ocserv, ca_cert)