-
Notifications
You must be signed in to change notification settings - Fork 178
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incorrect handling for LDAP responses with Search Reference Results. #292
Comments
Please can you turn on debug logging in JupyterHub and show us your full logs? Can you also give us some example responses from your LDAP server including the |
Bit struggling to, as I don't have access to GitHub in the environment that shows the error. Will see what I can do. |
### Code to replicate
```python
import asyncio
import getpass
from traitlets.config import Config
from ldapauthenticator import LDAPAuthenticator
c = Config()
c.LDAPAuthenticator.server_address = "***"
c.LDAPAuthenticator.tls_strategy="before_bind"
c.LDAPAuthenticator.user_search_base = "dc=***,dc=***,dc=***"
c.LDAPAuthenticator.user_attribute = 'sAMAccountName'
c.LDAPAuthenticator.lookup_dn = True
c.LDAPAuthenticator.lookup_dn_user_dn_attribute = 'sAMAccountName'
c.LDAPAuthenticator.lookup_dn_search_user = '***'
c.LDAPAuthenticator.lookup_dn_search_password = '***'
# Run test
authenticator = LDAPAuthenticator(config=c)
username = input("Username: ")
password = getpass.getpass()
data = dict(username=username, password=password)
return_value = asyncio.run(authenticator.authenticate(None, data))
```
### Logs
```
2024-10-30 13:25:23,668 [DEBUG] Attempting to bind ***
2024-10-30 13:25:24,686 [DEBUG] Successfully bound ***
2024-10-30 13:25:24,686 [DEBUG] Looking up user with:
search_base = 'dc=***,dc=***,dc=***'
search_filter = '(sAMAccountName=USERNAME)'
attributes = '[sAMAccountName]'
2024-10-30 13:25:29,677 [WARNING] Failed to lookup a unique DN for username 'USERNAME'
```
### LDAP search_filter response
```
[{'raw_dn': b'CN=Foo, Bar,OU=Users,OU=***,OU=***,OU=***,DC=***,DC=***,DC=***',
'dn': 'CN=Foo, Bar,OU=Users,OU=***,OU=***,OU=***,DC=***,DC=***,DC=***',
'raw_attributes': {'sAMAccountName': [b'USERNAME']}
'attributes': {},
'type': 'searchResEntry'},
{'uri': ['ldap://***/DC=***,DC=***,DC=***,DC=***'],
'type': 'searchResRef'}]
```
|
Thanks. The error is generated here ldapauthenticator/ldapauthenticator/ldapauthenticator.py Lines 464 to 467 in 7638a6e
so we can probably add a configurable filter to select a response from the list:
|
This is #292 (comment) but formatted, it could be that this formatting is disabled because it was an email response comment? Code to replicateimport asyncio
import getpass
from traitlets.config import Config
from ldapauthenticator import LDAPAuthenticator
c = Config()
c.LDAPAuthenticator.server_address = "***"
c.LDAPAuthenticator.tls_strategy="before_bind"
c.LDAPAuthenticator.user_search_base = "dc=***,dc=***,dc=***"
c.LDAPAuthenticator.user_attribute = 'sAMAccountName'
c.LDAPAuthenticator.lookup_dn = True
c.LDAPAuthenticator.lookup_dn_user_dn_attribute = 'sAMAccountName'
c.LDAPAuthenticator.lookup_dn_search_user = '***'
c.LDAPAuthenticator.lookup_dn_search_password = '***'
# Run test
authenticator = LDAPAuthenticator(config=c)
username = input("Username: ")
password = getpass.getpass()
data = dict(username=username, password=password)
return_value = asyncio.run(authenticator.authenticate(None, data)) Logs
LDAP search_filter response
|
I think currently we can at least say this project is incorrectly concluding a failure to find a unique DN, because here is an example not about that but about getting multiple types of response entries where one isn't even providing a I found some details about this in:
I figure we can look for problem_causing_response = [
{
'raw_dn': b'CN=Foo, Bar,OU=Users,OU=***,OU=***,OU=***,DC=***,DC=***,DC=***',
'dn': 'CN=Foo, Bar,OU=Users,OU=***,OU=***,OU=***,DC=***,DC=***,DC=***',
'raw_attributes': { 'sAMAccountName': [b'USERNAME'] },
'attributes': { 'sAMAccountName': 'USERNAME' },
'type': 'searchResEntry',
},
{
'uri': ['ldap://***/DC=***,DC=***,DC=***,DC=***'],
'type': 'searchResRef',
},
]
test_server_response = [
{
'raw_dn': b'cn=Philip J. Fry,ou=people,dc=planetexpress,dc=com',
'dn': 'cn=Philip J. Fry,ou=people,dc=planetexpress,dc=com',
'raw_attributes': {
'cn': [b'Philip J. Fry'],
},
'attributes': {'cn': ['Philip J. Fry']},
'type': 'searchResEntry',
}
] |
@franciscaestecker looking at the response you got, I see it doesn't include entries under
|
Apologies, this is a more accurate response. Commenting the if statements allows it to work for me. problem_causing_response = [
{
'raw_dn': b'CN=Foo, Bar,OU=Users,OU=***,OU=***,OU=***,DC=***,DC=***,DC=***',
'dn': 'CN=Foo, Bar,OU=Users,OU=***,OU=***,OU=***,DC=***,DC=***,DC=***',
'raw_attributes': { 'sAMAccountName': [b'USERNAME'] },
'attributes': { 'sAMAccountName': 'USERNAME' },
'type': 'searchResEntry',
},
{
'uri': ['ldap://***/DC=***,DC=***,DC=***,DC=***'],
'type': 'searchResRef',
},
] |
I think a clear improvement is to filter the responses to those with |
I'm more concerned about other types of responses that we have to filter/exclude, which is why I suggested something configurable by the admin. However if we know filtering by |
Ldap3 docs give these possible results: searchResEntry Source: https://ldap3.readthedocs.io/en/latest/searches.html (under Response) |
Behaviour prior to change assumed first result was valid and had the body structure of a searchResEntry. I think it's safe to change the check to only check for a unique searchResEntry. This should achieve the additional desired validation. |
I opened #294 about this for now, looking to work it to completion but I'm not sure exactly on what I think is a suitable path yet. |
@franciscaestecker-bb are you able to adjust the code and try things? I'm curious about if things resolve if you adjust this line of code:
To be... response = conn.entries |
The recent change where response handling is based on the length of the LDAP responses, doesn't take into account alternative responses, such as Search Reference Result (https://docs.ldap.com/ldap-sdk/docs/javadoc/com/unboundid/ldap/sdk/SearchResultReference.html)
For example, I have an LDAP server that always returns a SearchRefResult as part of the response. So if no user is found, the response is length 1. If it does find a username, the response is length 2.
I currently don't have a work around for this. This worked fine in previous versions.
The text was updated successfully, but these errors were encountered: