From 0d505fa55ad1b6341d12e3b88b5ec7377b1709e7 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Fri, 9 Sep 2022 11:29:09 +0200 Subject: [PATCH] Changing error handling on LDAP operations. --- lib/pp_admintools/app/ldap.py | 37 ++++++- lib/pp_admintools/app/remove_ldap_user.py | 112 +++++++++++++++++----- 2 files changed, 122 insertions(+), 27 deletions(-) diff --git a/lib/pp_admintools/app/ldap.py b/lib/pp_admintools/app/ldap.py index 12d5fb0..ec73916 100644 --- a/lib/pp_admintools/app/ldap.py +++ b/lib/pp_admintools/app/ldap.py @@ -50,7 +50,7 @@ from ..config.ldap import LdapConnectionInfo, LdapConfiguration # rom ..config.ldap import DEFAULT_PORT_LDAP, DEFAULT_PORT_LDAPS from ..config.ldap import DEFAULT_TIMEOUT -__version__ = '0.4.7' +__version__ = '0.5.1' LOG = logging.getLogger(__name__) _ = XLATOR.gettext @@ -69,6 +69,12 @@ class FatalLDAPError(LdapAppError): pass +# ============================================================================= +class LDAPExecutionError(FatalLDAPError): + """Error class in case, a LDAP operation was not successful.""" + pass + + # ============================================================================= class WriteLDAPItemError(FatalLDAPError): """Error class in case, a LDAP item could not be written.""" @@ -931,10 +937,26 @@ class BaseLdapApplication(BaseDPXApplication): msg = _("Modification NOT successfull - {c}: {e}").format(c=e.__class__.__name__, e=e) msg += '\n' + _("Changes:") + '\n' + pp(changes) raise WriteLDAPItemError(msg) - LOG.debug(_('Modification successful.')) + + # Example result on a not successful modification: + # { 'description': 'objectClassViolation', + # 'dn': '', + # 'message': 'attribute "loginShell" not allowed\n', + # 'referrals': None, + # 'result': 65, + # 'type': 'modifyResponse'} + + if self.verbose > 1: + LOG.debug(_("Modification status: {!r}.").format(req_status)) if self.verbose > 2: LOG.debug(_("Result of modifying:") + '\n' + pp(req_result)) + if not req_status: + msg = _("Modification NOT successful: {desc} - {msg}").format( + desc=req_result['description'], msg=req_result['message'].strip()) + raise WriteLDAPItemError(msg) + + LOG.debug(_('Modification successful.')) return True # ------------------------------------------------------------------------- @@ -956,10 +978,19 @@ class BaseLdapApplication(BaseDPXApplication): except LDAPException as e: msg = _("Deletion NOT successfull - {c}: {e}").format(c=e.__class__.__name__, e=e) raise DeleteLDAPItemError(msg) - LOG.debug(_('Deletion successful.')) + + if self.verbose > 1: + LOG.debug(_("Deletion status: {!r}.").format(req_status)) if self.verbose > 2: LOG.debug(_("Result of deletion:") + '\n' + pp(req_result)) + if not req_status: + msg = _("Deletion NOT successful: {desc} - {msg}").format( + desc=req_result['description'], msg=req_result['message'].strip()) + raise DeleteLDAPItemError(msg) + + LOG.debug(_('Deletion successful.')) + return True # ------------------------------------------------------------------------- diff --git a/lib/pp_admintools/app/remove_ldap_user.py b/lib/pp_admintools/app/remove_ldap_user.py index bade2c5..f4c52c5 100644 --- a/lib/pp_admintools/app/remove_ldap_user.py +++ b/lib/pp_admintools/app/remove_ldap_user.py @@ -22,10 +22,10 @@ from ..xlate import XLATOR from . import AbortAppError, TimeoutOnPromptError -from .ldap import LdapAppError +from .ldap import LdapAppError, FatalLDAPError from .ldap import BaseLdapApplication -__version__ = '0.4.5' +__version__ = '0.5.1' LOG = logging.getLogger(__name__) _ = XLATOR.gettext @@ -192,7 +192,8 @@ class RemoveLdapUserApplication(BaseLdapApplication): LOG.warn(msg) for inst in self.dns: - self.remove_users_from_inst(inst) + if not self.remove_users_from_inst(inst): + break # ------------------------------------------------------------------------- def request_for_remove(self): @@ -298,7 +299,10 @@ class RemoveLdapUserApplication(BaseLdapApplication): LOG.info(msg) for dn in self.dns[inst]: - self.remove_user(inst, dn) + if not self.remove_user(inst, dn): + return False + + return True # ------------------------------------------------------------------------- def remove_user(self, inst, dn): @@ -318,17 +322,38 @@ class RemoveLdapUserApplication(BaseLdapApplication): msg = _("Attributes of {!r}:").format(dn) LOG.debug(msg + '\n' + pp(attributes.as_dict())) - self.setting_user_status(inst, dn, attributes) - self.remove_all_memberships(inst, dn) - self.remove_all_unique_memberships(inst, dn) + if not self.setting_user_status(inst, dn, attributes): + return False + if not self.remove_all_memberships(inst, dn): + return False + if not self.remove_all_unique_memberships(inst, dn): + return False if 'uid' in attributes: for uid in attributes['uid']: - self.remove_all_posixgroup_memberships(inst, uid) - self.remove_all_sudogroup_memberships(inst, uid) + if not self.remove_all_posixgroup_memberships(inst, uid): + return False + if not self.remove_all_sudogroup_memberships(inst, uid): + return False if not self.deactivate: - self.delete_entry(inst, dn) + try: + self.delete_entry(inst, dn) + except FatalLDAPError as e: + msg = _("{c} on removing user {dn!r}: {e}").format( + c=e.__class__.__name__, dn=dn, e=e) + LOG.error(msg) + return False + + if self.deactivate: + msg = _("User {dn!r} successful deactivated on {inst}.").format( + dn=dn, inst=connect_info.url) + else: + msg = _("User {dn!r} successful removed from {inst}.").format( + dn=dn, inst=connect_info.url) + LOG.info(msg) + + return True # ------------------------------------------------------------------------- def setting_user_status(self, inst, dn, attributes): @@ -336,18 +361,12 @@ class RemoveLdapUserApplication(BaseLdapApplication): connect_info = self.cfg.ldap_connection[inst] changes = {} - is_mail_user = False + if 'inetUser' in attributes: + changes['inetUserStatus'] = [(MODIFY_REPLACE, 'inactive')] if 'inetMailUser' in attributes['objectClass']: - is_mail_user = True - LOG.debug(_("User {!r} is a mail user.").format(dn)) - else: - LOG.debug(_("User {!r} is not a mail user.").format(dn)) - - changes['inetUserStatus'] = [(MODIFY_REPLACE, 'inactive')] - if is_mail_user: changes['mailUserStatus'] = [(MODIFY_REPLACE, 'inactive')] - if 'userPassword' in attributes: + if 'userPassword' in attributes and 'inetOrgPerson' in attributes['objectClass']: old_pwd_hash = attributes['userPassword'][0] changes['carLicense'] = [(MODIFY_ADD, old_pwd_hash)] changes['userPassword'] = [(MODIFY_REPLACE, self.raw_empty_passwd)] @@ -358,7 +377,16 @@ class RemoveLdapUserApplication(BaseLdapApplication): LOG.info(_("Updating user info for {dn!r} on {inst} ...").format( dn=dn, inst=connect_info.url)) - self.modify_entry(inst, dn, changes) + try: + self.modify_entry(inst, dn, changes) + except FatalLDAPError as e: + msg = _("{c} on deactivating user {dn!r}: {e}").format( + c=e.__class__.__name__, dn=dn, e=e) + msg += '\n' + _('Changes:') + '\n' + pp(changes) + LOG.error(msg) + return False + + return True # ------------------------------------------------------------------------- def remove_all_memberships(self, inst, dn): @@ -376,7 +404,16 @@ class RemoveLdapUserApplication(BaseLdapApplication): for group_dn in group_dns: LOG.info(_("Removing user {u!r} from group {g!r} ...").format(u=dn, g=group_dn)) changes = {'member': [(MODIFY_DELETE, dn)], } - self.modify_entry(inst, group_dn, changes) + try: + self.modify_entry(inst, group_dn, changes) + except FatalLDAPError as e: + msg = _("{c} on removing user {dn!r} from group {g!r}: {e}").format( + c=e.__class__.__name__, dn=dn, g=group_dn, e=e) + msg += '\n' + _('Changes:') + '\n' + pp(changes) + LOG.error(msg) + return False + + return True # ------------------------------------------------------------------------- def remove_all_unique_memberships(self, inst, dn): @@ -394,7 +431,16 @@ class RemoveLdapUserApplication(BaseLdapApplication): for group_dn in group_dns: LOG.info(_("Removing user {u!r} from group {g!r} ...").format(u=dn, g=group_dn)) changes = {'uniqueMember': [(MODIFY_DELETE, dn)], } - self.modify_entry(inst, group_dn, changes) + try: + self.modify_entry(inst, group_dn, changes) + except FatalLDAPError as e: + msg = _("{c} on removing user {dn!r} from group {g!r}: {e}").format( + c=e.__class__.__name__, dn=dn, g=group_dn, e=e) + msg += '\n' + _('Changes:') + '\n' + pp(changes) + LOG.error(msg) + return False + + return True # ------------------------------------------------------------------------- def remove_all_posixgroup_memberships(self, inst, uid): @@ -416,7 +462,16 @@ class RemoveLdapUserApplication(BaseLdapApplication): for group_dn in group_dns: LOG.info(_("Removing user {u!r} from group {g!r} ...").format(u=uid, g=group_dn)) changes = {'memberUid': [(MODIFY_DELETE, uid)], } - self.modify_entry(inst, group_dn, changes) + try: + self.modify_entry(inst, group_dn, changes) + except FatalLDAPError as e: + msg = _("{c} on removing user {dn!r} from group {g!r}: {e}").format( + c=e.__class__.__name__, dn=uid, g=group_dn, e=e) + msg += '\n' + _('Changes:') + '\n' + pp(changes) + LOG.error(msg) + return False + + return True # ------------------------------------------------------------------------- def remove_all_sudogroup_memberships(self, inst, uid): @@ -438,7 +493,16 @@ class RemoveLdapUserApplication(BaseLdapApplication): for group_dn in group_dns: LOG.info(_("Removing user {u!r} from group {g!r} ...").format(u=uid, g=group_dn)) changes = {'sudoUser': [(MODIFY_DELETE, uid)], } - self.modify_entry(inst, group_dn, changes) + try: + self.modify_entry(inst, group_dn, changes) + except FatalLDAPError as e: + msg = _("{c} on removing user {dn!r} from group {g!r}: {e}").format( + c=e.__class__.__name__, dn=uid, g=group_dn, e=e) + msg += '\n' + _('Changes:') + '\n' + pp(changes) + LOG.error(msg) + return False + + return True # ============================================================================= -- 2.39.5