1
0
mirror of https://github.com/kakwa/ldapcherry synced 2024-06-09 12:27:50 +02:00
ldapcherry/ldapcherry/roles.py

174 lines
5.5 KiB
Python
Raw Normal View History

2015-04-15 21:13:14 +02:00
# -*- coding: utf-8 -*-
# vim:set expandtab tabstop=4 shiftwidth=4:
#
# The MIT License (MIT)
# LdapCherry
# Copyright (c) 2014 Carpentier Pierre-Francois
import os
import sys
2015-05-14 22:10:26 +02:00
from sets import Set
2015-05-12 01:24:16 +02:00
from ldapcherry.pyyamlwrapper import loadNoDump
from ldapcherry.pyyamlwrapper import DumplicatedKey
from ldapcherry.exceptions import DumplicateRoleKey, MissingKey, DumplicateRoleContent, MissingRolesFile
2015-05-15 01:03:31 +02:00
import yaml
2015-05-12 01:24:16 +02:00
2015-05-15 01:03:31 +02:00
class CustomDumper(yaml.SafeDumper):
"A custom YAML dumper that never emits aliases"
def ignore_aliases(self, _data):
return True
2015-04-15 21:13:14 +02:00
class Roles:
def __init__(self, role_file):
2015-05-14 22:10:26 +02:00
self.role_file = role_file
self.backends = Set([])
try:
stream = open(role_file, 'r')
except:
raise MissingRolesFile(role_file)
try:
self.roles_raw = loadNoDump(stream)
except DumplicatedKey as e:
raise DumplicateRoleKey(e.key)
2015-05-12 01:24:16 +02:00
stream.close()
2015-05-15 01:03:31 +02:00
self.roles = {}
2015-05-12 01:24:16 +02:00
self._nest()
2015-04-15 21:13:14 +02:00
2015-05-15 01:03:31 +02:00
def _is_parent(self, roleid1, roleid2):
"""Test if roleid1 is contained inside roleid2"""
2015-05-15 01:03:31 +02:00
role2 = self.roles_raw[roleid2]
role1 = self.roles_raw[roleid1]
if role1 == role2:
return False
2015-05-15 01:03:31 +02:00
# 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
# If role2 is inside role1, roles are equal, throw exception
2015-05-15 01:03:31 +02:00
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)
2015-05-12 01:24:16 +02:00
def _nest(self):
2015-04-15 21:13:14 +02:00
"""nests the roles (creates roles hierarchy)"""
2015-05-15 01:03:31 +02:00
parents = {}
2015-05-14 22:10:26 +02:00
for roleid in self.roles_raw:
role = self.roles_raw[roleid]
# Display name is mandatory
if not 'display_name' in role:
raise MissingKey('display_name', role, self.role_file)
# Backend is mandatory
if not 'backends' in role:
raise MissingKey('backends', role, self.role_file)
# Create the list of backends
for backend in role['backends']:
2015-05-15 01:03:31 +02:00
self.backends.add(backend)
2015-05-14 22:10:26 +02:00
# Create the nested groups
2015-05-15 01:03:31 +02:00
for roleid in self.roles_raw:
role = self.roles_raw[roleid]
parents[roleid]=[]
2015-05-14 22:10:26 +02:00
for roleid2 in self.roles_raw:
role2 = self.roles_raw[roleid2]
2015-05-15 01:03:31 +02:00
if self._is_parent(roleid, roleid2):
parents[roleid].append(roleid2)
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
2015-04-15 21:13:14 +02:00
2015-05-15 01:03:31 +02:00
for p in parents.keys():
if p in parents:
self.roles[p] = nest(p)
def dump_nest(self):
"""dump the nested role hierarchy"""
2015-05-15 01:03:31 +02:00
return yaml.dump(self.roles, Dumper=CustomDumper)
2015-04-15 21:13:14 +02:00
def _check_member(role, groups, notroles, roles, parentroles, usedgroups):
if role in notroles:
return False
if not (role in parentroles or role in roles):
for b in self.roles[role]['backends']:
for g in self.roles[role]['backends'][b]['groups']:
if b not in groups:
notroles.add(role)
return False
if not g in groups[b]:
notroles.add(role)
return False
for b in self.roles[role]['backends']:
if not b in usedgroups:
usedgroups[b] = Set([])
for g in self.roles[role]['backends'][b]['groups']:
usedgroups[b].add(g)
flag = True
for subrole in self.roles[role]['subroles']:
flag = flag and not self._check_member(subrole, groups, notroles, roles, parentroles, usedgroups)
if flag:
roles.add(role)
else:
if role in roles:
roles.remove(role)
parentroles.add(role)
return True
2015-04-15 21:13:14 +02:00
def get_roles(self, groups):
"""get list of roles and list of standalone groups"""
roles = Set([])
parentroles = Set([])
notroles = Set([])
usedgroups = {}
unusedgroups = {}
ret = {}
for r in self.roles:
self._check_member(role, groups, notroles, roles, parentroles, usedgroups)
for b in groups:
for g in groups[b]:
if not b in usedgroups or not g in usedgroups[b]:
if b not in unusedgroups:
unusedgroups[b] = Set([])
unusedgroups[b].add(g)
ret['roles'] = roles
ret['unusedgroups'] = unusedgroups
return ret
2015-04-15 21:13:14 +02:00
def get_groups(self, roles):
"""get the list of groups from roles"""
pass