Skip to content

ldap getUserDN handle multiple users #151

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

Merged
merged 5 commits into from
Jan 6, 2025

Conversation

helenfufu
Copy link
Collaborator

@helenfufu helenfufu commented Jan 6, 2025

This PR adds a check in the ldap package's getUserDN function that ensures the number of entries returned from the user DN LDAP search is one (in the same way we already handle multiple users in getUserBindDN). This should prevent authentication attacks that can leverage the fact that we currently return the last user DN if there are duplicate users.

The bulk of the changes are unit tests additions at the getUserBindDN and getUserDN level, which include test cases ensuring we error when there are multiple users returned.

Ticket: VAULT-27421

Comment on lines +522 to +537
{
name: "failed-with-anon-bind-upn-domain-multiple-users-returned",
username: "mallory",
password: "password",
clientConfig: &ldap.ClientConfig{
URLs: []string{fmt.Sprintf("ldaps://127.0.0.1:%d", td.Port())},
Certificates: []string{td.Cert()},
DiscoverDN: true,
UserDN: testdirectory.DefaultUserDN,
GroupDN: testdirectory.DefaultGroupDN,
UPNDomain: "example.com",
},
opts: []ldap.Option{ldap.WithGroups()},
wantErr: true,
wantErrContains: "LDAP search for binddn 0 or not unique",
},
Copy link
Collaborator Author

@helenfufu helenfufu Jan 6, 2025

Choose a reason for hiding this comment

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

This test covers the failure path for multiple search results during the getUserBindDN call in Authenticate.

For context, I also tried adding another case that somehow could pass with a single search result in getUserBindDN then fail with multiple search results in getUserDN, but I wasn't able to find a test setup that would follow this path.

Since I wasn't able to get a test path to hit the multiple search results in getUserDN from Authenticate, opted to add unit tests directly at the getUserBindDN and getUserDN level in client_test.go, though it may be a bit redundant.

I'm pretty new to LDAP though (first time working with it as of this PR), so appreciate any guidance if there's a simpler way to test the change in getUserDN!

@helenfufu helenfufu marked this pull request as ready for review January 6, 2025 18:36
@helenfufu helenfufu requested a review from a team as a code owner January 6, 2025 18:36
Copy link
Contributor

@johanbrandhorst johanbrandhorst left a comment

Choose a reason for hiding this comment

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

This looks great to me. I'm also not too familiar with this area of the code (CC @jimlambrt), but I see the problem and I agree that this code fixes it, as described.

for _, e := range result.Entries {
userDN = e.DN
if len(result.Entries) != 1 {
return "", fmt.Errorf("%s: LDAP search for user 0 or not unique", op)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is a potential breaking change for users. We should get guidance from the cap library owners on how to proceed. In the past we have added config fields to toggle on any new behavior that breaks backwards compatibility.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thanks for raising, @fairclothjm! (And out of curiosity, any chance you have an example of this toggle pattern used in practice for previous breaking changes in this library?)

@johanbrandhorst @jimlambrt could we get some guidance on the preferred approach to introduce this potential breaking change?

Copy link
Contributor

Choose a reason for hiding this comment

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

I will defer to Jim for the definite recommendation, but this seems to me only to be a breaking change in the case we actually care about - where the security issue exists. That seems enough to me to justify making this change without an option to turn it off.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with @johanbrandhorst -- I don't think we should offer an option to opt-in or out.

Copy link
Collaborator

@jimlambrt jimlambrt left a comment

Choose a reason for hiding this comment

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

Ty!

for _, e := range result.Entries {
userDN = e.DN
if len(result.Entries) != 1 {
return "", fmt.Errorf("%s: LDAP search for user 0 or not unique", op)
Copy link
Collaborator

Choose a reason for hiding this comment

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

I agree with @johanbrandhorst -- I don't think we should offer an option to opt-in or out.

@helenfufu helenfufu merged commit 9047b8b into main Jan 6, 2025
6 checks passed
@helenfufu helenfufu deleted the vault-27076-ldap-getUserDN-handle-multiple-users branch January 6, 2025 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants