go-gitea / gitea

Git with a cup of tea! Painless self-hosted all-in-one software development service, including Git hosting, code review, team collaboration, package registry and CI/CD
https://gitea.com
MIT License
44.98k stars 5.48k forks source link

LDAP Sync Problems (is_admin, is_restricted and is_active) #13419

Open lcnittl opened 4 years ago

lcnittl commented 4 years ago

Description

We are encountering 2/3 main issues with LDAP authentication:

  1. is_admin is set correctly on account creation (fist login to Gitea) but is not updated anymore on subsequent logins
  2. is_restricted is not updated anymore on subsequent logins (have not tested on account creation yet, sry)
  3. Although "AllowDeactivateAll": false is set ( #9879 ) each user's is_active attribute is set to false (cf. https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-0-log-L177-L178 ff.) when using Synchronize external user data in admin/monitor in the web UI (and also on cron started synchronizations).

This is our configuration of the authentication method:

# SELECT * FROM gitea.login_source WHERE id=2;
id: 2
type: 2
name: ldap.our.domain.com
is_actived: 1
is_sync_enabled: 1
cfg:
  Name: ldap.our.domain.com
  Host: ldap.lxc0
  Port: 389
  SecurityProtocol: 0
  SkipVerify: false
  BindDN: ''
  BindPassword: ''
  UserBase: OU=users,DC=our,DC=domain,DC=com
  UserDN: ''
  AttributeUsername: ''
  AttributeName: givenName
  AttributeSurname: sn
  AttributeMail: mail
  AttributesInBind: true
  AttributeSSHPublicKey: ''
  SearchPageSize: 0
  Filter: (&(objectClass=posixAccount)(UID=%s)(!(memberOf=CN=disabled,OU=roles,DC=our,DC=domain,DC=com)))
  AdminFilter: (memberOf=CN=admin,OU=roles,DC=our,DC=domain,DC=com)
  RestrictedFilter: (&(memberOf=CN=ext,OU=roles,DC=our,DC=domain,DC=com)(!(memberOf=CN=gitea,OU=roles,DC=our,DC=domain,DC=com)))
  Enabled: true
  AllowDeactivateAll: false
created_unix: 1603901943
updated_unix: 1604430791

This is the list of our users (probably important for the log gist):

user00: [admin]
user01: [admin]
user02: []
user03: []
user04: []
user05: [ext]
user06: [disabled]
user07: []
user08: [ext]
user09: []
user10: []
user11: []
user12: [ext]
user13: []
user14: []
user15: []
user16: []
user17: [disabled]
user18: []
user19: []
user20: [disabled]
user21: [disabled]
user22: []
user23: []
user24: []
user25: []
user26: [disabled]
user27: [disabled]
user28: [disabled]
user29: [disabled]
user30: [disabled]
user31: [disabled]
user32: [disabled]
user33: []
user34: []
user35: []
user36: [ext]
user37: [disabled, ext]
user38: [ext]
user39: [ext]
user40: [ext]
user41: []
user42: []
user43: []
user44: []
user45: []
user46: []

The values after the user keys are the roles each user has (eg user00 is admin and (memberOf=CN=admin,OU=roles,DC=our,DC=domain,DC=com) evaluates to true).

When the filters are run manually with ldapsearch they return the correct user entries.

Issue 1)

Should theoretically be fixed already (cf. https://github.com/go-gitea/gitea/issues/10538#issuecomment-592652285 ) but is not working for me: Is my admin filter wrong? If yes, why is the attribute correct on creation?

On subsequent login, LDAP seems to correctly filter for admin as it is not logging [T] LDAP Admin Search found no matching entries when the admin role is set:

2020/11/03 23:38:48 ...es/auth/ldap/ldap.go:161:checkAdmin() [T] Checking admin with filter (memberOf=CN=admin,OU=roles,DC=our,DC=domain,DC=com) and base uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:38:48 ...es/auth/ldap/ldap.go:147:bindUser() [T] Binding with userDN: uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:56:19 ...es/auth/ldap/ldap.go:161:checkAdmin() [T] Checking admin with filter (memberOf=CN=admin,OU=roles,DC=our,DC=domain,DC=com) and base uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:56:19 ...es/auth/ldap/ldap.go:172:checkAdmin() [T] LDAP Admin Search found no matching entries.
2020/11/03 23:56:19 ...es/auth/ldap/ldap.go:186:checkRestricted() [T] Checking restricted with filter (&(memberOf=CN=ext,OU=roles,DC=our,DC=domain,DC=com)(!(memberOf=CN=gitea,OU=roles,DC=our,DC=domain,DC=com))) and base uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:56:19 ...es/auth/ldap/ldap.go:197:checkRestricted() [T] LDAP Restricted Search found no matching entries.
2020/11/03 23:56:19 ...es/auth/ldap/ldap.go:147:bindUser() [T] Binding with userDN: uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:56:19 ...es/auth/ldap/ldap.go:153:bindUser() [T] Bound successfully with userDN: uid=user08,ou=users,DC=our,DC=domain,DC=com

Yet, the is_admin flag remains unaltered.

Issue 2)

This was tested (for the log) by adding ext role to user08.

Here again, according to the log, LDAP seems to correctly apply the filter (No [T] LDAP Restricted Search found no matching entries login):

2020/11/04 00:10:27 ...es/auth/ldap/ldap.go:186:checkRestricted() [T] Checking restricted with filter (&(memberOf=CN=ext,OU=roles,DC=our,DC=domain,DC=com)(!(memberOf=CN=gitea,OU=roles,DC=our,DC=domain,DC=com))) and base uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/04 00:10:27 ...es/auth/ldap/ldap.go:147:bindUser() [T] Binding with userDN: uid=user08,ou=users,DC=our,DC=domain,DC=com

Is is_restricted supposed to get updated on each login?

Issue 3)

I think this -- deactivation of all users -- should not happen in our case because

  1. The user search filter should, in our setup, not return an empty list for any user (the the best of my knowledge, all users exist in LDAP).
  2. Even if it would, AllowDeactivateAll is set to false (so it should never deactivate all users?)
  3. Only the admin and restricted filters are returning empty lists, for obvious reasons

But probably there is a filter problem here as well?

Any input welcome! If there is further info needed, please let me know!

Related

zeripath commented 4 years ago

This is very interesting. Why is it that the ldap is giving different results for the same query?

2020/11/03 23:38:48 ...es/auth/ldap/ldap.go:88:findUserDN() [T] Search for LDAP user: user08
2020/11/03 23:38:48 ...es/auth/ldap/ldap.go:96:findUserDN() [T] Searching for DN using filter (&(objectClass=posixAccount)(UID=user08)(!(memberOf=CN=disabled,OU=roles,DC=our,DC=domain,DC=com))) and base OU=users,DC=our,DC=domain,DC=com
2020/11/03 23:38:48 ...es/auth/ldap/ldap.go:286:SearchEntry() [T] Fetching attributes '', 'givenName', 'sn', 'mail', '' with filter (&(objectClass=posixAccount)(UID=user08)(!(memberOf=CN=disabled,OU=roles,DC=our,DC=domain,DC=com))) and base uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:38:48 ...es/auth/ldap/ldap.go:161:checkAdmin() [T] Checking admin with filter (memberOf=CN=admin,OU=roles,DC=our,DC=domain,DC=com) and base uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:38:48 ...es/auth/ldap/ldap.go:147:bindUser() [T] Binding with userDN: uid=user08,ou=users,DC=our,DC=domain,DC=com
020/11/03 23:56:19 ...es/auth/ldap/ldap.go:161:checkAdmin() [T] Checking admin with filter (memberOf=CN=admin,OU=roles,DC=our,DC=domain,DC=com) and base uid=user08,ou=users,DC=our,DC=domain,DC=com
2020/11/03 23:56:19 ...es/auth/ldap/ldap.go:172:checkAdmin() [T] LDAP Admin Search found no matching entries.

There's something very odd going on here. Is there request limiting? Are we sending some whitespace by accident?

lcnittl commented 4 years ago

Maybe I was not very clear, sorry for that: The different results from the same query are expected, as in the first case the admin role was set (user08 has the memberOf=CN=admin,OU=roles,DC=our,DC=domain,DC=com attribute set) and in the second case that attribute was removed. This was done to rule out that a failed LDAP query is the reason for the is_admin flag being not altered. But indeed, Gitea's LDAP query correctly found whether the user is supposed to be admin or not.

SnailShea commented 3 years ago

