示例#1
0
class DatabaseWrapper(BaseDatabaseWrapper):
    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)

        self.charset = "utf-8"
        self.creation = DatabaseCreation(self)
        self.features = DatabaseFeatures(self)
        if django.VERSION > (1, 4):
            self.ops = DatabaseOperations(self)
        else:
            self.ops = DatabaseOperations()
        self.settings_dict['SUPPORTS_TRANSACTIONS'] = False

    def close(self):
        pass

    def _commit(self):
        pass

    def _cursor(self):
        if self.connection is None:
#            self.connection = ldap.initialize(self.settings_dict['NAME'])
            self.connection = ReconnectLDAPObject(self.settings_dict['NAME'])
            self.connection.simple_bind_s(
                self.settings_dict['USER'],
                self.settings_dict['PASSWORD'])
        return DatabaseCursor(self.connection)

    def _rollback(self):
        pass

    def add_s(self, dn, modlist):
        cursor = self._cursor()
        return cursor.connection.add_s(dn.encode(self.charset), modlist)

    def delete_s(self, dn):
        cursor = self._cursor()
        return cursor.connection.delete_s(dn.encode(self.charset))

    def modify_s(self, dn, modlist):
        cursor = self._cursor()
        return cursor.connection.modify_s(dn.encode(self.charset), modlist)

    def rename_s(self, dn, newrdn):
        cursor = self._cursor()
        return cursor.connection.rename_s(dn.encode(self.charset), newrdn.encode(self.charset))

    def search_s(self, base, scope, filterstr='(objectClass=*)',attrlist=None):
        logger.debug("base: %s; scope: %s; filter: %s, attrs: %s" % (base, scope, filterstr, attrlist))
        cursor = self._cursor()
        results = cursor.connection.search_s(base, scope, filterstr.encode(self.charset), attrlist)
        output = []
        for dn, attrs in results:
            output.append((dn.decode(self.charset), attrs))
        return output
示例#2
0
 def simple_bind_s(self, who='', cred='', serverctrls=None,
                   clientctrls=None):
     res = ReconnectLDAPObject.simple_bind_s(self, who, cred, serverctrls,
                                             clientctrls)
     self.connected = True
     self.who = who
     self.cred = cred
     return res
示例#3
0
    def _cursor(self):
        if self.connection is None:
#            self.connection = ldap.initialize(self.settings_dict['NAME'])
            self.connection = ReconnectLDAPObject(self.settings_dict['NAME'])
            self.connection.simple_bind_s(
                self.settings_dict['USER'],
                self.settings_dict['PASSWORD'])
        return DatabaseCursor(self.connection)
示例#4
0
文件: __init__.py 项目: keis/ldappool
 def unbind_ext_s(self, serverctrls=None, clientctrls=None):
     try:
         return ReconnectLDAPObject.unbind_ext_s(self, serverctrls,
                                                 clientctrls)
     finally:
         self.connected = False
         self.who = None
         self.cred = None
示例#5
0
 def connect(self):
     try:
         self.connection = ReconnectLDAPObject(self.uri)
         if self.user is not None:
             self.connection.simple_bind_s(self.user, self.password)
     except:
         logger.exception("LDAP connection failed")
         return False
     return True
示例#6
0
文件: __init__.py 项目: keis/ldappool
 def simple_bind_s(self, who='', cred='', serverctrls=None,
                   clientctrls=None):
     res = ReconnectLDAPObject.simple_bind_s(self, who, cred, serverctrls,
                                             clientctrls)
     self.connected = True
     self.who = who
     self.cred = cred
     if self._connection_time is None:
         self._connection_time = time.time()
     return res
示例#7
0
    def ensure_connection(self):
        if self.connection is None:
            #self.connection = ldap.initialize(self.settings_dict['NAME'])
            self.connection = ReconnectLDAPObject(self.settings_dict['NAME'])

            options = self.settings_dict.get('CONNECTION_OPTIONS', {})
            for opt, value in options.items():
                self.connection.set_option(opt, value)

            if self.settings_dict.get('TLS', False):
                self.connection.start_tls_s()

            self.connection.simple_bind_s(
                self.settings_dict['USER'],
                self.settings_dict['PASSWORD'])
示例#8
0
def main():
    # Skip handshake when testing manually
    if stdin.isatty():
        print('stdin is tty, skipping handshake')
    else:
        if stdin.readline() == 'HELO\t1\n':
            output('OK', 'pdns-ldap-py is ready')
        else:
            output('FAIL')
            stdin.readline()
            exit(1)

    # XXX Global variable
    global connection
    connection = ReconnectLDAPObject(config.uri, retry_max=4, retry_delay=5)
    # XXX A little ugly here
    connection.deref = ldap.DEREF_FINDING

    if config.start_tls:
        ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
        connection.start_tls_s()

    connection.bind_s(config.binddn, config.bindpw)

    while True:
        line = stdin.readline()
        if len(line) == 0:
            continue
        fields = line.rstrip('\n').split('\t')
        try:
            if respond(fields):
                output('END')
            else:
                output('FAIL')
        except Exception:
            output('FAIL')
            output('LOG', 'Shutting down on unexpected error. Traceback:')
            tb_lines = traceback.format_exc().split('\n')
            for line in tb_lines:
                output('LOG', line)
            break
示例#9
0
文件: __init__.py 项目: keis/ldappool
 def __init__(self, *args, **kw):
     ReconnectLDAPObject.__init__(self, *args, **kw)
     self.connected = False
     self.who = ''
     self.cred = ''
     self._connection_time = None
示例#10
0
class DatabaseWrapper(BaseDatabaseWrapper):
    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)

        self.charset = "utf-8"
        self.creation = DatabaseCreation(self)
        self.features = DatabaseFeatures(self)
        if django.VERSION > (1, 4):
            self.ops = DatabaseOperations(self)
        else:
            self.ops = DatabaseOperations()
        self.settings_dict['SUPPORTS_TRANSACTIONS'] = False

    def close(self):
        if hasattr(self, 'validate_thread_sharing'):
            # django >= 1.4
            self.validate_thread_sharing()
        if self.connection is not None:
            self.connection.unbind_s()
            self.connection = None

    def _commit(self):
        pass

    def _cursor(self):
        if self.connection is None:
#            self.connection = ldap.initialize(self.settings_dict['NAME'])
            self.connection = ReconnectLDAPObject(self.settings_dict['NAME'])
            self.connection.simple_bind_s(
                self.settings_dict['USER'],
                self.settings_dict['PASSWORD'])

        return DatabaseCursor(self.connection)

    def _rollback(self):
        pass

    def add_s(self, dn, modlist):
        cursor = self._cursor()
        return cursor.connection.add_s(dn.encode(self.charset), modlist)

    def delete_s(self, dn):
        cursor = self._cursor()
        return cursor.connection.delete_s(dn.encode(self.charset))

    def modify_s(self, dn, modlist):
        cursor = self._cursor()
        return cursor.connection.modify_s(dn.encode(self.charset), modlist)

    def rename_s(self, dn, newrdn):
        cursor = self._cursor()
        return cursor.connection.rename_s(dn.encode(self.charset),
                                          newrdn.encode(self.charset))

    def search_s(self, base, scope, filterstr='(objectClass=*)',
                 attrlist=None):
        logger.debug("base: %s; scope: %s; filter: %s, attrs: %s" % (base, scope, filterstr, attrlist))
        cursor = self._cursor()
        results = cursor.connection.search_s(base, scope,
                                             filterstr.encode(self.charset),
                                             attrlist)
        output = []
        for dn, attrs in results:
            output.append((dn.decode(self.charset), attrs))
        return output
示例#11
0
def ldap_connect(settings, use_cache=True):
    """Establishes an LDAP connection.

    Establishes a connection to the LDAP server from the `uri` in the
    ``settings``.

    To establish a connection, the settings must be specified:
     - ``uri``: valid URI which points to a LDAP server,
     - ``bind_dn``: `dn` used to initially bind every LDAP connection
     - ``bind_password``" password used for the initial bind
     - ``tls``: ``True`` if the connection should use TLS encryption
     - ``starttls``: ``True`` to negotiate TLS with the server

    `Note`: ``starttls`` is ignored if the URI uses LDAPS and ``tls`` is
    set to ``True``.

    This function re-uses an existing LDAP connection if there is one
    available in the application context, unless caching is disabled.

    :param settings: dict -- The settings for a LDAP provider.
    :param use_cache: bool -- If the connection should be cached.
    :return: The ldap connection.
    """

    if use_cache:
        cache = _get_ldap_cache()
        cache_key = frozenset(
            (k, hash(v)) for k, v in iteritems(settings) if k in conn_keys)
        conn = cache.get(cache_key)
        if conn is not None:
            return conn

    uri_info = urlparse(settings['uri'])
    use_ldaps = uri_info.scheme == 'ldaps'
    credentials = (settings['bind_dn'], settings['bind_password'])
    ldap_connection = ReconnectLDAPObject(settings['uri'])
    ldap_connection.protocol_version = ldap.VERSION3
    ldap_connection.set_option(ldap.OPT_REFERRALS, 0)
    ldap_connection.set_option(
        ldap.OPT_X_TLS,
        ldap.OPT_X_TLS_DEMAND if use_ldaps else ldap.OPT_X_TLS_NEVER)
    if settings['verify_cert'] and settings['cert_file']:
        ldap_connection.set_option(ldap.OPT_X_TLS_CACERTFILE,
                                   settings['cert_file'])
    ldap_connection.set_option(
        ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_DEMAND
        if settings['verify_cert'] else ldap.OPT_X_TLS_ALLOW)
    # force the creation of a new TLS context. This must be the last TLS option.
    # see: http://stackoverflow.com/a/27713355/298479
    ldap_connection.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
    if use_ldaps and settings['starttls']:
        warn(
            "Unable to start TLS, LDAP connection already secured over SSL (LDAPS)"
        )
    elif settings['starttls']:
        ldap_connection.start_tls_s()
    # TODO: allow anonymous bind
    ldap_connection.simple_bind_s(*credentials)
    if use_cache:
        cache[cache_key] = ldap_connection
    return ldap_connection
示例#12
0
class DatabaseWrapper(BaseDatabaseWrapper):
    vendor = 'ldap'

    # NOTE: These are copied from the mysql DatabaseWrapper
    operators = {
        'exact': '= %s',
        'iexact': 'LIKE %s',
        'contains': 'LIKE BINARY %s',
        'icontains': 'LIKE %s',
        'regex': 'REGEXP BINARY %s',
        'iregex': 'REGEXP %s',
        'gt': '> %s',
        'gte': '>= %s',
        'lt': '< %s',
        'lte': '<= %s',
        'startswith': 'LIKE BINARY %s',
        'endswith': 'LIKE BINARY %s',
        'istartswith': 'LIKE %s',
        'iendswith': 'LIKE %s',
    }

    def __init__(self, *args, **kwargs):
        super(DatabaseWrapper, self).__init__(*args, **kwargs)

        self.charset = "utf-8"
        self.creation = DatabaseCreation(self)
        self.features = DatabaseFeatures(self)
        if django.VERSION > (1, 4):
            self.ops = DatabaseOperations(self)
        else:
            self.ops = DatabaseOperations()
        self.settings_dict['SUPPORTS_TRANSACTIONS'] = True
        self.autocommit = True

    def close(self):
        if hasattr(self, 'validate_thread_sharing'):
            # django >= 1.4
            self.validate_thread_sharing()
        if self.connection is not None:
            self.connection.unbind_s()
            self.connection = None

    def ensure_connection(self):
        if self.connection is None:
            #self.connection = ldap.initialize(self.settings_dict['NAME'])
            self.connection = ReconnectLDAPObject(self.settings_dict['NAME'])

            options = self.settings_dict.get('CONNECTION_OPTIONS', {})
            for opt, value in options.items():
                self.connection.set_option(opt, value)

            if self.settings_dict.get('TLS', False):
                self.connection.start_tls_s()

            self.connection.simple_bind_s(
                self.settings_dict['USER'],
                self.settings_dict['PASSWORD'])

    def _commit(self):
        pass

    def _cursor(self):
        self.ensure_connection()
        return DatabaseCursor(self.connection)

    def _rollback(self):
        pass

    def _set_autocommit(self, autocommit):
        pass

    def add_s(self, dn, modlist):
        cursor = self._cursor()
        return cursor.connection.add_s(dn.encode(self.charset), modlist)

    def delete_s(self, dn):
        cursor = self._cursor()
        return cursor.connection.delete_s(dn.encode(self.charset))

    def modify_s(self, dn, modlist):
        cursor = self._cursor()
        return cursor.connection.modify_s(dn.encode(self.charset), modlist)

    def rename_s(self, dn, newrdn):
        cursor = self._cursor()
        return cursor.connection.rename_s(dn.encode(self.charset),
                                          newrdn.encode(self.charset))

    def search_s(self, base, scope, filterstr='(objectClass=*)',
                 attrlist=None):
        cursor = self._cursor()
        results = cursor.connection.search_s(base, scope,
                                             filterstr.encode(self.charset),
                                             attrlist)
        output = []
        for dn, attrs in results:
            # skip referrals
            if dn is not None:
                output.append((dn.decode(self.charset), attrs))
        return output
示例#13
0
class LDAPUser(object):

    EPOCH_DATE = datetime.datetime.fromtimestamp(0)
    LOGIN_SHELL = "/bin/bash"
    HOME_BASE_DIRECTORY = "/home"
    GROUP_ID_NUMBER = None
    CREATOR = None
    VERIFY_CREATOR = True

    password_compile = re.compile("^{(%s)}(\S+)$" % "|".join(SUPPORT_METHOD))

    def __init__(self,
                 ldap_uri,
                 base_dn,
                 admin_user,
                 admin_password,
                 home_base_directory=None,
                 group_id=None):
        self.ldap_uri = ldap_uri
        self.ldap_com = ReconnectLDAPObject(ldap_uri,
                                            retry_max=10,
                                            retry_delay=3)
        # self.ldap_com = ldap.initialize(ldap_uri)
        self.ldap_base_dn = base_dn
        if home_base_directory is not None:
            self.HOME_BASE_DIRECTORY = home_base_directory
        if group_id is not None:
            self.GROUP_ID_NUMBER = "%s" % group_id
        self.ldap_admin = "cn=%s,%s" % (admin_user, self.ldap_base_dn)
        self.people_base_cn = "ou=People,%s" % self.ldap_base_dn
        self.ldap_com.bind_s(self.ldap_admin, admin_password)

    def __get_next_uid_number(self):
        filter_str = "uid=*"
        attributes = ["uidNumber", "gidNumber"]
        items = self.ldap_com.search_s(self.people_base_cn, LDAP_SCOPE_SUBTREE,
                                       filter_str, attributes)
        max_number = 1000
        for item in items:
            if "uidNumber" in item[1]:
                u_number = int(item[1]["uidNumber"][0])
                if max_number < u_number:
                    max_number = u_number
        return max_number + 1

    def delete_user(self, user_name):
        if self.exist(user_name) is None:
            return True
        dn = "uid=%s,%s" % (user_name, self.people_base_cn)
        return self.ldap_com.delete_s(dn)

    def add_user(self,
                 user_name,
                 uid_number=None,
                 gid_number=None,
                 home_directory=None):
        dn = "uid=%s,%s" % (user_name, self.people_base_cn)
        attributes = dict()
        for key in ("uid", "cn", "sn"):
            attributes[key] = encode(user_name)
        attributes["objectClass"] = [
            "top", "person", "inetOrgPerson", "posixAccount",
            "organizationalPerson", "shadowAccount"
        ]
        if uid_number is None:
            attributes["uidNumber"] = encode(self.__get_next_uid_number())
        else:
            attributes["uidNumber"] = encode(uid_number)
        if gid_number is None:
            attributes["gidNumber"] = encode(self.GROUP_ID_NUMBER)
        else:
            attributes["gidNumber"] = encode(gid_number)
        if attributes["gidNumber"] is None:
            raise LDAPError("please set gidNumber")
        if home_directory is None:
            home_directory = os.path.join(self.HOME_BASE_DIRECTORY, user_name)
        attributes["homeDirectory"] = encode(home_directory)
        attributes["loginShell"] = encode(self.LOGIN_SHELL)
        if self.CREATOR is not None:
            attributes["givenName"] = encode(self.CREATOR)
        mod_list = ldap.modlist.addModlist(attributes)
        self.ldap_com.add_s(dn, mod_list)

    def expire_user(self, user_name, shadow_expire=None):
        user_entry = self.exist(user_name)
        if user_entry is None:
            return False
        old_attributes = user_entry[1]
        attributes = dict(**old_attributes)
        if shadow_expire is None:
            attributes["shadowExpire"] = [
                "%s" % (datetime.datetime.now() - self.EPOCH_DATE).days
            ]
        else:
            attributes["shadowExpire"] = ""
        mod_list = ldap.modlist.modifyModlist(old_attributes, attributes)
        return self.ldap_com.modify_s(user_entry[0], mod_list)

    def block_user(self, user_name):
        return self.expire_user(user_name)

    def unlock_user(self, user_name):
        user_entry = self.exist(user_name, "pwdAccountLockedTime",
                                "shadowExpire")
        if user_entry is None:
            return False
        old_attributes = user_entry[1]
        attributes = dict(**old_attributes)
        if "pwdAccountLockedTime" in attributes:
            attributes["pwdAccountLockedTime"] = ""
        if "shadowExpire" in attributes:
            attributes["shadowExpire"] = ""
        mod_list = ldap.modlist.modifyModlist(old_attributes, attributes)
        return self.ldap_com.modify_s(user_entry[0], mod_list)

    def _verify_creator(self, user_entry):
        if self.CREATOR is None or self.VERIFY_CREATOR is False:
            return True
        if "givenName" not in user_entry:
            return False
        return self.CREATOR in user_entry["givenName"]

    def exist(self, user_name, *attributes):
        l_attributes = set(attributes)
        sr = self.ldap_com.search_s(self.ldap_base_dn, LDAP_SCOPE_SUBTREE,
                                    "uid=%s" % user_name, l_attributes)
        if len(sr) <= 0:
            return None
        return sr[0]

    def verify_password(self, password, ldap_password):
        match_r = self.password_compile.match(ldap_password)
        if match_r is not None:
            method = match_r.groups()[0]
            cipher_text = match_r.groups()[1]
            return verify(method, password, cipher_text)
        return password == ldap_password

    def login(self, user_name, password):
        user_entry = self.exist(user_name)
        if user_entry is None:
            return False
        attr = user_entry[1]
        if "userPassword" not in attr:
            return False
        ldap_password = attr["userPassword"][0]
        return self.verify_password(password, ldap_password)

    def login2(self, user_name, password):
        user_entry = self.exist(user_name)
        if user_entry is None:
            return False
        attr = user_entry[1]
        if "userPassword" not in attr:
            return False
        try:
            self.ldap_com.simple_bind_s(user_entry[0], password)
            return True
        except ldap.INVALID_CREDENTIALS:
            return False

    def set_password(self, user_name, new_password):
        user_entry = self.exist(user_name)
        if user_entry is None:
            return False
        if self._verify_creator(user_entry) is False:
            return False
        pr = self.ldap_com.passwd_s(user_entry[0], None, new_password)
        if pr[0] is None and pr[1] is None:
            return True
        return False
示例#14
0
  def __init__(self,uri,
    trace_level=0,trace_file=None,trace_stack_limit=5,
    retry_max=1,retry_delay=60.0,
    who='',cred='',
    start_tls=1,
    tls_cacertfile=None,tls_cacertdir=None,
    tls_clcertfile=None,tls_clkeyfile=None,
  ):
    """
    Return LDAPObject instance by opening LDAP connection to
    LDAP host specified by LDAP URL.

    Unlike ldap.initialize() this function also trys to bind
    explicitly with the bind DN and credential given as parameter,
    probe the supported LDAP version and trys to use
    StartTLS extended operation if this was specified.

    Parameters like ReconnectLDAPObject.__init__() with these
    additional arguments:
    who,cred
        The Bind-DN and credential to use for simple bind
        right after connecting.
    start_tls
        Determines if StartTLS extended operation is tried
        on a LDAPv3 server and if the LDAP URL scheme is ldap:.
        If LDAP URL scheme is not ldap: (e.g. ldaps: or ldapi:)
        this parameter is ignored.
        0       Don't use StartTLS ext op
        1       Try StartTLS ext op but proceed when unavailable
        2       Try StartTLS ext op and re-raise exception if it fails
    tls_cacertfile

    tls_clcertfile

    tls_clkeyfile

    """
    # Initialize LDAP connection
    ReconnectLDAPObject.__init__(
      self,uri,
      trace_level=trace_level,
      trace_file=trace_file,
      trace_stack_limit=trace_stack_limit,
      retry_max=retry_max,
      retry_delay=retry_delay
    )
    # Set protocol version to LDAPv3
    self.protocol_version = ldap.VERSION3
    self.started_tls = 0
    try:
        self.simple_bind_s(who,cred)
    except ldap.PROTOCOL_ERROR:
        # Drop connection completely
        self.unbind_s() ; del self._l
        self._l = ldap.functions._ldap_function_call(_ldap.initialize,self._uri)
        self.protocol_version = ldap.VERSION2
        self.simple_bind_s(who,cred)
    # Try to start TLS if requested
    if start_tls>0 and uri[:5]=='ldaps:':
        if self.protocol_version>=ldap.VERSION3:
            try:
                self.start_tls_s()
            except (ldap.PROTOCOL_ERROR,ldap.CONNECT_ERROR):
                if start_tls>=2:
                    # Application does not accept clear-text connection
                    # => re-raise exception
                    raise
            else:
                self.started_tls = 1
        else:
            if start_tls>=2:
                raise ValueError,"StartTLS extended operation only possible on LDAPv3+ server!"
    if self.protocol_version==ldap.VERSION2 or (who and cred):
        self.simple_bind_s(who,cred)
