Skip to content
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

Fix parsing of search response #294

Merged
merged 8 commits into from
Nov 5, 2024

Conversation

consideRatio
Copy link
Member

@consideRatio consideRatio commented Oct 31, 2024

Fixes #292 and a bug that maybe never surfaced where things could work before 2.0.0 when the conn.response list had multiple elements thanks to being ordered in a way where the first element was the one of relevance, even though LDAP specification sais any ordering is allowed. Maybe the ldap3 client orders them, but who knows.

Also fixes #295

Investigation

  • Should we use conn.entries instead of conn.response? How is conn.entries populated? Is it the type=searchResEntry responses?
    Answer: yes we should use conn.entries, it is only including type=searchResEntry responses, see the code here.

References

@manics
Copy link
Member

manics commented Oct 31, 2024

Assuming this works can you add a unit test for _filter_search_response using the responses in #292 (comment) as test data?

@consideRatio
Copy link
Member Author

@manics I'll make sure to include that if the function is retained, but I think maybe use of conn.entries can make it irrelevant. The documentation isn't so clear, so I look to investigate further.

@consideRatio consideRatio changed the title Preliminary work on fixing search result handling Fix parsing of search response Nov 1, 2024
We were using conn.response but should have used conn.entries as we only
cared for search results and not other kinds of messages that could be
part of conn.response.
@consideRatio consideRatio marked this pull request as ready for review November 1, 2024 11:05
@consideRatio
Copy link
Member Author

@manics @franciscaestecker this is ready for review now. I think the bug resided in this projet's use of conn.response while we expected the data from conn.entries that doesn't include anything but the searchResEntry type of responses.

ldapauthenticator/ldapauthenticator.py Outdated Show resolved Hide resolved
@@ -547,6 +550,9 @@ def get_user_attributes(self, conn, userdn):
search_filter="(objectClass=*)",
attributes=self.auth_state_attributes,
)
# FIXME: Handle situations with multiple entries below or comment
# why its not important to do.
#
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should throw an error, same as in resolve_username? If there's a possibility of the entries corresponding to different Identities this implies a change in the LDAP server could lead to a different ordering of responses, resulting in a user gaining access to another user's account.

If it's two entries for the same user we still need to understand what the difference is, in case some attributes are different which could lead to inconsistent configuration of the singleuser server.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think users will get access to another JupyterHub account, as its just impacting the auth state (see code below from the end of af the authenticate function) - but they could get access to another users ldap data through their jupyterhub account.

I'll open an issue for this to be tracked separately from this PR - do you think its important to get fixed before release?

        user_attributes = self.get_user_attributes(conn, userdn)
        self.log.debug("username:%s attributes:%s", login_username, user_attributes)

        username = resolved_username if self.use_lookup_dn_username else login_username
        auth_state = {
            "ldap_groups": ldap_groups,
            "user_attributes": user_attributes,
        }
        return {"name": username, "auth_state": auth_state}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manics btw off topic, but I just wanted to say I greatly appreciate your effort into the jupyterhub - you regularly make me very thankful!!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My preference is to include this in the next release.

I think we should try and avoid any ambiguities in authenticator given their importance- I'd rather we were too strict and then relax things later. Ideally we'd get more input from people with expertise in LDAP, but it's clear we don't have that, and unfortunately the only way we can get real-world input is to release something and wait for bug reports.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree, I figure it makes sense to be in a separate PR though - I'll work it next!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've come to disagree with my former self, this is in scope of "Fix parsing of search response".

I pushed the commit to this PR!

It seems like a error in how things were setup if this happens.

Co-authored-by: Simon Li <[email protected]>
@consideRatio
Copy link
Member Author

I iterated a bit on the log messages as well to make errors have some pointer on what may be configured wrong or similar. I'm hands off now!

Copy link
Member

@manics manics left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more detailed logging is good! I'm worried about including login ... denied in resolve_username though, since the decision is made in authenticate(). If there's a future refactor this could easily be missed, resulting in incorrect logs. Can we split the errors logs, so the resolve_username error contains the detail of why a username wasn't resolve, and put the definite denied error log in

resolved_username, resolved_dn = self.resolve_username(login_username)
if not resolved_dn:
return None

instead?

The two log messages will still occur together so there's no loss of context.

@consideRatio
Copy link
Member Author

Good point @manics, I've made the resolve_username function not draw conclusions on whats happening outside the function and instead focused on logging things in scope for the function to log based on its purpose only.

Copy link
Member

@manics manics left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!
@franciscaestecker please could you try this PR? Assuming it fixes your bug reported in #292 we can release this in the next few days as 2.0.2

@consideRatio consideRatio merged commit f338ca3 into jupyterhub:main Nov 5, 2024
7 checks passed
@consideRatio
Copy link
Member Author

@manics I'll proceed with a release

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
2 participants