]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Asking first questions in bin/set-ldap-password
authorFrank Brehm <frank.brehm@pixelpark.com>
Thu, 22 Sep 2022 12:15:04 +0000 (14:15 +0200)
committerFrank Brehm <frank.brehm@pixelpark.com>
Thu, 22 Sep 2022 12:15:04 +0000 (14:15 +0200)
lib/pp_admintools/app/set_ldap_password.py

index 22382e75cb3fdd00a2e8cd39c2b702f30d9ff573..7231a6020e1e161cfe732898dab9f71adeb9f3ce 100644 (file)
@@ -10,26 +10,25 @@ from __future__ import absolute_import
 # Standard modules
 import logging
 import os
-import pwd
 import getpass
 
 # Third party modules
-from ldap3 import MODIFY_REPLACE, MODIFY_ADD, MODIFY_DELETE
+# from ldap3 import MODIFY_REPLACE, MODIFY_ADD, MODIFY_DELETE
+from ldap3.core.exceptions import LDAPBindError
 
 import passlib.apps
 
 # Own modules
-from fb_tools.common import to_bool, is_sequence, pp
+# from fb_tools.common import to_bool, is_sequence, pp
+from fb_tools.common import is_sequence
 
 from ..xlate import XLATOR
 
-from . import AbortAppError, TimeoutOnPromptError
-
-from .ldap import LdapAppError, FatalLDAPError
+from .ldap import LdapAppError
 from .ldap import BaseLdapApplication
 from .ldap import PasswordFileOptionAction
 
-__version__ = '0.2.0'
+__version__ = '0.3.1'
 LOG = logging.getLogger(__name__)
 
 _ = XLATOR.gettext
@@ -116,8 +115,6 @@ class SetLdapPasswordApplication(BaseLdapApplication):
     # -------------------------------------------------------------------------
     def init_arg_parser(self):
 
-        super(SetLdapPasswordApplication, self).init_arg_parser()
-
         app_group = self.arg_parser.add_argument_group(_("Options for {}").format(
             self.appname))
 
