diff options
Diffstat (limited to 'ldap3/extend')
22 files changed, 292 insertions, 215 deletions
diff --git a/ldap3/extend/__init__.py b/ldap3/extend/__init__.py index 24f426e..32795ef 100644 --- a/ldap3/extend/__init__.py +++ b/ldap3/extend/__init__.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -169,6 +169,33 @@ class StandardExtendedOperations(ExtendedOperationContainer): streaming,
callback)
+ def funnel_search(self,
+ search_base='',
+ search_filter='',
+ search_scope=SUBTREE,
+ dereference_aliases=DEREF_NEVER,
+ attributes=ALL_ATTRIBUTES,
+ size_limit=0,
+ time_limit=0,
+ controls=None,
+ streaming=False,
+ callback=None
+ ):
+ return PersistentSearch(self._connection,
+ search_base,
+ search_filter,
+ search_scope,
+ dereference_aliases,
+ attributes,
+ size_limit,
+ time_limit,
+ controls,
+ None,
+ None,
+ None,
+ streaming,
+ callback)
+
class NovellExtendedOperations(ExtendedOperationContainer):
def get_bind_dn(self, controls=None):
diff --git a/ldap3/extend/microsoft/addMembersToGroups.py b/ldap3/extend/microsoft/addMembersToGroups.py index 28c409f..eaf6cfd 100644 --- a/ldap3/extend/microsoft/addMembersToGroups.py +++ b/ldap3/extend/microsoft/addMembersToGroups.py @@ -1,81 +1,93 @@ -"""
-"""
-
-# Created on 2016.12.26
-#
-# Author: Giovanni Cannata
-#
-# Copyright 2016 - 2018 Giovanni Cannata
-#
-# This file is part of ldap3.
-#
-# ldap3 is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# ldap3 is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with ldap3 in the COPYING and COPYING.LESSER files.
-# If not, see <http://www.gnu.org/licenses/>.
-from ...core.exceptions import LDAPInvalidDnError
-from ... import SEQUENCE_TYPES, MODIFY_ADD, BASE, DEREF_NEVER
-
-
-def ad_add_members_to_groups(connection,
- members_dn,
- groups_dn,
- fix=True):
- """
- :param connection: a bound Connection object
- :param members_dn: the list of members to add to groups
- :param groups_dn: the list of groups where members are to be added
- :param fix: checks for group existence and already assigned members
- :return: a boolean where True means that the operation was successful and False means an error has happened
- Establishes users-groups relations following the Active Directory rules: users are added to the member attribute of groups.
- Raises LDAPInvalidDnError if members or groups are not found in the DIT.
- """
-
- if not isinstance(members_dn, SEQUENCE_TYPES):
- members_dn = [members_dn]
-
- if not isinstance(groups_dn, SEQUENCE_TYPES):
- groups_dn = [groups_dn]
-
- error = False
- for group in groups_dn:
- if fix: # checks for existance of group and for already assigned members
- result = connection.search(group, '(objectclass=*)', BASE, dereference_aliases=DEREF_NEVER, attributes=['member'])
-
- if not connection.strategy.sync:
- response, result = connection.get_response(result)
- else:
- response, result = connection.response, connection.result
-
- if not result['description'] == 'success':
- raise LDAPInvalidDnError(group + ' not found')
-
- existing_members = response[0]['attributes']['member'] if 'member' in response[0]['attributes'] else []
- existing_members = [element.lower() for element in existing_members]
- else:
- existing_members = []
-
- changes = dict()
- member_to_add = [element for element in members_dn if element.lower() not in existing_members]
- if member_to_add:
- changes['member'] = (MODIFY_ADD, member_to_add)
- if changes:
- result = connection.modify(group, changes)
- if not connection.strategy.sync:
- _, result = connection.get_response(result)
- else:
- result = connection.result
- if result['description'] != 'success':
- error = True
- break
-
- return not error # returns True if no error is raised in the LDAP operations
+""" +""" + +# Created on 2016.12.26 +# +# Author: Giovanni Cannata +# +# Copyright 2016 - 2020 Giovanni Cannata +# +# This file is part of ldap3. +# +# ldap3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ldap3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with ldap3 in the COPYING and COPYING.LESSER files. +# If not, see <http://www.gnu.org/licenses/>. + +from ... import SEQUENCE_TYPES, MODIFY_ADD, BASE, DEREF_NEVER +from ...core.exceptions import LDAPInvalidDnError, LDAPOperationsErrorResult +from ...utils.dn import safe_dn + + +def ad_add_members_to_groups(connection, + members_dn, + groups_dn, + fix=True, + raise_error=False): + """ + :param connection: a bound Connection object + :param members_dn: the list of members to add to groups + :param groups_dn: the list of groups where members are to be added + :param fix: checks for group existence and already assigned members + :param raise_error: If the operation fails it raises an error instead of returning False + :return: a boolean where True means that the operation was successful and False means an error has happened + Establishes users-groups relations following the Active Directory rules: users are added to the member attribute of groups. + Raises LDAPInvalidDnError if members or groups are not found in the DIT. + """ + + if not isinstance(members_dn, SEQUENCE_TYPES): + members_dn = [members_dn] + + if not isinstance(groups_dn, SEQUENCE_TYPES): + groups_dn = [groups_dn] + + if connection.check_names: # builds new lists with sanitized dn + members_dn = [safe_dn(member_dn) for member_dn in members_dn] + groups_dn = [safe_dn(group_dn) for group_dn in groups_dn] + + error = False + for group in groups_dn: + if fix: # checks for existance of group and for already assigned members + result = connection.search(group, '(objectclass=*)', BASE, dereference_aliases=DEREF_NEVER, + attributes=['member']) + + if not connection.strategy.sync: + response, result = connection.get_response(result) + else: + response, result = connection.response, connection.result + + if not result['description'] == 'success': + raise LDAPInvalidDnError(group + ' not found') + + existing_members = response[0]['attributes']['member'] if 'member' in response[0]['attributes'] else [] + existing_members = [element.lower() for element in existing_members] + else: + existing_members = [] + + changes = dict() + member_to_add = [element for element in members_dn if element.lower() not in existing_members] + if member_to_add: + changes['member'] = (MODIFY_ADD, member_to_add) + if changes: + result = connection.modify(group, changes) + if not connection.strategy.sync: + _, result = connection.get_response(result) + else: + result = connection.result + if result['description'] != 'success': + error = True + result_error_params = ['result', 'description', 'dn', 'message'] + if raise_error: + raise LDAPOperationsErrorResult([(k, v) for k, v in result.items() if k in result_error_params]) + break + + return not error # returns True if no error is raised in the LDAP operations diff --git a/ldap3/extend/microsoft/dirSync.py b/ldap3/extend/microsoft/dirSync.py index cb18e7a..db403a1 100644 --- a/ldap3/extend/microsoft/dirSync.py +++ b/ldap3/extend/microsoft/dirSync.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2015 - 2018 Giovanni Cannata
+# Copyright 2015 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/microsoft/modifyPassword.py b/ldap3/extend/microsoft/modifyPassword.py index 4a17fb0..0bf1c06 100644 --- a/ldap3/extend/microsoft/modifyPassword.py +++ b/ldap3/extend/microsoft/modifyPassword.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2015 - 2018 Giovanni Cannata
+# Copyright 2015 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/microsoft/removeMembersFromGroups.py b/ldap3/extend/microsoft/removeMembersFromGroups.py index 1b7feb3..0998713 100644 --- a/ldap3/extend/microsoft/removeMembersFromGroups.py +++ b/ldap3/extend/microsoft/removeMembersFromGroups.py @@ -1,93 +1,92 @@ -"""
-"""
-
-# Created on 2016.12.26
-#
-# Author: Giovanni Cannata
-#
-# Copyright 2016 - 2018 Giovanni Cannata
-#
-# This file is part of ldap3.
-#
-# ldap3 is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published
-# by the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# ldap3 is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with ldap3 in the COPYING and COPYING.LESSER files.
-# If not, see <http://www.gnu.org/licenses/>.
-from ...core.exceptions import LDAPInvalidDnError
-from ... import SEQUENCE_TYPES, MODIFY_DELETE, BASE, DEREF_NEVER
-from ...utils.dn import safe_dn
-
-
-def ad_remove_members_from_groups(connection,
- members_dn,
- groups_dn,
- fix):
- """
- :param connection: a bound Connection object
- :param members_dn: the list of members to remove from groups
- :param groups_dn: the list of groups where members are to be removed
- :param fix: checks for group existence and existing members
- :return: a boolean where True means that the operation was successful and False means an error has happened
- Removes users-groups relations following the Activwe Directory rules: users are removed from groups' member attribute
-
- """
- if not isinstance(members_dn, SEQUENCE_TYPES):
- members_dn = [members_dn]
-
- if not isinstance(groups_dn, SEQUENCE_TYPES):
- groups_dn = [groups_dn]
-
- if connection.check_names: # builds new lists with sanitized dn
- safe_members_dn = []
- safe_groups_dn = []
- for member_dn in members_dn:
- safe_members_dn.append(safe_dn(member_dn))
- for group_dn in groups_dn:
- safe_groups_dn.append(safe_dn(group_dn))
-
- members_dn = safe_members_dn
- groups_dn = safe_groups_dn
-
- error = False
-
- for group in groups_dn:
- if fix: # checks for existance of group and for already assigned members
- result = connection.search(group, '(objectclass=*)', BASE, dereference_aliases=DEREF_NEVER, attributes=['member'])
-
- if not connection.strategy.sync:
- response, result = connection.get_response(result)
- else:
- response, result = connection.response, connection.result
-
- if not result['description'] == 'success':
- raise LDAPInvalidDnError(group + ' not found')
-
- existing_members = response[0]['attributes']['member'] if 'member' in response[0]['attributes'] else []
- else:
- existing_members = members_dn
-
- existing_members = [element.lower() for element in existing_members]
- changes = dict()
- member_to_remove = [element for element in members_dn if element.lower() in existing_members]
- if member_to_remove:
- changes['member'] = (MODIFY_DELETE, member_to_remove)
- if changes:
- result = connection.modify(group, changes)
- if not connection.strategy.sync:
- _, result = connection.get_response(result)
- else:
- result = connection.result
- if result['description'] != 'success':
- error = True
- break
-
- return not error
+""" +""" + +# Created on 2016.12.26 +# +# Author: Giovanni Cannata +# +# Copyright 2016 - 2020 Giovanni Cannata +# +# This file is part of ldap3. +# +# ldap3 is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# ldap3 is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with ldap3 in the COPYING and COPYING.LESSER files. +# If not, see <http://www.gnu.org/licenses/>. + +from ...core.exceptions import LDAPInvalidDnError, LDAPOperationsErrorResult +from ... import SEQUENCE_TYPES, MODIFY_DELETE, BASE, DEREF_NEVER +from ...utils.dn import safe_dn + + +def ad_remove_members_from_groups(connection, + members_dn, + groups_dn, + fix, + raise_error=False): + """ + :param connection: a bound Connection object + :param members_dn: the list of members to remove from groups + :param groups_dn: the list of groups where members are to be removed + :param fix: checks for group existence and existing members + :param raise_error: If the operation fails it raises an error instead of returning False + :return: a boolean where True means that the operation was successful and False means an error has happened + Removes users-groups relations following the Activwe Directory rules: users are removed from groups' member attribute + + """ + if not isinstance(members_dn, SEQUENCE_TYPES): + members_dn = [members_dn] + + if not isinstance(groups_dn, SEQUENCE_TYPES): + groups_dn = [groups_dn] + + if connection.check_names: # builds new lists with sanitized dn + members_dn = [safe_dn(member_dn) for member_dn in members_dn] + groups_dn = [safe_dn(group_dn) for group_dn in groups_dn] + + error = False + + for group in groups_dn: + if fix: # checks for existance of group and for already assigned members + result = connection.search(group, '(objectclass=*)', BASE, dereference_aliases=DEREF_NEVER, attributes=['member']) + + if not connection.strategy.sync: + response, result = connection.get_response(result) + else: + response, result = connection.response, connection.result + + if not result['description'] == 'success': + raise LDAPInvalidDnError(group + ' not found') + + existing_members = response[0]['attributes']['member'] if 'member' in response[0]['attributes'] else [] + else: + existing_members = members_dn + + existing_members = [element.lower() for element in existing_members] + changes = dict() + member_to_remove = [element for element in members_dn if element.lower() in existing_members] + if member_to_remove: + changes['member'] = (MODIFY_DELETE, member_to_remove) + if changes: + result = connection.modify(group, changes) + if not connection.strategy.sync: + _, result = connection.get_response(result) + else: + result = connection.result + if result['description'] != 'success': + error = True + result_error_params = ['result', 'description', 'dn', 'message'] + if raise_error: + raise LDAPOperationsErrorResult([(k, v) for k, v in result.items() if k in result_error_params]) + break + + return not error diff --git a/ldap3/extend/microsoft/unlockAccount.py b/ldap3/extend/microsoft/unlockAccount.py index 60b9ed3..bc59b58 100644 --- a/ldap3/extend/microsoft/unlockAccount.py +++ b/ldap3/extend/microsoft/unlockAccount.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2015 - 2018 Giovanni Cannata
+# Copyright 2015 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -34,7 +34,7 @@ def ad_unlock_account(connection, user_dn, controls=None): if connection.check_names:
user_dn = safe_dn(user_dn)
result = connection.modify(user_dn,
- {'lockoutTime': [(MODIFY_REPLACE, [0])]},
+ {'lockoutTime': [(MODIFY_REPLACE, ['0'])]},
controls)
if not connection.strategy.sync:
diff --git a/ldap3/extend/novell/addMembersToGroups.py b/ldap3/extend/novell/addMembersToGroups.py index 5583549..d649dc8 100644 --- a/ldap3/extend/novell/addMembersToGroups.py +++ b/ldap3/extend/novell/addMembersToGroups.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2016 - 2018 Giovanni Cannata
+# Copyright 2016 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/checkGroupsMemberships.py b/ldap3/extend/novell/checkGroupsMemberships.py index 1013fde..c51dbf2 100644 --- a/ldap3/extend/novell/checkGroupsMemberships.py +++ b/ldap3/extend/novell/checkGroupsMemberships.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2016 - 2018 Giovanni Cannata
+# Copyright 2016 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/endTransaction.py b/ldap3/extend/novell/endTransaction.py index 0e9a58c..18bc041 100644 --- a/ldap3/extend/novell/endTransaction.py +++ b/ldap3/extend/novell/endTransaction.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2016 - 2018 Giovanni Cannata
+# Copyright 2016 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/getBindDn.py b/ldap3/extend/novell/getBindDn.py index 39fae2b..492bcdd 100644 --- a/ldap3/extend/novell/getBindDn.py +++ b/ldap3/extend/novell/getBindDn.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/listReplicas.py b/ldap3/extend/novell/listReplicas.py index fdc6d08..8ccf2ff 100644 --- a/ldap3/extend/novell/listReplicas.py +++ b/ldap3/extend/novell/listReplicas.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -45,6 +45,6 @@ class ListReplicas(ExtendedOperation): def populate_result(self):
try:
- self.result['replicas'] = str(self.decoded_response['replicaList']) if self.decoded_response['replicaList'] else None
+ self.result['replicas'] = [str(replica) for replica in self.decoded_response] if self.decoded_response else None
except TypeError:
self.result['replicas'] = None
diff --git a/ldap3/extend/novell/nmasGetUniversalPassword.py b/ldap3/extend/novell/nmasGetUniversalPassword.py index 20aa928..291ae92 100644 --- a/ldap3/extend/novell/nmasGetUniversalPassword.py +++ b/ldap3/extend/novell/nmasGetUniversalPassword.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -46,9 +46,11 @@ class NmasGetUniversalPassword(ExtendedOperation): self.request_value['reqdn'] = user
def populate_result(self):
- self.result['nmasver'] = int(self.decoded_response['nmasver'])
- self.result['error'] = int(self.decoded_response['err'])
- try:
- self.result['password'] = str(self.decoded_response['passwd']) if self.decoded_response['passwd'] else None
- except TypeError:
- self.result['password'] = None
+ if self.decoded_response:
+ self.result['nmasver'] = int(self.decoded_response['nmasver'])
+ self.result['error'] = int(self.decoded_response['err'])
+ try:
+
+ self.result['password'] = str(self.decoded_response['passwd']) if self.decoded_response['passwd'].hasValue() else None
+ except TypeError:
+ self.result['password'] = None
diff --git a/ldap3/extend/novell/nmasSetUniversalPassword.py b/ldap3/extend/novell/nmasSetUniversalPassword.py index 65ea0d6..dadab59 100644 --- a/ldap3/extend/novell/nmasSetUniversalPassword.py +++ b/ldap3/extend/novell/nmasSetUniversalPassword.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/partition_entry_count.py b/ldap3/extend/novell/partition_entry_count.py index 8218aea..3d46c7a 100644 --- a/ldap3/extend/novell/partition_entry_count.py +++ b/ldap3/extend/novell/partition_entry_count.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/removeMembersFromGroups.py b/ldap3/extend/novell/removeMembersFromGroups.py index df493ba..c46c275 100644 --- a/ldap3/extend/novell/removeMembersFromGroups.py +++ b/ldap3/extend/novell/removeMembersFromGroups.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2016 - 2018 Giovanni Cannata
+# Copyright 2016 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/replicaInfo.py b/ldap3/extend/novell/replicaInfo.py index 45bd0e9..057f934 100644 --- a/ldap3/extend/novell/replicaInfo.py +++ b/ldap3/extend/novell/replicaInfo.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/novell/startTransaction.py b/ldap3/extend/novell/startTransaction.py index 2ed21c2..6179cb0 100644 --- a/ldap3/extend/novell/startTransaction.py +++ b/ldap3/extend/novell/startTransaction.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2016 - 2018 Giovanni Cannata
+# Copyright 2016 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/operation.py b/ldap3/extend/operation.py index 9906885..c1d478c 100644 --- a/ldap3/extend/operation.py +++ b/ldap3/extend/operation.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
diff --git a/ldap3/extend/standard/PagedSearch.py b/ldap3/extend/standard/PagedSearch.py index 6fb1a56..f8bc7e6 100644 --- a/ldap3/extend/standard/PagedSearch.py +++ b/ldap3/extend/standard/PagedSearch.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -25,7 +25,7 @@ from ... import SUBTREE, DEREF_ALWAYS
from ...utils.dn import safe_dn
-from ...core.results import DO_NOT_RAISE_EXCEPTIONS
+from ...core.results import DO_NOT_RAISE_EXCEPTIONS, RESULT_SIZE_LIMIT_EXCEEDED
from ...core.exceptions import LDAPOperationResult
from ...utils.log import log, log_enabled, ERROR, BASIC, PROTOCOL, NETWORK, EXTENDED
@@ -47,7 +47,11 @@ def paged_search_generator(connection, search_base = safe_dn(search_base)
responses = []
- cookie = True # performs search at least one time
+ original_connection = None
+ original_auto_referrals = connection.auto_referrals
+ connection.auto_referrals = False # disable auto referrals because it cannot handle paged searches
+ cookie = True # performs search operation at least one time
+ cachekey = None # for referrals cache
while cookie:
result = connection.search(search_base,
search_filter,
@@ -69,10 +73,11 @@ def paged_search_generator(connection, response = connection.response
result = connection.result
- if result and result['result'] not in DO_NOT_RAISE_EXCEPTIONS:
- if log_enabled(PROTOCOL):
- log(PROTOCOL, 'paged search operation result <%s> for <%s>', result, connection)
- raise LDAPOperationResult(result=result['result'], description=result['description'], dn=result['dn'], message=result['message'], response_type=result['type'])
+ if result['referrals'] and original_auto_referrals: # if rererrals are returned start over the loop with a new connection to the referral
+ if not original_connection:
+ original_connection = connection
+ _, connection, cachekey = connection.strategy.create_referral_connection(result['referrals']) # change connection to a valid referrals
+ continue
responses.extend(response)
try:
@@ -80,9 +85,25 @@ def paged_search_generator(connection, except KeyError:
cookie = None
+ if connection.raise_exceptions and result and result['result'] not in DO_NOT_RAISE_EXCEPTIONS:
+ if log_enabled(PROTOCOL):
+ log(PROTOCOL, 'paged search operation result <%s> for <%s>', result, connection)
+ if result['result'] == RESULT_SIZE_LIMIT_EXCEEDED:
+ while responses:
+ yield responses.pop()
+ raise LDAPOperationResult(result=result['result'], description=result['description'], dn=result['dn'], message=result['message'], response_type=result['type'])
+
while responses:
yield responses.pop()
+ if original_connection:
+ connection = original_connection
+ if connection.use_referral_cache and cachekey:
+ connection.strategy.referral_cache[cachekey] = connection
+ else:
+ connection.unbind()
+
+ connection.auto_referrals = original_auto_referrals
connection.response = None
diff --git a/ldap3/extend/standard/PersistentSearch.py b/ldap3/extend/standard/PersistentSearch.py index 62286e1..b25ec68 100644 --- a/ldap3/extend/standard/PersistentSearch.py +++ b/ldap3/extend/standard/PersistentSearch.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2016 - 2018 Giovanni Cannata
+# Copyright 2016 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -80,7 +80,8 @@ class PersistentSearch(object): else:
self.controls = controls
- self.controls.append(persistent_search_control(events_type, changes_only, notifications))
+ if events_type and changes_only and notifications:
+ self.controls.append(persistent_search_control(events_type, changes_only, notifications))
self.start()
def start(self):
@@ -101,9 +102,10 @@ class PersistentSearch(object): controls=self.controls)
self.connection.strategy.persistent_search_message_id = self.message_id
- def stop(self):
+ def stop(self, unbind=True):
self.connection.abandon(self.message_id)
- self.connection.unbind()
+ if unbind:
+ self.connection.unbind()
if self.message_id in self.connection.strategy._responses:
del self.connection.strategy._responses[self.message_id]
if hasattr(self.connection.strategy, '_requests') and self.message_id in self.connection.strategy._requests: # asynchronous strategy has a dict of request that could be returned by get_response()
@@ -111,11 +113,25 @@ class PersistentSearch(object): self.connection.strategy.persistent_search_message_id = None
self.message_id = None
- def next(self):
+ def next(self, block=False, timeout=None):
if not self.connection.strategy.streaming and not self.connection.strategy.callback:
try:
- return self.connection.strategy.events.get_nowait()
+ return self.connection.strategy.events.get(block, timeout)
except Empty:
return None
raise LDAPExtensionError('Persistent search is not accumulating events in queue')
+
+ def funnel(self, block=False, timeout=None):
+ done = False
+ while not done:
+ try:
+ entry = self.connection.strategy.events.get(block, timeout)
+ except Empty:
+ yield None
+ if entry['type'] == 'searchResEntry':
+ yield entry
+ else:
+ done = True
+
+ yield entry
diff --git a/ldap3/extend/standard/modifyPassword.py b/ldap3/extend/standard/modifyPassword.py index 167816e..7837355 100644 --- a/ldap3/extend/standard/modifyPassword.py +++ b/ldap3/extend/standard/modifyPassword.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -67,6 +67,6 @@ class ModifyPassword(ExtendedOperation): self.result[self.response_attribute] = True
else: # change was not successful, raises exception if raise_exception = True in connection or returns the operation result, error code is in result['result']
self.result[self.response_attribute] = False
- if not self.connection.raise_exceptions:
+ if self.connection.raise_exceptions:
from ...core.exceptions import LDAPOperationResult
raise LDAPOperationResult(result=self.result['result'], description=self.result['description'], dn=self.result['dn'], message=self.result['message'], response_type=self.result['type'])
diff --git a/ldap3/extend/standard/whoAmI.py b/ldap3/extend/standard/whoAmI.py index 121e40b..a6c08a8 100644 --- a/ldap3/extend/standard/whoAmI.py +++ b/ldap3/extend/standard/whoAmI.py @@ -5,7 +5,7 @@ #
# Author: Giovanni Cannata
#
-# Copyright 2014 - 2018 Giovanni Cannata
+# Copyright 2014 - 2020 Giovanni Cannata
#
# This file is part of ldap3.
#
@@ -24,10 +24,10 @@ # If not, see <http://www.gnu.org/licenses/>.
# implements RFC4532
-
from ...extend.operation import ExtendedOperation
from ...utils.conv import to_unicode
+
class WhoAmI(ExtendedOperation):
def config(self):
self.request_name = '1.3.6.1.4.1.4203.1.11.3'
|