Commit fd08a0dc authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

Merge branch 'work/authtsig'

parents 46629b17 d3da4f1f
......@@ -686,6 +686,7 @@ AC_CONFIG_FILES([Makefile
src/bin/bindctl/tests/Makefile
src/bin/cfgmgr/Makefile
src/bin/cfgmgr/plugins/Makefile
src/bin/cfgmgr/plugins/tests/Makefile
src/bin/cfgmgr/tests/Makefile
src/bin/host/Makefile
src/bin/loadzone/Makefile
......
......@@ -18,6 +18,7 @@
import sys; sys.path.append ('@@PYTHONPATH@@')
from isc.config.cfgmgr import ConfigManager, ConfigManagerDataReadError
import bind10_config
from isc.cc import SessionError
import isc.util.process
import signal
......@@ -28,24 +29,10 @@ import os.path
isc.util.process.rename()
# If B10_FROM_SOURCE is set in the environment, we use data files
# from a directory relative to the value of that variable, or, if defined,
# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR. Otherwise
# we use the ones installed on the system.
# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
# tests where we want to use variuos types of configuration within the test
# environment. (We may want to make it even more generic so that the path is
# passed from the boss process)
if "B10_FROM_SOURCE" in os.environ:
if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
else:
DATA_PATH = os.environ["B10_FROM_SOURCE"]
PLUGIN_PATHS = [DATA_PATH + '/src/bin/cfgmgr/plugins']
else:
PREFIX = "@prefix@"
DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"]
# Import some paths from our configuration
DATA_PATH = bind10_config.DATA_PATH
PLUGIN_PATHS = bind10_config.PLUGIN_PATHS
PREFIX = bind10_config.PREFIX
DEFAULT_CONFIG_FILE = "b10-config.db"
cm = None
......
EXTRA_DIST = README
SUBDIRS = tests
EXTRA_DIST = README tsig_keys.py tsig_keys.spec
config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
config_plugin_DATA = tsig_keys.py tsig_keys.spec
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
PYTESTS = tsig_keys_test.py
EXTRA_DIST = $(PYTESTS)
# test using command-line arguments, so use check-local target instead of TESTS
check-local:
if ENABLE_PYTHON_COVERAGE
touch $(abs_top_srcdir)/.coverage
rm -f .coverage
${LN_S} $(abs_top_srcdir)/.coverage .coverage
endif
for pytest in $(PYTESTS) ; do \
echo Running test: $$pytest ; \
env B10_TEST_PLUGIN_DIR=$(abs_srcdir)/..:$(abs_builddir)/.. \
env PYTHONPATH=$(abs_top_srcdir)/src/lib/python:$(abs_top_builddir)/src/lib/python:$(abs_top_builddir)/src/bin/cfgmgr:$(abs_top_builddir)/src/lib/dns/python/.libs \
$(PYCOVERAGE_RUN) $(abs_srcdir)/$$pytest || exit ; \
done
# Copyright (C) 2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# Make sure we can load the module, put it into path
import sys
import os
sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
import tsig_keys
import unittest
import isc.config.module_spec
class TSigKeysTest(unittest.TestCase):
def test_load(self):
"""
Checks the entry point returns the correct values.
"""
(spec, check) = tsig_keys.load()
# It returns the checking function
self.assertEqual(check, tsig_keys.check)
# The plugin stores it's spec
self.assertEqual(spec, tsig_keys.spec)
def test_spec(self):
"""
Checks the spec is looking sane (doesn't do really deep check here).
"""
spec = tsig_keys.spec
# In python, we don't generally check the type of something, because
# of the duck typing.
# But this is unittest, so we check it does what we intend and
# supplying that's behaving the same but is different is not our
# intention
self.assertTrue(isinstance(spec, isc.config.module_spec.ModuleSpec))
# Correct name
self.assertEqual("tsig_keys", spec.get_module_name())
# There are no commands, nobody would handle them anyway
self.assertEqual([], spec.get_commands_spec())
# There's some nonempty configuration
self.assertNotEqual({}, spec.get_config_spec())
def test_missing_keys(self):
"""
Test that missing keys doesn't kill us. There are just no keys there.
"""
self.assertEqual(None, tsig_keys.check({}))
def test_data_empty(self):
"""Check we accept valid config with empty set of tsig keys."""
self.assertEqual(None, tsig_keys.check({'keys': []}))
def test_keys_valid(self):
"""
Check we accept some valid keys (we don't check all the algorithms,
that's the job of isc.dns.TSIGKey).
"""
self.assertEqual(None, tsig_keys.check({'keys':
['testkey:QklORCAxMCBpcyBjb29sCg==',
'test.key:QklORCAxMCBpcyBjb29sCg==:hmac-sha1']}))
def test_keys_same_name(self):
"""
Test we reject when we have multiple keys with the same name.
"""
self.assertEqual("Multiple TSIG keys with name 'test.key.'",
tsig_keys.check({'keys':
['test.key:QklORCAxMCBpcyBjb29sCg==',
'test.key:b3RoZXIK']}))
def test_invalid_key(self):
"""
Test we reject invalid key.
"""
self.assertEqual("TSIG: Invalid TSIG key string: invalid.key",
tsig_keys.check({'keys': ['invalid.key']}))
self.assertEqual(
"TSIG: attempt to decode a value not in base64 char set",
tsig_keys.check({'keys': ['invalid.key:123']}))
def test_bad_format(self):
"""
Test we fail on bad format. We don't really care much how here, though,
as this should not get in trough config manager anyway.
"""
self.assertNotEqual(None, tsig_keys.check({'bad_name': {}}))
self.assertNotEqual(None, tsig_keys.check({'keys': 'not_list'}))
self.assertNotEqual(None, tsig_keys.check({'keys': 42}))
self.assertNotEqual(None, tsig_keys.check({'keys': {}}))
if __name__ == '__main__':
unittest.main()
# Copyright (C) 2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# This is the plugin for tsig_keys configuration section. The TSIG keyring
# lives there (eg. all the shared secrets, with some exceptions where there
# are some TSIG keys elsewhere, but these should be removed soon). We do
# sanity checking of user configuration here, simply by trying to construct
# all the keys here.
from isc.config.module_spec import module_spec_from_file
from isc.util.file import path_search
from pydnspp import TSIGKey, InvalidParameter
from bind10_config import PLUGIN_PATHS
spec = module_spec_from_file(path_search('tsig_keys.spec', PLUGIN_PATHS))
def check(config):
# Check the data layout first
errors=[]
if not spec.validate_config(False, config, errors):
return ' '.join(errors)
# Get the list of keys, if any
keys = config.get('keys', [])
# Run through them, check they can be constructed and there are no
# duplicates
keyNames = set()
for key in keys:
try:
name = str(TSIGKey(key).get_key_name())
except InvalidParameter as e:
return "TSIG: " + str(e)
if name in keyNames:
return "Multiple TSIG keys with name '" + name + "'"
keyNames.add(name)
# No error found, so let's assume it's OK
return None
def load():
return (spec, check)
{
"module_spec": {
"module_name": "tsig_keys",
"module_description": "The TSIG keyring is stored here",
"config_data": [
{
"item_name": "keys",
"item_type": "list",
"item_optional": false,
"item_default": [],
"list_item_spec": {
"item_name": "key",
"item_type": "string",
"item_optional": false,
"item_default": ""
}
}
],
"commands": []
}
}
......@@ -20,6 +20,7 @@
import unittest
import os
import sys
import bind10_config
from isc.testutils.parse_args import OptsError, TestOptParser
class MyConfigManager:
......@@ -110,6 +111,7 @@ class TestConfigManagerStartup(unittest.TestCase):
env_var = os.environ["B10_FROM_SOURCE"]
os.environ["B10_FROM_SOURCE"] = tmp_env_var
bind10_config.reload()
b = __import__("b10-cfgmgr", globals(), locals())
b.PLUGIN_PATH = [] # It's enough to test plugins in one test
b.ConfigManager = MyConfigManager
......@@ -117,6 +119,7 @@ class TestConfigManagerStartup(unittest.TestCase):
if env_var != None:
os.environ["B10_FROM_SOURCE"] = env_var
bind10_config.reload()
sys.modules.pop("b10-cfgmgr")
......
......@@ -17,7 +17,37 @@
# variables to python scripts and libraries.
import os
BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
"@PACKAGE_NAME@",
"msgq_socket").replace("${prefix}",
"@prefix@")
def reload():
# In a function, for testing purposes
global BIND10_MSGQ_SOCKET_FILE
global DATA_PATH
global PLUGIN_PATHS
global PREFIX
BIND10_MSGQ_SOCKET_FILE = os.path.join("@localstatedir@",
"@PACKAGE_NAME@",
"msgq_socket").replace("${prefix}",
"@prefix@")
# If B10_FROM_SOURCE is set in the environment, we use data files
# from a directory relative to the value of that variable, or, if defined,
# relative to the value of B10_FROM_SOURCE_LOCALSTATEDIR. Otherwise
# we use the ones installed on the system.
# B10_FROM_SOURCE_LOCALSTATEDIR is specifically intended to be used for
# tests where we want to use variuos types of configuration within the test
# environment. (We may want to make it even more generic so that the path is
# passed from the boss process)
if "B10_FROM_SOURCE" in os.environ:
if "B10_FROM_SOURCE_LOCALSTATEDIR" in os.environ:
DATA_PATH = os.environ["B10_FROM_SOURCE_LOCALSTATEDIR"]
else:
DATA_PATH = os.environ["B10_FROM_SOURCE"]
PLUGIN_PATHS = [DATA_PATH + '/src/bin/cfgmgr/plugins']
else:
PREFIX = "@prefix@"
DATA_PATH = "@localstatedir@/@PACKAGE@".replace("${prefix}", PREFIX)
PLUGIN_PATHS = ["@prefix@/share/@PACKAGE@/config_plugins"]
# For testing the plugins so they can find their own spec files
if "B10_TEST_PLUGIN_DIR" in os.environ:
PLUGIN_PATHS = os.environ["B10_TEST_PLUGIN_DIR"].split(':')
reload()
SUBDIRS = . tests
python_PYTHON = __init__.py process.py socketserver_mixin.py
python_PYTHON = __init__.py process.py socketserver_mixin.py file.py
pythondir = $(pyexecdir)/isc/util
# Copyright (C) 2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
"""Various functions for working with files and directories."""
from os.path import exists, join
def path_search(filename, paths):
"""
Searches list of paths to find filename in one of them. The found one will
be returned or IOError will be returned if it isn't found.
"""
for p in paths:
f = join(p, filename)
if exists(f):
return f
raise IOError("'" + filename + "' not found in " + str(paths))
PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
PYTESTS = process_test.py socketserver_mixin_test.py
PYTESTS = process_test.py socketserver_mixin_test.py file_test.py
EXTRA_DIST = $(PYTESTS)
# test using command-line arguments, so use check-local target instead of TESTS
......
# Copyright (C) 2011 Internet Systems Consortium.
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
# INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
# FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
import isc.util.file
import unittest
class FileTest(unittest.TestCase):
def test_search_path_find(self):
"""Test it returns the first occurence of the file"""
self.assertEqual('./Makefile',
isc.util.file.path_search('Makefile',
['/no/such/directory/', '.',
'../tests/']))
def test_search_path_notfound(self):
"""Test it throws an exception when the file can't be found"""
self.assertRaises(IOError, isc.util.file.path_search, 'no file', ['/no/such/directory'])
if __name__ == "__main__":
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment