From 667db40da4db362d7ca0a1f7f1c4ba40fb71795a Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 30 May 2011 09:57:19 +0200 Subject: Provide python bindings for the HBAC evaluator library --- src/tests/pyhbac-test.py | 468 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 468 insertions(+) create mode 100755 src/tests/pyhbac-test.py (limited to 'src/tests/pyhbac-test.py') diff --git a/src/tests/pyhbac-test.py b/src/tests/pyhbac-test.py new file mode 100755 index 00000000..fdf4ac32 --- /dev/null +++ b/src/tests/pyhbac-test.py @@ -0,0 +1,468 @@ +#!/usr/bin/python + +import unittest +import sys +import os +import copy + +srcdir = os.getenv('builddir') +if not srcdir: + srcdir = "." +MODPATH = srcdir + "/.libs" #FIXME - is there a way to get this from libtool? + +def compat_assertItemsEqual(this, expected_seq, actual_seq, msg=None): + return self.assertEqual(sorted(expected_seq), sorted(actual_seq)) + +def compat_assertIsInstance(this, obj, cls, msg=None): + return self.assertTrue(isinstance(obj, cls)) + +# add compat methods for old unittest.TestCase versions +# (python < 2.7, RHEL5 for instance) +if not hasattr(unittest.TestCase, "assertItemsEqual"): + setattr(unittest.TestCase, "assertItemsEqual", compat_assertItemsEqual) +if not hasattr(unittest.TestCase, "assertIsInstance"): + setattr(unittest.TestCase, "assertIsInstance", compat_assertIsInstance) + +class PyHbacImport(unittest.TestCase): + def setUp(self): + " Make sure we load the in-tree module " + self.system_path = sys.path[:] + sys.path = [ MODPATH ] + + def tearDown(self): + " Restore the system path " + sys.path = self.system_path + + def testImport(self): + " Import the module and assert it comes from tree " + try: + import pyhbac + except ImportError, e: + print >>sys.stderr, "Could not load the pyhbac module. Please check if it is compiled" + raise e + self.assertEqual(pyhbac.__file__, MODPATH + "/pyhbac.so") + +class PyHbacRuleElementTest(unittest.TestCase): + def testInstantiateEmpty(self): + el = pyhbac.HbacRuleElement() + self.assertItemsEqual(el.names, []) + self.assertItemsEqual(el.groups, []) + self.assertItemsEqual(el.category, set([pyhbac.HBAC_CATEGORY_NULL])) + + def testInit(self): + names = [ "foo", "bar" ] + el = pyhbac.HbacRuleElement(names=names) + self.assertItemsEqual(el.names, names) + + groups = [ "abc", "def" ] + el = pyhbac.HbacRuleElement(groups=groups) + self.assertItemsEqual(el.groups, groups) + + def testGetSet(self): + names = [ "foo", "bar" ] + el = pyhbac.HbacRuleElement() + self.assertItemsEqual(el.names, []) + el.names = names + self.assertItemsEqual(el.names, names) + + groups = [ "abc", "def" ] + el = pyhbac.HbacRuleElement() + self.assertItemsEqual(el.groups, []) + el.groups = groups + self.assertItemsEqual(el.groups, groups) + + # Test other iterables than list + groups = ( "abc", "def" ) + el = pyhbac.HbacRuleElement() + self.assertItemsEqual(el.groups, []) + el.groups = groups + self.assertItemsEqual(el.groups, groups) + + def testCategory(self): + el = pyhbac.HbacRuleElement() + assert pyhbac.HBAC_CATEGORY_NULL in el.category + assert pyhbac.HBAC_CATEGORY_ALL not in el.category + + el.category.add(pyhbac.HBAC_CATEGORY_ALL) + assert pyhbac.HBAC_CATEGORY_ALL in el.category + + el.category = set([pyhbac.HBAC_CATEGORY_ALL]) + assert pyhbac.HBAC_CATEGORY_ALL in el.category + + # negative tests + self.assertRaises(TypeError, el.__setattr__, "category", [pyhbac.HBAC_CATEGORY_ALL]) + self.assertRaises(TypeError, el.__setattr__, "category", None) + self.assertRaises(TypeError, el.__setattr__, "category", 1) + + def testNotIterable(self): + self.assertRaises(TypeError, pyhbac.HbacRuleElement, names=123) + self.assertRaises(TypeError, pyhbac.HbacRuleElement, names=None) + + def testRuleElementReference(self): + def _get_rule(): + users = [ "foo", "bar" ] + user_groups = [ "abc", "def" ] + return pyhbac.HbacRuleElement(names=users, groups=user_groups) + + el = _get_rule() + self.assertItemsEqual(el.names, [ "foo", "bar" ]) + self.assertItemsEqual(el.groups, [ "abc", "def" ]) + + def testRepr(self): + el = pyhbac.HbacRuleElement() + self.assertEquals(el.__repr__(), u'') + + el.category.add(pyhbac.HBAC_CATEGORY_ALL) + el.names = ['foo'] + el.groups = ['bar, baz'] + self.assertEquals(el.__repr__(), u'') + + +class PyHbacRuleTest(unittest.TestCase): + def testRuleGetSetName(self): + name = "testGetRule" + new_name = "testGetNewRule" + + rule = pyhbac.HbacRule(name) + self.assertEqual(rule.name, unicode(name)) + + rule.name = new_name + self.assertEqual(rule.name, unicode(new_name)) + + def testRuleGetSetEnabled(self): + rule = pyhbac.HbacRule("testRuleGetSetEnabled") + + rule.enabled = True + self.assertEqual(rule.enabled, True) + rule.enabled = False + self.assertEqual(rule.enabled, False) + + # negative test + self.assertRaises(TypeError, rule.__setattr__, "enabled", None) + + def testRuleElementInRule(self): + users = [ "foo", "bar" ] + user_groups = [ "abc", "def" ] + + # rule should contain empty elements after instantiation + rule = pyhbac.HbacRule("testRuleElement") + self.assertIsInstance(rule.users, pyhbac.HbacRuleElement) + self.assertIsInstance(rule.services, pyhbac.HbacRuleElement) + self.assertIsInstance(rule.targethosts, pyhbac.HbacRuleElement) + self.assertIsInstance(rule.srchosts, pyhbac.HbacRuleElement) + + self.assertIsInstance(rule.users.names, list) + self.assertIsInstance(rule.users.groups, list) + self.assertItemsEqual(rule.users.names, []) + self.assertItemsEqual(rule.users.groups, []) + + # Assign by copying a HbacRuleElement + user_el = pyhbac.HbacRuleElement(names=users, groups=user_groups) + rule = pyhbac.HbacRule("testRuleElement") + rule.users = user_el + self.assertItemsEqual(rule.users.names, users) + self.assertItemsEqual(rule.users.groups, user_groups) + + # Assign directly + rule = pyhbac.HbacRule("testRuleElement") + rule.users.names = users + rule.users.groups = user_groups + self.assertItemsEqual(rule.users.names, users) + self.assertItemsEqual(rule.users.groups, user_groups) + + def testRuleElementInRuleReference(self): + " Test that references to RuleElement are kept even if element goes out of scope " + def _get_rule(): + users = [ "foo", "bar" ] + user_groups = [ "abc", "def" ] + el = pyhbac.HbacRuleElement(names=users, groups=user_groups) + rule = pyhbac.HbacRule("testRuleElement") + rule.users = el + return rule + + rule = _get_rule() + self.assertItemsEqual(rule.users.names, [ "foo", "bar" ]) + self.assertItemsEqual(rule.users.groups, [ "abc", "def" ]) + + def testRepr(self): + r = pyhbac.HbacRule('foo') + self.assertEqual(r.__repr__(), u" " + "services " + "targethosts " + "srchosts >") + + name = "someuser" + service = "ssh" + srchost = "host1" + targethost = "host2" + + r.users.names = [ name ] + r.services.names = [ service ] + r.srchosts.names = [ srchost ] + r.targethosts.names = [ targethost ] + + self.assertEqual(r.__repr__(), u" " + "services " + "targethosts " + "srchosts >" % + (name, service, targethost, srchost)) + +class PyHbacRequestElementTest(unittest.TestCase): + def testInstantiateEmpty(self): + el = pyhbac.HbacRequestElement() + self.assertItemsEqual(el.name, "") + self.assertItemsEqual(el.groups, []) + + def testInit(self): + name = "foo" + el = pyhbac.HbacRequestElement(name=name) + self.assertItemsEqual(el.name, name) + + groups = [ "abc", "def" ] + el = pyhbac.HbacRequestElement(groups=groups) + self.assertItemsEqual(el.groups, groups) + + def testGetSet(self): + name = "foo" + el = pyhbac.HbacRequestElement() + self.assertItemsEqual(el.name, "") + el.name = name + self.assertItemsEqual(el.name, name) + + groups = [ "abc", "def" ] + el = pyhbac.HbacRequestElement() + self.assertItemsEqual(el.groups, []) + el.groups = groups + self.assertItemsEqual(el.groups, groups) + + # Test other iterables than list + groups = ( "abc", "def" ) + el = pyhbac.HbacRequestElement() + self.assertItemsEqual(el.groups, []) + el.groups = groups + self.assertItemsEqual(el.groups, groups) + + def testGroupsNotIterable(self): + self.assertRaises(TypeError, pyhbac.HbacRequestElement, groups=None) + self.assertRaises(TypeError, pyhbac.HbacRequestElement, groups=123) + + def testRepr(self): + r = pyhbac.HbacRequestElement() + self.assertEqual(r.__repr__(), u"") + + r.name = 'foo' + r.groups = ['bar', 'baz'] + self.assertEqual(r.__repr__(), u"") + +class PyHbacRequestTest(unittest.TestCase): + def testRequestElementHandling(self): + name = "req_name" + groups = [ "g1", "g2" ] + + # The request should be empty after instantiation + req = pyhbac.HbacRequest() + self.assertIsInstance(req.user, pyhbac.HbacRequestElement) + self.assertIsInstance(req.service, pyhbac.HbacRequestElement) + self.assertIsInstance(req.targethost, pyhbac.HbacRequestElement) + self.assertIsInstance(req.srchost, pyhbac.HbacRequestElement) + + self.assertEqual(req.user.name, "") + self.assertIsInstance(req.user.groups, list) + self.assertItemsEqual(req.user.groups, []) + + # Assign by copying a HbacRequestElement + user_el = pyhbac.HbacRequestElement(name=name, groups=groups) + req = pyhbac.HbacRequest() + req.user = user_el + self.assertItemsEqual(req.user.name, name) + self.assertItemsEqual(req.user.groups, groups) + + # Assign directly + req = pyhbac.HbacRequest() + req.user.name = name + req.user.groups = groups + self.assertItemsEqual(req.user.name, name) + self.assertItemsEqual(req.user.groups, groups) + + def testRuleName(self): + req = pyhbac.HbacRequest() + self.assertEqual(req.rule_name, None) + self.assertRaises(AttributeError, req.__setattr__, "rule_name", "foo") + + def testEvaluate(self): + name = "someuser" + service = "ssh" + srchost = "host1" + targethost = "host2" + + allow_rule = pyhbac.HbacRule("allowRule", enabled=True) + allow_rule.users.names = [ name ] + allow_rule.services.names = [ service ] + allow_rule.srchosts.names = [ srchost ] + allow_rule.targethosts.names = [ targethost ] + + req = pyhbac.HbacRequest() + req.user.name = name + req.service.name = service + req.srchost.name = srchost + req.targethost.name = targethost + + # Test that an allow rule on its own allows access + res = req.evaluate((allow_rule,)) + self.assertEqual(res, pyhbac.HBAC_EVAL_ALLOW) + self.assertEqual(req.rule_name, "allowRule") + + # Test that a user not in the rule is not allowed + savename = req.user.name + req.user.name = "someotheruser" + res = req.evaluate((allow_rule, )) + self.assertEqual(res, pyhbac.HBAC_EVAL_DENY) + self.assertEqual(req.rule_name, None) + + # But allows if the rule is an ALL rule + allow_rule.users.category.add(pyhbac.HBAC_CATEGORY_ALL) + res = req.evaluate((allow_rule, )) + self.assertEqual(res, pyhbac.HBAC_EVAL_ALLOW) + + def testRepr(self): + name = "someuser" + service = "ssh" + srchost = "host1" + targethost = "host2" + + req = pyhbac.HbacRequest() + + self.assertEqual(req.__repr__(), " " + "service " + "targethost " + "srchost >") + + req.user.name = name + req.service.name = service + req.srchost.name = srchost + req.targethost.name = targethost + + self.assertEqual(req.__repr__(), " " + "service " + "targethost " + "srchost >" % + (name, service, targethost, srchost)) + + def testEvaluateNegative(self): + name = "someuser" + service = "ssh" + srchost = "host1" + targethost = "host2" + + allow_rule = pyhbac.HbacRule("allowRule", enabled=True) + allow_rule.users.names = [ name ] + allow_rule.services.names = [ service ] + allow_rule.srchosts.names = [ srchost ] + allow_rule.targethosts.names = [ targethost ] + + req = pyhbac.HbacRequest() + req.service.name = service + req.srchost.name = srchost + req.targethost.name = targethost + req.user.name = name + + saveuser = req.user + req.user = None # need to catch this + + # catch invalid category value + savecat = copy.copy(allow_rule.users.category) + allow_rule.users.category.add(pyhbac.HBAC_EVAL_ERROR) + self.assertRaises(ValueError, req.evaluate, (allow_rule,)) + allow_rule.users.category = savecat + + # Test that invalid type is raised + self.assertRaises(TypeError, req.evaluate, (allow_rule,)) + + req.user = saveuser + allow_rule.users = None # need to catch this + self.assertRaises(TypeError, req.evaluate, (allow_rule,)) + + # catch invalid rule type + self.assertRaises(TypeError, req.evaluate, (allow_rule, None)) + +class PyHbacModuleTest(unittest.TestCase): + def testHasResultTypes(self): + assert hasattr(pyhbac, "HBAC_EVAL_ALLOW") + assert hasattr(pyhbac, "HBAC_EVAL_DENY") + assert hasattr(pyhbac, "HBAC_EVAL_ERROR") + + def testHasErrorTypes(self): + assert hasattr(pyhbac, "HBAC_ERROR_UNKNOWN") + assert hasattr(pyhbac, "HBAC_SUCCESS") + assert hasattr(pyhbac, "HBAC_ERROR_NOT_IMPLEMENTED") + assert hasattr(pyhbac, "HBAC_ERROR_OUT_OF_MEMORY") + assert hasattr(pyhbac, "HBAC_ERROR_UNPARSEABLE_RULE") + + def testHasCategories(self): + assert hasattr(pyhbac, "HBAC_CATEGORY_NULL") + assert hasattr(pyhbac, "HBAC_CATEGORY_ALL") + + def testHbacResultString(self): + results = [ pyhbac.HBAC_EVAL_ALLOW, pyhbac.HBAC_EVAL_DENY, + pyhbac.HBAC_EVAL_ERROR ] + for r in results: + s = pyhbac.hbac_result_string(r) + self.assertIsInstance(s, unicode) + assert len(s) > 0 + + def testHbacErrorString(self): + errors = [ pyhbac.HBAC_ERROR_UNKNOWN, + pyhbac.HBAC_SUCCESS, + pyhbac.HBAC_ERROR_NOT_IMPLEMENTED, + pyhbac.HBAC_ERROR_OUT_OF_MEMORY, + pyhbac.HBAC_ERROR_UNPARSEABLE_RULE ] + for e in errors: + s = pyhbac.hbac_error_string(e) + self.assertIsInstance(s, unicode) + assert len(s) > 0 + + +if __name__ == "__main__": + error = 0 + + suite = unittest.TestLoader().loadTestsFromTestCase(PyHbacImport) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x1 + # need to bail out here because pyhbac could not be imported + sys.exit(error) + + # import the pyhbac module into the global namespace, but make sure it's + # the one in tree + sys.path.insert(0, MODPATH) + import pyhbac + + suite = unittest.TestLoader().loadTestsFromTestCase(PyHbacRuleElementTest) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x2 + + suite = unittest.TestLoader().loadTestsFromTestCase(PyHbacRuleTest) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x3 + + suite = unittest.TestLoader().loadTestsFromTestCase(PyHbacRequestElementTest) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x4 + + suite = unittest.TestLoader().loadTestsFromTestCase(PyHbacRequestTest) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x5 + + suite = unittest.TestLoader().loadTestsFromTestCase(PyHbacModuleTest) + res = unittest.TextTestRunner().run(suite) + if not res.wasSuccessful(): + error |= 0x6 + + sys.exit(error) + -- cgit