flask_ldap3_login/__init__.py
def authenticate_search_bind(self, username, password):
        """
        Performs a search bind to authenticate a user. This is
        required when a the login attribute is not the same
        as the RDN, since we cannot string together their DN on
        the fly, instead we have to find it in the LDAP, then attempt
        to bind with their credentials.

        Args:
            username (str): Username of the user to bind (the field specified
                            as LDAP_BIND_LOGIN_ATTR)
            password (str): User's password to bind with when we find their dn.

        Returns:
            AuthenticationResponse

        """
        connection = self._make_connection(
            bind_user=self.config.get('LDAP_BIND_USER_DN'),
            bind_password=self.config.get('LDAP_BIND_USER_PASSWORD'),
        )

        try:
            connection.bind()
            log.debug("Successfully bound to LDAP as '{0}' for search_bind method".format(
                self.config.get('LDAP_BIND_USER_DN') or 'Anonymous'
            ))
        except Exception as e:
            self.destroy_connection(connection)
            log.error(e)
            return AuthenticationResponse()

        # Find the user in the search path.
        user_filter = '({search_attr}={username})'.format(
            search_attr=self.config.get('LDAP_USER_LOGIN_ATTR'),
            username=username
        )
        search_filter = '(&{0}{1})'.format(
            self.config.get('LDAP_USER_OBJECT_FILTER'),
            user_filter,
        )

        log.debug(
            "Performing an LDAP Search using filter '{0}', base '{1}', "
            "and scope '{2}'".format(
                search_filter,
                self.full_user_search_dn,
                self.config.get('LDAP_USER_SEARCH_SCOPE')
            ))

        connection.search(
            search_base=self.full_user_search_dn,
            search_filter=search_filter,
            search_scope=getattr(
                ldap3, self.config.get('LDAP_USER_SEARCH_SCOPE')),
            attributes=self.config.get('LDAP_GET_USER_ATTRIBUTES')
        )

        response = AuthenticationResponse()

        if len(connection.response) == 0 or \
                (self.config.get('LDAP_FAIL_AUTH_ON_MULTIPLE_FOUND') and
                 len(connection.response) > 1):
            # Don't allow them to log in.
            log.debug(
                "Authentication was not successful for user '{0}'".format(username))

        else:
            for user in connection.response:
                # Attempt to bind with each user we find until we can find
                # one that works.

                if 'type' not in user or user.get('type') != 'searchResEntry':
                    # Issue #13 - Don't return non-entry results.
                    continue

                user_connection = self._make_connection(
                    bind_user=user['dn'],
                    bind_password=password
                )

                log.debug(
                    "Directly binding a connection to a server with "
                    "user:'{0}'".format(user['dn']))
                try:
                    user_connection.bind()
                    log.debug(
                        "Authentication was successful for user '{0}'".format(username))
                    response.status = AuthenticationResponseStatus.success

                    # Populate User Data
                    user['attributes']['dn'] = user['dn']
                    response.user_info = user['attributes']
                    response.user_id = username
                    response.user_dn = user['dn']
                    if self.config.get('LDAP_SEARCH_FOR_GROUPS'):
                        response.user_groups = self.get_user_groups(
                            dn=user['dn'], _connection=connection)
                    self.destroy_connection(user_connection)
                    break

                except ldap3.core.exceptions.LDAPInvalidCredentialsResult:
                    log.debug(
                        "Authentication was not successful for "
                        "user '{0}'".format(username))
                    response.status = AuthenticationResponseStatus.fail
                except Exception as e:  # pragma: no cover
                    # This should never happen, however in case ldap3 does ever
                    # throw an error here, we catch it and log it
                    log.error(e)
                    response.status = AuthenticationResponseStatus.fail

                self.destroy_connection(user_connection)

        self.destroy_connection(connection)
        return response
