]> Frank Brehm's Git Trees - pixelpark/pp-admin-tools.git/commitdiff
Adding class LdapConnection to module pp_admintools.ldap_app.
authorFrank Brehm <frank@brehm-online.com>
Thu, 19 May 2022 16:38:28 +0000 (18:38 +0200)
committerFrank Brehm <frank@brehm-online.com>
Thu, 19 May 2022 16:38:28 +0000 (18:38 +0200)
lib/pp_admintools/ldap_app.py
requirements.txt

index fc426be054a0c97161e76811eab857725775a598..9be1033ef5214bf1785d2002bea86b62d5b31a8f 100644 (file)
@@ -18,10 +18,25 @@ except ImportError:
     from pathlib2 import Path
 
 # Third party modules
+
+# ldap3 classes and objects
+from ldap3 import Server, Connection, NONE, DSA, SCHEMA, ALL, IP_V4_PREFERRED, SAFE_SYNC
+from ldap3 import AUTO_BIND_NONE
+from ldap3 import BASE, LEVEL, SUBTREE, DEREF_NEVER, DEREF_SEARCH, DEREF_BASE, DEREF_ALWAYS
+from ldap3 import ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES
+from ldap3 import MODIFY_ADD, MODIFY_DELETE, MODIFY_REPLACE
+from ldap3.core.exceptions import LDAPInvalidDnError, LDAPInvalidValueError
+from ldap3.core.exceptions import LDAPException, LDAPBindError
+
+from ldap3.utils.log import set_library_log_detail_level, ERROR, BASIC, PROTOCOL, NETWORK, EXTENDED
+
+# fb_tools stuff
 from fb_tools.cfg_app import FbConfigApplication
 
 from fb_tools.errors import FbAppError
 
+from fb_tools.obj import FbBaseObject
+
 # Own modules
 from . import __version__ as GLOBAL_VERSION
 
@@ -36,7 +51,7 @@ from .ldap_config import LdapConnectionInfo, LdapConfiguration
 # rom .ldap_config import DEFAULT_PORT_LDAP, DEFAULT_PORT_LDAPS
 from .ldap_config import DEFAULT_TIMEOUT
 
-__version__ = '0.2.2'
+__version__ = '0.3.0'
 LOG = logging.getLogger(__name__)
 
 _ = XLATOR.gettext
@@ -45,10 +60,124 @@ ngettext = XLATOR.ngettext
 
 # =============================================================================
 class LdapAppError(FbAppError):
-    """ Base exception class for all exceptions in all LDAP using application classes."""
+    """Base exception class for all exceptions in all LDAP using application classes."""
     pass
 
 
+# =============================================================================
+class LdapConnection(FbBaseObject):
+    """Class encapsulating exact one LDAP connection."""
+
+    # -------------------------------------------------------------------------
+    def __init__(
+        self, connect_info, get_info=DSA, mode=IP_V4_PREFERRED, connect_timeout=DEFAULT_TIMEOUT,
+            client_strategy=SAFE_SYNC, auto_bind=AUTO_BIND_NONE, read_only=False,
+            receive_timeout=DEFAULT_TIMEOUT, auto_range=True, auto_escape=True, auto_encode=True,
+            appname=None, verbose=0, version=__version__, base_dir=None, initialized=False):
+
+        self.conn = None
+        self.server_opts = {}
+        self.server = None
+        self.client_strategy = client_strategy
+        self.auto_bind = auto_bind
+        self.read_only = bool(read_only)
+        self.receive_timeout = receive_timeout
+        self.auto_range = bool(auto_range)
+        self.auto_escape = bool(auto_escape)
+        self.auto_encode = bool(auto_encode)
+
+        if not isinstance(connect_info, LdapConnectionInfo):
+            msg = _("Given parameter {p!r} is not a {c} object.").format(
+                p='connect_info', c='LdapConnectionInfo')
+            raise LdapAppError(msg)
+
+        self.connect_info = connect_info
+
+        super(LdapConnection, self).__init__(
+            appname=appname, verbose=verbose, version=version,
+            base_dir=base_dir, initialized=False)
+
+        self.server_opts['host'] = connect_info.host
+
+        if connect_info.use_ldaps:
+            self.server_opts['use_ssl'] = True
+            if connect_info.port != 636:
+                self.server_opts['port'] = connect_info.port
+        else:
+            self.server_opts['use_ssl'] = False
+            if connect_info.port != 389:
+                self.server_opts['port'] = connect_info.port
+
+        self.server_opts['get_info'] = get_info
+        self.server_opts['mode'] = mode
+        self.server_opts['connect_timeout'] = connect_timeout
+
+        if self.verbose > 1:
+            msg = _("Connect options to LDAP server")
+            LOG.debug(msg + ': ' + pp(self.server_opts))
+
+        self.server = Server(**server_opts)
+
+    # -------------------------------------------------------------------------
+    def connect(self):
+
+        if self.verbose:
+            LOG.info(_("Connecting to LDAP server {!r} ...").format(self.connect_info.host))
+
+        self.conn = Connection(
+            self.server, self.connect_info.bind_dn, self.connect_info.bind_pw,
+            client_strategy=self.client_strategy, auto_bind=self.auto_bind,
+            read_only=self.read_only, receive_timeout=self.receive_timeout,
+            auto_range=self.auto_range, auto_escape=self.auto_escape, auto_encode=self.auto_encode)
+
+        LOG.debug(_("Connected to LDAP server {!r}, binding to it ...").format(
+            self.connect_info.host))
+
+        self.conn.bind()
+
+        LOG.debug(_("Bounded to LDAP server {!r}.").format(self.connect_info.host))
+
+        if self.verbose > 1:
+            if hasattr(self.server, 'info') and self.server.info:
+                LOG.debug(_("Server information:") + '\n' + pp(self.server.info))
+
+    # -----------------------------------------------------------
+    @property
+    def connected(self):
+        """Indicate, the the server is connected."""
+        if self.conn:
+            return True
+        else:
+            return False
+
+    # -----------------------------------------------------------
+    @property
+    def bound(self):
+        """Indicate, the the server is connected and bound."""
+        if not self.connected:
+            return False
+        if self.conn.closed:
+            return False
+        return self.conn.bound
+
+    # -------------------------------------------------------------------------
+    def unbind(self):
+
+        if not self.connected:
+            return
+
+        if not self.bound:
+            return
+
+        LOG.debug(_("Unbind from LDAP server {!r} ...").format(self.connect_info.host))
+        self.conn.unbind()
+
+    # -------------------------------------------------------------------------
+    def __del__(self):
+
+        self.unbind()
+
+
 # =============================================================================
 class BaseLdapApplication(FbConfigApplication):
     """
index 6016009afce64557777374b84d03ca8ed9ab222b..2a56f0e4cfcc9f176587dedd6b466a8a13e7b92b 100644 (file)
@@ -8,6 +8,7 @@ paramiko
 dnspython
 flake8
 psutil
+ldap3
 setuptools
 hjson
 toml