Skip to content

Search with filter doesn't return correct results #356

Open
@WhileLoop

Description

@WhileLoop

I have encountered a situation where using the search filter(&(objectClass=inetOrgPerson)(uid=user01)) in go-ldap returns no results but when I search with (objectClass=*) I can see that the object exists.

Using ldapsearch with (&(objectClass=inetOrgPerson)(uid=user01)) returns the expected result.

My LDAP server is Bitnami OpenLDAP docker image. To reproduce:

docker-compose.yml

version: '3.4'
services:
  openldap:
    image: docker.io/bitnami/openldap:2.5
    ports:
      - '389:1389'
    environment:
      - LDAP_ADMIN_USERNAME=admin
      - LDAP_ADMIN_PASSWORD=adminpassword
      - LDAP_USERS=user01
      - LDAP_PASSWORDS=password1
    volumes:
      - 'openldap_data:/bitnami/openldap'
volumes:
  openldap_data:
    driver: local

program.go

package main

import (
	"log"
	"fmt"
	"github.com/go-ldap/ldap/v3"
)

func main() {
	if err := findUser(); err != nil {
		log.Fatal(err)
	}
}

func findUser() error {
	ldapURL := "ldap://0.0.0.0:389"
	adminusername := "cn=admin,dc=example,dc=org"
	adminpassword := "adminpassword"
	baseDN := "dc=example,dc=org"

	l, err := ldap.DialURL(ldapURL)
	if err != nil {
		return err
	}
	l.Start()

	err = l.Bind(adminusername, adminpassword)
	if err != nil {
		return err
	}

	searchAll := &ldap.SearchRequest{
		BaseDN: baseDN,
		Scope:  ldap.ScopeWholeSubtree,
		Filter: "(objectClass=*)",
	}

	fmt.Println("Search: (objectClass=*)")
	sr, err := l.Search(searchAll)
	if err != nil {
		return err
	}

	printResult(sr.Entries)

	fmt.Println("")
	fmt.Println("(&(objectClass=inetOrgPerson)(uid=user01))")
	searchSpecificUser := &ldap.SearchRequest{
		BaseDN: baseDN,
		Scope:  ldap.ScopeWholeSubtree,
		Filter: "(&(objectClass=inetOrgPerson)(uid=user01))",
	}

	sr, err = l.Search(searchSpecificUser)
	if err != nil {
		return err
	}

	if len(sr.Entries) != 1 {
		fmt.Printf("%+v\n", sr)
		log.Fatal("User does not exist or too many entries returned")
	} else {
		fmt.Printf("****** FOUND! ******")
	}
	return nil
}

func printResult(entries []*ldap.Entry) {
	for _, entry := range entries {
		fmt.Println("DN:", entry.DN)
		for _, attr := range entry.Attributes {
			for i := 0; i < len(attr.Values); i++ {
				fmt.Printf("%s: %s\n", attr.Name, attr.Values[i])
			}
		}
		fmt.Println()
	}
}

program output:

$ go run ldap-find-user.go 
Search: (objectClass=*)
DN: ou=users,dc=example,dc=org
objectClass: organizationalUnit
ou: users

DN: dc=example,dc=org
objectClass: dcObject
objectClass: organization
dc: example
o: example

DN: cn=user01,ou=users,dc=example,dc=org
cn: User1
cn: user01
sn: Bar1
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
userPassword: password1
uid: user01
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/user01

DN: cn=readers,ou=users,dc=example,dc=org
cn: readers
objectClass: groupOfNames
member: cn=user01,ou=users,dc=example,dc=org


(&(objectClass=inetOrgPerson)(uid=user01))
&{Entries:[] Referrals:[] Controls:[]}
2022/01/23 19:23:04 User does not exist or too many entries returned
exit status 1

ldapsearch test:

$ ldapsearch -x -b "dc=example,dc=org" -H ldap://0.0.0.0 -D cn=admin,dc=example,dc=org -w adminpassword "(&(objectclass=inetOrgPerson)(uid=user01))"
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=org> with scope subtree
# filter: (&(objectclass=inetOrgPerson)(uid=user01))
# requesting: ALL
#

# user01, users, example.org
dn: cn=user01,ou=users,dc=example,dc=org
cn: User1
cn: user01
sn: Bar1
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
userPassword:: cGFzc3dvcmQx
uid: user01
uidNumber: 1000
gidNumber: 1000
homeDirectory: /home/user01

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

Full repo: https://github.com/WhileLoop/go-ldap-test

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions