Issue Description:
Create a module in lib389 to Convert a byte sequence to a properly escaped for LDAP
https://www.python-ldap.org/en/python-ldap-3.2.0/reference/ldap-dn.html?highlight=escape#ldap.dn.escape_dn_chars
https://www.python-ldap.org/en/python-ldap-3.2.0/reference/ldap-filter.html?highlight=escape#ldap.filter.escape_filter_chars
Metadata Update from @firstyear: - Custom field origin adjusted to None - Custom field reviewstatus adjusted to None
There are mainly two times you need this - dn escaping, and filter escaping. python-ldap provides both, and lib389 automatically handles this in _mapped_object in most cases.
The only other thing is url escaping, which should be around here but I don't see it (mainly for ldapi). https://www.python-ldap.org/en/python-ldap-3.2.0/reference/ldapurl.html?highlight=url
I think I want to know what your problem case is and what you are trying to achieve, because I think these apis already exist and work correctly ....
I have this binary value :
crt = b'0\x82\x05X0\x82\x03@\xa0\x03\x02\x01\x02\x02\x05\x00\xb1fg\xcd0\r\x06\t\x86H\x86\xf7\r\x01\x01\x0b\x05\x000e1\x0b0\t\x06\x03U\x04\x06\x13\x02AU1\x130\x11\x06\x03U\x04\x08\x13\nQueensland1\x0e0\x0c\x06\x03U\x04\x07\x13\x05389ds1\x100\x0e\x06\x03U\x04\n\x13\x07testing1\x1f0\x1d\x06\x03U\x04\x03\x13\x16ssca.389ds.example.com0\x1e\x17\r190613115811Z\x17\r210613115811Z0e1\x0b0\t\x06\x03U\x04\x06\x13\x02AU1\x130\x11\x06\x03U\x04\x08\x13\nQueensland1\x0e0\x0c\x06\x03U\x04\x07\x13\x05389ds1\x100\x0e\x06\x03U\x04\n\x13\x07testing1\x1f0\x1d\x06\x03U\x04\x03\x13\x16ssca.389ds.example.com0\x82\x02"0\r\x06\t\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x02\x0f\x000\x82\x02\n\x02\x82\x02\x01\x00\xd6\xc6\x9e\xe7\x1cn\xd0\xe8l\xba\xb7\t/\x1b\xd9\xd6\xf7Du\x88\xd26\xcd.#\xa4@\xbde\xfcV\xb3XE\x10\x079\xdb\xd4\x18\xc3\x7f\xa4\x02K\x96#\x1c\xe1Jh\xaa\xdeh\xef\xfeO\xff3\xd1tl\xe0\xf9\x07\x8e7<\xa6]\x8bo\xe7\xc7iF\xd4\x951\xee\xe8\x97\x87\xc3\xb6\x9a\x9fo\xc81w\x9b\xe9lK\x8e\xd6u.\x98\xa9\xed\xd7T\xf6\x91\x05p\x14r\xb0\x93\x16(\xf0\x16:\xff,\xb8\xc5\x8e:\xe8\x13\xa8\x97\x17k\x93q\xf9]K\x1a\xfc2\x02\xcf!\xa8\x86-\xd0\xe3E\xbcIX\xb2\x86\x92Rz+\xd0\x1d\xeb{\xac\xc1t(k\xb3T\xf7t\xfd\xf4\x0bvY\x16c\xcc\xd3 -\xe58\xd8Xs\x99\xe4\x94gT\xae\xfa\t\x8axd\x98B\xf4v\xea\xe6\xfbfhG%\xc8R\xe2\x9a|(\xa2f\x1a\xaeT\xa1\x8d\xceN\xb9N\xbeE!]\xd0\x7f\xfc\xfcs5{\xe6z#\xea\xadrO\xfb\x0c[\xfc\xbf{\x0ck-\x9cN\xe6N\x8fAW\xb8\x08.H:\xb2C\x944\xd0\xfc{&i\xc4\x06\xb1\xd0\xf4\xbfy\xd6\xe2\xee\x9e\xb2\xc6\x0f-O0\xab\x0cF\xfc(\x9f\xa5;\x17xt|\xac\x8a b\xbf\xa7\xa3d\xf9VA\x05\xa2\x1d\xcd\xc7w\xcbI[muB\xa8br\xae\xdf\xe4\x1e\xc9\xe64\xd3\x1d^\x88\xb2\xc0\("\xa8z\x90\x1cEm\xfc[\'\x01\x08\'\x06,\x18\xc46\xcbF\x0b\xcc\x0b\x83\x17|l2,\x0c\x08\xda\x1e%a\x00\x19\x90\xd7_i\x03\xa5\xe4\xcc\xda\x8b\xces\xa0<;\x13\xc8\x04z\x8eK\xbb\xdb\x9a\xdf\x8e\xa3\x98u\xba\x18\x84\xf0\xfbO\x94\xa8\xefN]3-f\xcd\x11g<\xb6\xd5\x0c\xa6\x18\xb3+\xf99j\xff\xbe\xe2y\xf4\xac\x94=\x15\xb0\xea\x7fH\x03T\xe7\xb6\xa63\xde\x16H\x99\xa0\x1bL^\xfd\xaa]74\xe3\xa5[\xd6\x0f$.\xe3\x9d\xcb\xc69w\xe0\xa3\x8e\xcfE\xc2g\x0ff\x07\x11S\xf1\xfd5]Z\xf1\xd7\xeb\x1d\xd7#\xd3X^\x9dR{\xdb\x02\x03\x01\x00\x01\xa3\x0f0\r0\x0b\x06\x03U\x1d\x0f\x04\x04\x03\x02\x02\x040\r\x06\t*\x86H\x86\xf7\r\x01\x01\x0b\x05\x00\x03\x82\x02\x01\x00\xd2\x86\xc5\x020\xb4\x9a(\xec\xe9\xd0\xbc\xc0)u\xf8?\x9d\x95a\x1e\xe7=\xa6\x8e\xb7\x86Q\x8f\x8bM\xc4\x05\xe5\x07|\x04z;\x93^\xc1\xdf;\xa6\xfe0\xe4\x9e\x9ezE\x10k\x15v\xbf\xaa@4s\xa0\xaf\x16\xf9\xb0\xdbK\x14\xf5\xa9\x0e\xb6}\xfa\x86xv\x1f\xa1\x15\x8a\x83\x87\xbb\xeb\x89\xe9\xa8\x88t/Il\xcc\xee\xb4\x82!P\xa2\x95\t@\x1bE+\xfbbs9\xb3<Mkw<1\xca\x13\x1fZ\xd8|\x9eB\xf4\x03S!\t\x9f\xa7\xb3\xb85ID\xfbf\xd4#<\x86\xd3\xed<\x02LD\xcd\xc0\xa0\x16\x14\xcb\x17\x98r\x1e\\\x80\x99\xab\nC\x92m\x04\xfd\xa5a\xc5\x1f\x9e^C\xcci\xad\xc34\xfa{@\xb7\xc1_\x11\x0b\xe5\x0bT \xc25\xff\x15\x06\xd9\xdd\x06\x7f\x1f)\x84\x98\x91\xc73S[ATZ\xc3\x87^qR\xa9\xcf\x9a\xaf!d@{au\xa0\xac\xfc\x8e\xad&\xbf\x84\x10\xc7Z\xf1\x1e~?\xae\xf6\xd3i\x04e\xc7\x1e\x06\xf2~\x9c\xa8\r\xc6\xf1\xb1\xa4^\xec\x06\xa1\xa7PS\x1e\xe2O\xb4e\x98\x1au=4\x90\x81\xa3\xd3\xef\x19gY\xf5\x08\xe9\xc5\xba\xfc=\xac\xe1\xce\x95\x05\xdd\x8f\xe2\x7fH$\x8e\t\x94\x8bcz,\xe5\xbe3\xb0\xee\xfc\1\x11\xd7}u\xbe\xfd\xad\x83\xfdn\xa5}\xab#\xc8\xd8\x85\xebkhX\x9f\x81\xd2/2@\xcb\x10:K\xd5b\xc8\xf3\xce\xb43\x84\x07\xe8\xd7\xe3\xaf\x85etP%\xcb\xd9Y%\xbd\x84\xc7A\x0e\xae\x9e\x16\xeb\xde)]\xb3\xc2\xd6\xf1\x05w\x8b\xb9\xa6:9a\x1b?O\xb7\xbd/-ISS(\xbc/\x15\x0e\xd2\xfb\xd1\xc7!\xc2\x94\x03f\x81 \x11\xf2\x81E\xeb\xde\xb7/\x00\x1d\xa54\xe8\xab\xf2\xf7\x9b\x80<\x05\xdc\x0cEL\x8f\x1f\x16\x96t\xc3\xeb\xc9"\xc5\xf9\xf5\x9d\xf7(P(e\xef\xe9\xc8\xd8\x92u\x9c\xa8lBoQS\xc8\xac\xbd5Z\xf6$c-\xef\xb1_W\xdd#\xe5B\xbd8 \x1c\xf5\x93\xeek\xea\xae]7\xed\xc8'
e\xfcV\xb3XE\x10\x079\xdb\xd4\x18\xc3\x7f\xa4\x02K\x96#\x1c\xe1Jh\xaa\xdeh\xef\xfeO\xff3\xd1tl\xe0\xf9\x07\x8e7<\xa6]\x8bo\xe7\xc7iF\xd4\x951\xee\xe8\x97\x87\xc3\xb6\x9a\x9fo\xc81w\x9b\xe9lK\x8e\xd6u.\x98\xa9\xed\xd7T\xf6\x91\x05p\x14r\xb0\x93\x16(\xf0\x16:\xff,\xb8\xc5\x8e:\xe8\x13\xa8\x97\x17k\x93q\xf9]K\x1a\xfc2\x02\xcf!\xa8\x86-\xd0\xe3E\xbcIX\xb2\x86\x92Rz+\xd0\x1d\xeb{\xac\xc1t(k\xb3T\xf7t
\x93^\xc1\xdf;\xa6\xfe0\xe4\x9e\x9ezE\x10k\x15v\xbf\xaa@4s\xa0\xaf\x16\xf9\xb0\xdbK\x14\xf5\xa9\x0e\xb6}\xfa\x86xv\x1f\xa1\x15\x8a\x83\x87\xbb\xeb\x89\xe9\xa8\x88t/Il\xcc\xee\xb4\x82!P\xa2\x95\t@\x1bE+\xfbbs9\xb3<Mkw<1\xca\x13\x1fZ\xd8|\x9eB\xf4\x03S!\t\x9f\xa7\xb3\xb85ID\xfbf\xd4#<\x86\xd3\xed<\x02LD\xcd\xc0\xa0\x16\x14\xcb\x17\x98r\x1e\\\x80\x99\xab\nC\x92m\x04\xfd\xa5a\xc5\x1f\x9e^C\xcci\xad\xc34\xfa{@\xb7\xc1_\x11\x0b\xe5\x0bT \xc25\xff\x15\x06\xd9\xdd\x06\x7f\x1f)\x84\x98\x91\xc73S[ATZ\xc3\x87^qR\xa9\xcf\x9a\xaf!d@{au\xa0\xac\xfc\x8e\xad&\xbf\x84\x10\xc7Z\xf1\x1e~?\xae\xf6\xd3i\x04e\xc7\x1e\x06\xf2~\x9c\xa8\r\xc6\xf1\xb1\xa4^\xec\x06\xa1\xa7PS\x1e\xe2O\xb4e\x98\x1au=4\x90\x81\xa3\xd3\xef\x19gY\xf5\x08\xe9\xc5\xba\xfc=\xac\xe1\xce\x95\x05\xdd\x8f\xe2\x7fH$\x8e\t\x94\x8bcz,\xe5\xbe3\xb0
Now i want to put it on filter
Accounts(standalone, DEFAULT_SUFFIX).filter(f"(userCertificate={crt})")
Pretty sure that should "just work". You don't need to escape anything, as ldap is capable of searching this field and filtering on it. It could be good to check your lib389 log or access log to see if you are leaking in python byto flags or similar. IE you may need ensure_str first on your f string.
Saying this, This looks like userCert stuff which you were asking about on the mailing list - I asked you about the test cas you wanted to write and the steps you needed and you didn't respond ... so maybe we should respond to that mail first to discuss the approach you are taking here to be sure it is the right way. Sometimes looking at these problems is distracting from different issues which is the approach to the greater problem.
So please answer the mail on the list about the test case and the steps you need to perform, then let's talk about what we need to do. Thanks,
Metadata Update from @firstyear: - Issue close_status updated to: invalid - Issue status updated to: Closed (was: Open)
Metadata Update from @vashirov: - Issue status updated to: Open (was: Closed)
@firstyear, escape_filter_chars() doesn't take care of non-ascii symbols: https://github.com/python-ldap/python-ldap/blob/adf47613f2df5a9b080d00f9b2632da556a61ea8/Lib/ldap/filter.py#L17
escape_filter_chars()
ldap3 module does handle this: https://github.com/cannatag/ldap3/blob/08810e435392a1f1a96d5e65bb444b9cb9e96ae3/ldap3/utils/conv.py#L91 by using escape_bytes().
escape_bytes()
The use case: I need to read der certificate file and escape it so it's suitable for an LDAP filter:
>>> from ldap.filter import escape_filter_chars >>> from ldap3.utils.conv import escape_bytes >>> cert_der = open('user-testuser1.der', 'rb').read()[:10] >>> escape_bytes(cert_der) '\\30\\82\\05\\73\\30\\82\\03\\5b\\a0\\03' >>> escape_filter_chars(cert_der) Traceback (most recent call last): File "<input>", line 1, in <module> escape_filter_chars(cert_der) File "/usr/lib64/python3.7/site-packages/ldap/filter.py", line 41, in escape_filter_chars s = assertion_value.replace('\\', r'\5c') TypeError: a bytes-like object is required, not 'str'
Would it be safe to add the escape_bytes into the filter generation / escaping areas in _mapped_object.py by default? Or is it only safe to add this for byte-only expressions?
Metadata Update from @mreynolds: - Issue set to the milestone: 1.4.2
@firstyear, I think it should be safe to add it to mapped_object.py, me and @aborah will test it.
mapped_object.py
Or is it only safe to add this for byte-only expressions?
You mean add it to ensure_bytes?
ensure_bytes
So we did a quick tests and adding it to mapped_object.py is not solving our problem. escape_bytes should be applied to only to one part of the filter (the one in bytes). I think we should have just escape_bytes method and use it only when needed, like when we're constructing a filter.
escape_bytes
Sure, sounds reasonable.
An additional patch for PR #50739 (since one cannot attach on a PR): <img alt="0001-Fix-random-issues.patch" src="/389-ds-base/issue/raw/files/2b05395c78cc1af83605976cb34882b0a08d1c74a5950a904f693c82ad4bb06f-0001-Fix-random-issues.patch" />
Commit cad1bbe fixes this issue
389-ds-base is moving from Pagure to Github. This means that new issues and pull requests will be accepted only in 389-ds-base's github repository.
This issue has been cloned to Github and is available here: - https://github.com/389ds/389-ds-base/issues/3501
If you want to receive further updates on the issue, please navigate to the github issue and click on subscribe button.
subscribe
Thank you for understanding. We apologize for all inconvenience.
Metadata Update from @spichugi: - Issue close_status updated to: wontfix (was: Fixed)
Login to comment on this ticket.