@@ -125,7 +122,7 @@ class SetLdapPasswordApplication(BaseLdapApplication):
 
         pw_group.add_argument(
             '-w', '--password', metavar=_("PASSWORD"), dest="current_pw",
-            help=_("Use PASSWORD as the current user password."),
+            help=_("Use {} as the current user password.").format(_("PASSWORD")),
         )
 
         pw_group.add_argument(
@@ -138,13 +135,20 @@ class SetLdapPasswordApplication(BaseLdapApplication):
         pw_group.add_argument(
             '-y', '--password-file', metavar=_('PASSWORD_FILE'), dest="current_pw_file",
             must_absolute=False, action=PasswordFileOptionAction,
-            help=_("Use contents of PASSWORD_FILE as the current user password."),
+            help=_("Use contents of {} as the current user password.").format(_('PASSWORD_FILE')),
+        )
+
+        app_group.add_argument(
+            '-n', '--new-password', metavar=_("PASSWORD"), dest="new_pw",
+            help=_(
+                "Use {} as the new user password. If not given, it will be "
+                "asked for it.").format(_("PASSWORD")),
         )
 
         user_help = _(
-                "The user, which password in the given LDAP instance should be changed. "
-                "It may be given by its Uid (the alphanumeric POSIX name), its mail address "
-                "or its LDAP DN.")
+            "The user, which password in the given LDAP instance should be changed. "
+            "It may be given by its Uid (the alphanumeric POSIX name), its mail address "
+            "or its LDAP DN.")
         if self.current_user:
             user_help += ' ' + _(
                 "If not given, then your current user name {!r} will be used.").format(
@@ -160,6 +164,8 @@ class SetLdapPasswordApplication(BaseLdapApplication):
             app_group.add_argument(
                 'user', metavar=_('USER'), help=user_help)
 
+        super(SetLdapPasswordApplication, self).init_arg_parser()
+
     # -------------------------------------------------------------------------
     def post_init(self):
         """
@@ -195,6 +201,9 @@ class SetLdapPasswordApplication(BaseLdapApplication):
             self.current_password = self.read_password_file(self.args.current_pw_file)
             self.do_user_bind = True
 
+        if self.args.new_pw:
+            self.new_password = self.args.new_pw
+
         inst = self.ldap_instances[0]
         ldap = self.cfg.ldap_connection[inst]
         if not ldap.is_admin or ldap.readonly:
@@ -206,19 +215,108 @@ class SetLdapPasswordApplication(BaseLdapApplication):
         LOG.debug("Pre running tasks ...")
         super(SetLdapPasswordApplication, self).pre_run()
 
+    # -------------------------------------------------------------------------
+    def _run(self):
+
+        inst = self.ldap_instances[0]
+        connect_info = self.cfg.ldap_connection[inst]
+        msg = _("Using LDAP instance {inst!r} - {url}.").format(inst=inst, url=connect_info.url)
+        LOG.info(msg)
+
+        self.user_dn = self.search_user_dn()
+
         if self.do_user_bind and not self.current_password:
             first_prompt = _("Current password of user {!r}:").format(self.user_uid) + ' '
             second_prompt = _('Repeat password:') + ' '
             self.current_password = self.get_password(
                 first_prompt, second_prompt, may_empty=False, repeat=False)
 
+        if self.do_user_bind:
+            self.test_user_bind()
+
+        if not self.new_password:
+            first_prompt = _("New password of user {!r}:").format(self.user_uid) + ' '
+            second_prompt = _('Repeat password:') + ' '
+            self.new_password = self.get_password(
+                first_prompt, second_prompt, may_empty=False, repeat=True)
+
     # -------------------------------------------------------------------------
-    def _run(self):
+    def test_user_bind(self):
 
         inst = self.ldap_instances[0]
-        ldap = self.cfg.ldap_connection[inst]
-        msg = _("Using LDAP instance {inst!r} - {url}.").format(inst=inst, url=ldap.url)
-        LOG.info(msg)
+        connect_info = self.cfg.ldap_connection[inst]
+
+        msg = _(
+            "Testing connect to LDAP-Server {url} with current user {dn!r} and "
+            "password ...").format(url=connect_info.url, dn=self.user_dn)
+        LOG.debug(msg)
+
+        ldap_server = None
+        ldap_connection = None
+
+        try:
+            ldap_server = self.get_ldap_server_obj(inst)
+            ldap_connection = self.connect_to_ldap_server(
+                ldap_server, inst, bind_dn=self.user_dn, bind_pw=self.current_password)
+            msg = _("Successful connected as {dn!r} to {url}.").format(
+                url=connect_info.url, dn=self.user_dn)
+            LOG.debug(msg)
+
+        except LDAPBindError as e:
+            msg = _("Could not connect to {url} as {dn!r}: {e}").format(
+                url=connect_info.url, dn=self.user_dn, e=e)
+            self.exit(6, msg)
+
+        finally:
+            if ldap_connection:
+                if self.verbose > 1:
+                    LOG.debug(_("Unbinding from LDAP server {!r} ...").format(connect_info.url))
+                ldap_connection.unbind()
+                ldap_connection = None
+            del ldap_connection
+
+            if ldap_server:
+                if self.verbose > 1:
+                    LOG.debug(_("Disconnecting from LDAP server {!r} ...").format(
+                        connect_info.url))
+            del ldap_server
+
+    # -------------------------------------------------------------------------
+    def search_user_dn(self):
+        """Searching the LDAP DN of the user, whos password should be changed."""
+
+        inst = self.ldap_instances[0]
+        connect_info = self.cfg.ldap_connection[inst]
+
+        dns = self.get_user_dn(self.user_uid, inst)
+        if dns:
+            if self.verbose > 2:
+                msg = _("Got DN {dn!r} for user {user!r} in LDAP instance {inst}.").format(
+                    dn=dns, user=self.user_uid, inst=connect_info.url)
+                LOG.debug(msg)
+            if is_sequence(dns):
+                if len(dns) > 1:
+                    msg = _("Found {nr} entries for user {u!r} in LDAP instance {i}.").format(
+                        nr=len(dns), u=self.user_uid, i=connect_info.url)
+                    msg += ' ' + _(
+                        "Please use another username, or use the correct DN from the following "
+                        "list as a parameter for this script instead of the username:")
+                    for dn in dns:
+                        msg += '\n * ' + dn
+                    LOG.warn(msg)
+                    self.exit(7)
+                    return
+                self.user_dn = dns[0]
+            else:
+                self.user_dn = dns
+        else:
+            msg = _("Did not found user {user!r} in LDAP instance {inst}.").format(
+                user=self.user_uid, inst=connect_info.url)
+            LOG.error(msg)
+            self.exit(7)
+
+        LOG.info(_("Changing the password of user {dn!r} in LDAP instance {inst}.").format(
+            dn=self.user_dn, inst=connect_info.url))
 
 
 # =============================================================================