pyceo/ceod/model/User.py

187 lines
6.8 KiB
Python

import copy
import os
from typing import List, Dict, Union
from zope import component
from zope.interface import implementer
from .utils import strings_to_bytes, bytes_to_strings
from ceo_common.interfaces import ILDAPService, IKerberosService, IFileService, \
IUser, IConfig
@implementer(IUser)
class User:
def __init__(
self, uid: str, cn: str,
program: Union[str, None] = None,
terms: Union[List[str], None] = None,
non_member_terms: Union[List[str], None] = None,
login_shell: str = '/bin/bash',
uid_number: Union[int, None] = None,
gid_number: Union[int, None] = None,
home_directory: Union[str, None] = None,
positions: Union[List[str], None] = None,
mail_local_addresses: Union[List[str], None] = None,
is_club: bool = False,
):
if not is_club and not terms and not non_member_terms:
raise Exception('terms and non_member_terms cannot both be empty')
cfg = component.getUtility(IConfig)
self.uid = uid
self.cn = cn
self.program = program
self.terms = terms or []
self.non_member_terms = non_member_terms or []
self.login_shell = login_shell
self.uid_number = uid_number
self.gid_number = gid_number
if home_directory is None:
if is_club:
home_parent = cfg.get('member_home')
else:
home_parent = cfg.get('club_home')
self.home_directory = os.path.join(home_parent, uid)
else:
self.home_directory = home_directory
self.positions = positions or []
self.mail_local_addresses = mail_local_addresses or []
self._is_club = is_club
self.ldap_sasl_realm = cfg.get('ldap_sasl_realm')
self.dn = f'uid={uid},{cfg.get("ldap_users_base")}'
self.ldap_srv = component.getUtility(ILDAPService)
self.krb_srv = component.getUtility(IKerberosService)
self.file_srv = component.getUtility(IFileService)
def __repr__(self) -> str:
lines = [
'dn: ' + self.dn,
'cn: ' + self.cn,
'uid: ' + self.uid,
'objectClass: top',
'objectClass: account',
'objectClass: posixAccount',
'objectClass: shadowAccount',
'objectClass: ' + ('club' if self.is_club() else 'member'),
'uidNumber: ' + str(self.uid_number),
'gidNumber: ' + str(self.gid_number),
'loginShell: ' + self.login_shell,
'homeDirectory: ' + self.home_directory,
]
if self.program:
lines.append('program: ' + self.program)
for term in self.terms:
lines.append('term: ' + term)
for term in self.non_member_terms:
lines.append('nonMemberTerm: ' + term)
for position in self.positions:
lines.append('position: ' + position)
for address in self.mail_local_addresses:
lines.append('mailLocalAddress: ' + address)
return '\n'.join(lines)
def is_club(self) -> bool:
return self._is_club
def add_to_ldap(self):
new_member = self.ldap_srv.add_user(self)
self.uid_number = new_member.uid_number
self.gid_number = new_member.gid_number
def add_to_kerberos(self, password: str):
self.krb_srv.addprinc(self.uid, password)
def change_password(self, password: str):
self.krb_srv.change_password(self.uid, password)
def create_home_dir(self):
self.file_srv.create_home_dir(self.uid, self._is_club)
def serialize_for_modlist(self) -> Dict:
data = {
'cn': [self.cn],
'loginShell': [self.login_shell],
'homeDirectory': [self.home_directory],
'uid': [self.uid],
'uidNumber': [str(self.uid_number)],
'gidNumber': [str(self.gid_number)],
'objectClass': [
'top',
'account',
'posixAccount',
'shadowAccount',
],
}
if self.is_club():
data['objectClass'].append('club')
else:
data['objectClass'].append('member')
data['userPassword'] = ['{SASL}%s@%s' % (self.uid, self.ldap_sasl_realm)]
if self.program:
data['program'] = [self.program]
if self.terms:
data['term'] = self.terms
if self.non_member_terms:
data['nonMemberTerm'] = self.non_member_terms
if self.positions:
data['position'] = self.positions
if self.mail_local_addresses:
data['mailLocalAddress'] = self.mail_local_addresses
data['objectClass'].append('inetLocalMailRecipient')
return strings_to_bytes(data)
@staticmethod
def deserialize_from_dict(data: Dict[str, List[bytes]]) -> IUser:
data = bytes_to_strings(data)
return User(
uid=data['uid'][0],
cn=data['cn'][0],
program=data.get('program', [None])[0],
terms=data.get('term'),
non_member_terms=data.get('nonUserTerm'),
login_shell=data['loginShell'][0],
uid_number=int(data['uidNumber'][0]),
gid_number=int(data['gidNumber'][0]),
home_directory=data['homeDirectory'][0],
positions=data.get('position'),
mail_local_addresses=data.get('mailLocalAddress', []),
is_club=('club' in data['objectClass']),
)
def add_terms(self, terms: List[str]):
new_user = copy.copy(self)
new_user.terms = self.terms.copy()
new_user.terms.extend(terms)
self.ldap_srv.modify_user(self, new_user)
self.terms = new_user.terms
def add_non_member_terms(self, terms: List[str]):
new_user = copy.copy(self)
new_user.non_member_terms = self.non_member_terms.copy()
new_user.non_member_terms.extend(terms)
self.ldap_srv.modify_user(self, new_user)
self.non_member_terms = new_user.non_member_terms
def add_position(self, position: str):
new_user = copy.copy(self)
new_user.positions = [*self.positions, position]
self.ldap_srv.modify_user(self, new_user)
self.positions = new_user.positions
def remove_position(self, position: str):
new_user = copy.copy(self)
new_user.positions = self.positions.copy()
new_user.positions.remove(position)
self.ldap_srv.modify_user(self, new_user)
self.positions = new_user.positions
def get_forwarding_addresses(self) -> List[str]:
return self.file_srv.get_forwarding_addresses(self.uid)
def set_forwarding_addresses(self, addresses: List[str]):
self.file_srv.set_forwarding_addresses(self.uid, addresses)
forwarding_addresses = property(get_forwarding_addresses, set_forwarding_addresses)