示例#15
0
class CSHLDAP:
    __domain__ = "csh.rit.edu"

    def __init__(self,
                 bind_dn,
                 bind_pw,
                 batch_mods=False,
                 sasl=False,
                 ro=False):
        """Handler for bindings to CSH LDAP.

        Keyword arguments:
        batch_mods -- whether or not to batch LDAP writes (default False)
        sasl -- whether or not to bypass bind_dn and bind_pw and use SASL bind
        ro -- whether or not CSH LDAP is in read only mode (default False)
        """
        if ro:
            print("########################################\n"
                  "#                                      #\n"
                  "#    CSH LDAP IS IN READ ONLY MODE     #\n"
                  "#                                      #\n"
                  "########################################")
        ldap_srvs = srvlookup.lookup("ldap", "tcp", self.__domain__)
        ldap_uris = ""
        for uri in ldap_srvs:
            ldap_uris += "ldaps://" + uri.hostname + ","
        self.__con__ = ReconnectLDAPObject(ldap_uris)
        if sasl:
            self.__con__.sasl_non_interactive_bind_s('')
        else:
            self.__con__.simple_bind_s(bind_dn, bind_pw)
        self.__mod_queue__ = {}
        self.__pending_mod_dn__ = []
        self.__batch_mods__ = batch_mods
        self.__ro__ = ro

    def get_member(self, val, uid=False):
        """Get a CSHMember object.

        Arguments:
        val -- the uuid (or uid) of the member

        Keyword arguments:
        uid -- whether or not val is a uid (default False)
        """
        return CSHMember(self, val, uid)

    def get_member_ibutton(self, val):
        """Get a CSHMember object.

        Arguments:
        val -- the iButton ID of the member

        Returns:
        None if the iButton supplied does not correspond to a CSH Member
        """
        members = self.__con__.search_s(CSHMember.__ldap_user_ou__,
                                        ldap.SCOPE_SUBTREE,
                                        "(ibutton=%s)" % val, ['ipaUniqueID'])
        if members:
            return CSHMember(self,
                             members[0][1]['ipaUniqueID'][0].decode('utf-8'),
                             False)
        return None

    def get_group(self, val):
        """Get a CSHGroup object.

        Arguments:
        val -- the cn of the group

        """
        return CSHGroup(self, val)

    def get_con(self):
        """Get the PyLDAP Connection"""
        return self.__con__

    def get_directorship_heads(self, val):
        """Get the head of a directorship

        Arguments:
        val -- the cn of the directorship
        """

        __ldap_group_ou__ = "cn=groups,cn=accounts,dc=csh,dc=rit,dc=edu"

        res = self.__con__.search_s(__ldap_group_ou__, ldap.SCOPE_SUBTREE,
                                    "(cn=eboard-%s)" % val, ['member'])

        ret = []
        for member in res[0][1]['member']:
            try:
                ret.append(member.decode('utf-8'))
            except UnicodeDecodeError:
                ret.append(member)
            except KeyError:
                continue

        return [
            CSHMember(self,
                      dn.split('=')[1].split(',')[0], True) for dn in ret
        ]

    def enqueue_mod(self, dn, mod):
        """Enqueue a LDAP modification.

        Arguments:
        dn -- the distinguished name of the object to modify
        mod -- an ldap modfication entry to enqueue
        """
        # mark for update
        if dn not in self.__pending_mod_dn__:
            self.__pending_mod_dn__.append(dn)
            self.__mod_queue__[dn] = []

        self.__mod_queue__[dn].append(mod)

    def flush_mod(self):
        """Flush all pending LDAP modifications."""
        for dn in self.__pending_mod_dn__:
            try:
                if self.__ro__:
                    for mod in self.__mod_queue__[dn]:
                        if mod[0] == ldap.MOD_DELETE:
                            mod_str = "DELETE"
                        elif mod[0] == ldap.MOD_ADD:
                            mod_str = "ADD"
                        else:
                            mod_str = "REPLACE"
                        print("{} VALUE {} = {} FOR {}".format(
                            mod_str, mod[1], mod[2], dn))
                else:
                    self.__con__.modify_s(dn, self.__mod_queue__[dn])
            except ldap.TYPE_OR_VALUE_EXISTS:
                print("Error! Conflicting Batch Modification: %s" %
                      str(self.__mod_queue__[dn]))
                continue
            except ldap.NO_SUCH_ATTRIBUTE:
                print("Error! Conflicting Batch Modification: %s" %
                      str(self.__mod_queue__[dn]))
                continue
            self.__mod_queue__[dn] = None
        self.__pending_mod_dn__ = []
