summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--interface-definitions/include/pki/ca-certificate.xml.i8
-rw-r--r--interface-definitions/include/pki/certificate.xml.i8
-rw-r--r--interface-definitions/include/pki/private-key.xml.i8
-rw-r--r--interface-definitions/include/pki/public-key.xml.i8
-rw-r--r--python/vyos/util.py31
-rwxr-xr-xsrc/conf_mode/pki.py46
-rw-r--r--src/tests/test_dict_search.py21
7 files changed, 101 insertions, 29 deletions
diff --git a/interface-definitions/include/pki/ca-certificate.xml.i b/interface-definitions/include/pki/ca-certificate.xml.i
index 14295a281..b32bb676a 100644
--- a/interface-definitions/include/pki/ca-certificate.xml.i
+++ b/interface-definitions/include/pki/ca-certificate.xml.i
@@ -2,13 +2,13 @@
<leafNode name="ca-certificate">
<properties>
<help>Certificate Authority in PKI configuration</help>
- <valueHelp>
- <format>CA name</format>
- <description>Name of CA in PKI configuration</description>
- </valueHelp>
<completionHelp>
<path>pki ca</path>
</completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of CA in PKI configuration</description>
+ </valueHelp>
</properties>
</leafNode>
<!-- include end -->
diff --git a/interface-definitions/include/pki/certificate.xml.i b/interface-definitions/include/pki/certificate.xml.i
index 436aa90ba..1ba70e058 100644
--- a/interface-definitions/include/pki/certificate.xml.i
+++ b/interface-definitions/include/pki/certificate.xml.i
@@ -2,13 +2,13 @@
<leafNode name="certificate">
<properties>
<help>Certificate in PKI configuration</help>
- <valueHelp>
- <format>cert name</format>
- <description>Name of certificate in PKI configuration</description>
- </valueHelp>
<completionHelp>
<path>pki certificate</path>
</completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of certificate in PKI configuration</description>
+ </valueHelp>
</properties>
</leafNode>
<!-- include end -->
diff --git a/interface-definitions/include/pki/private-key.xml.i b/interface-definitions/include/pki/private-key.xml.i
index 6099daa89..ae4e9103e 100644
--- a/interface-definitions/include/pki/private-key.xml.i
+++ b/interface-definitions/include/pki/private-key.xml.i
@@ -7,13 +7,13 @@
<leafNode name="key">
<properties>
<help>Private key in PKI configuration</help>
- <valueHelp>
- <format>key name</format>
- <description>Name of private key in PKI configuration</description>
- </valueHelp>
<completionHelp>
<path>pki key-pair</path>
</completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of private key in PKI configuration</description>
+ </valueHelp>
</properties>
</leafNode>
<leafNode name="passphrase">
diff --git a/interface-definitions/include/pki/public-key.xml.i b/interface-definitions/include/pki/public-key.xml.i
index dfc6979fd..3067bff74 100644
--- a/interface-definitions/include/pki/public-key.xml.i
+++ b/interface-definitions/include/pki/public-key.xml.i
@@ -2,13 +2,13 @@
<leafNode name="public-key">
<properties>
<help>Public key in PKI configuration</help>
- <valueHelp>
- <format>key name</format>
- <description>Name of public key in PKI configuration</description>
- </valueHelp>
<completionHelp>
<path>pki key-pair</path>
</completionHelp>
+ <valueHelp>
+ <format>txt</format>
+ <description>Name of public key in PKI configuration</description>
+ </valueHelp>
</properties>
</leafNode>
<!-- include end -->
diff --git a/python/vyos/util.py b/python/vyos/util.py
index 93a2f6640..b41c5b346 100644
--- a/python/vyos/util.py
+++ b/python/vyos/util.py
@@ -692,21 +692,21 @@ def find_device_file(device):
return None
-def dict_search(path, my_dict):
- """ Traverse Python dictionary (my_dict) delimited by dot (.).
+def dict_search(path, dict_object):
+ """ Traverse Python dictionary (dict_object) delimited by dot (.).
Return value of key if found, None otherwise.
- This is faster implementation then jmespath.search('foo.bar', my_dict)"""
- if not isinstance(my_dict, dict) or not path:
+ This is faster implementation then jmespath.search('foo.bar', dict_object)"""
+ if not isinstance(dict_object, dict) or not path:
return None
parts = path.split('.')
inside = parts[:-1]
if not inside:
- if path not in my_dict:
+ if path not in dict_object:
return None
- return my_dict[path]
- c = my_dict
+ return dict_object[path]
+ c = dict_object
for p in parts[:-1]:
c = c.get(p, {})
return c.get(parts[-1], None)
@@ -724,6 +724,23 @@ def dict_search_args(dict_object, *path):
dict_object = dict_object[item]
return dict_object
+def dict_search_recursive(dict_object, key):
+ """ Traverse a dictionary recurisvely and return the value of the key
+ we are looking for.
+
+ Thankfully copied from https://stackoverflow.com/a/19871956
+ """
+ if isinstance(dict_object, list):
+ for i in dict_object:
+ for x in dict_search_recursive(i, key):
+ yield x
+ elif isinstance(dict_object, dict):
+ if key in dict_object:
+ yield dict_object[key]
+ for j in dict_object.values():
+ for x in dict_search_recursive(j, key):
+ yield x
+
def get_interface_config(interface):
""" Returns the used encapsulation protocol for given interface.
If interface does not exist, None is returned.
diff --git a/src/conf_mode/pki.py b/src/conf_mode/pki.py
index ef1b57650..efa3578b4 100755
--- a/src/conf_mode/pki.py
+++ b/src/conf_mode/pki.py
@@ -16,8 +16,11 @@
from sys import exit
+import jmespath
+
from vyos.config import Config
from vyos.configdict import dict_merge
+from vyos.configdict import node_changed
from vyos.pki import is_ca_certificate
from vyos.pki import load_certificate
from vyos.pki import load_certificate_request
@@ -26,6 +29,7 @@ from vyos.pki import load_private_key
from vyos.pki import load_crl
from vyos.pki import load_dh_parameters
from vyos.util import ask_input
+from vyos.util import dict_search_recursive
from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -37,14 +41,29 @@ def get_config(config=None):
else:
conf = Config()
base = ['pki']
- if not conf.exists(base):
- return None
pki = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
+ get_first_key=True,
+ no_tag_node_value_mangle=True)
+
+ pki['changed'] = {}
+ tmp = node_changed(conf, base + ['ca'], key_mangling=('-', '_'))
+ if tmp: pki['changed'].update({'ca' : tmp})
+
+ tmp = node_changed(conf, base + ['certificate'], key_mangling=('-', '_'))
+ if tmp: pki['changed'].update({'certificate' : tmp})
+
+ # We only merge on the defaults of there is a configuration at all
+ if conf.exists(base):
+ default_values = defaults(base)
+ pki = dict_merge(default_values, pki)
+
+ # We need to get the entire system configuration to verify that we are not
+ # deleting a certificate that is still referenced somewhere!
+ pki['system'] = conf.get_config_dict([], key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True)
- default_values = defaults(base)
- pki = dict_merge(default_values, pki)
return pki
def is_valid_certificate(raw_data):
@@ -142,6 +161,21 @@ def verify(pki):
if len(country) != 2 or not country.isalpha():
raise ConfigError(f'Invalid default country value. Value must be 2 alpha characters.')
+ if 'changed' in pki:
+ # if the list is getting longer, we can move to a dict() and also embed the
+ # search key as value from line 173 or 176
+ for cert_type in ['ca', 'certificate']:
+ if not cert_type in pki['changed']:
+ continue
+ for certificate in pki['changed'][cert_type]:
+ if cert_type not in pki or certificate not in pki['changed'][cert_type]:
+ if cert_type == 'ca':
+ if certificate in dict_search_recursive(pki['system'], 'ca_certificate'):
+ raise ConfigError(f'CA certificate "{certificate}" is still in use!')
+ elif cert_type == 'certificate':
+ if certificate in dict_search_recursive(pki['system'], 'certificate'):
+ raise ConfigError(f'Certificate "{certificate}" is still in use!')
+
return None
def generate(pki):
@@ -154,6 +188,8 @@ def apply(pki):
if not pki:
return None
+ # XXX: restart services if the content of a certificate changes
+
return None
if __name__ == '__main__':
diff --git a/src/tests/test_dict_search.py b/src/tests/test_dict_search.py
index 991722f0f..1028437b2 100644
--- a/src/tests/test_dict_search.py
+++ b/src/tests/test_dict_search.py
@@ -16,13 +16,25 @@
from unittest import TestCase
from vyos.util import dict_search
+from vyos.util import dict_search_recursive
data = {
'string': 'fooo',
'nested': {'string': 'bar', 'empty': '', 'list': ['foo', 'bar']},
'non': {},
'list': ['bar', 'baz'],
- 'dict': {'key_1': {}, 'key_2': 'vyos'}
+ 'dict': {'key_1': {}, 'key_2': 'vyos'},
+ 'interfaces': {'dummy': {'dum0': {'address': ['192.0.2.17/29']}},
+ 'ethernet': {'eth0': {'address': ['2001:db8::1/64', '192.0.2.1/29'],
+ 'description': 'Test123',
+ 'duplex': 'auto',
+ 'hw_id': '00:00:00:00:00:01',
+ 'speed': 'auto'},
+ 'eth1': {'address': ['192.0.2.9/29'],
+ 'description': 'Test456',
+ 'duplex': 'auto',
+ 'hw_id': '00:00:00:00:00:02',
+ 'speed': 'auto'}}}
}
class TestDictSearch(TestCase):
@@ -63,3 +75,10 @@ class TestDictSearch(TestCase):
# TestDictSearch: Return list items when querying nested list
self.assertEqual(dict_search('nested.list', None), None)
self.assertEqual(dict_search(None, data), None)
+
+ def test_dict_search_recursive(self):
+ # Test nested search in dictionary
+ tmp = list(dict_search_recursive(data, 'hw_id'))
+ self.assertEqual(len(tmp), 2)
+ tmp = list(dict_search_recursive(data, 'address'))
+ self.assertEqual(len(tmp), 3)