gitea icon indicating copy to clipboard operation
gitea copied to clipboard

LDAP Sync Problems (is_admin, is_restricted and is_active)

Open lcnittl opened this issue 5 years ago • 13 comments

  • Gitea version (or commit ref): 1.12.4
  • Git version: 2.20.1
  • OpenLDAP version: 2.4.47+dfsg-3+deb10u3
  • Operating system: Debian 10
  • Downloaded from https://dl.gitea.io/gitea/1.12.4/gitea-1.12.4-linux-amd64
  • Runs via gitea service (https://github.com/go-gitea/gitea/raw/master/contrib/systemd/gitea.service)
  • Database (use [x]):
    • [ ] PostgreSQL
    • [x] MySQL
    • [ ] MSSQL
    • [ ] SQLite
  • Can you reproduce the bug at https://try.gitea.io:
    • [ ] Yes (provide example URL)
    • [x] No -- Not relevant
  • Log gist: https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e
    • Synchronize external user data: https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-0-log
    • Login with user who was changed to admin: https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-1-log
    • Login with user that is not admin: https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-2-log
    • Login with user that is ext (restricted): https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-3-log

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:

  • admin role is set ( https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-1-log-L34-L35 )
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
  • vs admin role is not set ( https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-2-log-L14-L19 )
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):

  • ext role is set ( https://gist.github.com/lcnittl/60045a167285b50d72f0037f8a37cc2e#file-gitea-trace-3-log-L16-L17 )
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

  • to issue 1)
    • #8849
    • #10538
  • to issue 3)
    • #7949
    • #6241

lcnittl avatar Nov 03 '20 23:11 lcnittl

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?

zeripath avatar Nov 08 '20 20:11 zeripath

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.

lcnittl avatar Nov 09 '20 10:11 lcnittl

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.

SnailShea avatar Dec 29 '20 02:12 SnailShea

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.

SirIntellegence avatar Mar 29 '21 15:03 SirIntellegence

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.

SnailShea avatar Mar 29 '21 15:03 SnailShea

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

SirIntellegence avatar Mar 29 '21 16:03 SirIntellegence

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.

SnailShea avatar Mar 29 '21 16:03 SnailShea

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...

SirIntellegence avatar Mar 29 '21 16:03 SirIntellegence

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?

youngmit avatar May 17 '21 20:05 youngmit

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.

Alexey-I avatar May 31 '21 12:05 Alexey-I

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.

Oasis6604 avatar Sep 27 '22 09:09 Oasis6604

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.

night-gold avatar Nov 15 '22 15:11 night-gold

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”.

Samachi avatar May 31 '24 01:05 Samachi