May be unrelated to the cause of issues others have had (I've seen at least one screenshot showing my fix would not help them on other related issues) but I was having issues with user deactivation after a sync. Turns out if you have, in my example a User Filter of (&(objectClass=posixAccount)(uid=%s)) but leave the Username Attribute field blank, deactivation of any previously signed in users will occur. Adding uid to Username Attribute resolved the issue I was having. It was strange, I was able to sign in just fine but the user list would only populate with that name after signing in, and no other names from the LDAP instance. And, of course, upon sync that account would then be locked. After applying the fix as it pertained to my issue, all users in the LDAP show up in the account list on gitea.

Hoping this helps someone.

SirIntellegence commented 3 years ago

This issue is happening for me as well. I don't know if it is related to me leaving the "Username Attribute" field empty since out LDAP apparently doesn't support the UID attribute and the closest thing I can use "userPrincipalName" is effectively their domain email address.

SnailShea commented 3 years ago

This issue is happening for me as well. I don't know if it is related to me leaving the "Username Attribute" field empty since out LDAP apparently doesn't support the UID attribute and the closest thing I can use "userPrincipalName" is effectively their domain email address.

Is your user attribute cn instead of uid perhaps? Essentially I think the field should be populated with whatever attribute indicates a unique user entry.

SirIntellegence commented 3 years ago

From what I can tell by running queries, cn contains the user's name ("Billy Bob"), not the username ("bbob").

SnailShea commented 3 years ago

From what I can tell by running queries, cn contains the user's name ("Billy Bob"), not the username ("bbob").

If you're directly referencing a user object in your LDAP structure how do you do so? For me it would be like uid=mxlinux,cn=Users,dc=domain,dc=tld the part where I have uid might be different for you but I think still an expected part of any LDAP structure.

SirIntellegence commented 3 years ago

I am using userPrincipalName for the filter and I haven' gotten the group filter field to work, so I am using (&(&(&(objectClass=person)(memberOf:=CN=Programming,CN=Users,DC=domain,DC=com)(userPrincipalName=%s)))) Also, I am not sure if this is related entirely to the issue and if this discussion should be held here. Don't want to hijack an issue...

youngmit commented 3 years ago

May be unrelated to the cause of issues others have had (I've seen at least one screenshot showing my fix would not help them on other related issues) but I was having issues with user deactivation after a sync. Turns out if you have, in my example a User Filter of (&(objectClass=posixAccount)(uid=%s)) but leave the Username Attribute field blank, deactivation of any previously signed in users will occur. Adding uid to Username Attribute resolved the issue I was having. It was strange, I was able to sign in just fine but the user list would only populate with that name after signing in, and no other names from the LDAP instance. And, of course, upon sync that account would then be locked. After applying the fix as it pertained to my issue, all users in the LDAP show up in the account list on gitea.

Hoping this helps someone.

This is extremely helpful! I had left this option blank, because the "Leave empty to use the username entered in Gitea" guidance implies that all it is used for is to determine the Gitea-internal username for the user. Adding sAMAccountName (we use AD) fixed it for me. I'm wondering if just making more explicit that this is also important for the sync operation to work correctly would clear up a lot of confusion for folks?

Alexey-I commented 3 years ago

Hi! I can probably add a bit. We've just experienced the sync issue with Gitea Version: 1.15.0+dev-358-gfb6c6895f (Docker image). Users who were able to register via LDAP yesterday, became Deactivated today. After a bit of experimenting I was able to fix this issue by changing Username Attribute = samaccountname to Username Attribute = sAMAccountName on Authentication Source settings. This is probably my fault, I should have used correct spelling from the very beginning but with user registration it worked. It's synchronization which seems to insist to be case sensitive.

Oasis6604 commented 2 years ago

Hi! I can probably add a bit. We've just experienced the sync issue with Gitea Version: 1.15.0+dev-358-gfb6c6895f (Docker image). Users who were able to register via LDAP yesterday, became Deactivated today. After a bit of experimenting I was able to fix this issue by changing Username Attribute = samaccountname to Username Attribute = sAMAccountName on Authentication Source settings. This is probably my fault, I should have used correct spelling from the very beginning but with user registration it worked. It's synchronization which seems to insist to be case sensitive.

Same here! Login works even with lowercase writing and tools like ldapsearch work aswell. But the issue that my users become disabled is gone since I use the correct writing.

night-gold commented 1 year ago

Hello, just find out that there is a solution that works for us here . You have to put a valid value username attribute. CN is an example in the post, I had to put 'uid' as the 'cn' is empty in our ldap.

Samachi commented 5 months ago

1.22.0, the issue still exist, while using LDAP (via BindDN) as authentication source, Gitea deactivates LDAP users almost once a day or when you run “Synchronize external user data”.