osixia / docker-openldap

OpenLDAP container image 🐳🌴
MIT License
4.02k stars 973 forks source link

memberOf with groupOfUniqueNames not working #304

Open ookerberry opened 5 years ago

ookerberry commented 5 years ago

It seems from the comments on https://github.com/osixia/docker-openldap/issues/49 that memberOf is included in this docker image and should be working as long as the group is of objectClass: groupOfUniqueNames and if each member of the group is a uniqueMember.
Is this right?

I am not getting any memberOf info when I search.

Here is an example of an LDIF to add a group and member: dn: cn=admin,ou=groups,dc=example,dc=com objectClass: groupofuniquenames cn: admin description: Admin users uniquemember: uid=john,ou=users,dc=example,dc=com

Here is an example of how I'm searching: ldapsearch -x -D cn=admin,dc=example,dc=com -w admin -b dc=example,dc=com -h 127.0.0.1 uid=john memberOf

The output is just: dn: cn=john,ou=users,dc=example,dc=com but I'd expect it to be: dn: cn=john,ou=users,dc=example,dc=com memberOf: cn=admin,ou=groups,dc=example,dc=com

Should this be working or am I doing something wrong?

obourdon commented 5 years ago

@ookerberry works perfectly well for me (tested on Docker for MacOSX):

# ldapsearch -LLL -x -D cn=admin,dc=example,dc=org -w admin -b dc=example,dc=org -h 127.0.0.1 uid=john memberOf dn: uid=john,ou=Users,dc=example,dc=org memberOf: cn=admin,ou=Groups,dc=example,dc=org

Full search output and ldif file available here

iddm commented 5 years ago

It does not work for me as well. Latest openldap from docker, seems to be 1.2.4.

UPD: the output is the same, I don't get memberOf but the search works fine (tested with gitea).

obourdon commented 5 years ago

@ookerberry @vityafx could you please post the complete output of slapcat run within your container Again it works perfectly well for me for 1.2.4 on my MacOSX Docker

obourdon commented 5 years ago

@ookerberry @vityafx may be you could also try my initial ldif file from here to see if it works properly or not

iddm commented 5 years ago

@obourdon I am sorry, but I have no interest in spending time on it right now. I have a lot of my own stuff to do, so I pass. I hope someone else will help you.

From my side, I can say that memberOf works fine with uniqueMember in the group. I used Apache Directory Studio to check this out but I had to enable a checkbox for operational attributes. Once I ticked it, memberOf did show in the window as an attribute. I guess, this checkbox modifies the search request somehow and makes it return memberOf as well. Also, search filters in my gitea instance did work well with it, so I don't have this problem anymore.

obourdon commented 5 years ago

@vityafx no problem and many thanks for your answer. Hopefully this now seem to work for you. Will still dig into this later on to see if I can find something worth mentioning

iddm commented 5 years ago

@obourdon I really apologize for not helping you now, I would like to help. I am also not that good with ldap and don't even know about this ldif files (yet). I don't also know when I will at least read about them and try, but I have done my ldap stuff. At least for now, every little thing I needed to do works, so I can finally forget it for a certain period of time. So, if I could and had a chance, I'd help you of course.

I remain subscribed to this issue, so once I know I can help you or anyone else experiencing this problem, I'd post a comment for sure.

obourdon commented 5 years ago

@vityafx do not worry, I am definitely no expert either, just may be a little bit more advanced than you are right now. In my case, I just need to use this container as a replacement for a full fledge mail system that I built several years ago which relies on LDAP for (virtual)mail accounts, forwarding, permissions, vacations, ... moving away from process based baremetal installation to docker on cloud ;-)

HariSekhon commented 5 years ago

+1 for memberOf support

obourdon commented 5 years ago

@HariSekhon sorry if it is not clear for me. Does your +1 means that memberOf support works well for you ?

quanah commented 5 years ago

per the configuration, it is supposed to work with groupOfUniqueNames

https://github.com/osixia/docker-openldap/blob/stable/image/service/slapd/assets/config/bootstrap/ldif/03-memberOf.ldif

westwin commented 5 years ago

Same issue for me on macos with osixia/openldap:1.2.4

the overlay only works for groupOfNames/member, but not working for groupOfUniqueNames/uniqueMember

drhuh commented 5 years ago

@obourdon I can confirm that "memberOf" only works for groupOfUniqueNames and not for groupOfNames. Which log output do you need to investigate this problem?

obourdon commented 4 years ago

@westwin @drhuh, guys from what you are respectively writing, it seems to me that you are contradicting each another. Doing more tests on my side showed that @drhuh is right (like @quanah also suggests in its own post)

@drhuh sorry but I have not enough expertise in this area to tell you if this can be debugged/fixed/relative to docker container or openldap itself

nick-randal commented 4 years ago

I have tested and it is working for me with groupOfUniqueNames however...

I was hoping it would resolve nested groups and it is not. Is it supposed to and not working, or not supported?

kernighan commented 4 years ago

@nick-randal There is no support for "nested" groups in OpenLDAP, if by that you mean groups of groups.

quanah commented 4 years ago

@obourdon I can confirm that "memberOf" only works for groupOfUniqueNames and not for groupOfNames. Which log output do you need to investigate this problem?

Note, that's specifically because of the way it's implemented in docker-openldap. You can see this in the link I referenced. If the configuration was modified to use groupOfNames/member, then it should work with those types of groups. It should generally be possible to do that with an ldapmodify after the fact.

encryptblockr commented 4 years ago

this is not working for me also @obourdon

i tried to add new group using the command below

dn: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
cn: finance
gidnumber: 505
uniqueMember: uid=jdoe,ou=users,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames
objectclass: top

and got the following errors in phpldapadmin dashboard

LDAP said: | Object class violation
-- | --
Error number: | 0x41 (LDAP_OBJECT_CLASS_VIOLATION)

i really want to get this memberof to work but i dont understand why it is such a problem especially knowing that apps want to use it and i mean this is supposed to be an ldap server, ofcourse people need to know what groups users belong...it is beyond ,e why this does not work out of the box

encryptblockr commented 4 years ago

per the configuration, it is supposed to work with groupOfUniqueNames

https://github.com/osixia/docker-openldap/blob/stable/image/service/slapd/assets/config/bootstrap/ldif/03-memberOf.ldif

Do i apply this ldif for memberof to work? If yes, then how do i apply the ldif to my ldap server???

i have tried and i get these errors

LDIF Import Parse Error
Description:    DN does not exist cn=module{0},cn=config []
Line:   6
Data:
    add: olcModuleLoad
    olcModuleLoad: memberof
quanah commented 4 years ago

The LDIF isn't literal (it has variables that need substitution fixing), and I assume it's applied as a part of the Osixia install process. I would suggest checking your existing configuration to see if it's already there.

quanah commented 4 years ago

this is not working for me also @obourdon

i tried to add new group using the command below

dn: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
cn: finance
gidnumber: 505
uniqueMember: uid=jdoe,ou=users,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames
objectclass: top

and got the following errors in phpldapadmin dashboard

LDAP said: | Object class violation
-- | --
Error number: | 0x41 (LDAP_OBJECT_CLASS_VIOLATION)

This error is correct. Your entry clearly violates the requirements for a groupOfUniqueNames object. I suggest reading the schema.

encryptblockr commented 4 years ago

The LDIF isn't literal (it has variables that need substitution fixing), and I assume it's applied as a part of the Osixia install process. I would suggest checking your existing configuration to see if it's already there.

how do i check if its there? where do i look? and how do i apply if not there? what do i change? will appreciate your help..thanks

encryptblockr commented 4 years ago

this is not working for me also @obourdon i tried to add new group using the command below

dn: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
cn: finance
gidnumber: 505
uniqueMember: uid=jdoe,ou=users,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames
objectclass: top

