nginxinc / nginx-ldap-auth

Example of LDAP authentication using ngx_http_auth_request_module
BSD 2-Clause "Simplified" License
678 stars 202 forks source link

Fails to auth if BaseDN isn't maximally narrow OU #79

Closed Drugoy closed 3 years ago

Drugoy commented 3 years ago

I have a problem that this module seems to generally work, however I can't make it work for all of our users: Our users (CNs in AD) are located in different OUs and there's no way to specify as BaseDN some common ancestor: if I do so - all users fail to log in.

Reduced case: In AD: CN=UserA,OU=X,OU=Users,OU=BranchA,DC=my,DC=corp CN=UserB,OU=Y,OU=Users,OU=BranchB,DC=my,DC=corp both are members of the group CN=access-group,OU=special_groups,OU=technical_stuff,DC=my,DC=corp tech account, used for binding with AD: CN=ldap_gatekeeper,OU=Service Accounts,DC=my,DC=corp

In nginx vhost config:

  proxy_set_header X-Ldap-URL "ldap://my.corp:389";
  proxy_set_header X-Ldap-BaseDN "DC=my,DC=corp"; # fails to auth both UserA and UserB
  proxy_set_header X-Ldap-BindDN "CN=ldap_gatekeeper,OU=Service Accounts,DC=my,DC=corp";
  proxy_set_header X-Ldap-BindPass "passwordhere";
  proxy_set_header X-Ldap-Template "(&(objectClass=user)(sAMAccountName=%(username)s)(memberOf=CN=access-group,OU=special_groups,OU=technical_stuff,DC=my,DC=corp))"";

It appears as if nginx-ldap-auth doesn't search for users in specified BaseDN recursively.

Log looks like this:

- using username/password from authorization header
UserA searching on server "ldap:/my.corp:389" with base dn "DC=my,DC=corp" with filter "(&(objectClass=user)(sAMAccountName=UserA)(memberOf=CN=access-group,OU=special_groups,OU=technical_stuff,DC=my,DC=corp))"
UserA Error while running search query: {'info': '000004DC: LdapErr: DSID-0C090A7D, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, V3839', 'desc': 'Operations error'}, server="ldap://my.corp:389", login="UserA"
UserA "GET /auth HTTP/1.0" 401 -

When nginx vhost is configured so:

  proxy_set_header X-Ldap-BaseDN "OU=Y,OU=Users,OU=BranchB,DC=my,DC=corp"; # successfully auths UserA, but fails to auth UserB

the log looks like this:

- using username/password from authorization header
UserA searching on server "ldap:/my.corp:389" with base dn "OU=Y,OU=Users,OU=BranchB,DC=my,DC=corp" with filter "(&(objectClass=user)(sAMAccountName=UserA)(memberOf=CN=access-group,OU=special_groups,OU=technical_stuff,DC=my,DC=corp))"
UserA attempting to bind using dn "CN=John Smith,OU=Y,OU=Users,OU=BranchB,DC=my,DC=corp"
UserA Auth OK for user "UserA"
UserA "Get /auth HTTP/1.0" 200 -

Judging by the error's wording it looks like it fails even to bind to LDAP, but mind you, that my nginx vhost conf contains X-Ldap-BindDN and X-Ldap-BindPass headers configured to use a service account.

oxpa commented 3 years ago

It looks like the first time there was no attempt to bind to the server while the second time the connection is authenticated with "CN=John Smith" username. Could you please make sure that your configuration has correct username and password to bind to AD?

Here is the line where the search is performed: https://github.com/nginxinc/nginx-ldap-auth/blob/master/nginx-ldap-auth-daemon.py#L238 as you can see it's done with 'scope=subtree'

Drugoy commented 3 years ago

Yeah, I've grepped the code and found that line as well. I am sure that the configuration has correct username and password, as the only line in config that was changed between 2 checks is BaseDN.

Besides, the log entry of successful auth basically tells that nginx-ldap-auth used user's input to bind. If that works - why would I even bother using a special bind account?

oxpa commented 3 years ago

It would help a lot if you could show log entries, ldap records and corresponding configuration with minor (automatically done) substitutions if needed.

The daemon uses bind credentials to find the DN to use with password provided. Most of directories won't allow searching without binding. So you have to bind with preconfigured user, find the user which attempts authentication and then try binding with password provided for the found user.

Drugoy commented 3 years ago

Already done, see initial post, all the necessary info is there.

admintechblog commented 3 years ago

Hi, I confirm this issue exists. I have two users, one is part of the OU=STUDENT, and the other is part of OU=STAFF.

If I setup the following: proxy_set_header X-Ldap-BaseDN "OU=STUDENT,DC=my,DC=corp"; then the student will be found by the query but not the employee.

If I setup the following: proxy_set_header X-Ldap-BaseDN "OU=STAFF,DC=my,DC=corp"; then the employee will be found by the query but not the student.

if I setup the following: proxy_set_header X-Ldap-BaseDN "DC=my,DC=corp"; then the query will fail with "Error while running search query: {'desc': 'Operations error', 'info': '000004DC: LdapErr: DSID-0C0907E1, comment: In order to perform this operation a successful bind must be completed on the connection."

If I use ldapsearch via cli the BaseDN "DC=my,DC=corp" does work. This happens only with the nginx-ldap-auth daemon.

In all cases only the X-Ldap-BaseDN line was modified. So I can confirm that the issue exists as reported: "Fails to auth if BaseDN isn't maximally narrow OU"

admintechblog commented 3 years ago

I have some good news for you Drugoy. To solve the issue simply add the following line to your nginx configuration parameters:

proxy_set_header X-Ldap-DisableReferrals "true";

So your config should look as:

proxy_set_header X-Ldap-URL "ldap://my.corp:389"; proxy_set_header X-Ldap-DisableReferrals "true"; proxy_set_header X-Ldap-BaseDN "DC=my,DC=corp"; # fails to auth both UserA and UserB proxy_set_header X-Ldap-BindDN "CN=ldap_gatekeeper,OU=Service Accounts,DC=my,DC=corp"; proxy_set_header X-Ldap-BindPass "passwordhere"; proxy_set_header X-Ldap-Template "(&(objectClass=user)(sAMAccountName=%(username)s)(memberOf=CN=access-group,OU=special_groups,OU=technical_stuff,DC=my,DC=corp))"";

This info should be added to the documentation!!

Also check: https://github.com/nginxinc/nginx-ldap-auth/blob/master/nginx-ldap-auth-daemon.py#L224

Drugoy commented 3 years ago

@admintechblog oh, man, thank you so much for this solution! It worked!