pyceo/ceod/model/Group.py

116 lines
3.8 KiB
Python
Raw Normal View History

2021-08-04 02:33:50 -04:00
import json
2021-08-15 01:04:49 -04:00
from typing import List, Union
2021-07-19 01:47:39 -04:00
2021-08-15 01:04:49 -04:00
import ldap3
2021-07-19 01:47:39 -04:00
from zope import component
from zope.interface import implementer
2021-08-15 01:04:49 -04:00
from .utils import dn_to_uid
2021-08-18 19:48:17 -04:00
from ceo_common.errors import UserAlreadyInGroupError, UserNotInGroupError, \
UserNotFoundError
2021-08-15 01:04:49 -04:00
from ceo_common.interfaces import ILDAPService, IGroup
2021-08-18 19:48:17 -04:00
from ceo_common.logger_factory import logger_factory
logger = logger_factory(__name__)
2021-07-19 01:47:39 -04:00
@implementer(IGroup)
class Group:
def __init__(
2021-08-15 01:04:49 -04:00
self,
cn: str,
gid_number: int,
2021-08-18 19:48:17 -04:00
description: Union[str, None] = None,
2021-07-19 01:47:39 -04:00
members: Union[List[str], None] = None,
2021-08-15 01:04:49 -04:00
ldap3_entry: Union[ldap3.Entry, None] = None,
2021-08-18 19:48:17 -04:00
user_cn: Union[str, None] = None,
2021-07-19 01:47:39 -04:00
):
self.cn = cn
self.gid_number = gid_number
2021-08-18 19:48:17 -04:00
self.description = description
2021-08-04 02:33:50 -04:00
# this is a list of the usernames of the members in this group
self.members = members or []
2021-08-15 01:04:49 -04:00
self.ldap3_entry = ldap3_entry
2021-08-18 19:48:17 -04:00
self.user_cn = user_cn
2021-07-19 01:47:39 -04:00
self.ldap_srv = component.getUtility(ILDAPService)
def __repr__(self) -> str:
2021-08-04 02:33:50 -04:00
return json.dumps(self.to_dict(), indent=2)
def to_dict(self):
2021-08-18 19:48:17 -04:00
data = {
2021-08-04 02:33:50 -04:00
'cn': self.cn,
'gid_number': self.gid_number,
}
2021-08-18 19:48:17 -04:00
description = None
if self.description:
description = self.description
elif self.user_cn:
# for clubs, the human-readable description is stored in the
# 'cn' attribute of the associated user
description = self.user_cn
else:
try:
# TODO: only fetch the CN to save bandwidth
user = self.ldap_srv.get_user(self.cn)
description = user.cn
self.user_cn = user.cn
except UserNotFoundError:
# some groups, like syscom, don't have an associated user
pass
if description:
data['description'] = description
# to_dict() is usually called for display purposes, so get some more
# information to display
data['members'] = self.ldap_srv.get_display_info_for_users(self.members)
return data
2021-07-19 01:47:39 -04:00
def add_to_ldap(self):
self.ldap_srv.add_group(self)
2021-07-24 17:09:10 -04:00
def remove_from_ldap(self):
self.ldap_srv.remove_group(self)
2021-07-19 01:47:39 -04:00
@staticmethod
2021-08-15 01:04:49 -04:00
def deserialize_from_ldap(entry: ldap3.Entry) -> IGroup:
"""Deserialize this group from an LDAP entry."""
attrs = entry.entry_attributes_as_dict
2021-07-19 01:47:39 -04:00
return Group(
2021-08-15 01:04:49 -04:00
cn=attrs['cn'][0],
gid_number=attrs['gidNumber'][0],
2021-08-18 19:48:17 -04:00
description=attrs.get('description', [None])[0],
2021-08-04 02:33:50 -04:00
members=[
2021-08-15 01:04:49 -04:00
dn_to_uid(dn) for dn in attrs.get('uniqueMember', [])
2021-08-04 02:33:50 -04:00
],
2021-08-15 01:04:49 -04:00
ldap3_entry=entry,
2021-07-19 01:47:39 -04:00
)
def add_member(self, username: str):
2021-08-15 01:04:49 -04:00
dn = self.ldap_srv.uid_to_dn(username)
2021-08-18 19:48:17 -04:00
try:
with self.ldap_srv.entry_ctx_for_group(self) as entry:
entry.uniqueMember.add(dn)
2021-08-18 20:19:57 -04:00
except ldap3.core.exceptions.LDAPAttributeOrValueExistsResult as err:
logger.warning(err)
2021-08-18 19:48:17 -04:00
raise UserAlreadyInGroupError()
2021-08-15 01:04:49 -04:00
self.members.append(username)
2021-07-19 01:47:39 -04:00
def remove_member(self, username: str):
2021-08-15 01:04:49 -04:00
dn = self.ldap_srv.uid_to_dn(username)
2021-08-18 19:48:17 -04:00
try:
with self.ldap_srv.entry_ctx_for_group(self) as entry:
entry.uniqueMember.delete(dn)
2021-08-18 20:19:57 -04:00
except ldap3.core.exceptions.LDAPCursorError as err:
logger.warning(err)
2021-08-18 19:48:17 -04:00
raise UserNotInGroupError()
2021-08-15 01:04:49 -04:00
self.members.remove(username)
def set_members(self, usernames: List[str]):
DNs = [
self.ldap_srv.uid_to_dn(username) for username in usernames
]
with self.ldap_srv.entry_ctx_for_group(self) as entry:
entry.uniqueMember = DNs
self.members = usernames