and got the following errors in phpldapadmin dashboard

LDAP said: | Object class violation
-- | --
Error number: | 0x41 (LDAP_OBJECT_CLASS_VIOLATION)

This error is correct. Your entry clearly violates the requirements for a groupOfUniqueNames object. I suggest reading the schema.

this is what others have said worked for them...so not sure what violates..if you have the right way to do it can you post so i can get the help i need and i will really appreciate it..thanks

quanah commented 4 years ago

Generally, one can read the related RFCs, or look at the schema files themselves. For example, if you look at the core schema file that ships with OpenLDAP, you can trivially find the definition for the groupOfUniqueNames objectClass:

objectclass ( 2.5.6.17 NAME 'groupOfUniqueNames'
    DESC 'RFC2256: a group of unique names (DN and Unique Identifier)'
    SUP top STRUCTURAL
    MUST ( uniqueMember $ cn )
    MAY ( businessCategory $ seeAlso $ owner $ ou $ o $ description ) )

As you can see, "gidNumber" is not a valid attribute for this objectClass.

quanah commented 4 years ago

The LDIF isn't literal (it has variables that need substitution fixing), and I assume it's applied as a part of the Osixia install process. I would suggest checking your existing configuration to see if it's already there.

how do i check if its there? where do i look? and how do i apply if not there? what do i change? will appreciate your help..thanks

slapcat -n 0 -l /tmp/config.ldif

Will export your current cn=config configuration to a file in LDIF format. You'll likely need to run the command as root.

encryptblockr commented 4 years ago

/tmp/config.ldif

where do i get this file from or content of the file /tmp/config.ldif

quanah commented 4 years ago

The slapcat command I listed will create /tmp/config.ldif when run. Please see the slapcat(8C) man page if you have questions on how slapcat functions.

encryptblockr commented 4 years ago

why does memberof not come by default? this is one thing i can never understand..i mean this is ldap server why does it not come with memberof by default as many apps need it? why does this need additional setup to work? why? why? why?

never will understand that..been a pain to get it to work..days of back and forth and still not working.

quanah commented 4 years ago

memberOf is a custom system developed by Microsoft that has no defined specification and as is currently implemented, is entirely unsafe to use with replication. I personally avoid using memberOf entirely.

encryptblockr commented 4 years ago

@quanah one question i have here is this..after setting up the ldap server what commands do i need to run to enable memberof? that is all i have been trying to do for past few weeks and have not been able to succeed

anyone that can just tell me what steps and commands to run to enable it because it cant be this much of rocket science as i have tried all i have seen and still nothing

quanah commented 4 years ago

@encryptblockr I don't use Osixia docker, so I don't know what default state it is in after deployment. Did you ever run the slapcat command I described? Did you examine the configuration, if so?

encryptblockr commented 4 years ago

you dont use Osixia docker but you in the issue responding to questions? i dont think it takes more than 5 minutes to have one up..just incase you plan to use it ever

quanah commented 4 years ago

@encryptblockr We get a lot of unhappy users of Osixia who come to the OpenLDAP project email lists complaining, so I do my best to keep them off the list by answering questions here as much as I can since the OpenLDAP project has no links to Osixia.

BertrandGouny commented 4 years ago

@quanah your help to answer user questions is very appreciated, thanks :)

quanah commented 4 years ago

@BertrandGouny Definitely. :) The more that can be resolved here the better the product is, and the happier everyone's experience becomes.

encryptblockr commented 4 years ago

@BertrandGouny willing to help with my issue with memberof? and why it is not enabled by default? Will ldap be un-usable if memberof is enabled by default because it is just beyond me to keep trying to fix this memberof issue

cant find any guide with exact steps to enable it..always bunch of craps everywhere and one has to put thing together by oneself I have not be able to enabled memberof, anyone willing to help me? kind of deperate at this point after spending several weeks now

quanah commented 4 years ago

