Open PlkMarudny opened 6 years ago
Using this in a project I'm working on with AD and this took me a bit to find out.
"(&(member=%s)(objectClass=group))" where "%s" is the user distinguished name -- I just grabbed the user dn from the attributes once they were authenticated. Hope this helps.
I'm trying to use AD for authorization only.. I bind as a read-only user to query the list of groups a user is in, and I'm having a heck of a time getting the GroupFilter written properly to get anything but an empty set of groups. If you have a code example of how you're making this work, I would be very grateful, @arpachuilo!
@eklein I've changed jobs since then, so I don't have access to the codebase to share a snippet -- nor do I remember what I did.
I hazily remember using "(&(member=%s)(objectClass=group))"
as the GroupFilter. Then I guess beyond that when calling GetGroupsOfUser
I passed in the user distinguished name of the user. Do not remember how I was getting a hold of the user DN beyond recreating it because I don't think I was doing Authentication either. I just remember the DN being essential to getting groups properly.
Not much, but hope this helps.
I thought I had cracked this with (&(member=%s)(objectCategory=group))
then passing the sAMAccount name but then I noticed I was using the DN.
Time to create a quick helper function to grab the DN I guess
@eklein My GetGroupsOfUser
is now working using the modified version below, Give it a go and see if it works for you. It could do with a bit of cleanup but should get you started.
// GetGroupsOfUser returns the group for a user.
func (lc *LDAPClient) GetGroupsOfUser(username string) ([]string, error) {
err := lc.Connect()
if err != nil {
return nil, err
}
defer lc.Close()
// First Bind with read only user
if lc.BindDN != "" && lc.BindPassword != "" {
err = lc.Conn.Bind(lc.BindDN, lc.BindPassword)
if err != nil {
return nil, err
}
}
// Get the users DN
// Search for the given username
searchRequest := ldap.NewSearchRequest(
lc.Base,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf(lc.UserFilter, username),
[]string{"dn"},
nil,
)
sr, err := lc.Conn.Search(searchRequest)
if err != nil {
return nil, err
}
if len(sr.Entries) != 1 {
return nil, errors.New("User does not exist")
}
userdn := sr.Entries[0].DN
searchRequest = ldap.NewSearchRequest(
lc.Base,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf(lc.GroupFilter, userdn),
[]string{"cn"}, // can it be something else than "cn"?
nil,
)
sr, err = lc.Conn.Search(searchRequest)
if err != nil {
return nil, err
}
groups := []string{}
for _, entry := range sr.Entries {
groups = append(groups, entry.GetAttributeValue("cn"))
}
return groups, nil
}
Wish I would have seen this about 10 minutes ago 😂. I just sat down and wrote a helper function to do the same. This indeed did work for me, though I wonder if this breaks things when using openldap. Need to look into that since I have a need to authenticate against both. Thank you both very much for your help! @arpachuilo @Joffcom
To follow-up, it does indeed break when trying to authenticate against openldap. I'll need to rewrite things to support both based on whether it's openldap or AD.
Hi @Joffcom your example don't return the primary groups, like "Users" or "Domain Users". Any way to return all groups of a specific user including Primary Groups? Best regards
Good question @abolinhas, I have not really played with this for a couple of years now but I would have expected it to work with the primary group as well as the user would still be a member 🤔
I don't have an AD server to test against anymore either.
What would be the GroupFilter in that case? User filter is "(sAMAccountName=%s)", BTW