summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorgoodNETnick <33053932+goodNETnick@users.noreply.github.com>2022-04-01 12:09:56 +1000
committergoodNETnick <pknet@ya.ru>2022-04-09 01:33:25 -0400
commit1da9cc02d7c83898c267070618e2cc91e16eb1cf (patch)
treebfe672212ef22b525420428d3f36ff02d6cd5aa0 /src
parentaa5b35b68c1170bfd0b9661bafa72bb10fe6ca95 (diff)
parent53e20097d227ebf4bdb4dc6c85427ec9c5ec3982 (diff)
downloadvyos-1x-1da9cc02d7c83898c267070618e2cc91e16eb1cf.tar.gz
vyos-1x-1da9cc02d7c83898c267070618e2cc91e16eb1cf.zip
ocserv: T4231: Added OTP support for Openconnect 2FA
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py30
-rwxr-xr-xsrc/conf_mode/vrf.py8
-rwxr-xr-xsrc/migration-scripts/openconnect/1-to-214
-rw-r--r--src/tests/test_util.py15
4 files changed, 46 insertions, 21 deletions
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 8e100d9f9..84d31f9a5 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -24,6 +24,7 @@ from vyos.pki import wrap_private_key
from vyos.template import render
from vyos.util import call
from vyos.util import is_systemd_service_running
+from vyos.util import dict_search
from vyos.xml import defaults
from vyos import ConfigError
from crypt import crypt, mksalt, METHOD_SHA512
@@ -55,6 +56,16 @@ def get_config():
default_values = defaults(base)
ocserv = dict_merge(default_values, ocserv)
+ # workaround a "know limitation" - https://phabricator.vyos.net/T2665
+ del ocserv['authentication']['local_users']['username']['otp']
+ if not ocserv["authentication"]["local_users"]["username"]:
+ raise ConfigError('openconnect mode local required at least one user')
+ default_ocserv_usr_values = default_values['authentication']['local_users']['username']['otp']
+ for user, params in ocserv['authentication']['local_users']['username'].items():
+ # Not every configuration requires OTP settings
+ if ocserv['authentication']['local_users']['username'][user].get('otp'):
+ ocserv['authentication']['local_users']['username'][user]['otp'] = dict_merge(default_ocserv_usr_values, ocserv['authentication']['local_users']['username'][user]['otp'])
+
if ocserv:
ocserv['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
@@ -69,19 +80,18 @@ def verify(ocserv):
if "mode" in ocserv["authentication"]:
if "local" in ocserv["authentication"]["mode"]:
if "radius" in ocserv["authentication"]["mode"]:
- raise ConfigError('openconnect supports only one authentication mode. Currently configured \'local\' and \'radius\' modes')
+ raise ConfigError('OpenConnect authentication modes are mutually-exclusive, remove either local or radius from your configuration')
if not ocserv["authentication"]["local_users"]:
- raise ConfigError('openconnect mode local required at leat one user')
+ raise ConfigError('openconnect mode local required at least one user')
if not ocserv["authentication"]["local_users"]["username"]:
- raise ConfigError('openconnect mode local required at leat one user')
+ raise ConfigError('openconnect mode local required at least one user')
else:
# For OTP mode: verify that each local user has an OTP key
if "otp" in ocserv["authentication"]["mode"]["local"]:
users_wo_key = []
- for user in ocserv["authentication"]["local_users"]["username"]:
- if not ocserv["authentication"]["local_users"]["username"][user].get("otp"):
- users_wo_key.append(user)
- elif not ocserv["authentication"]["local_users"]["username"][user]["otp"].get("key"):
+ for user, user_config in ocserv["authentication"]["local_users"]["username"].items():
+ # User has no OTP key defined
+ if dict_search('otp.key', user_config) == None:
users_wo_key.append(user)
if users_wo_key:
raise ConfigError(f'OTP enabled, but no OTP key is configured for these users:\n{users_wo_key}')
@@ -156,9 +166,9 @@ def generate(ocserv):
if "local_users" in ocserv["authentication"]:
for user in ocserv["authentication"]["local_users"]["username"]:
# OTP token type from CLI parameters:
- otp_interval = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("interval", "30")
- token_type = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("token-type", "hotp-time")
- otp_length = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("otp-length", "6")
+ otp_interval = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("interval"))
+ token_type = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("token_type")
+ otp_length = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("otp_length"))
if token_type == "hotp-time":
otp_type = "HOTP/T" + otp_interval
elif token_type == "hotp-event":
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index 6a521a0dd..c3e2d8efd 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -30,6 +30,7 @@ from vyos.util import get_interface_config
from vyos.util import popen
from vyos.util import run
from vyos.util import sysctl_write
+from vyos.util import is_ipv6_enabled
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -215,10 +216,11 @@ def apply(vrf):
# set VRF description for e.g. SNMP monitoring
vrf_if = Interface(name)
- # We also should add proper loopback IP addresses to the newly
- # created VRFs for services bound to the loopback address (SNMP, NTP)
+ # We also should add proper loopback IP addresses to the newly added
+ # VRF for services bound to the loopback address (SNMP, NTP)
vrf_if.add_addr('127.0.0.1/8')
- vrf_if.add_addr('::1/128')
+ if is_ipv6_enabled():
+ vrf_if.add_addr('::1/128')
# add VRF description if available
vrf_if.set_alias(config.get('description', ''))
diff --git a/src/migration-scripts/openconnect/1-to-2 b/src/migration-scripts/openconnect/1-to-2
index 36d807a3c..7031fb252 100755
--- a/src/migration-scripts/openconnect/1-to-2
+++ b/src/migration-scripts/openconnect/1-to-2
@@ -37,15 +37,15 @@ if not config.exists(cfg_base):
# Nothing to do
sys.exit(0)
else:
- if config.exists(cfg_base + ['authentication'] + ['mode']):
- if config.return_value(cfg_base + ['authentication'] + ['mode']) == 'radius':
+ if config.exists(cfg_base + ['authentication', 'mode']):
+ if config.return_value(cfg_base + ['authentication', 'mode']) == 'radius':
# if "mode value radius", change to "tag node mode + valueless node radius"
- config.delete(cfg_base + ['authentication'] + ['mode'] + ['radius'])
- config.set(cfg_base + ['authentication'] + ['mode'] + ['radius'], value=None, replace=True)
- elif not config.exists(cfg_base + ['authentication'] + ['mode'] + ['local']):
+ config.delete(cfg_base + ['authentication','mode', 'radius'])
+ config.set(cfg_base + ['authentication', 'mode', 'radius'], value=None, replace=True)
+ elif not config.exists(cfg_base + ['authentication', 'mode', 'local']):
# if "mode local", change to "tag node mode + node local value password"
- config.delete(cfg_base + ['authentication'] + ['mode'] + ['local'])
- config.set(cfg_base + ['authentication'] + ['mode'] + ['local'], value='password', replace=True)
+ config.delete(cfg_base + ['authentication', 'mode', 'local'])
+ config.set(cfg_base + ['authentication', 'mode', 'local'], value='password', replace=True)
try:
with open(file_name, 'w') as f:
f.write(config.to_string())
diff --git a/src/tests/test_util.py b/src/tests/test_util.py
index 9bd27adc0..91890262c 100644
--- a/src/tests/test_util.py
+++ b/src/tests/test_util.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# Copyright (C) 2020-2022 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -23,3 +23,16 @@ class TestVyOSUtil(TestCase):
expected_data = {"foo_bar": {"baz_quux": None}}
new_data = mangle_dict_keys(data, '-', '_')
self.assertEqual(new_data, expected_data)
+
+ def test_sysctl_read(self):
+ self.assertEqual(sysctl_read('net.ipv4.conf.lo.forwarding'), '1')
+
+ def test_ipv6_enabled(self):
+ tmp = sysctl_read('net.ipv6.conf.all.disable_ipv6')
+ # We need to test for both variants as this depends on how the
+ # Docker container is started (with or without IPv6 support) - so we
+ # will simply check both cases to not make the users life miserable.
+ if tmp == '0':
+ self.assertTrue(is_ipv6_enabled())
+ else:
+ self.assertFalse(is_ipv6_enabled())