示例#16
0
class LDAPLookup:
    """ Wraps ldap library query

    Args:
        ldap_url: LDAP server in the form of 'ldap://ldaphost'
        ldap_base: LDAP base for search ('ou=users,dc=department,dc=org')
        ldap_retry_max: LDAP number of reconnect attempts
        ldap_retry_delay: LDAP seconds between reconnect attempts
    """

    DEFAULT_QUERY_FIELDS: List[str] = ['uid']
    DEFAULT_RETURN_FIELDS: List[str] = ['uid', 'cn', 'mail']

    def __init__(self,
                 ldap_url: str,
                 ldap_base: str,
                 ldap_retry_max: int = 3,
                 ldap_retry_delay: float = 5.0):
        self.ldap_url = ldap_url
        self.ldap_base = ldap_base

        self.ldap_retry_max = ldap_retry_max
        self.ldap_retry_delay = ldap_retry_delay

        self._ldap_client = None  # lazy client init

    @property
    def ldap_client(self):
        if not self._ldap_client:
            self._ldap_client = ReconnectLDAPObject(
                self.ldap_url,
                retry_max=self.ldap_retry_max,
                retry_delay=self.ldap_retry_delay)

            self._ldap_client.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
            self._ldap_client.set_option(ldap.OPT_REFERRALS, 0)

        return self._ldap_client

    def query(
        self,
        query: str,
        query_fields: List[str] = None,
        return_fields: List[str] = None,
        raise_exception: bool = False,
    ) -> List[dict]:
        """ Perform LDAP query

        Args:
            query: String to search
            query_fields: Which LDAP fields to search in
            return_fields: What LDAP fields to return
            raise_exception: If True - raise exception if no results

        Returns:
            List if dicts with LDAP results

            Example:

            [
                {'uid': 'us1', 'cn': 'user 1', 'mail': '*****@*****.**'},

                {'uid': 'us2', 'cn': 'user 2', 'mail': '*****@*****.**'}

            ]

        Raises:
            LDAPQueryNotFoundError: No result while raise_exception True
        """

        query = query.rstrip('*')

        if not query_fields:
            query_fields = self.DEFAULT_QUERY_FIELDS

        if not return_fields:
            return_fields = self.DEFAULT_RETURN_FIELDS

        if len(query_fields) == 1:
            query_string = f'{query_fields[0]}={query}'
        else:
            # Example: (|(cn=query*)(sn=query*)(mail=query*))
            field_queries = [
                f'({field}={query}*)' for field in query_fields if field
            ]
            query_string = '(|%s)' % ''.join(field_queries)

        res = self.ldap_client.search_s(self.ldap_base, ldap.SCOPE_SUBTREE,
                                        query_string, return_fields)

        if raise_exception and not res:
            raise LDAPQueryNotFoundError(f'Query not found in LDAP: {query}')

        # Extract first values, convert from bytes
        return [{k: v[0].decode('utf-8')
                 for k, v in record[1].items()} for record in res]
示例#17
0
class LdapLookup(object):

    connection = None
    uri = None
    user = None
    password = None

    user_searchbase = ''
    group_searchbase = ''

    user_searchfilter = {'objectClass': 'user'}
    group_searchfilter = {'objectClass': 'group'}

    def __init__(self, **kw):
        for key, item in kw.items():
            if hasattr(self, key) and not key.startswith('_'):
                setattr(self, key, item)

    def connect(self):
        try:
            self.connection = ReconnectLDAPObject(self.uri)
            if self.user is not None:
                self.connection.simple_bind_s(self.user, self.password)
        except:
            logger.exception("LDAP connection failed")
            return False
        return True

    def get_safe(self, basedn, **kw):
        return self.get(basedn, **dict([(ldap_escape(k), ldap_escape(v)) for k, v in kw.iteritems()]))

    def get(self, basedn, **kw):
        search = '(&%s)' % ''.join(['(%s=%s)' % item for item in kw.iteritems()])
        result = self.connection.search_s(basedn, ldap.SCOPE_SUBTREE, search)
        return result

    def get_dn(self, dn):
        res = self.connection.search_s(dn, ldap.SCOPE_BASE, '(objectClass=*)')
        if len(res) == 0:
            return None
        else:
            return res[0]

    def get_users(self):
        return self.get(self.user_searchbase, **self.user_searchfilter)

    def get_user(self, username):
        search = self.user_searchfilter.copy()
        if '@' in username:
            search['userPrincipalName'] = username
        else:
            search['sAMAccountName'] = username

        res = self.get_safe(self.user_searchbase, **search)
        if len(res) == 0:
            return None
        else:
            return res[0]

    def get_groups(self):
        return self.get(self.group_searchbase, **self.group_searchfilter)

    def get_group(self, groupname):
        search = self.group_searchfilter.copy()
        search['name'] = groupname
        res = self.get_safe(self.group_searchbase, **search)

        if len(res) == 0:
            return None
        else:
            return res[0]
示例#18
0
 def __init__(self, *args, **kw):
     ReconnectLDAPObject.__init__(self, *args, **kw)
     self.connected = False
     self.who = ''
     self.cred = ''
     self._connection_time = None
