jtblin / go-ldap-client

Simple ldap client to authenticate, retrieve basic information and groups for a user.
Other
261 stars 90 forks source link

GetGroupsOfUser() for Active Directory database #13

Open PlkMarudny opened 6 years ago

PlkMarudny commented 6 years ago

What would be the GroupFilter in that case? User filter is "(sAMAccountName=%s)", BTW

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

eklein commented 5 years ago

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!

arpachuilo commented 5 years ago

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

Joffcom commented 5 years ago

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

Joffcom commented 5 years ago

@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
}
eklein commented 5 years ago

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

eklein commented 5 years ago

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.

abolinhas commented 2 years ago

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

Joffcom commented 2 years ago

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.