2025-12-25 upload
This commit is contained in:
0
venv/Lib/site-packages/ldap3/operation/__init__.py
Normal file
0
venv/Lib/site-packages/ldap3/operation/__init__.py
Normal file
36
venv/Lib/site-packages/ldap3/operation/abandon.py
Normal file
36
venv/Lib/site-packages/ldap3/operation/abandon.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 ..protocol.rfc4511 import AbandonRequest, MessageID
|
||||
|
||||
|
||||
def abandon_operation(msg_id):
|
||||
# AbandonRequest ::= [APPLICATION 16] MessageID
|
||||
request = AbandonRequest(MessageID(msg_id))
|
||||
return request
|
||||
|
||||
|
||||
def abandon_request_to_dict(request):
|
||||
return {'messageId': str(request)}
|
||||
72
venv/Lib/site-packages/ldap3/operation/add.py
Normal file
72
venv/Lib/site-packages/ldap3/operation/add.py
Normal file
@@ -0,0 +1,72 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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
|
||||
from ..protocol.rfc4511 import AddRequest, LDAPDN, AttributeList, Attribute, AttributeDescription, ResultCode, Vals
|
||||
from ..protocol.convert import referrals_to_list, attributes_to_dict, validate_attribute_value, prepare_for_sending
|
||||
|
||||
|
||||
def add_operation(dn,
|
||||
attributes,
|
||||
auto_encode,
|
||||
schema=None,
|
||||
validator=None,
|
||||
check_names=False):
|
||||
# AddRequest ::= [APPLICATION 8] SEQUENCE {
|
||||
# entry LDAPDN,
|
||||
# attributes AttributeList }
|
||||
#
|
||||
# attributes is a dictionary in the form 'attribute': ['val1', 'val2', 'valN']
|
||||
attribute_list = AttributeList()
|
||||
for pos, attribute in enumerate(attributes):
|
||||
attribute_list[pos] = Attribute()
|
||||
attribute_list[pos]['type'] = AttributeDescription(attribute)
|
||||
vals = Vals() # changed from ValsAtLeast1() for allowing empty member value in groups
|
||||
if isinstance(attributes[attribute], SEQUENCE_TYPES):
|
||||
for index, value in enumerate(attributes[attribute]):
|
||||
vals.setComponentByPosition(index, prepare_for_sending(validate_attribute_value(schema, attribute, value, auto_encode, validator, check_names)))
|
||||
else:
|
||||
vals.setComponentByPosition(0, prepare_for_sending(validate_attribute_value(schema, attribute, attributes[attribute], auto_encode, validator, check_names)))
|
||||
|
||||
attribute_list[pos]['vals'] = vals
|
||||
|
||||
request = AddRequest()
|
||||
request['entry'] = LDAPDN(dn)
|
||||
request['attributes'] = attribute_list
|
||||
|
||||
return request
|
||||
|
||||
|
||||
def add_request_to_dict(request):
|
||||
return {'entry': str(request['entry']),
|
||||
'attributes': attributes_to_dict(request['attributes'])}
|
||||
|
||||
|
||||
def add_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'dn': str(response['matchedDN']),
|
||||
'message': str(response['diagnosticMessage']),
|
||||
'referrals': referrals_to_list(response['referral'])}
|
||||
160
venv/Lib/site-packages/ldap3/operation/bind.py
Normal file
160
venv/Lib/site-packages/ldap3/operation/bind.py
Normal file
@@ -0,0 +1,160 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 SIMPLE, ANONYMOUS, SASL, STRING_TYPES
|
||||
from ..core.results import RESULT_CODES
|
||||
from ..core.exceptions import LDAPUserNameIsMandatoryError, LDAPPasswordIsMandatoryError, LDAPUnknownAuthenticationMethodError, LDAPUserNameNotAllowedError
|
||||
from ..protocol.sasl.sasl import validate_simple_password
|
||||
from ..protocol.rfc4511 import Version, AuthenticationChoice, Simple, BindRequest, ResultCode, SaslCredentials, BindResponse, \
|
||||
LDAPDN, LDAPString, Referral, ServerSaslCreds, SicilyPackageDiscovery, SicilyNegotiate, SicilyResponse
|
||||
from ..protocol.convert import authentication_choice_to_dict, referrals_to_list
|
||||
from ..utils.conv import to_unicode, to_raw
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
def bind_operation(version,
|
||||
authentication,
|
||||
name='',
|
||||
password=None,
|
||||
sasl_mechanism=None,
|
||||
sasl_credentials=None,
|
||||
auto_encode=False):
|
||||
# BindRequest ::= [APPLICATION 0] SEQUENCE {
|
||||
# version INTEGER (1 .. 127),
|
||||
# name LDAPDN,
|
||||
# authentication AuthenticationChoice }
|
||||
request = BindRequest()
|
||||
request['version'] = Version(version)
|
||||
if name is None:
|
||||
name = ''
|
||||
if isinstance(name, STRING_TYPES):
|
||||
request['name'] = to_unicode(name) if auto_encode else name
|
||||
if authentication == SIMPLE:
|
||||
if not name:
|
||||
raise LDAPUserNameIsMandatoryError('user name is mandatory in simple bind')
|
||||
if password:
|
||||
request['authentication'] = AuthenticationChoice().setComponentByName('simple', Simple(validate_simple_password(password)))
|
||||
else:
|
||||
raise LDAPPasswordIsMandatoryError('password is mandatory in simple bind')
|
||||
elif authentication == SASL:
|
||||
sasl_creds = SaslCredentials()
|
||||
sasl_creds['mechanism'] = sasl_mechanism
|
||||
if sasl_credentials is not None:
|
||||
sasl_creds['credentials'] = sasl_credentials
|
||||
# else:
|
||||
# sasl_creds['credentials'] = None
|
||||
request['authentication'] = AuthenticationChoice().setComponentByName('sasl', sasl_creds)
|
||||
elif authentication == ANONYMOUS:
|
||||
if name:
|
||||
raise LDAPUserNameNotAllowedError('user name not allowed in anonymous bind')
|
||||
request['name'] = ''
|
||||
request['authentication'] = AuthenticationChoice().setComponentByName('simple', Simple(''))
|
||||
elif authentication == 'SICILY_PACKAGE_DISCOVERY': # https://msdn.microsoft.com/en-us/library/cc223501.aspx
|
||||
request['name'] = ''
|
||||
request['authentication'] = AuthenticationChoice().setComponentByName('sicilyPackageDiscovery', SicilyPackageDiscovery(''))
|
||||
elif authentication == 'SICILY_NEGOTIATE_NTLM': # https://msdn.microsoft.com/en-us/library/cc223501.aspx
|
||||
request['name'] = 'NTLM'
|
||||
request['authentication'] = AuthenticationChoice().setComponentByName('sicilyNegotiate', SicilyNegotiate(name.create_negotiate_message())) # ntlm client in self.name
|
||||
elif authentication == 'SICILY_RESPONSE_NTLM': # https://msdn.microsoft.com/en-us/library/cc223501.aspx
|
||||
name.parse_challenge_message(password) # server_creds returned by server in password
|
||||
server_creds = name.create_authenticate_message()
|
||||
if server_creds:
|
||||
request['name'] = ''
|
||||
request['authentication'] = AuthenticationChoice().setComponentByName('sicilyResponse', SicilyResponse(server_creds))
|
||||
else:
|
||||
request = None
|
||||
else:
|
||||
raise LDAPUnknownAuthenticationMethodError('unknown authentication method')
|
||||
|
||||
return request
|
||||
|
||||
|
||||
def bind_request_to_dict(request):
|
||||
return {'version': int(request['version']),
|
||||
'name': str(request['name']),
|
||||
'authentication': authentication_choice_to_dict(request['authentication'])}
|
||||
|
||||
|
||||
def bind_response_operation(result_code,
|
||||
matched_dn='',
|
||||
diagnostic_message='',
|
||||
referral=None,
|
||||
server_sasl_credentials=None):
|
||||
# BindResponse ::= [APPLICATION 1] SEQUENCE {
|
||||
# COMPONENTS OF LDAPResult,
|
||||
# serverSaslCreds [7] OCTET STRING OPTIONAL }
|
||||
response = BindResponse()
|
||||
response['resultCode'] = ResultCode(result_code)
|
||||
response['matchedDN'] = LDAPDN(matched_dn)
|
||||
response['diagnosticMessage'] = LDAPString(diagnostic_message)
|
||||
if referral:
|
||||
response['referral'] = Referral(referral)
|
||||
|
||||
if server_sasl_credentials:
|
||||
response['serverSaslCreds'] = ServerSaslCreds(server_sasl_credentials)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def bind_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'dn': str(response['matchedDN']),
|
||||
'message': str(response['diagnosticMessage']),
|
||||
'referrals': referrals_to_list(response['referral']) if response['referral'] is not None and response['referral'].hasValue() else [],
|
||||
'saslCreds': bytes(response['serverSaslCreds']) if response['serverSaslCreds'] is not None and response['serverSaslCreds'].hasValue() else None}
|
||||
|
||||
|
||||
def sicily_bind_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'server_creds': bytes(response['matchedDN']),
|
||||
'error_message': str(response['diagnosticMessage'])}
|
||||
|
||||
|
||||
def bind_response_to_dict_fast(response):
|
||||
response_dict = dict()
|
||||
response_dict['result'] = int(response[0][3]) # resultCode
|
||||
response_dict['description'] = RESULT_CODES[response_dict['result']]
|
||||
response_dict['dn'] = to_unicode(response[1][3], from_server=True) # matchedDN
|
||||
response_dict['message'] = to_unicode(response[2][3], from_server=True) # diagnosticMessage
|
||||
response_dict['referrals'] = None # referrals
|
||||
response_dict['saslCreds'] = None # saslCreds
|
||||
for r in response[3:]:
|
||||
if r[2] == 3: # referrals
|
||||
response_dict['referrals'] = referrals_to_list(r[3]) # referrals
|
||||
else:
|
||||
response_dict['saslCreds'] = bytes(r[3]) # saslCreds
|
||||
|
||||
return response_dict
|
||||
|
||||
|
||||
def sicily_bind_response_to_dict_fast(response):
|
||||
response_dict = dict()
|
||||
response_dict['result'] = int(response[0][3]) # resultCode
|
||||
response_dict['description'] = RESULT_CODES[response_dict['result']]
|
||||
response_dict['server_creds'] = bytes(response[1][3]) # server_creds
|
||||
response_dict['error_message'] = to_unicode(response[2][3], from_server=True) # error_message
|
||||
|
||||
return response_dict
|
||||
64
venv/Lib/site-packages/ldap3/operation/compare.py
Normal file
64
venv/Lib/site-packages/ldap3/operation/compare.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 ..protocol.convert import validate_attribute_value, prepare_for_sending
|
||||
from ..protocol.rfc4511 import CompareRequest, AttributeValueAssertion, AttributeDescription, LDAPDN, AssertionValue, ResultCode
|
||||
from ..operation.search import ava_to_dict
|
||||
from ..operation.bind import referrals_to_list
|
||||
|
||||
|
||||
def compare_operation(dn,
|
||||
attribute,
|
||||
value,
|
||||
auto_encode,
|
||||
schema=None,
|
||||
validator=None,
|
||||
check_names=False):
|
||||
# CompareRequest ::= [APPLICATION 14] SEQUENCE {
|
||||
# entry LDAPDN,
|
||||
# ava AttributeValueAssertion }
|
||||
ava = AttributeValueAssertion()
|
||||
ava['attributeDesc'] = AttributeDescription(attribute)
|
||||
ava['assertionValue'] = AssertionValue(prepare_for_sending(validate_attribute_value(schema, attribute, value, auto_encode, validator, check_names=check_names)))
|
||||
|
||||
request = CompareRequest()
|
||||
request['entry'] = LDAPDN(dn)
|
||||
request['ava'] = ava
|
||||
|
||||
return request
|
||||
|
||||
|
||||
def compare_request_to_dict(request):
|
||||
ava = ava_to_dict(request['ava'])
|
||||
return {'entry': str(request['entry']),
|
||||
'attribute': ava['attribute'],
|
||||
'value': ava['value']}
|
||||
|
||||
|
||||
def compare_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'dn': str(response['matchedDN']), 'message': str(response['diagnosticMessage']),
|
||||
'referrals': referrals_to_list(response['referral'])}
|
||||
46
venv/Lib/site-packages/ldap3/operation/delete.py
Normal file
46
venv/Lib/site-packages/ldap3/operation/delete.py
Normal file
@@ -0,0 +1,46 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 ..protocol.rfc4511 import DelRequest, LDAPDN, ResultCode
|
||||
from ..operation.bind import referrals_to_list
|
||||
|
||||
|
||||
def delete_operation(dn):
|
||||
# DelRequest ::= [APPLICATION 10] LDAPDN
|
||||
request = DelRequest(LDAPDN(dn))
|
||||
|
||||
return request
|
||||
|
||||
|
||||
def delete_request_to_dict(request):
|
||||
return {'entry': str(request)}
|
||||
|
||||
|
||||
def delete_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'dn': str(response['matchedDN']),
|
||||
'message': str(response['diagnosticMessage']),
|
||||
'referrals': referrals_to_list(response['referral'])}
|
||||
109
venv/Lib/site-packages/ldap3/operation/extended.py
Normal file
109
venv/Lib/site-packages/ldap3/operation/extended.py
Normal file
@@ -0,0 +1,109 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 pyasn1.type.univ import OctetString
|
||||
from pyasn1.type.base import Asn1Item
|
||||
|
||||
from ..core.results import RESULT_CODES
|
||||
from ..protocol.rfc4511 import ExtendedRequest, RequestName, ResultCode, RequestValue
|
||||
from ..protocol.convert import referrals_to_list
|
||||
from ..utils.asn1 import encode
|
||||
from ..utils.conv import to_unicode
|
||||
|
||||
# ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
|
||||
# requestName [0] LDAPOID,
|
||||
# requestValue [1] OCTET STRING OPTIONAL }
|
||||
|
||||
|
||||
def extended_operation(request_name,
|
||||
request_value=None,
|
||||
no_encode=None):
|
||||
request = ExtendedRequest()
|
||||
request['requestName'] = RequestName(request_name)
|
||||
if request_value and isinstance(request_value, Asn1Item):
|
||||
request['requestValue'] = RequestValue(encode(request_value))
|
||||
elif str is not bytes and isinstance(request_value, (bytes, bytearray)): # in Python 3 doesn't try to encode a byte value
|
||||
request['requestValue'] = request_value
|
||||
elif request_value and no_encode: # doesn't encode the value
|
||||
request['requestValue'] = request_value
|
||||
elif request_value: # tries to encode as a octet string
|
||||
request['requestValue'] = RequestValue(encode(OctetString(str(request_value))))
|
||||
|
||||
# elif request_value is not None:
|
||||
# raise LDAPExtensionError('unable to encode value for extended operation')
|
||||
return request
|
||||
|
||||
|
||||
def extended_request_to_dict(request):
|
||||
# return {'name': str(request['requestName']), 'value': bytes(request['requestValue']) if request['requestValue'] else None}
|
||||
return {'name': str(request['requestName']), 'value': bytes(request['requestValue']) if 'requestValue' in request and request['requestValue'] is not None and request['requestValue'].hasValue() else None}
|
||||
|
||||
def extended_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'dn': str(response['matchedDN']),
|
||||
'message': str(response['diagnosticMessage']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'referrals': referrals_to_list(response['referral']),
|
||||
'responseName': str(response['responseName']) if response['responseName'] is not None and response['responseName'].hasValue() else str(),
|
||||
'responseValue': bytes(response['responseValue']) if response['responseValue'] is not None and response['responseValue'].hasValue() else bytes()}
|
||||
|
||||
|
||||
def intermediate_response_to_dict(response):
|
||||
return {'responseName': str(response['responseName']),
|
||||
'responseValue': bytes(response['responseValue']) if response['responseValue'] else bytes()}
|
||||
|
||||
|
||||
def extended_response_to_dict_fast(response):
|
||||
response_dict = dict()
|
||||
response_dict['result'] = int(response[0][3]) # resultCode
|
||||
response_dict['description'] = RESULT_CODES[response_dict['result']]
|
||||
response_dict['dn'] = to_unicode(response[1][3], from_server=True) # matchedDN
|
||||
response_dict['message'] = to_unicode(response[2][3], from_server=True) # diagnosticMessage
|
||||
response_dict['referrals'] = None # referrals
|
||||
response_dict['responseName'] = None # referrals
|
||||
response_dict['responseValue'] = None # responseValue
|
||||
|
||||
for r in response[3:]:
|
||||
if r[2] == 3: # referrals
|
||||
response_dict['referrals'] = referrals_to_list(r[3]) # referrals
|
||||
elif r[2] == 10: # responseName
|
||||
response_dict['responseName'] = to_unicode(r[3], from_server=True)
|
||||
response_dict['responseValue'] = b'' # responseValue could be empty
|
||||
|
||||
else: # responseValue (11)
|
||||
response_dict['responseValue'] = bytes(r[3])
|
||||
|
||||
return response_dict
|
||||
|
||||
|
||||
def intermediate_response_to_dict_fast(response):
|
||||
response_dict = dict()
|
||||
for r in response:
|
||||
if r[2] == 0: # responseName
|
||||
response_dict['responseName'] = to_unicode(r[3], from_server=True)
|
||||
else: # responseValue (1)
|
||||
response_dict['responseValue'] = bytes(r[3])
|
||||
|
||||
return response_dict
|
||||
96
venv/Lib/site-packages/ldap3/operation/modify.py
Normal file
96
venv/Lib/site-packages/ldap3/operation/modify.py
Normal file
@@ -0,0 +1,96 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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, MODIFY_DELETE, MODIFY_REPLACE, MODIFY_INCREMENT
|
||||
from ..protocol.rfc4511 import ModifyRequest, LDAPDN, Changes, Change, Operation, PartialAttribute, AttributeDescription, Vals, ResultCode
|
||||
from ..operation.bind import referrals_to_list
|
||||
from ..protocol.convert import changes_to_list, validate_attribute_value, prepare_for_sending
|
||||
|
||||
# ModifyRequest ::= [APPLICATION 6] SEQUENCE {
|
||||
# object LDAPDN,
|
||||
# changes SEQUENCE OF change SEQUENCE {
|
||||
# operation ENUMERATED {
|
||||
# add (0),
|
||||
# delete (1),
|
||||
# replace (2),
|
||||
# ... },
|
||||
# modification PartialAttribute } }
|
||||
|
||||
change_table = {MODIFY_ADD: 0, # accepts actual values too
|
||||
MODIFY_DELETE: 1,
|
||||
MODIFY_REPLACE: 2,
|
||||
MODIFY_INCREMENT: 3,
|
||||
0: 0,
|
||||
1: 1,
|
||||
2: 2,
|
||||
3: 3}
|
||||
|
||||
|
||||
def modify_operation(dn,
|
||||
changes,
|
||||
auto_encode,
|
||||
schema=None,
|
||||
validator=None,
|
||||
check_names=False):
|
||||
# changes is a dictionary in the form {'attribute': [(operation, [val1, ...]), ...], ...}
|
||||
# operation is 0 (add), 1 (delete), 2 (replace), 3 (increment)
|
||||
# increment as per RFC4525
|
||||
|
||||
change_list = Changes()
|
||||
pos = 0
|
||||
for attribute in changes:
|
||||
for change_operation in changes[attribute]:
|
||||
partial_attribute = PartialAttribute()
|
||||
partial_attribute['type'] = AttributeDescription(attribute)
|
||||
partial_attribute['vals'] = Vals()
|
||||
if isinstance(change_operation[1], SEQUENCE_TYPES):
|
||||
for index, value in enumerate(change_operation[1]):
|
||||
partial_attribute['vals'].setComponentByPosition(index, prepare_for_sending(validate_attribute_value(schema, attribute, value, auto_encode, validator, check_names=check_names)))
|
||||
else:
|
||||
partial_attribute['vals'].setComponentByPosition(0, prepare_for_sending(validate_attribute_value(schema, attribute, change_operation[1], auto_encode, validator, check_names=check_names)))
|
||||
change = Change()
|
||||
change['operation'] = Operation(change_table[change_operation[0]])
|
||||
change['modification'] = partial_attribute
|
||||
|
||||
change_list[pos] = change
|
||||
pos += 1
|
||||
|
||||
request = ModifyRequest()
|
||||
request['object'] = LDAPDN(dn)
|
||||
request['changes'] = change_list
|
||||
return request
|
||||
|
||||
|
||||
def modify_request_to_dict(request):
|
||||
return {'entry': str(request['object']),
|
||||
'changes': changes_to_list(request['changes'])}
|
||||
|
||||
|
||||
def modify_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'message': str(response['diagnosticMessage']),
|
||||
'dn': str(response['matchedDN']),
|
||||
'referrals': referrals_to_list(response['referral'])}
|
||||
62
venv/Lib/site-packages/ldap3/operation/modifyDn.py
Normal file
62
venv/Lib/site-packages/ldap3/operation/modifyDn.py
Normal file
@@ -0,0 +1,62 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.05.31
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 ..protocol.rfc4511 import ModifyDNRequest, LDAPDN, RelativeLDAPDN, DeleteOldRDN, NewSuperior, ResultCode
|
||||
from ..operation.bind import referrals_to_list
|
||||
|
||||
# ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
|
||||
# entry LDAPDN,
|
||||
# newrdn RelativeLDAPDN,
|
||||
# deleteoldrdn BOOLEAN,
|
||||
# newSuperior [0] LDAPDN OPTIONAL }
|
||||
|
||||
|
||||
def modify_dn_operation(dn,
|
||||
new_relative_dn,
|
||||
delete_old_rdn=True,
|
||||
new_superior=None):
|
||||
request = ModifyDNRequest()
|
||||
request['entry'] = LDAPDN(dn)
|
||||
request['newrdn'] = RelativeLDAPDN(new_relative_dn)
|
||||
request['deleteoldrdn'] = DeleteOldRDN(delete_old_rdn)
|
||||
if new_superior:
|
||||
request['newSuperior'] = NewSuperior(new_superior)
|
||||
|
||||
return request
|
||||
|
||||
|
||||
def modify_dn_request_to_dict(request):
|
||||
return {'entry': str(request['entry']),
|
||||
'newRdn': str(request['newrdn']),
|
||||
'deleteOldRdn': bool(request['deleteoldrdn']),
|
||||
'newSuperior': str(request['newSuperior']) if request['newSuperior'] is not None and request['newSuperior'].hasValue() else None}
|
||||
|
||||
|
||||
def modify_dn_response_to_dict(response):
|
||||
return {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'dn': str(response['matchedDN']),
|
||||
'referrals': referrals_to_list(response['referral']),
|
||||
'message': str(response['diagnosticMessage'])}
|
||||
579
venv/Lib/site-packages/ldap3/operation/search.py
Normal file
579
venv/Lib/site-packages/ldap3/operation/search.py
Normal file
@@ -0,0 +1,579 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.06.02
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 string import whitespace
|
||||
from os import linesep
|
||||
|
||||
from .. import DEREF_NEVER, BASE, LEVEL, SUBTREE, DEREF_SEARCH, DEREF_BASE, DEREF_ALWAYS, NO_ATTRIBUTES, SEQUENCE_TYPES, get_config_parameter, STRING_TYPES
|
||||
|
||||
from ..core.exceptions import LDAPInvalidFilterError, LDAPAttributeError, LDAPInvalidScopeError, LDAPInvalidDereferenceAliasesError
|
||||
from ..utils.ciDict import CaseInsensitiveDict
|
||||
from ..protocol.rfc4511 import SearchRequest, LDAPDN, Scope, DerefAliases, Integer0ToMax, TypesOnly, \
|
||||
AttributeSelection, Selector, EqualityMatch, AttributeDescription, AssertionValue, Filter, \
|
||||
Not, And, Or, ApproxMatch, GreaterOrEqual, LessOrEqual, ExtensibleMatch, Present, SubstringFilter, \
|
||||
Substrings, Final, Initial, Any, ResultCode, Substring, MatchingRule, Type, MatchValue, DnAttributes
|
||||
from ..operation.bind import referrals_to_list
|
||||
from ..protocol.convert import ava_to_dict, attributes_to_list, search_refs_to_list, validate_assertion_value, prepare_filter_for_sending, search_refs_to_list_fast
|
||||
from ..protocol.formatters.standard import format_attribute_values
|
||||
from ..utils.conv import to_unicode, to_raw
|
||||
|
||||
ROOT = 0
|
||||
AND = 1
|
||||
OR = 2
|
||||
NOT = 3
|
||||
MATCH_APPROX = 4
|
||||
MATCH_GREATER_OR_EQUAL = 5
|
||||
MATCH_LESS_OR_EQUAL = 6
|
||||
MATCH_EXTENSIBLE = 7
|
||||
MATCH_PRESENT = 8
|
||||
MATCH_SUBSTRING = 9
|
||||
MATCH_EQUAL = 10
|
||||
|
||||
SEARCH_OPEN = 20
|
||||
SEARCH_OPEN_OR_CLOSE = 21
|
||||
SEARCH_MATCH_OR_CLOSE = 22
|
||||
SEARCH_MATCH_OR_CONTROL = 23
|
||||
|
||||
|
||||
class FilterNode(object):
|
||||
def __init__(self, tag=None, assertion=None):
|
||||
self.tag = tag
|
||||
self.parent = None
|
||||
self.assertion = assertion
|
||||
self.elements = []
|
||||
|
||||
def append(self, filter_node):
|
||||
filter_node.parent = self
|
||||
self.elements.append(filter_node)
|
||||
return filter_node
|
||||
|
||||
def __str__(self, pos=0):
|
||||
self.__repr__(pos)
|
||||
|
||||
def __repr__(self, pos=0):
|
||||
node_tags = ['ROOT', 'AND', 'OR', 'NOT', 'MATCH_APPROX', 'MATCH_GREATER_OR_EQUAL', 'MATCH_LESS_OR_EQUAL', 'MATCH_EXTENSIBLE', 'MATCH_PRESENT', 'MATCH_SUBSTRING', 'MATCH_EQUAL']
|
||||
representation = ' ' * pos + 'tag: ' + node_tags[self.tag] + ' - assertion: ' + str(self.assertion)
|
||||
if self.elements:
|
||||
representation += ' - elements: ' + str(len(self.elements))
|
||||
for element in self.elements:
|
||||
representation += linesep + ' ' * pos + element.__repr__(pos + 2)
|
||||
return representation
|
||||
|
||||
|
||||
def evaluate_match(match, schema, auto_escape, auto_encode, validator, check_names):
|
||||
left_part, equal_sign, right_part = match.strip().partition('=')
|
||||
if not equal_sign:
|
||||
raise LDAPInvalidFilterError('invalid matching assertion')
|
||||
if left_part.endswith('~'): # approximate match '~='
|
||||
tag = MATCH_APPROX
|
||||
left_part = left_part[:-1].strip()
|
||||
right_part = right_part.strip()
|
||||
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
|
||||
elif left_part.endswith('>'): # greater or equal match '>='
|
||||
tag = MATCH_GREATER_OR_EQUAL
|
||||
left_part = left_part[:-1].strip()
|
||||
right_part = right_part.strip()
|
||||
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
|
||||
elif left_part.endswith('<'): # less or equal match '<='
|
||||
tag = MATCH_LESS_OR_EQUAL
|
||||
left_part = left_part[:-1].strip()
|
||||
right_part = right_part.strip()
|
||||
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
|
||||
elif left_part.endswith(':'): # extensible match ':='
|
||||
tag = MATCH_EXTENSIBLE
|
||||
left_part = left_part[:-1].strip()
|
||||
right_part = right_part.strip()
|
||||
extended_filter_list = left_part.split(':')
|
||||
matching_rule = False
|
||||
dn_attributes = False
|
||||
attribute_name = False
|
||||
if extended_filter_list[0] == '': # extensible filter format [:dn]:matchingRule:=assertionValue
|
||||
if len(extended_filter_list) == 2 and extended_filter_list[1].lower().strip() != 'dn':
|
||||
matching_rule = extended_filter_list[1]
|
||||
elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn':
|
||||
dn_attributes = True
|
||||
matching_rule = extended_filter_list[2]
|
||||
else:
|
||||
raise LDAPInvalidFilterError('invalid extensible filter')
|
||||
elif len(extended_filter_list) <= 3: # extensible filter format attr[:dn][:matchingRule]:=assertionValue
|
||||
if len(extended_filter_list) == 1:
|
||||
attribute_name = extended_filter_list[0]
|
||||
elif len(extended_filter_list) == 2:
|
||||
attribute_name = extended_filter_list[0]
|
||||
if extended_filter_list[1].lower().strip() == 'dn':
|
||||
dn_attributes = True
|
||||
else:
|
||||
matching_rule = extended_filter_list[1]
|
||||
elif len(extended_filter_list) == 3 and extended_filter_list[1].lower().strip() == 'dn':
|
||||
attribute_name = extended_filter_list[0]
|
||||
dn_attributes = True
|
||||
matching_rule = extended_filter_list[2]
|
||||
else:
|
||||
raise LDAPInvalidFilterError('invalid extensible filter')
|
||||
|
||||
if not attribute_name and not matching_rule:
|
||||
raise LDAPInvalidFilterError('invalid extensible filter')
|
||||
attribute_name = attribute_name.strip() if attribute_name else False
|
||||
matching_rule = matching_rule.strip() if matching_rule else False
|
||||
assertion = {'attr': attribute_name, 'value': validate_assertion_value(schema, attribute_name, right_part, auto_escape, auto_encode, validator, check_names), 'matchingRule': matching_rule, 'dnAttributes': dn_attributes}
|
||||
elif right_part == '*': # attribute present match '=*'
|
||||
tag = MATCH_PRESENT
|
||||
left_part = left_part.strip()
|
||||
assertion = {'attr': left_part}
|
||||
elif '*' in right_part: # substring match '=initial*substring*substring*final'
|
||||
tag = MATCH_SUBSTRING
|
||||
left_part = left_part.strip()
|
||||
right_part = right_part.strip()
|
||||
substrings = right_part.split('*')
|
||||
initial = validate_assertion_value(schema, left_part, substrings[0], auto_escape, auto_encode, validator, check_names) if substrings[0] else None
|
||||
final = validate_assertion_value(schema, left_part, substrings[-1], auto_escape, auto_encode, validator, check_names) if substrings[-1] else None
|
||||
any_string = [validate_assertion_value(schema, left_part, substring, auto_escape, auto_encode, validator, check_names) for substring in substrings[1:-1] if substring]
|
||||
#assertion = {'attr': left_part, 'initial': initial, 'any': any_string, 'final': final}
|
||||
assertion = {'attr': left_part}
|
||||
if initial:
|
||||
assertion['initial'] = initial
|
||||
if any_string:
|
||||
assertion['any'] = any_string
|
||||
if final:
|
||||
assertion['final'] = final
|
||||
else: # equality match '='
|
||||
tag = MATCH_EQUAL
|
||||
left_part = left_part.strip()
|
||||
right_part = right_part.strip()
|
||||
assertion = {'attr': left_part, 'value': validate_assertion_value(schema, left_part, right_part, auto_escape, auto_encode, validator, check_names)}
|
||||
|
||||
return FilterNode(tag, assertion)
|
||||
|
||||
|
||||
def parse_filter(search_filter, schema, auto_escape, auto_encode, validator, check_names):
|
||||
if str is not bytes and isinstance(search_filter, bytes): # python 3 with byte filter
|
||||
search_filter = to_unicode(search_filter)
|
||||
search_filter = search_filter.strip()
|
||||
if search_filter and search_filter.count('(') == search_filter.count(')') and search_filter.startswith('(') and search_filter.endswith(')'):
|
||||
state = SEARCH_OPEN_OR_CLOSE
|
||||
root = FilterNode(ROOT)
|
||||
current_node = root
|
||||
start_pos = None
|
||||
skip_white_space = True
|
||||
just_closed = False
|
||||
for pos, c in enumerate(search_filter):
|
||||
if skip_white_space and c in whitespace:
|
||||
continue
|
||||
elif (state == SEARCH_OPEN or state == SEARCH_OPEN_OR_CLOSE) and c == '(':
|
||||
state = SEARCH_MATCH_OR_CONTROL
|
||||
just_closed = False
|
||||
elif state == SEARCH_MATCH_OR_CONTROL and c in '&!|':
|
||||
if c == '&':
|
||||
current_node = current_node.append(FilterNode(AND))
|
||||
elif c == '|':
|
||||
current_node = current_node.append(FilterNode(OR))
|
||||
elif c == '!':
|
||||
current_node = current_node.append(FilterNode(NOT))
|
||||
state = SEARCH_OPEN
|
||||
elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_OPEN_OR_CLOSE) and c == ')':
|
||||
if just_closed:
|
||||
current_node = current_node.parent
|
||||
else:
|
||||
just_closed = True
|
||||
skip_white_space = True
|
||||
end_pos = pos
|
||||
if start_pos:
|
||||
if current_node.tag == NOT and len(current_node.elements) > 0:
|
||||
raise LDAPInvalidFilterError('NOT (!) clause in filter cannot be multiple')
|
||||
current_node.append(evaluate_match(search_filter[start_pos:end_pos], schema, auto_escape, auto_encode, validator, check_names))
|
||||
start_pos = None
|
||||
state = SEARCH_OPEN_OR_CLOSE
|
||||
elif (state == SEARCH_MATCH_OR_CLOSE or state == SEARCH_MATCH_OR_CONTROL) and c not in '()':
|
||||
skip_white_space = False
|
||||
if not start_pos:
|
||||
start_pos = pos
|
||||
state = SEARCH_MATCH_OR_CLOSE
|
||||
else:
|
||||
raise LDAPInvalidFilterError('malformed filter')
|
||||
if len(root.elements) != 1:
|
||||
raise LDAPInvalidFilterError('missing boolean operator in filter')
|
||||
return root
|
||||
else:
|
||||
raise LDAPInvalidFilterError('invalid filter')
|
||||
|
||||
|
||||
def compile_filter(filter_node):
|
||||
"""Builds ASN1 structure for filter, converts from filter LDAP escaping to bytes"""
|
||||
compiled_filter = Filter()
|
||||
if filter_node.tag == AND:
|
||||
boolean_filter = And()
|
||||
pos = 0
|
||||
for element in filter_node.elements:
|
||||
boolean_filter[pos] = compile_filter(element)
|
||||
pos += 1
|
||||
compiled_filter['and'] = boolean_filter
|
||||
elif filter_node.tag == OR:
|
||||
boolean_filter = Or()
|
||||
pos = 0
|
||||
for element in filter_node.elements:
|
||||
boolean_filter[pos] = compile_filter(element)
|
||||
pos += 1
|
||||
compiled_filter['or'] = boolean_filter
|
||||
elif filter_node.tag == NOT:
|
||||
boolean_filter = Not()
|
||||
boolean_filter['innerNotFilter'] = compile_filter(filter_node.elements[0])
|
||||
compiled_filter.setComponentByName('notFilter', boolean_filter, verifyConstraints=False) # do not verify constraints because of hack for recursive filters in rfc4511
|
||||
|
||||
elif filter_node.tag == MATCH_APPROX:
|
||||
matching_filter = ApproxMatch()
|
||||
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
|
||||
matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
|
||||
compiled_filter['approxMatch'] = matching_filter
|
||||
elif filter_node.tag == MATCH_GREATER_OR_EQUAL:
|
||||
matching_filter = GreaterOrEqual()
|
||||
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
|
||||
matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
|
||||
compiled_filter['greaterOrEqual'] = matching_filter
|
||||
elif filter_node.tag == MATCH_LESS_OR_EQUAL:
|
||||
matching_filter = LessOrEqual()
|
||||
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
|
||||
matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
|
||||
compiled_filter['lessOrEqual'] = matching_filter
|
||||
elif filter_node.tag == MATCH_EXTENSIBLE:
|
||||
matching_filter = ExtensibleMatch()
|
||||
if filter_node.assertion['matchingRule']:
|
||||
matching_filter['matchingRule'] = MatchingRule(filter_node.assertion['matchingRule'])
|
||||
if filter_node.assertion['attr']:
|
||||
matching_filter['type'] = Type(filter_node.assertion['attr'])
|
||||
matching_filter['matchValue'] = MatchValue(prepare_filter_for_sending(filter_node.assertion['value']))
|
||||
matching_filter['dnAttributes'] = DnAttributes(filter_node.assertion['dnAttributes'])
|
||||
compiled_filter['extensibleMatch'] = matching_filter
|
||||
elif filter_node.tag == MATCH_PRESENT:
|
||||
matching_filter = Present(AttributeDescription(filter_node.assertion['attr']))
|
||||
compiled_filter['present'] = matching_filter
|
||||
elif filter_node.tag == MATCH_SUBSTRING:
|
||||
matching_filter = SubstringFilter()
|
||||
matching_filter['type'] = AttributeDescription(filter_node.assertion['attr'])
|
||||
substrings = Substrings()
|
||||
pos = 0
|
||||
if 'initial' in filter_node.assertion and filter_node.assertion['initial']:
|
||||
substrings[pos] = Substring().setComponentByName('initial', Initial(prepare_filter_for_sending(filter_node.assertion['initial'])))
|
||||
pos += 1
|
||||
if 'any' in filter_node.assertion and filter_node.assertion['any']:
|
||||
for substring in filter_node.assertion['any']:
|
||||
substrings[pos] = Substring().setComponentByName('any', Any(prepare_filter_for_sending(substring)))
|
||||
pos += 1
|
||||
if 'final' in filter_node.assertion and filter_node.assertion['final']:
|
||||
substrings[pos] = Substring().setComponentByName('final', Final(prepare_filter_for_sending(filter_node.assertion['final'])))
|
||||
matching_filter['substrings'] = substrings
|
||||
compiled_filter['substringFilter'] = matching_filter
|
||||
elif filter_node.tag == MATCH_EQUAL:
|
||||
matching_filter = EqualityMatch()
|
||||
matching_filter['attributeDesc'] = AttributeDescription(filter_node.assertion['attr'])
|
||||
matching_filter['assertionValue'] = AssertionValue(prepare_filter_for_sending(filter_node.assertion['value']))
|
||||
compiled_filter.setComponentByName('equalityMatch', matching_filter)
|
||||
else:
|
||||
raise LDAPInvalidFilterError('unknown filter node tag')
|
||||
|
||||
return compiled_filter
|
||||
|
||||
|
||||
def build_attribute_selection(attribute_list, schema):
|
||||
conf_attributes_excluded_from_check = [v.lower() for v in get_config_parameter('ATTRIBUTES_EXCLUDED_FROM_CHECK')]
|
||||
|
||||
attribute_selection = AttributeSelection()
|
||||
for index, attribute in enumerate(attribute_list):
|
||||
if schema and schema.attribute_types:
|
||||
if ';' in attribute: # exclude tags from validation
|
||||
if not attribute[0:attribute.index(';')] in schema.attribute_types and attribute.lower() not in conf_attributes_excluded_from_check:
|
||||
raise LDAPAttributeError('invalid attribute type in attribute list: ' + attribute)
|
||||
else:
|
||||
if attribute not in schema.attribute_types and attribute.lower() not in conf_attributes_excluded_from_check:
|
||||
raise LDAPAttributeError('invalid attribute type in attribute list: ' + attribute)
|
||||
attribute_selection[index] = Selector(attribute)
|
||||
|
||||
return attribute_selection
|
||||
|
||||
|
||||
def search_operation(search_base,
|
||||
search_filter,
|
||||
search_scope,
|
||||
dereference_aliases,
|
||||
attributes,
|
||||
size_limit,
|
||||
time_limit,
|
||||
types_only,
|
||||
auto_escape,
|
||||
auto_encode,
|
||||
schema=None,
|
||||
validator=None,
|
||||
check_names=False):
|
||||
# SearchRequest ::= [APPLICATION 3] SEQUENCE {
|
||||
# baseObject LDAPDN,
|
||||
# scope ENUMERATED {
|
||||
# baseObject (0),
|
||||
# singleLevel (1),
|
||||
# wholeSubtree (2),
|
||||
# ... },
|
||||
# derefAliases ENUMERATED {
|
||||
# neverDerefAliases (0),
|
||||
# derefInSearching (1),
|
||||
# derefFindingBaseObj (2),
|
||||
# derefAlways (3) },
|
||||
# sizeLimit INTEGER (0 .. maxInt),
|
||||
# timeLimit INTEGER (0 .. maxInt),
|
||||
# typesOnly BOOLEAN,
|
||||
# filter Filter,
|
||||
# attributes AttributeSelection }
|
||||
request = SearchRequest()
|
||||
request['baseObject'] = LDAPDN(search_base)
|
||||
|
||||
if search_scope == BASE or search_scope == 0:
|
||||
request['scope'] = Scope('baseObject')
|
||||
elif search_scope == LEVEL or search_scope == 1:
|
||||
request['scope'] = Scope('singleLevel')
|
||||
elif search_scope == SUBTREE or search_scope == 2:
|
||||
request['scope'] = Scope('wholeSubtree')
|
||||
else:
|
||||
raise LDAPInvalidScopeError('invalid scope type')
|
||||
|
||||
if dereference_aliases == DEREF_NEVER or dereference_aliases == 0:
|
||||
request['derefAliases'] = DerefAliases('neverDerefAliases')
|
||||
elif dereference_aliases == DEREF_SEARCH or dereference_aliases == 1:
|
||||
request['derefAliases'] = DerefAliases('derefInSearching')
|
||||
elif dereference_aliases == DEREF_BASE or dereference_aliases == 2:
|
||||
request['derefAliases'] = DerefAliases('derefFindingBaseObj')
|
||||
elif dereference_aliases == DEREF_ALWAYS or dereference_aliases == 3:
|
||||
request['derefAliases'] = DerefAliases('derefAlways')
|
||||
else:
|
||||
raise LDAPInvalidDereferenceAliasesError('invalid dereference aliases type')
|
||||
|
||||
request['sizeLimit'] = Integer0ToMax(size_limit)
|
||||
request['timeLimit'] = Integer0ToMax(time_limit)
|
||||
request['typesOnly'] = TypesOnly(True) if types_only else TypesOnly(False)
|
||||
request['filter'] = compile_filter(parse_filter(search_filter, schema, auto_escape, auto_encode, validator, check_names).elements[0]) # parse the searchFilter string and compile it starting from the root node
|
||||
if not isinstance(attributes, SEQUENCE_TYPES):
|
||||
attributes = [NO_ATTRIBUTES]
|
||||
|
||||
request['attributes'] = build_attribute_selection(attributes, schema)
|
||||
|
||||
return request
|
||||
|
||||
|
||||
def decode_vals(vals):
|
||||
try:
|
||||
return [str(val) for val in vals if val] if vals else None
|
||||
except UnicodeDecodeError:
|
||||
return decode_raw_vals(vals)
|
||||
|
||||
def decode_vals_fast(vals):
|
||||
try:
|
||||
return [to_unicode(val[3], from_server=True) for val in vals if val] if vals else None
|
||||
except UnicodeDecodeError:
|
||||
return [val[3] for val in vals if val] if vals else None
|
||||
|
||||
|
||||
def attributes_to_dict(attribute_list):
|
||||
conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
|
||||
attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
|
||||
for attribute in attribute_list:
|
||||
attributes[str(attribute['type'])] = decode_vals(attribute['vals'])
|
||||
return attributes
|
||||
|
||||
|
||||
def attributes_to_dict_fast(attribute_list):
|
||||
conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
|
||||
attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
|
||||
for attribute in attribute_list:
|
||||
attributes[to_unicode(attribute[3][0][3], from_server=True)] = decode_vals_fast(attribute[3][1][3])
|
||||
|
||||
return attributes
|
||||
|
||||
|
||||
def decode_raw_vals(vals):
|
||||
return [bytes(val) for val in vals] if vals else None
|
||||
|
||||
|
||||
def decode_raw_vals_fast(vals):
|
||||
return [bytes(val[3]) for val in vals] if vals else None
|
||||
|
||||
|
||||
def raw_attributes_to_dict(attribute_list):
|
||||
conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
|
||||
|
||||
attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
|
||||
for attribute in attribute_list:
|
||||
attributes[str(attribute['type'])] = decode_raw_vals(attribute['vals'])
|
||||
|
||||
return attributes
|
||||
|
||||
|
||||
def raw_attributes_to_dict_fast(attribute_list):
|
||||
conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
|
||||
attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
|
||||
for attribute in attribute_list:
|
||||
attributes[to_unicode(attribute[3][0][3], from_server=True)] = decode_raw_vals_fast(attribute[3][1][3])
|
||||
|
||||
return attributes
|
||||
|
||||
|
||||
def checked_attributes_to_dict(attribute_list, schema=None, custom_formatter=None):
|
||||
conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
|
||||
|
||||
checked_attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
|
||||
for attribute in attribute_list:
|
||||
name = str(attribute['type'])
|
||||
checked_attributes[name] = format_attribute_values(schema, name, decode_raw_vals(attribute['vals']) or [], custom_formatter)
|
||||
return checked_attributes
|
||||
|
||||
|
||||
def checked_attributes_to_dict_fast(attribute_list, schema=None, custom_formatter=None):
|
||||
conf_case_insensitive_attributes = get_config_parameter('CASE_INSENSITIVE_ATTRIBUTE_NAMES')
|
||||
|
||||
checked_attributes = CaseInsensitiveDict() if conf_case_insensitive_attributes else dict()
|
||||
for attribute in attribute_list:
|
||||
name = to_unicode(attribute[3][0][3], from_server=True)
|
||||
checked_attributes[name] = format_attribute_values(schema, name, decode_raw_vals_fast(attribute[3][1][3]) or [], custom_formatter)
|
||||
return checked_attributes
|
||||
|
||||
|
||||
def matching_rule_assertion_to_string(matching_rule_assertion):
|
||||
return str(matching_rule_assertion)
|
||||
|
||||
|
||||
def filter_to_string(filter_object):
|
||||
filter_type = filter_object.getName()
|
||||
filter_string = '('
|
||||
if filter_type == 'and':
|
||||
filter_string += '&'
|
||||
for f in filter_object['and']:
|
||||
filter_string += filter_to_string(f)
|
||||
elif filter_type == 'or':
|
||||
filter_string += '|'
|
||||
for f in filter_object['or']:
|
||||
filter_string += filter_to_string(f)
|
||||
elif filter_type == 'notFilter':
|
||||
filter_string += '!' + filter_to_string(filter_object['notFilter']['innerNotFilter'])
|
||||
elif filter_type == 'equalityMatch':
|
||||
ava = ava_to_dict(filter_object['equalityMatch'])
|
||||
filter_string += ava['attribute'] + '=' + ava['value']
|
||||
elif filter_type == 'substringFilter':
|
||||
attribute = filter_object['substringFilter']['type']
|
||||
filter_string += str(attribute) + '='
|
||||
for substring in filter_object['substringFilter']['substrings']:
|
||||
component = substring.getName()
|
||||
if substring[component] is not None and substring[component].hasValue():
|
||||
if component == 'initial':
|
||||
filter_string += str(substring['initial']) + '*'
|
||||
elif component == 'any':
|
||||
filter_string += str(substring['any']) if filter_string.endswith('*') else '*' + str(substring['any'])
|
||||
filter_string += '*'
|
||||
elif component == 'final':
|
||||
filter_string += '*' + str(substring['final'])
|
||||
elif filter_type == 'greaterOrEqual':
|
||||
ava = ava_to_dict(filter_object['greaterOrEqual'])
|
||||
filter_string += ava['attribute'] + '>=' + ava['value']
|
||||
elif filter_type == 'lessOrEqual':
|
||||
ava = ava_to_dict(filter_object['lessOrEqual'])
|
||||
filter_string += ava['attribute'] + '<=' + ava['value']
|
||||
elif filter_type == 'present':
|
||||
filter_string += str(filter_object['present']) + '=*'
|
||||
elif filter_type == 'approxMatch':
|
||||
ava = ava_to_dict(filter_object['approxMatch'])
|
||||
filter_string += ava['attribute'] + '~=' + ava['value']
|
||||
elif filter_type == 'extensibleMatch':
|
||||
filter_string += matching_rule_assertion_to_string(filter_object['extensibleMatch'])
|
||||
else:
|
||||
raise LDAPInvalidFilterError('error converting filter to string')
|
||||
filter_string += ')'
|
||||
|
||||
if str is bytes: # Python2, forces conversion to Unicode
|
||||
filter_string = to_unicode(filter_string)
|
||||
|
||||
return filter_string
|
||||
|
||||
|
||||
def search_request_to_dict(request):
|
||||
return {'base': str(request['baseObject']),
|
||||
'scope': int(request['scope']),
|
||||
'dereferenceAlias': int(request['derefAliases']),
|
||||
'sizeLimit': int(request['sizeLimit']),
|
||||
'timeLimit': int(request['timeLimit']),
|
||||
'typesOnly': bool(request['typesOnly']),
|
||||
'filter': filter_to_string(request['filter']),
|
||||
'attributes': attributes_to_list(request['attributes'])}
|
||||
|
||||
|
||||
def search_result_entry_response_to_dict(response, schema, custom_formatter, check_names):
|
||||
entry = dict()
|
||||
# entry['dn'] = str(response['object'])
|
||||
if response['object']:
|
||||
if isinstance(response['object'], STRING_TYPES): # mock strategies return string not a PyAsn1 object
|
||||
entry['raw_dn'] = to_raw(response['object'])
|
||||
entry['dn'] = to_unicode(response['object'])
|
||||
else:
|
||||
entry['raw_dn'] = str(response['object'])
|
||||
entry['dn'] = to_unicode(bytes(response['object']), from_server=True)
|
||||
else:
|
||||
entry['raw_dn'] = b''
|
||||
entry['dn'] = ''
|
||||
entry['raw_attributes'] = raw_attributes_to_dict(response['attributes'])
|
||||
if check_names:
|
||||
entry['attributes'] = checked_attributes_to_dict(response['attributes'], schema, custom_formatter)
|
||||
else:
|
||||
entry['attributes'] = attributes_to_dict(response['attributes'])
|
||||
|
||||
return entry
|
||||
|
||||
|
||||
def search_result_done_response_to_dict(response):
|
||||
result = {'result': int(response['resultCode']),
|
||||
'description': ResultCode().getNamedValues().getName(response['resultCode']),
|
||||
'message': str(response['diagnosticMessage']),
|
||||
'dn': str(response['matchedDN']),
|
||||
'referrals': referrals_to_list(response['referral'])}
|
||||
|
||||
if 'controls' in response: # used for returning controls in Mock strategies
|
||||
result['controls'] = dict()
|
||||
for control in response['controls']:
|
||||
result['controls'][control[0]] = control[1]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def search_result_reference_response_to_dict(response):
|
||||
return {'uri': search_refs_to_list(response)}
|
||||
|
||||
|
||||
def search_result_entry_response_to_dict_fast(response, schema, custom_formatter, check_names):
|
||||
entry_dict = dict()
|
||||
entry_dict['raw_dn'] = response[0][3]
|
||||
entry_dict['dn'] = to_unicode(response[0][3], from_server=True)
|
||||
entry_dict['raw_attributes'] = raw_attributes_to_dict_fast(response[1][3]) # attributes
|
||||
if check_names:
|
||||
entry_dict['attributes'] = checked_attributes_to_dict_fast(response[1][3], schema, custom_formatter) # attributes
|
||||
else:
|
||||
entry_dict['attributes'] = attributes_to_dict_fast(response[1][3]) # attributes
|
||||
|
||||
return entry_dict
|
||||
|
||||
|
||||
def search_result_reference_response_to_dict_fast(response):
|
||||
return {'uri': search_refs_to_list_fast([r[3] for r in response])}
|
||||
32
venv/Lib/site-packages/ldap3/operation/unbind.py
Normal file
32
venv/Lib/site-packages/ldap3/operation/unbind.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""
|
||||
"""
|
||||
|
||||
# Created on 2013.09.03
|
||||
#
|
||||
# Author: Giovanni Cannata
|
||||
#
|
||||
# Copyright 2013 - 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 ..protocol.rfc4511 import UnbindRequest
|
||||
|
||||
|
||||
def unbind_operation():
|
||||
# UnbindRequest ::= [APPLICATION 2] NULL
|
||||
request = UnbindRequest()
|
||||
return request
|
||||
Reference in New Issue
Block a user