“This is the sixth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

When we work with other organizations, we may not be the party that builds the server, but the party that belongs to the client, and need to get the organizational structure of the server, according to certain conditions to get the data of the server, or it can be the synchronous organizational structure

While golang’s data structure is not as rich as c++, there are libraries that handle ldap

Pkg.go. dev/gopkg.in/ld…

We can also download the library on Github

go get github.com/go-ldap/ldap/v3
Copy the code

The latest Version of Golang for the LDAP library is Version: V3.1.0

Start coding

Let’s write a demo that captures the organizational structure of the LDAP server we set up last time

This is our simple LDAP server, you can use the LDAP Admin visual management tool to view the specific page effect

After we download the library, our coding idea is as follows:

  • Enter the LDAP server address and administrator information to establish a connection to the LDAP server
  • Write a query request and start querying the LDAP server
  • Print out the query structure as provided by the LDAP V3 library

Connecting to the server

Func DialURL(addr String, opts… DialOpt) (*Conn, error) to establish a connection to the LDAP server

ml, err := ldap.DialURL("ldap://xxxx")
	iferr ! =nil {
		log.Fatal(err)
	}
	defer ml.Close()
Copy the code

We fill in the address, can not input port number, library function has been done for us, we can look at the source

The DialURL function is used to connect to the LDAP server and a successful connection will return us a new connection

We can continue to look at this function call c, err := dc.dial(u).

Golang’s library determines whether to perform encrypted or unencrypted transmission based on whether the address we enter is LDAP or LDAPS, which corresponds to port 389 for unencrypted access and port 636 for encrypted access

Add administrator binding information

The LDAP domain information is dc=xiaomotong,dc=com

My administrator is cn=admin,dc=xiaomotong,dc=com

_, err = ml.SimpleBind(&ldap.SimpleBindRequest{
		Username: "cn=admin,dc=xiaomotong,dc=com",
		Password: "123123",})iferr ! =nil {
		log.Fatalf("Failed to bind: %s\n", err)
	}

	fmt.Println("connect successfully !!")
Copy the code

Take a look at the SimpleBindRequest data structure in action

// SimpleBindRequest represents a username/password bind operation
type SimpleBindRequest struct {
	// Username is the name of the Directory object that the client wishes to bind as
	Username string
	// Password is the credentials to bind with
	Password string
	// Controls are optional controls to send with the bind request
	Controls []Control
	// AllowEmptyPassword sets whether the client allows binding with an empty password
	// (normally used for unauthenticated bind).
	AllowEmptyPassword bool
}
Copy the code
  • Username
  • Password

The domain user and password to be bound to the client

  • Controls

The control that needs to bind the request

  • AllowEmptyPassword

Whether to allow an empty password. If an empty password is used, an unauthorized user is bound

Write the query request and start querying the LDAP server

searchRequest := ldap.NewSearchRequest(
		"dc=xiaomotong,dc=com",
		ldap.ScopeWholeSubtree,
		ldap.NeverDerefAliases,
		0.0.false."(ou=People)"And []string{},
		nil,
	)
	searchResult, err := ml.Search(searchRequest)
	iferr ! =nil {
		log.Println("can't search ", err.Error())
	}
	log.Printf("%d".len(searchResult.Entries))
Copy the code

Write a query request, that is, simply give our structure a negative operation, fill in the corresponding parameters, you can start the query, let’s take a look at the structure NewSearchRequest

Basically fill in the corresponding domain information

  • BaseDN, a unique identifier for a domain
  • Scope scope is selected by defaultScopeWholeSubtreeTo query all subtrees
  • DerefAliases, SizeLimit, TimeLimit, TypesOnly Fill in the default value
  • Filter, the Filter condition that the query needs, can write the condition according to our actual situation, just like the condition that writes the query database, cannot be empty here, otherwise the program will crash
F:\codegitee\golang_study\later_learning\ldap_test>go run main.go
connect successfully !!
2021/11/06 21:07:59 can't search  LDAP Result Code 201 "Filter Compile Error": ldap: error parsing filter
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x4 pc=0xa33cef]

goroutine 1 [running]:
main.main()
        F:/codegitee/golang_study/later_learning/ldap_test/main.go:40 +0x24f
exit status 2
Copy the code
  • Attributes, which Attributes need to be returned, is a slice that will return all Attributes if we default to fill in the blank

View the source of the corresponding Search function

The general logic of the code is that doRequest sends the data group package to the LDAP server for a request, and when the request is successful, the data in response is parsed according to the different contents of the tag

Finally returns a pointer to the *SearchResult query result

Enter query information

for _, item := range searchResult.Entries {
   item.Print()
   fmt.Printf("\n\n")}Copy the code

In the source code above, we can see that the output query information is iterated through searchresult. Entries and we can see the corresponding data structure

We can see in the result that there is a single Entry []*Entry, which is a slice containing multiple * Entries. In ldap servers, one Entry represents a unique record

The Entry structure is the corresponding DN, the unique identification name of a record, and its related attributes

So in EntryAttribute structure, we can see that we have Name, we have Values, and this is the RDN that we talked about earlier, which is a key-value pair, multiple key-value pairs that form a DN

Finally, let’s see what happens

>go run main.go
connect successfully !!
2021/11/06 21:20:58 1
DN: ou=People,dc=xiaomotong,dc=com
objectClass: [organizationalUnit]
ou: [People]
Copy the code

The result is one message. Yes, since our ou=people has only one record, if we need to query the entire LDAP server, we can change the Filter position of the above code to objectClass=*

Explain the above results:

  • DN represents a unique record and is used to identify the meaning of the name
  • ObjectClass is a class. OrganizationalUnit represents an organization unit OU, which can be understood as a group
  • Ou: [People] indicates that the name of the ou is People

Welcome to like, follow and favorites

Friends, your support and encouragement, I insist on sharing, improve the quality of the power

All right, that’s it for this time

Technology is open, our mentality, should be more open. Embrace change, live in the sun, and strive to move forward.

I am Nezha, welcome to like, see you next time ~