from typing import Union, List import ldap3 from zope import component from zope.interface import implementer from .UWLDAPRecord import UWLDAPRecord from ceo_common.interfaces import IUWLDAPService, IConfig @implementer(IUWLDAPService) class UWLDAPService: def __init__(self): cfg = component.getUtility(IConfig) self.uwldap_server_url = cfg.get('uwldap_server_url') self.uwldap_base = cfg.get('uwldap_base') def _get_conn(self) -> ldap3.Connection: return ldap3.Connection( self.uwldap_server_url, auto_bind=True, read_only=True, raise_exceptions=True) def get_user(self, username: str) -> Union[UWLDAPRecord, None]: conn = self._get_conn() conn.search( self.uwldap_base, f'(uid={username})', attributes=UWLDAPRecord.ldap_attributes, size_limit=1) if not conn.entries: return None return UWLDAPRecord.deserialize_from_ldap(conn.entries[0]) def get_programs_for_users(self, usernames: List[str]) -> List[Union[str, None]]: filter_str = '(|' + ''.join([f'(uid={uid})' for uid in usernames]) + ')' programs = [None] * len(usernames) user_indices = {uid: i for i, uid in enumerate(usernames)} conn = self._get_conn() conn.search( self.uwldap_base, filter_str, attributes=['ou', 'uid'], size_limit=len(usernames)) for entry in conn.entries: # some records in UWLDAP have two UIDs because UIDs # were historically limited to 8 characters uid = None for uw_uid in entry.uid.values: if uw_uid in user_indices: uid = uw_uid break # sanity check assert uid is not None idx = user_indices[uid] program = entry.ou.value if program: programs[idx] = program return programs