From 7524a189fee60a525e2368452accddf5640f8e0f Mon Sep 17 00:00:00 2001 From: kakwa Date: Fri, 15 May 2015 01:03:31 +0200 Subject: [PATCH] implementing nesting roles --- conf/roles.yml | 67 ++++++++++++----------- ldapcherry/exceptions.py | 2 - ldapcherry/roles.py | 63 ++++++++++++++++++++-- misc/debug_roles.py | 20 +++++++ tests/cfg/roles.yml | 49 +---------------- tests/cfg/roles_content_dump.yml | 19 ------- tests/cfg/roles_content_dup.yml | 57 ++++++++++++++++++++ tests/cfg/roles_key_dup.yml | 61 ++++++++++++++------- tests/cfg/roles_missing_backends.yml | 39 ++++++++++++++ tests/cfg/roles_missing_diplay_name.yml | 70 +++++++++++++------------ tests/test_Roles.py | 11 +++- 11 files changed, 295 insertions(+), 163 deletions(-) create mode 100644 misc/debug_roles.py mode change 100644 => 120000 tests/cfg/roles.yml delete mode 100644 tests/cfg/roles_content_dump.yml create mode 100644 tests/cfg/roles_content_dup.yml create mode 100644 tests/cfg/roles_missing_backends.yml diff --git a/conf/roles.yml b/conf/roles.yml index a6ca291..0f0714e 100644 --- a/conf/roles.yml +++ b/conf/roles.yml @@ -2,47 +2,46 @@ admin-lv3: display_name: Administrators Level 3 LC_admins: True backends: - - backend_name: ldap - groups: - - cn=dns admins,ou=group,dc=example,dc=com - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=puppet admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users - - Administrators - - Domain Controllers + ldap: + groups: + - cn=dns admins,ou=group,dc=example,dc=com + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=puppet admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + - Administrators + - Domain Controllers admin-lv2: display_name: Administrators Level 2 backends: - - backend_name: ldap - groups: - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users + ldap: + groups: + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users developpers: - diplay_name: Developpers + display_name: Developpers backends: - - backend_name: ldap - groups: - - cn=nagios user,ou=group,dc=example,dc=com - - cn=developpers,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users + ldap: + groups: + - cn=developpers,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users users: - diplay_name: Simple Users + display_name: Simple Users backends: - - backend_name: ldap - groups: - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users + ldap: + groups: + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users diff --git a/ldapcherry/exceptions.py b/ldapcherry/exceptions.py index 44fb287..a9361d2 100644 --- a/ldapcherry/exceptions.py +++ b/ldapcherry/exceptions.py @@ -33,5 +33,3 @@ class MissingRolesFile(Exception): def __init__(self, rolefile): self.rolefile = rolefile self.log = "fail to open role file <%(rolefile)s>" % { 'rolefile' : rolefile} - - diff --git a/ldapcherry/roles.py b/ldapcherry/roles.py index 9479a78..d338555 100644 --- a/ldapcherry/roles.py +++ b/ldapcherry/roles.py @@ -12,7 +12,13 @@ from sets import Set from ldapcherry.pyyamlwrapper import loadNoDump from ldapcherry.pyyamlwrapper import DumplicatedKey from ldapcherry.exceptions import DumplicateRoleKey, MissingKey, DumplicateRoleContent, MissingRolesFile +import yaml +class CustomDumper(yaml.SafeDumper): + "A custom YAML dumper that never emits aliases" + + def ignore_aliases(self, _data): + return True class Roles: @@ -28,10 +34,33 @@ class Roles: except DumplicatedKey as e: raise DumplicateRoleKey(e.key) stream.close() + self.roles = {} self._nest() + def _is_parent(self, roleid1, roleid2): + role2 = self.roles_raw[roleid2] + role1 = self.roles_raw[roleid1] + + if role1 == role2: + return False + # Check if role1 is contained by role2 + for b1 in role1['backends']: + if not b1 in role2['backends']: + return False + for group in role1['backends'][b1]['groups']: + if not group in role2['backends'][b1]['groups']: + return False + for b2 in role2['backends']: + if not b2 in role1['backends']: + return True + for group in role2['backends'][b2]['groups']: + if not group in role1['backends'][b2]['groups']: + return True + raise DumplicateRoleContent(roleid1, roleid2) + def _nest(self): """nests the roles (creates roles hierarchy)""" + parents = {} for roleid in self.roles_raw: role = self.roles_raw[roleid] @@ -45,16 +74,42 @@ class Roles: # Create the list of backends for backend in role['backends']: - self.backends.add(backend['name']) + self.backends.add(backend) # Create the nested groups + for roleid in self.roles_raw: + role = self.roles_raw[roleid] + + parents[roleid]=[] for roleid2 in self.roles_raw: role2 = self.roles_raw[roleid2] - self.roles = self.roles_raw + if self._is_parent(roleid, roleid2): + parents[roleid].append(roleid2) - def write(self, out_file): + for r in parents: + for p in parents[r]: + for p2 in parents[r]: + if p != p2 and p in parents[p2]: + parents[r].remove(p) + + def nest(p): + ret = self.roles_raw[p] + ret['subroles'] = {} + if len(parents[p]) == 0: + return ret + else: + for i in parents[p]: + sub = nest(i) + ret['subroles'][i] = sub + return ret + + for p in parents.keys(): + if p in parents: + self.roles[p] = nest(p) + + def dump_nest(self): """write the nested role hierarchy to a file""" - pass + return yaml.dump(self.roles, Dumper=CustomDumper) def get_roles(self, groups): """get list of roles and list of standalone groups""" diff --git a/misc/debug_roles.py b/misc/debug_roles.py new file mode 100644 index 0000000..6bf2dae --- /dev/null +++ b/misc/debug_roles.py @@ -0,0 +1,20 @@ +from ldapcherry.roles import Roles +from ldapcherry.exceptions import DumplicateRoleKey, MissingKey, DumplicateRoleContent, MissingRolesFile +from ldapcherry.pyyamlwrapper import DumplicatedKey, RelationError +from yaml import load, dump +import yaml + +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + +class CustomDumper(yaml.SafeDumper): + "A custom YAML dumper that never emits aliases" + + def ignore_aliases(self, _data): + return True + +inv = Roles('./conf/roles.yml') +print +print inv.dump_nest() diff --git a/tests/cfg/roles.yml b/tests/cfg/roles.yml deleted file mode 100644 index fd8c9ee..0000000 --- a/tests/cfg/roles.yml +++ /dev/null @@ -1,48 +0,0 @@ -admin-lv3: - display_name: Administrators Level 3 - LC_admins: True - backends: - - name: ldap - groups: - - cn=dns admins,ou=group,dc=example,dc=com - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=puppet admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - name: ad - groups: - - Domain Users - - Administrators - - Domain Controllers - -admin-lv2: - display_name: Administrators Level 2 - backends: - - name: ldap - groups: - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - name: ad - groups: - - Domain Users - -developpers: - display_name: Developpers - backends: - - name: ldap - groups: - - cn=nagios user,ou=group,dc=example,dc=com - - cn=developpers,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - name: ad - groups: - - Domain Users - -users: - display_name: Simple Users - backends: - - name: ldap - groups: - - cn=users,ou=group,dc=example,dc=com - - name: ad - groups: - - Domain Users diff --git a/tests/cfg/roles.yml b/tests/cfg/roles.yml new file mode 120000 index 0000000..ad11f87 --- /dev/null +++ b/tests/cfg/roles.yml @@ -0,0 +1 @@ +../../conf/roles.yml \ No newline at end of file diff --git a/tests/cfg/roles_content_dump.yml b/tests/cfg/roles_content_dump.yml deleted file mode 100644 index 070ba61..0000000 --- a/tests/cfg/roles_content_dump.yml +++ /dev/null @@ -1,19 +0,0 @@ -users2: - diplay_name: Simple Users2 - backends: - - backend_name: ldap - groups: - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users -users: - diplay_name: Simple Users - LC_admins: True - backends: - - backend_name: ldap - groups: - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users diff --git a/tests/cfg/roles_content_dup.yml b/tests/cfg/roles_content_dup.yml new file mode 100644 index 0000000..e80a04c --- /dev/null +++ b/tests/cfg/roles_content_dup.yml @@ -0,0 +1,57 @@ +admin-lv3: + display_name: Administrators Level 3 + LC_admins: True + backends: + ldap: + groups: + - cn=dns admins,ou=group,dc=example,dc=com + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=puppet admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + - Administrators + - Domain Controllers + +admin-lv2: + display_name: Administrators Level 2 + backends: + ldap: + groups: + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + +developpers: + display_name: Developpers + backends: + ldap: + groups: + - cn=developpers,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + +users: + display_name: Simple Users + backends: + ldap: + groups: + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + +users2: + display_name: Simple Users 2 + backends: + ldap: + groups: + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users diff --git a/tests/cfg/roles_key_dup.yml b/tests/cfg/roles_key_dup.yml index bab1745..a5e3d8f 100644 --- a/tests/cfg/roles_key_dup.yml +++ b/tests/cfg/roles_key_dup.yml @@ -1,26 +1,47 @@ -admin-lv2: +admin-lv3: display_name: Administrators Level 3 LC_admins: True backends: - - backend_name: ldap - groups: - - cn=dns admins,ou=group,dc=example,dc=com - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=puppet admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users - - Administrators - - Domain Controllers + ldap: + groups: + - cn=dns admins,ou=group,dc=example,dc=com + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=puppet admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + - Administrators + - Domain Controllers -admin-lv2: +admin-lv3: display_name: Administrators Level 2 backends: - - backend_name: ldap - groups: - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users + ldap: + groups: + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + +developpers: + display_name: Developpers + backends: + ldap: + groups: + - cn=developpers,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + +users: + display_name: Simple Users + backends: + ldap: + groups: + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users diff --git a/tests/cfg/roles_missing_backends.yml b/tests/cfg/roles_missing_backends.yml new file mode 100644 index 0000000..f10a1a2 --- /dev/null +++ b/tests/cfg/roles_missing_backends.yml @@ -0,0 +1,39 @@ +admin-lv3: + display_name: Administrators Level 3 + LC_admins: True + backends: + ldap: + groups: + - cn=dns admins,ou=group,dc=example,dc=com + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=puppet admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + - Administrators + - Domain Controllers + +admin-lv2: + display_name: Administrators Level 2 + +developpers: + display_name: Developpers + backends: + ldap: + groups: + - cn=developpers,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + +users: + display_name: Simple Users + backends: + ldap: + groups: + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users diff --git a/tests/cfg/roles_missing_diplay_name.yml b/tests/cfg/roles_missing_diplay_name.yml index 9c1fe8d..082000e 100644 --- a/tests/cfg/roles_missing_diplay_name.yml +++ b/tests/cfg/roles_missing_diplay_name.yml @@ -2,43 +2,45 @@ admin-lv3: display_name: Administrators Level 3 LC_admins: True backends: - - backend_name: ldap - groups: - - cn=dns admins,ou=group,dc=example,dc=com - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=puppet admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users - - Administrators - - Domain Controllers + ldap: + groups: + - cn=dns admins,ou=group,dc=example,dc=com + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=puppet admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + - Administrators + - Domain Controllers + admin-lv2: - display_name: Administrators Level 2 backends: - - backend_name: ldap - groups: - - cn=nagios admins,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users + ldap: + groups: + - cn=nagios admins,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + developpers: + display_name: Developpers backends: - - backend_name: ldap - groups: - - cn=nagios user,ou=group,dc=example,dc=com - - cn=developpers,ou=group,dc=example,dc=com - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users + ldap: + groups: + - cn=developpers,ou=group,dc=example,dc=com + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users + users: - diplay_name: Simple Users + display_name: Simple Users backends: - - backend_name: ldap - groups: - - cn=users,ou=group,dc=example,dc=com - - backend_name: ad - groups: - - Domain Users + ldap: + groups: + - cn=users,ou=group,dc=example,dc=com + ad: + groups: + - Domain Users diff --git a/tests/test_Roles.py b/tests/test_Roles.py index dea4c54..8505729 100644 --- a/tests/test_Roles.py +++ b/tests/test_Roles.py @@ -10,7 +10,6 @@ from ldapcherry.roles import Roles from ldapcherry.exceptions import DumplicateRoleKey, MissingKey, DumplicateRoleContent, MissingRolesFile from ldapcherry.pyyamlwrapper import DumplicatedKey, RelationError - class TestError(object): def testNominal(self): @@ -26,6 +25,14 @@ class TestError(object): else: raise AssertionError("expected an exception") + def testMissingBackends(self): + try: + inv = Roles('./tests/cfg/roles_missing_backends.yml') + except MissingKey: + return + else: + raise AssertionError("expected an exception") + def testRoleKeyDuplication(self): try: inv = Roles('./tests/cfg/roles_key_dup.yml') @@ -45,7 +52,7 @@ class TestError(object): def testRoleContentDuplication(self): try: - inv = Roles('./tests/cfg/roles_content_dump.yml') + inv = Roles('./tests/cfg/roles_content_dup.yml') except DumplicateRoleContent: return else: