#!/usr/bin/env python
# SSSD
#
# SSSD HBAC python API tests
#
# Copyright (C) Red Hat
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
from __future__ import print_function
import unittest
import sys
import os
import copy
import tempfile
BUILD_DIR = os.getenv('builddir') or "."
TEST_DIR = os.path.realpath(os.getenv('SSS_TEST_DIR') or ".")
MODPATH = tempfile.mkdtemp(prefix="tp_pyhbac_", dir=TEST_DIR)
if sys.version_info[0] > 2:
unicode = str
def compat_assertIsInstance(this, obj, cls, msg=None):
return this.assertTrue(isinstance(obj, cls))
def compat_assertItemsEqual(this, expected_seq, actual_seq, msg=None):
return this.assertEqual(sorted(expected_seq), sorted(actual_seq))
# add compat assertIsInstance for old unittest.TestCase versions
# (python < 2.7, RHEL6 for instance)
if not hasattr(unittest.TestCase, "assertIsInstance"):
setattr(unittest.TestCase, "assertIsInstance", compat_assertIsInstance)
# Python3 renamed assertItemsEqual to assertCountEqual but at the same time
# Python2 doesn't have assertCountEqual, see http://bugs.python.org/issue17866
if not hasattr(unittest.TestCase, "assertCountEqual"):
if not hasattr(unittest.TestCase, "assertItemsEqual"):
# This is RHEL-6
setattr(unittest.TestCase, "assertItemsEqual", compat_assertItemsEqual)
setattr(unittest.TestCase,
"assertCountEqual",
unittest.TestCase.assertItemsEqual)
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:
dest_module_path = MODPATH + "/pyhbac.so"
if sys.version_info[0] > 2:
src_module_path = BUILD_DIR + "/.libs/_py3hbac.so"
else:
src_module_path = BUILD_DIR + "/.libs/_py2hbac.so"
src_module_path = os.path.abspath(src_module_path)
os.symlink(src_module_path, dest_module_path)
import pyhbac
except ImportError as e:
print("Could not load the pyhbac module. Please check if it is "
"compiled", file=sys.stderr)
raise e
self.assertEqual(os.path.realpath(pyhbac.__file__),
os.path.realpath(MODPATH + "/pyhbac.so"))
class PyHbacRuleElementTest(unittest.TestCase):
def testInstantiateEmpty(self):
el = pyhbac.HbacRuleElement()
self.assertCountEqual(el.names, [])
self.assertCountEqual(el.groups, [])
self.assertCountEqual(el.category, set([pyhbac.HBAC_CATEGORY_NULL]))
def testInit(self):
names = ["foo", "bar"]
el = pyhbac.HbacRuleElement(names=names)
self.assertCountEqual(el.names, names)
groups = ["abc", "def"]
el = pyhbac.HbacRuleElement(groups=groups)
self.assertCountEqual(el.groups, groups)
def testGetSet(self):
names = ["foo", "bar"]
el = pyhbac.HbacRuleElement()
self.assertCountEqual(el.names, [])
el.names = names
self.assertCountEqual(el.names, names)
groups = ["abc", "def"]
el = pyhbac.HbacRuleElement()
self.assertCountEqual(el.groups, [])
el.groups = groups
self.assertCountEqual(el.groups, groups)
# Test other iterables than list
groups = ("abc", "def")
el = pyhbac.HbacRuleElement()
self.assertCountEqual(el.groups, [])
el.groups = groups
self.assertCountEqual(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.assertCountEqual(el.names, ["foo", "bar"])
self.assertCountEqual(el.groups, ["abc", "def"])
def testRepr(self):
el = pyhbac.HbacRuleElement()
self.assertEqual(el.__repr__(), u'')
el.category.add(pyhbac.HBAC_CATEGORY_ALL)
el.names = ['foo']
el.groups = ['bar, baz']
self.assertEqual(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)
rule.enabled = "TRUE"
self.assertEqual(rule.enabled, True)
rule.enabled = "FALSE"
self.assertEqual(rule.enabled, False)
rule.enabled = "true"
self.assertEqual(rule.enabled, True)
rule.enabled = "false"
self.assertEqual(rule.enabled, False)
rule.enabled = "True"
self.assertEqual(rule.enabled, True)
rule.enabled = "False"
self.assertEqual(rule.enabled, False)
rule.enabled = 1
self.assertEqual(rule.enabled, True)
rule.enabled = 0
self.assertEqual(rule.enabled, False)
# negative test
self.assertRaises(TypeError, rule.__setattr__, "enabled", None)
self.assertRaises(TypeError, rule.__setattr__, "enabled", [])
self.assertRaises(ValueError, rule.__setattr__, "enabled", "foo")
self.assertRaises(ValueError, rule.__setattr__, "enabled", 5)
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.assertCountEqual(rule.users.names, [])
self.assertCountEqual(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.assertCountEqual(rule.users.names, users)
self.assertCountEqual(rule.users.groups, user_groups)
# Assign directly
rule = pyhbac.HbacRule("testRuleElement")
rule.users.names = users
rule.users.groups = user_groups
self.assertCountEqual(rule.users.names, users)
self.assertCountEqual(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.assertCountEqual(rule.users.names, ["foo", "bar"])
self.assertCountEqual(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))
def testValidate(self):
r = pyhbac.HbacRule('valid_rule')
valid, missing = r.validate()
self.assertEqual(valid, False)
self.assertCountEqual(missing, (pyhbac.HBAC_RULE_ELEMENT_USERS,
pyhbac.HBAC_RULE_ELEMENT_SERVICES,
pyhbac.HBAC_RULE_ELEMENT_TARGETHOSTS,
pyhbac.HBAC_RULE_ELEMENT_SOURCEHOSTS))
r.users.names = ["someuser"]
r.services.names = ["ssh"]
valid, missing = r.validate()
self.assertEqual(valid, False)
self.assertCountEqual(missing, (pyhbac.HBAC_RULE_ELEMENT_TARGETHOSTS,
pyhbac.HBAC_RULE_ELEMENT_SOURCEHOSTS))
r.srchosts.names = ["host1"]
r.targethosts.names = ["host2"]
valid, missing = r.validate()
self.assertEqual(valid, True)
class PyHbacRequestElementTest(unittest.TestCase):
def testInstantiateEmpty(self):
el = pyhbac.HbacRequestElement()
self.assertCountEqual(el.name, "")
self.assertCountEqual(el.groups, [])
def testInit(self):
name = "foo"
el = pyhbac.HbacRequestElement(name=name)
self.assertCountEqual(el.name, name)
groups = ["abc", "def"]
el = pyhbac.HbacRequestElement(groups=groups)
self.assertCountEqual(el.groups, groups)
def testGetSet(self):
name = "foo"
el = pyhbac.HbacRequestElement()
self.assertCountEqual(el.name, "")
el.name = name
self.assertCountEqual(el.name, name)
groups = ["abc", "def"]
el = pyhbac.HbacRequestElement()
self.assertCountEqual(el.groups, [])
el.groups = groups
self.assertCountEqual(el.groups, groups)
# Test other iterables than list
groups = ("abc", "def")
el = pyhbac.HbacRequestElement()
self.assertCountEqual(el.groups, [])
el.groups = groups
self.assertCountEqual(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.assertCountEqual(req.user.groups, [])
# Assign by copying a HbacRequestElement
user_el = pyhbac.HbacRequestElement(name=name, groups=groups)
req = pyhbac.HbacRequest()
req.user = user_el
self.assertCountEqual(req.user.name, name)
self.assertCountEqual(req.user.groups, groups)
# Assign directly
req = pyhbac.HbacRequest()
req.user.name = name
req.user.groups = groups
self.assertCountEqual(req.user.name, name)
self.assertCountEqual(req.user.groups, groups)
def testRuleName(self):
req = pyhbac.HbacRequest()
self.assertEqual(req.rule_name, None)
# python 2.4 raises TypError, 2.7 raises AttributeError
self.assertRaises((TypeError, 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
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):
@classmethod
def tearDownClass(cls):
os.unlink(MODPATH + "/pyhbac.so")
os.rmdir(MODPATH)
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 testHasRuleElementTypes(self):
assert hasattr(pyhbac, "HBAC_RULE_ELEMENT_USERS")
assert hasattr(pyhbac, "HBAC_RULE_ELEMENT_SERVICES")
assert hasattr(pyhbac, "HBAC_RULE_ELEMENT_TARGETHOSTS")
assert hasattr(pyhbac, "HBAC_RULE_ELEMENT_SOURCEHOSTS")
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
loadTestsFromTestCase = unittest.TestLoader().loadTestsFromTestCase
suite = loadTestsFromTestCase(PyHbacRuleElementTest)
res = unittest.TextTestRunner().run(suite)
if not res.wasSuccessful():
error |= 0x2
suite = loadTestsFromTestCase(PyHbacRuleTest)
res = unittest.TextTestRunner().run(suite)
if not res.wasSuccessful():
error |= 0x3
suite = loadTestsFromTestCase(PyHbacRequestElementTest)
res = unittest.TextTestRunner().run(suite)
if not res.wasSuccessful():
error |= 0x4
suite = loadTestsFromTestCase(PyHbacRequestTest)
res = unittest.TextTestRunner().run(suite)
if not res.wasSuccessful():
error |= 0x5
suite = loadTestsFromTestCase(PyHbacModuleTest)
res = unittest.TextTestRunner().run(suite)
if not res.wasSuccessful():
error |= 0x6
sys.exit(error)