RocketChat / Rocket.Chat

The communications platform that puts data protection first.
https://rocket.chat/
Other
40.57k stars 10.58k forks source link

Login NoSuchObjectError when LDAP_Sync_User_Data_Groups set to true #15621

Closed dusatvoj closed 10 months ago

dusatvoj commented 5 years ago

Description:

I've enabled LDAP_Sync_User_Data_Groups and after that failed every login try from every type of device (old sessions persists and groups from LDAP are synchronized) or app with NoSuchObjectError. It's critical issue in #14278 for us. IDK what's wrong. When I disable LDAP_Sync_User_Data_Groups everything is OK (even with synchronized groups from LDAP).

Search filter:

(&(cn=#{groupName})(uniqueMember=uid=#{username},ou=users,dc=example,dc=org))

Expected behavior:

Working LDAP_Sync_User_Data_Groups option

Actual behavior:

Not working LDAP_Sync_User_Data_Groups = true

Server Setup Information:

Relevant logs:

server.js:212 LDAP ➔ Search.error { NoSuchObjectError: No Such Object
    at messageCallback (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1419:45)
    at Parser.onMessage (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1089:14)
    at emitOne (events.js:116:13)
    at Parser.emit (events.js:211:7)
    at Parser.write (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/messages/parser.js:111:8)
    at Socket.onData (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1076:22)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at addChunk (_stream_readable.js:263:12)
    at readableAddChunk (_stream_readable.js:250:11)
    at Socket.Readable.push (_stream_readable.js:208:10)
    at TCP.onread (net.js:601:20) lde_message: 'No Such Object', lde_dn: null }
Exception while invoking method 'login' { NoSuchObjectError: No Such Object
    at messageCallback (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1419:45)
    at Parser.onMessage (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1089:14)
    at emitOne (events.js:116:13)
    at Parser.emit (events.js:211:7)
    at Parser.write (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/messages/parser.js:111:8)
    at Socket.onData (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1076:22)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at addChunk (_stream_readable.js:263:12)
    at readableAddChunk (_stream_readable.js:250:11)
    at Socket.Readable.push (_stream_readable.js:208:10)
    at TCP.onread (net.js:601:20) lde_message: 'No Such Object', lde_dn: null }
wreiske commented 5 years ago

I think this is related to OpenLdap and not RC.

From: https://www.openldap.org/faq/data/cache/157.html

The "ldap_add: No such object" error is commonly returned if parent of the entry being added does not exist. Add the parent entry first...For example, if you are adding "cn=bob,dc=domain,dc=com" and you get: ldap_add: No such objectThe entry "dc=domain,dc=com" likely doesn't exist. You can use ldapsearch to see if does exist: ldapsearch -b 'dc=domain,dc=com' -s base '(objectclass=*)'If it doesn't, add it. See the Quick Start Guide (http://www.openldap.org/doc/admin/quickstart.html) for assistance.Note: if the entry being added is the same as database suffix, it's parent isn't required. Ie: if your suffix is "dc=domain,dc=com", "dc=com" doesn't need to exist to add "dc=domain,dc=com".

This error will also occur if you try to add any entry that the server is not configured to hold.For example, if your database suffix is "dc=domain,dc=com" and you attempt to add "dc=domain2,dc=com", "dc=com", "dc=domain,dc=org", "o=domain,c=us", or an other DN in the "dc=domain,dc=com" subtree, the server will return a "No such object" (or referral) error.slapd(8) will generally return "no global superior knowledge" as additional information indicating its return noSuchObject instead of a referral as the server is not configured with knowledge of a global superior server.

Also: https://www.openldap.org/faq/data/cache/343.html

The 'no such object' error is generally returned when the target DN of the operation cannot be located. This section details reasons common to all operations. You should also look for answers specific to the operation (as indicated in the error message).

The most common reason for this error is non-existance of the named object. First, check for typos.Also note that, by default, a new directory server holds no objects (except for a few system entries). So, if you are setting up a new directory server and get this message, it may simply be that you have yet to add the object you are trying to locate.

Are you using OpenLDAP or AD?

Have you looked at https://github.com/RocketChat/Rocket.Chat/pull/14278#issuecomment-533547519 or https://github.com/RocketChat/Rocket.Chat/pull/14278#issuecomment-538729262

dusatvoj commented 5 years ago

LDAP Search not working for me:

ldapsearch -Y EXTERNAL -H ldapi:/// -b "dc=example,dc=com" -s base '(objectclass=*)'
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope baseObject
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 2
result: 32 No such object

# numResponses: 1

Our "base" object looks like this:

dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: OrganizationName
dc: example
structuralObjectClass: organization

... so I've found an error but I don't know how to fix it.

Thank you @wreiske for help.

EDIT: That's weird. I tried RC LDAP account with same search and there's no NoSuchObbjectError:

ldapsearch -D "uid=rocketchat-admin,ou=system,dc=example,dc=com" -W -b "dc=example,dc=com" -s base '(objectclass=*)'
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope baseObject
# filter: (objectclass=*)
# requesting: ALL
#

# example.com
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: OrganizationName
dc: example

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
dusatvoj commented 5 years ago

@wreiske Any news? I'm not sure what's wrong and I'm stuck on it :confused:

dusatvoj commented 4 years ago

:-1: for a needed support @wreiske

wreiske commented 4 years ago

for a needed support @wreiske

Sorry, I'm not a Rocket.Chat developer, nor is there any expectation of community members to provide timely support. You can try contacting support@rocket.chat or poke around on open.rocket.chat.

dusatvoj commented 4 years ago

@wreiske Thank you. I will contact them.

dusatvoj commented 4 years ago

@wreiske you wrote this feature. Is there a possibility to relationship with not existing memberOf overlay in LDAP?

dusatvoj commented 4 years ago

I've tried apply memberOf overlay, but it didn't help. It's crashing here https://github.com/wreiske/Rocket.Chat/blob/23b043c4947c050ef78bff0323fa0fcfe449c6de/app/ldap/server/sync.js#L34 There's a debug log

server.js:212 LDAP ➔ Connection.info LDAP connected 
server.js:212 LDAP ➔ Bind.info Binding UserDN <Bind user DN>
server.js:212 LDAP ➔ Search.info Searching user dusatvoj 
server.js:212 LDAP ➔ Search.debug searchOptions { filter: '(&(objectclass=*)(uid=dusatvoj))',   scope: 'sub',   sizeLimit: 1000,   paged: { pageSize: 250, pagePause: false } } 
server.js:212 LDAP ➔ Search.debug BaseDN ou=users,dc=example,dc=com 
server.js:212 LDAP ➔ Search.info Search result count 1 
server.js:212 LDAP ➔ Auth.info Authenticating uid=dusatvoj,ou=users,dc=example,dc=com 
server.js:212 LDAP ➔ Search.info Search result count 1 
server.js:212 LDAP ➔ Auth.info Authenticated uid=dusatvoj,ou=users,dc=example,dc=com
server.js:212 LDAPHandler ➔ info Querying user 
server.js:212 LDAPHandler ➔ debug userQuery { 'services.ldap.id': '6475736174766f6a' } 
server.js:212 LDAPHandler ➔ info Logging user 
server.js:212 LDAPSync ➔ info Syncing user data 
server.js:212 LDAPSync ➔ debug user { email: undefined, _id: '6o4qKzbDPfqrMfZjN' } 
server.js:212 LDAPSync ➔ debug ldapUser undefined 
server.js:212 TemplateVarHandler ➔ debug template found. replacing values 
server.js:212 TemplateVarHandler ➔ debug replacing template var: #{cn} with value: Vojtěch 
server.js:212 TemplateVarHandler ➔ debug replacing template var: #{sn} with value: Dušátko 
server.js:212 LDAPSync ➔ debug User role exists for mapping accountant_external -> AccountantExternal 
server.js:212 LDAP ➔ Search.error { NoSuchObjectError: No Such Object     at messageCallback (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1419:45)     at Parser.onMessage (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1089:14)     at emitOne (events.js:116:13)     at Parser.emit (events.js:211:7)     at Parser.write (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/messages/parser.js:111:8)     at Socket.onData (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1076:22)     at emitOne (events.js:116:13)     at Socket.emit (events.js:211:7)     at addChunk (_stream_readable.js:263:12)     at readableAddChunk (_stream_readable.js:250:11)     at Socket.Readable.push (_stream_readable.js:208:10)     at TCP.onread (net.js:601:20) lde_message: 'No Such Object', lde_dn: null } 
Exception while invoking method 'login' { NoSuchObjectError: No Such Object     at messageCallback (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1419:45)     at Parser.onMessage (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1089:14)     at emitOne (events.js:116:13)     at Parser.emit (events.js:211:7)     at Parser.write (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/messages/parser.js:111:8)     at Socket.onData (/opt/Rocket.Chat/programs/server/npm/node_modules/ldapjs/lib/client/client.js:1076:22)     at emitOne (events.js:116:13)     at Socket.emit (events.js:211:7)     at addChunk (_stream_readable.js:263:12)     at readableAddChunk (_stream_readable.js:250:11)     at Socket.Readable.push (_stream_readable.js:208:10)     at TCP.onread (net.js:601:20) lde_message: 'No Such Object', lde_dn: null }

... I want to repair it but I'm not an JS developer :/ ... Any help wanted

axkng commented 4 years ago

Hi @wreiske , this is not necessarily a problem with OpenLDAP. I have hit this issue with ActiveDirectory as well.

All users that were synced prior to enabling LDAP role or channel mappings can login without problems. New users can not login. If I disable the mapping, the new users can login. Merge existing users is active, the group filter looks like this: (&(sAMAccountName=#{username})(memberOf=#{groupName}))

The LDAP-tree is a bit more structured and the solutions from your PR did not work for me. My filter worked flawless until I had to add new users.

Any Ideas?

dusatvoj commented 4 years ago

I think there are try-catches missing or something like that because NoSuchObject Error could mean isUserInLDAPGroup = false. Isn't it true?

matejak commented 4 years ago

I am getting exactly the same error, and I believe that I understand what caused it for me, and I think that it is your case as well.

Based on logs from my LDAP server, it goes on like this:

  1. First of all, the server binds as the "admin", i.e. as the user that is configured in the site's LDAP settings.
  2. Admin tries to find the user who would like to log in.
  3. If successful, the server tries to bind as the user who tries to log in.
  4. If successful, the server acknowledges that the user has authenticated (expressed by LDAPHandler ➔ info Logging user in the log)
  5. The group sync is performed, but not by admin, but by the user who is logging in. That user may not have access rights to read group membership, so it results in an error.

I see two possible bugs here:

battosai30 commented 4 years ago

I confirm this diagnostic as I had the same issue, and when I changed OpenLDAP ACL in order to allow user to read groups and members I successfully got a sync :)

+1 on matejak suggestions

dusatvoj commented 4 years ago

@matejak / @battosai30 Can you send me your ACLs? I have periodic sync without issue but I still cannot login :/

battosai30 commented 4 years ago

@matejak / @battosai30 Can you send me your ACLs? I have periodic sync without issue but I still cannot login :/

Of course !

database config
rootdn "gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth"
access to * 
     by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage 
     by dn.base="YOUR_BASE_DN" manage 
     by * break

database mdb
access to * 
     by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" manage 
     by dn.base="YOUR_BASE_DN" manage 
     by dn="cn=admin,YOUR_BASE_DN" manage
     by self read
     by anonymous auth
     by * none

I'm not bad about OpenLDAP but clearly not an expert of its ACL so maybe it's not a state of the art config, but as I tested it it seems to do the job (safe and not allowing too much ... ;) )

battosai30 commented 3 years ago

I'm sorry I figured out that I gave you a completely wrong config ....

Here the right one to use with ldapmodify :

dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword by anonymous auth by dn="cn=admin,YOUR_BASE_DN" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to dn.base="ou=groups,YOUR_BASE_DN" by users read
olcAccess: {3}to dn.children="ou=users,YOUR_BASE_DN" by dn="cn=admin,YOUR_BASE_DN write by self read
olcAccess: {4}to dn.base="cn=ppolicy,YOUR_BASE_DN" by dn="cn=admin,YOUR_BASE_DN" write
olcAccess: {5}to * by self write by dn="cn=admin,YOUR_BASE_DN" write by * read