@encryptblockr Reading through startup.sh, it looks like you need to add a line there to add the memberOf overlay (Similar to what's done on 304 for 02-security.ldif).

There are plenty of valid reasons why one would not want memberOf enabled at all, and I think it makes a sane default to have it optional.

encryptblockr commented 4 years ago

@encryptblockr Reading through startup.sh, it looks like you need to add a line there to add the memberOf overlay (Similar to what's done on 304 for 02-security.ldif).

There are plenty of valid reasons why one would not want memberOf enabled at all, and I think it makes a sane default to have it optional.

what command do i run to add memberof overlay? if i just want to enable it after i started the container

quanah commented 4 years ago

Generally, it looks like you could do something like:

encryptblockr commented 4 years ago

slapcat -n 0 -l /tmp/config.ldif

ok i ran this and when i checked the content of /tmp/config.ldif i see this at the very end of the file

dn: olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcMemberOf
olcOverlay: {0}memberof
olcMemberOfRefInt: TRUE
structuralObjectClass: olcMemberOf
entryUUID: a6b96cb8-a8b6-1039-8af0-cd3475fc2923
creatorsName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
createTimestamp: 20191201184638Z
entryCSN: 20191201184638.219112Z#000000#000#000000
modifiersName: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
modifyTimestamp: 20191201184638Z

i followed this guide https://tylersguides.com/guides/openldap-memberof-overlay/ for having below

and after following the link https://tylersguides.com/guides/openldap-memberof-overlay/ when i run this slapcat -n 0 | grep olcModuleLoad i got this

olcModuleLoad: {0}back_mdb
olcModuleLoad: {1}memberof
olcModuleLoad: {2}memberof.la
olcModuleLoad: {0}memberof.la

so what do i do from here? seems memberof is enabled but its not working still

quanah commented 4 years ago

@encryptblockr

If you want to match the Osixia configs, you're going to need to slapcat your config db, fix up the mess that's been made of the moduleload section, and update the module's configuration accordingly.

encryptblockr commented 4 years ago

ok will start from scratch and try your approach will get back on this..thanks for your help

encryptblockr commented 4 years ago

@quanah

here is a fresh setup

root@5e13c4f11f19:/tmp# slapcat -n 0 | grep olcModuleLoad
olcModuleLoad: {0}back_mdb

root@5e13c4f11f19:/tmp# vi memberof.ldif

root@5e13c4f11f19:/tmp# ldapadd -Y EXTERNAL -Q -H ldapi:/// -f memberof.ldif
modifying entry "cn=module{0},cn=config"

adding new entry "olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config"

root@5e13c4f11f19:/tmp# slapcat -n 0 | grep olcModuleLoad
olcModuleLoad: {0}back_mdb
olcModuleLoad: {1}memberof

now whats is next? any sample ldif file i can apply and use to test this memberof out? so that way i just follow what works

thanks again for your help

quanah commented 4 years ago

@encryptblockr

Generally the next step would to be to create a group using the groupOfUniqueNames objectClass that has at least one member defined in the uniqueMember attribute. If it's functioning, that should "magically" add memberOf to the members of the group.

encryptblockr commented 4 years ago

@quanah do you have sample ldif i can apply and just search with ldapsearch and see? i did have mine in the past but obviously i had issues so if i get a sample one that works it will be greatly appreciated

as you can see i had issues here https://github.com/osixia/docker-openldap/issues/385

quanah commented 4 years ago

@encryptblockr

Your previous bit was mostly correct. Something like

dn: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames
cn: finance
uniqueMember: uid=jdoe,ou=users,dc=ldap,dc=example,dc=com

should work, assuming that jdoe DN exists, etc.

encryptblockr commented 4 years ago

ok here is what i have now

i imported this ldif

# ou=groups,dc=ldap,dc=example,dc=com
dn: ou=groups,dc=ldap,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: groups

# cn=finance,ou=groups,dc=ldap,dc=example,dc=com
dn: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
cn: finance
uniqueMember: uid=jjordan,ou=users,dc=ldap,dc=example,dc=com
uniqueMember: uid=bbritton,ou=users,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames

# cn=engineering,ou=groups,dc=ldap,dc=example,dc=com
dn: cn=engineering,ou=groups,dc=ldap,dc=example,dc=com
cn: engineering
uniqueMember: uid=jjordan,ou=users,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames

# ou=users,dc=ldap,dc=example,dc=com
dn: ou=users,dc=ldap,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: users

# cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
dn: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
cn: Johnathan Jordan
gidnumber: 500
givenname: Johnathan
homedirectory: /home/users/jjordan
loginshell: /bin/bash
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: Jordan
uid: jjordan
uidnumber: 1000
userpassword: PaSsWoRd123

# cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
dn: cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
cn: Brandon Britton
gidnumber: 500
givenname: Brandon
homedirectory: /home/users/bbritton
loginshell: /bin/bash
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: Britton
uid: bbritton
uidnumber: 1001
userpassword: PaSsWoRd123

but when i try to run ldapsearch to find groups users are member of, i am not getting what i want. So not working. Do you have an example ldif and ldapsearch command that works for you i can use @quanah

ldapsearch -D "cn=admin,dc=ldap,dc=example,dc=com" -w PaSsWoRd123 -p 389 -h localhost -b "dc=ldap,dc=example,dc=com" "(uid=bbritton)" uid cn memberof

# extended LDIF
#
# LDAPv3
# base <dc=ldap,dc=example,dc=com> with scope subtree
# filter: (uid=bbritton)
# requesting: uid cn memberof
#

# Brandon Britton, users, ldap.bbops.xyz
dn: cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
cn: Brandon Britton
uid: bbritton

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

ldapsearch -D "cn=admin,dc=ldap,dc=example,dc=com" -w PaSsWoRd123 -p 389 -h localhost -b "dc=ldap,dc=example,dc=com" "(uid=jjordan)" uid cn memberof

# extended LDIF
#
# LDAPv3
# base <dc=ldap,dc=example,dc=com> with scope subtree
# filter: (uid=jjordan)
# requesting: uid cn memberof
#

# Johnathan Jordan, users, ldap.bbops.xyz
dn: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
cn: Johnathan Jordan
uid: jjordan

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

also did i do anything wrong?

thanks

quanah commented 4 years ago

@encryptblockr

Yes, this is incorrect. The uniqueMember attribute takes the DN of an entry. The user DNs in your database that you show are:

cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com

But what you put in uniquemember is:

uniqueMember: uid=jjordan,ou=users,dc=ldap,dc=example,dc=com
uniqueMember: uid=bbritton,ou=users,dc=ldap,dc=example,dc=com

The above do not appear to be valid DNs for your database. The term "DN" has an exact meaning. Overall, I would strongly advise taking some time to read up on LDAP terminology and structure.

encryptblockr commented 4 years ago

@quanah still does not work again if you have a sample ldif that works i can use that will be great to reduce the back and forth

here is what i have now

# ou=groups,dc=ldap,dc=example,dc=com
dn: ou=groups,dc=ldap,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: groups

# cn=finance,ou=groups,dc=ldap,dc=example,dc=com
dn: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
cn: finance
uniqueMember: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
uniqueMember: cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames

# cn=engineering,ou=groups,dc=ldap,dc=example,dc=com
dn: cn=engineering,ou=groups,dc=ldap,dc=example,dc=com
cn: engineering
uniqueMember: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
objectclass: groupOfUniqueNames

# ou=users,dc=ldap,dc=example,dc=com
dn: ou=users,dc=ldap,dc=example,dc=com
objectclass: organizationalUnit
objectclass: top
ou: users

# cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
dn: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
cn: Johnathan Jordan
gidnumber: 500
givenname: Johnathan
homedirectory: /home/users/jjordan
loginshell: /bin/bash
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: Jordan
uid: jjordan
uidnumber: 1000
userpassword: PaSsWoRd123

# cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
dn: cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
cn: Brandon Britton
gidnumber: 500
givenname: Brandon
homedirectory: /home/users/bbritton
loginshell: /bin/bash
objectclass: inetOrgPerson
objectclass: posixAccount
objectclass: top
sn: Britton
uid: bbritton
uidnumber: 1001
userpassword: PaSsWoRd123

ldapsearch -D "cn=admin,dc=ldap,dc=example,dc=com" -w PaSsWoRd123 -p 389 -h localhost -b "dc=ldap,dc=example,dc=com" "(uid=bbritton)" uid cn memberof

# extended LDIF
#
# LDAPv3
# base <dc=ldap,dc=example,dc=com> with scope subtree
# filter: (uid=bbritton)
# requesting: uid cn memberof
#

# Brandon Britton, users, ldap.example.com
dn: cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
cn: Brandon Britton
uid: bbritton

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

ldapsearch -D "cn=admin,dc=ldap,dc=example,dc=com" -w PaSsWoRd123 -p 389 -h localhost -b "dc=ldap,dc=example,dc=com" "(uid=jjordan)" uid cn memberof

# extended LDIF
#
# LDAPv3
# base <dc=ldap,dc=example,dc=com> with scope subtree
# filter: (uid=jjordan)
# requesting: uid cn memberof
#

# Johnathan Jordan, users, ldap.example.com
dn: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
cn: Johnathan Jordan
uid: jjordan

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1
quanah commented 4 years ago

@encryptblockr

I've done the following:

a) Load the memberof configuration as provided by Osixia:

ldapmodify -x -H ldap:// -D cn=config -w secret -f ./memberof.ldif
modifying entry "cn=module{0},cn=config"

adding new entry "olcOverlay={0}memberof,olcDatabase={1}mdb,cn=config"

b) Load your database:

