From 4e2cadaa92e5db9dff9e7111e82cf31217579718 Mon Sep 17 00:00:00 2001 From: Blallo Date: Sun, 28 Apr 2019 15:34:14 +0200 Subject: [PATCH] Extending model. --- src/phi/ldap/async_model.py | 118 ++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 6 deletions(-) diff --git a/src/phi/ldap/async_model.py b/src/phi/ldap/async_model.py index 3936a23..8c48908 100644 --- a/src/phi/ldap/async_model.py +++ b/src/phi/ldap/async_model.py @@ -44,13 +44,23 @@ def inheritance(obj, attr, root_cls=object): return res.strip(",") -class Entry: +async def iter_children(children): + return [child async for child in children] + + +class Entry(object): """ LDAP Entry. Interface to LDAP. """ kind = None _name = None + _instance = None + + def __new__(cls, *args, **kwargs): + if cls._instance is None: + cls._instance = object.__new__(cls) + return cls._instance @classmethod def name(cls): @@ -66,16 +76,42 @@ class Entry: self.client = client self.base_dn = client.base_dn + def __repr__(self): + return f"<{call_if_callable(self, 'name')} {self.dn}>" + + async def get_children(self): + async with self.client.connect(is_async=True) as conn: + for el in await conn.search(self.dn, 2): + yield el + + @property + def children(self): + """ + Synchronous property to enumerate the children. + """ + return asyncio.run(iter_children(self.get_children())) + @property def dn(self): return "{},{}".format(inheritance(self, "qualified_name", Entry), self.base_dn) async def describe(self): async with self.client.connect(is_async=True) as conn: - res = await conn.search(self.dn, 2) + res = await conn.search(self.dn, 0) return res +async def build_heritage(obj, ChildClass, attribute_id="uid"): + """ + Given the object and the child class, yields the + instances of the children. + """ + async for child in obj.get_children(): + if attribute_id in child: + _name = child[attribute_id][0] + yield ChildClass(_name, obj.client) + + class Hackers(Entry): """ This class is where Users belong. @@ -83,6 +119,13 @@ class Hackers(Entry): kind = "ou" + def __init__(self, client, *args, **kwargs): + super().__init__(client) + self._hackers = build_heritage(self, User) + + def __aiter__(self): + return self._hackers + class Robots(Entry): """ @@ -92,19 +135,51 @@ class Robots(Entry): kind = "ou" _name = "Services" + def __init__(self, client, *args, **kwargs): + super().__init__(client) + self._robots = build_heritage(self, Service) + + def __aiter__(self): + return self._robots + + +class Congregations(Entry): + """ + This class is where Groups belong. + """ + + kind = "ou" + _name = "Groups" + + def __init__(self, client, *args, **kwargs): + super().__init__(client) + self._groups = build_heritage(self, Group, attribute_id="cn") + + def __aiter__(self): + return self._groups + class User(Hackers): """ - This class models a user. User may have attributes - and belong to Groups. + This class models a user. Users may have attributes + and belong one or more Group(s). """ kind = "uid" + _instances = dict() + + def __new__(cls, name, *args, **kwargs): + if name not in cls._instances: + cls._instances[name] = object.__new__(cls) + return cls._instances[name] def __init__(self, name, *args, **kwargs): super().__init__(*args, **kwargs) self.name = name + def __repr__(self): + return f"<{get_class(self).__name__}({self.name}) {self.dn}>" + def qualified_name(self): return "{}={}".format(self.kind, self.name) @@ -119,8 +194,9 @@ class User(Hackers): class Service(Robots): """ - This class models a user. User may have attributes - and belong to Groups. + This class models a system user (i.e. users that are ancillary to + services on a machine). System user may have attributes + and belong to one or more Group(s). """ kind = "uid" @@ -129,6 +205,36 @@ class Service(Robots): super().__init__(*args, **kwargs) self.name = name + def __repr__(self): + return f"<{get_class(self).__name__}({self.name}) {self.dn}>" + + def qualified_name(self): + return "{}={}".format(self.kind, self.name) + + @property + def name(self): + return self._name + + @name.setter + def name(self, name): + self._name = name + + +class Group(Congregations): + """ + This class models a group. Groups may have attributes + and may have Users and Services belonging to them. + """ + + kind = "uid" + + def __init__(self, name, *args, **kwargs): + super().__init__(*args, **kwargs) + self.name = name + + def __repr__(self): + return f"<{get_class(self).__name__}({self.name}) {self.dn}>" + def qualified_name(self): return "{}={}".format(self.kind, self.name)