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
# 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
# =============================================================================
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):
"""