ldapadd -x -H ldap:// -D dc=example,dc=com -w secret -f ./exampledb.ldif

adding new entry "ou=groups,dc=ldap,dc=example,dc=com"

adding new entry "cn=finance,ou=groups,dc=ldap,dc=example,dc=com"

adding new entry "cn=engineering,ou=groups,dc=ldap,dc=example,dc=com"

adding new entry "ou=users,dc=ldap,dc=example,dc=com"

adding new entry "cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com"

adding new entry "cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com"

Now, this fails to generate memberOf because you created the users after you created the groups. This is one of the distinct failings of memberOf in its current form -- Users must exist in the database prior to them being added to a group for the overlay to work.

Now if I modify the groups:

ldapmodify -x -H ldap:// -D dc=example,dc=com -w secret
dn: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
changetype: modify
replace: uniqueMember
uniqueMember: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
uniqueMember: cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com

modifying entry "cn=finance,ou=groups,dc=ldap,dc=example,dc=com"

dn: cn=engineering,ou=groups,dc=ldap,dc=example,dc=com
changetype: modify
replace: uniqueMember
uniqueMember: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com

modifying entry "cn=engineering,ou=groups,dc=ldap,dc=example,dc=com"

The memberOf attribute is correctly created:

ldapsearch -x -LLL -H ldap:// -D dc=example,dc=com -w secret -b dc=ldap,dc=example,dc=com "cn=Brandon Britton" memberOf
dn: cn=Brandon Britton,ou=users,dc=ldap,dc=example,dc=com
memberOf: cn=finance,ou=groups,dc=ldap,dc=example,dc=com

ldapsearch -x -LLL -H ldap:// -D dc=example,dc=com -w secret -b dc=ldap,dc=example,dc=com "cn=Johnathan Jordan" memberOf
dn: cn=Johnathan Jordan,ou=users,dc=ldap,dc=example,dc=com
memberOf: cn=finance,ou=groups,dc=ldap,dc=example,dc=com
memberOf: cn=engineering,ou=groups,dc=ldap,dc=example,dc=com