def authenticate_search_bind(self, username, password):
        """
        Performs a search bind to authenticate a user. This is
        required when a the login attribute is not the same
        as the RDN, since we cannot string together their DN on
        the fly, instead we have to find it in the LDAP, then attempt
        to bind with their credentials.

        Args:
            username (str): Username of the user to bind (the field specified
                            as LDAP_BIND_LOGIN_ATTR)
            password (str): User's password to bind with when we find their dn.

        Returns:
            AuthenticationResponse

        """
        connection = self._make_connection(
            bind_user=self.config.get('LDAP_BIND_USER_DN'),
            bind_password=self.config.get('LDAP_BIND_USER_PASSWORD'),
        )

        try:
            connection.bind()
            log.debug("Successfully bound to LDAP as '{0}' for search_bind method".format(
                self.config.get('LDAP_BIND_USER_DN') or 'Anonymous'
            ))
        except Exception as e:
            self.destroy_connection(connection)
            log.error(e)
            return AuthenticationResponse()

        # Find the user in the search path.
        user_filter = '({search_attr}={username})'.format(
            search_attr=self.config.get('LDAP_USER_LOGIN_ATTR'),
            username=username
        )
        search_filter = '(&{0}{1})'.format(
            self.config.get('LDAP_USER_OBJECT_FILTER'),
            user_filter,
        )

        log.debug(
            "Performing an LDAP Search using filter '{0}', base '{1}', "
            "and scope '{2}'".format(
                search_filter,
                self.full_user_search_dn,
                self.config.get('LDAP_USER_SEARCH_SCOPE')
            ))

        connection.search(
            search_base=self.full_user_search_dn,
            search_filter=search_filter,
            search_scope=getattr(
                ldap3, self.config.get('LDAP_USER_SEARCH_SCOPE')),
            attributes=self.config.get('LDAP_GET_USER_ATTRIBUTES')
        )

        response = AuthenticationResponse()

        if len(connection.response) == 0 or \
                (self.config.get('LDAP_FAIL_AUTH_ON_MULTIPLE_FOUND') and
                 len(connection.response) > 1):
            # Don't allow them to log in.
            log.debug(
                "Authentication was not successful for user '{0}'".format(username))

        else:
            for user in connection.response:
                # Attempt to bind with each user we find until we can find
                # one that works.

                if 'type' not in user or user.get('type') != 'searchResEntry':
                    # Issue #13 - Don't return non-entry results.
                    continue

                user_connection = self._make_connection(
                    bind_user=user['dn'],
                    bind_password=password
                )

                log.debug(
                    "Directly binding a connection to a server with "
                    "user:'{0}'".format(user['dn']))
                try:
                    user_connection.bind()
                    log.debug(
                        "Authentication was successful for user '{0}'".format(username))
                    response.status = AuthenticationResponseStatus.success

                    # Populate User Data
                    user['attributes']['dn'] = user['dn']
                    response.user_info = user['attributes']
                    response.user_id = username
                    response.user_dn = user['dn']
                    if self.config.get('LDAP_SEARCH_FOR_GROUPS'):
                        response.user_groups = self.get_user_groups(
                            dn=user['dn'], _connection=connection)
                    self.destroy_connection(user_connection)
                    break

                except ldap3.core.exceptions.LDAPInvalidCredentialsResult:
                    log.debug(
                        "Authentication was not successful for "
                        "user '{0}'".format(username))
                    response.status = AuthenticationResponseStatus.fail
                except Exception as e:  # pragma: no cover
                    # This should never happen, however in case ldap3 does ever
                    # throw an error here, we catch it and log it
                    log.error(e)
                    response.status = AuthenticationResponseStatus.fail

                self.destroy_connection(user_connection)

        self.destroy_connection(connection)
        return response
Performs a search bind to authenticate a user. This is
        required when a the login attribute is not the same
        as the RDN, since we cannot string together their DN on
        the fly, instead we have to find it in the LDAP, then attempt
        to bind with their credentials.

        Args:
            username (str): Username of the user to bind (the field specified
                            as LDAP_BIND_LOGIN_ATTR)
            password (str): User's password to bind with when we find their dn.

        Returns:
            AuthenticationResponse