示例#19
0
def ldap_connect(settings, use_cache=True):
    """Establishes an LDAP connection.

    Establishes a connection to the LDAP server from the `uri` in the
    ``settings``.

    To establish a connection, the settings must be specified:
     - ``uri``: valid URI which points to a LDAP server,
     - ``bind_dn``: `dn` used to initially bind every LDAP connection
     - ``bind_password``" password used for the initial bind
     - ``tls``: ``True`` if the connection should use TLS encryption
     - ``starttls``: ``True`` to negotiate TLS with the server

    `Note`: ``starttls`` is ignored if the URI uses LDAPS and ``tls`` is
    set to ``True``.

    This function re-uses an existing LDAP connection if there is one
    available in the application context, unless caching is disabled.

    :param settings: dict -- The settings for a LDAP provider.
    :param use_cache: bool -- If the connection should be cached.
    :return: The ldap connection.
    """

    if use_cache:
        cache = _get_ldap_cache()
        cache_key = frozenset((k, hash(v)) for k, v in iteritems(settings) if k in conn_keys)
        conn = cache.get(cache_key)
        if conn is not None:
            return conn

    uri_info = urlparse(settings['uri'])
    use_ldaps = uri_info.scheme == 'ldaps'
    credentials = (settings['bind_dn'], settings['bind_password'])
    ldap_connection = ReconnectLDAPObject(settings['uri'])
    ldap_connection.protocol_version = ldap.VERSION3
    ldap_connection.set_option(ldap.OPT_REFERRALS, 0)
    ldap_connection.set_option(ldap.OPT_X_TLS, ldap.OPT_X_TLS_DEMAND if use_ldaps else ldap.OPT_X_TLS_NEVER)
    if settings['cert_file']:
        ldap_connection.set_option(ldap.OPT_X_TLS_CACERTFILE, settings['cert_file'])
    ldap_connection.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,
                               ldap.OPT_X_TLS_DEMAND if settings['verify_cert'] else ldap.OPT_X_TLS_ALLOW)
    # force the creation of a new TLS context. This must be the last TLS option.
    # see: http://stackoverflow.com/a/27713355/298479
    ldap_connection.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
    if use_ldaps and settings['starttls']:
        warn("Unable to start TLS, LDAP connection already secured over SSL (LDAPS)")
    elif settings['starttls']:
        ldap_connection.start_tls_s()
    # TODO: allow anonymous bind
    ldap_connection.simple_bind_s(*credentials)
    if use_cache:
        cache[cache_key] = ldap_connection
    return ldap_connection
示例#20
0
class LdapLookup(object):

    connection = None
    uri = None
    user = None
    password = None

    user_searchbase = ''
    group_searchbase = ''

    user_searchfilter = {'objectClass': 'user'}
    group_searchfilter = {'objectClass': 'group'}

    def __init__(self, **kw):
        for key, item in kw.items():
            if hasattr(self, key) and not key.startswith('_'):
                setattr(self, key, item)

    def connect(self):
        try:
            self.connection = ReconnectLDAPObject(self.uri)
            if self.user is not None:
                self.connection.simple_bind_s(self.user, self.password)
        except:
            logger.exception("LDAP connection failed")
            return False
        return True

    def get_safe(self, basedn, **kw):
        return self.get(
            basedn,
            **dict([(ldap_escape(k), ldap_escape(v))
                    for k, v in kw.iteritems()]))

    def get(self, basedn, **kw):
        search = '(&%s)' % ''.join(
            ['(%s=%s)' % item for item in kw.iteritems()])
        result = self.connection.search_s(basedn, ldap.SCOPE_SUBTREE, search)
        return result

    def get_dn(self, dn):
        res = self.connection.search_s(dn, ldap.SCOPE_BASE, '(objectClass=*)')
        if len(res) == 0:
            return None
        else:
            return res[0]

    def get_users(self):
        return self.get(self.user_searchbase, **self.user_searchfilter)

    def get_user(self, username):
        search = self.user_searchfilter.copy()
        if '@' in username:
            search['userPrincipalName'] = username
        else:
            search['sAMAccountName'] = username

        res = self.get_safe(self.user_searchbase, **search)
        if len(res) == 0:
            return None
        else:
            return res[0]

    def get_groups(self):
        return self.get(self.group_searchbase, **self.group_searchfilter)

    def get_group(self, groupname):
        search = self.group_searchfilter.copy()
        search['name'] = groupname
        res = self.get_safe(self.group_searchbase, **search)

        if len(res) == 0:
            return None
        else:
            return res[0]