### Setup Local LDAP Server and Run Tests Source: https://github.com/go-ldap/ldap/blob/master/README.md Instructions for setting up a local LDAP server using Docker/Podman and running Go tests. Ensure you have Docker or Podman installed. ```bash make local-server cd ./v3 make -f ../Makefile cd .. make stop-local-server ``` -------------------------------- ### Example: Creating a New Search Request Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Demonstrates how to instantiate a new search request using the NewSearchRequest function with common parameters. ```go searchReq := ldap.NewSearchRequest( "dc=example,dc=org", // BaseDN ldap.ScopeWholeSubtree, // Scope ldap.NeverDerefAliases, // DerefAliases 0, // SizeLimit (no limit) 0, // TimeLimit (no limit) false, // TypesOnly "(uid=john)", // Filter []string{"uid", "cn", "mail"}, // Attributes nil, // Controls ) ``` -------------------------------- ### Go LDAP Connection Lifecycle Example Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Demonstrates the basic lifecycle of an LDAP connection using DialURL, performing operations, and closing the connection. ```go // Create connection conn, err := ldap.DialURL("ldap://localhost:389") // Start goroutines (automatic with DialURL) // conn.Start() // Perform operations conn.Bind(...) conn.Search(...) // Close connection conn.Close() ``` -------------------------------- ### Basic LDAP Search Example Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Demonstrates how to perform a basic LDAP search request and process the results. Ensure to handle potential errors and check if any entries were found. ```go searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, "(uid=john)", []string{"uid", "cn", "mail"}, nil, ) result, err := conn.Search(searchReq) if err != nil { log.Fatal(err) } if len(result.Entries) == 0 { log.Print("User not found") } else { entry := result.Entries[0] log.Printf("Found: %s", entry.DN) } ``` -------------------------------- ### NewConn Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Returns a new Conn using the provided net.Conn for network I/O. Call Start() to initialize goroutines. ```APIDOC ## NewConn ### Description Returns a new Conn using the provided `net.Conn` for network I/O. Call `Start()` to initialize goroutines. ### Method `func NewConn(conn net.Conn, isTLS bool) *Conn` ### Parameters #### Path Parameters - **conn** (net.Conn) - Required - Network connection - **isTLS** (bool) - Required - Whether the connection is already TLS-encrypted ### Returns - `*Conn` ``` -------------------------------- ### Get Attribute Value Example Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Demonstrates how to retrieve the 'cn' attribute value from an Entry object. ```go cn := entry.GetAttributeValue("cn") ``` -------------------------------- ### Handling Password Policy Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Example of how to handle password policy information returned as an LDAP control. ```APIDOC ## Handling Password Policy ### Description This example demonstrates how to process the `ControlBeheraPasswordPolicy` to retrieve password policy-related information like errors and expiration times. ### Code Example ```go searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false, "(uid=john)", nil, []ldap.Control{}, ) result, err := conn.Search(searchReq) if err != nil { log.Fatal(err) } for _, control := range result.Controls { if control.GetControlType() == ldap.ControlTypeBeheraPasswordPolicy { pwdPolicy := control.(*ldap.ControlBeheraPasswordPolicy) if pwdPolicy.Error > 0 { log.Printf("Password Policy Error: %s", ldap.BeheraPasswordPolicyErrorMap[pwdPolicy.Error]) } if pwdPolicy.TimeBeforeExpiration > 0 { log.Printf("Password expires in %d seconds", pwdPolicy.TimeBeforeExpiration) } } } ``` ``` -------------------------------- ### Password Modification Examples Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/04-modify-operations.md Demonstrates changing the current user's password, an administrator changing another user's password, and requesting a server-generated password. ```go // Change current user's password req := ldap.NewPasswordModifyRequest("", "oldpass", "newpass") result, err := conn.PasswordModify(req) if err != nil { log.Fatal(err) } // Change another user's password (admin only) req := ldap.NewPasswordModifyRequest( "cn=john,dc=example,dc=org", "", // No old password needed for admin "newpass", ) result, err := conn.PasswordModify(req) if err != nil { log.Fatal(err) } // Server-generated password req := ldap.NewPasswordModifyRequest( "cn=john,dc=example,dc=org", "", "", // Empty new password requests server-generated ) result, err := conn.PasswordModify(req) if err == nil && result.GeneratedPassword != "" { log.Printf("Generated password: %s", result.GeneratedPassword) } ``` -------------------------------- ### Create New AddRequest in Go Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/04-modify-operations.md Initializes a new AddRequest for a specified DN. Use this to start building an entry creation request. ```go req := ldap.NewAddRequest("cn=john,dc=example,dc=org", nil) ``` -------------------------------- ### Create New Conn from net.Conn Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Returns a new Conn using the provided net.Conn for network I/O. Remember to call Start() to initialize goroutines. ```go func NewConn(conn net.Conn, isTLS bool) *Conn ``` -------------------------------- ### Common LDAP Filter String Examples Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Illustrates various common LDAP filter syntaxes, including equality matches, substrings, presence checks, range comparisons, logical AND/OR/NOT, and complex combinations. ```go // Equality match "(cn=John)" ``` ```go // Wildcard substring "(cn=John*)" "(cn=*Doe)" "(cn=*John*)" ``` ```go // Present (attribute exists) "(mail=*)" ``` ```go // Greater than or equal "(age>=18)" ``` ```go // Less than or equal "(loginTime<=2023-01-01)" ``` ```go // AND - all conditions must match "(&(cn=John)(objectClass=person))" ``` ```go // OR - at least one condition must match "(|(cn=John)(cn=Jane))" ``` ```go // NOT - negate condition "(!(cn=Admin))" ``` ```go // Complex filter "(&(|(cn=John)(cn=Jane))(objectClass=person)(!(disabled=TRUE)))" ``` -------------------------------- ### Example Usage of Paging Control in Search Request Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Demonstrates how to create a new search request and include a Paging control to specify the desired page size. The Paging control is added to the list of controls for the search request. ```go searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=*)", nil, []ldap.Control{ldap.NewControlPaging(1000)}, ) result, err := conn.Search(searchReq) ``` -------------------------------- ### Complex LDAP Filter Examples Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Illustrates various complex LDAP filter constructions using AND (&), OR (|), and NOT (!) operators. These examples demonstrate how to combine multiple conditions for sophisticated searches. ```ldap "(&(department=Engineering)(objectClass=person))" ``` ```ldap "(|(loginDisabled=TRUE)(createTimestamp>=20240101000000Z))" ``` ```ldap "(&(accountStatus=active)(|(role=admin)(role=manager))(!accountLocked=TRUE))" ``` ```ldap "(memberOf=cn=admins,ou=groups,dc=example,dc=org)" ``` ```ldap "(&(cn=*admin*)(|(mail=*@example.com)(mobile=*)))" ``` -------------------------------- ### LDAP Filter Examples Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Illustrates various LDAP filter syntaxes for common search criteria, including substring matching, object class filtering, AND/OR conditions, and negation. ```ldap "(cn=*John*)" ``` ```ldap "(objectClass=person)" ``` ```ldap "(&(cn=John)(mail=*))" ``` ```ldap "(|(cn=John)(cn=Jane))" ``` ```ldap "(!(memberOf=cn=admins,dc=example,dc=org))" ``` -------------------------------- ### Example: Find Paging Control Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Demonstrates how to find a Paging control within a list of controls and extract its cookie. This can be done by iterating or using the FindControl utility. ```go for _, control := range result.Controls { if control.GetControlType() == ldap.ControlTypePaging { pagingControl := control.(*ldap.ControlPaging) log.Printf("Cookie: %v", pagingControl.Cookie) } } // Or use FindControl pagingControl := ldap.FindControl(result.Controls, ldap.ControlTypePaging) if pagingControl != nil { cookie := pagingControl.(*ldap.ControlPaging).Cookie } ``` -------------------------------- ### Get Normalized DN String Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Retrieves the normalized string representation of a DN. The output is converted to lowercase as shown in the example. ```go dn, _ := ldap.ParseDN("cn=John,dc=example,dc=org") fmt.Println(dn.String()) // Output: cn=john,dc=example,dc=org (normalized to lowercase) ``` -------------------------------- ### User Struct with LDAP Tags Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/09-utility-functions.md Example of a Go struct definition using the `ldap` tag for field mapping during unmarshaling. ```go type User struct { DN string `ldap:"dn" CN string `ldap:"cn" Email string `ldap:"mail" Groups []string `ldap:"memberOf" } ``` -------------------------------- ### Build Search Filter Safely Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Demonstrates how to build an LDAP search filter by safely escaping user input using `ldap.EscapeFilter`. This prevents injection attacks when user-provided values are incorporated into filters. The example includes a full search operation. ```go package main import ( "fmt" "log" "github.com/go-ldap/ldap/v3" ) func buildSearchFilter(cn string) string { // Escape user input for use in filter return fmt.Sprintf("(cn=%s)", ldap.EscapeFilter(cn)) } func main() { conn, _ := ldap.DialURL("ldap://localhost:389") defer conn.Close() conn.Bind("cn=admin,dc=example,dc=org", "password") // Safe search with user input userInput := "John*Doe" filter := buildSearchFilter(userInput) // Result: (cn=John\2aDoe) searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, filter, []string{"cn", "mail"}, nil, ) result, err := conn.Search(searchReq) if err != nil { log.Fatal(err) } for _, entry := range result.Entries { log.Printf("Found: %s", entry.DN) } } ``` -------------------------------- ### Handle Specific LDAP Error Codes Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/08-error-handling.md Handle different LDAP errors based on their result codes. This example shows how to respond to 'Entry Already Exists' and 'No Such Object' errors. ```go req := ldap.NewAddRequest("cn=test,dc=example,dc=org", nil) req.Attribute("cn", []string{"test"}) err := conn.Add(req) if err != nil { if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) { log.Print("Entry already exists") } else if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) { log.Print("Parent entry does not exist") } else { log.Fatalf("Unexpected error: %v", err) } } ``` -------------------------------- ### Parse and Manipulate DN Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Demonstrates parsing a DN string into its components and accessing its Relative Distinguished Names (RDNs) and attributes. It also shows how to get a normalized string representation of the DN. ```go package main import ( "log" "github.com/go-ldap/ldap/v3" ) func main() { // Parse a DN dn, err := ldap.ParseDN("cn=John,ou=Users,dc=example,dc=org") if err != nil { log.Fatal(err) } // Access RDNs for _, rdn := range dn.RDNs { for _, atv := range rdn.Attributes { log.Printf("Type: %s, Value: %s", atv.Type, atv.Value) } } // Get string representation (normalized) log.Printf("Normalized DN: %s", dn.String()) } ``` -------------------------------- ### Importing and Initializing LDAP Client Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/10-types-reference.md Demonstrates how to import the Go LDAP library and establish a connection to an LDAP server using DialURL. It also shows variable declarations for common LDAP operations. ```go import ldap "github.com/go-ldap/ldap/v3" conn, err := ldap.DialURL("ldap://localhost:389") var req *ldap.SearchRequest var result *ldap.SearchResult var entry *ldap.Entry ``` -------------------------------- ### Conn.Start Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Initializes goroutines to read replies and process messages. Must be called after creating a Conn. ```APIDOC ## Conn.Start ### Description Initializes goroutines to read replies and process messages. Must be called after creating a Conn with `NewConn`. ### Method func (l *Conn) Start() ### Example ```go conn := ldap.NewConn(netConn, false) conn.Start() ``` ``` -------------------------------- ### Add User and Modify Password Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/04-modify-operations.md Demonstrates creating a new user with initial attributes and then changing their password. Ensure the connection is established before executing these operations. ```go req := ldap.NewAddRequest("cn=john,dc=example,dc=org", nil) req.Attribute("objectClass", []string{"inetOrgPerson"}) req.Attribute("cn", []string{"John Doe"}) req.Attribute("sn", []string{"Doe"}) req.Attribute("mail", []string{"john@example.com"}) req.Attribute("userPassword", []string{"initialpass123"}) err := conn.Add(req) if err != nil { log.Fatal(err) } // Later, change password pwdReq := ldap.NewPasswordModifyRequest( "cn=john,dc=example,dc=org", "initialpass123", "newpass456", ) _, err = conn.PasswordModify(pwdReq) ``` -------------------------------- ### Get All Attribute Values Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Retrieves all values for a given attribute name from an Entry. Returns an empty slice if the attribute is not found. ```go func (e *Entry) GetAttributeValues(attribute string) []string ``` -------------------------------- ### Create and Use Multiple LDAP Controls Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Shows how to create a slice of different LDAP controls, such as Paging and SortRequest, and include them in a search request. ```go controls := []ldap.Control{ ldap.NewControlPaging(500), ldap.NewControlSortRequest([]*ldap.SortKey{ {AttributeType: "cn", ReverseOrder: false}, }), } searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=person)", []string{"cn", "mail"}, controls, ) result, err := conn.Search(searchReq) ``` -------------------------------- ### Get Last LDAP Error Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/08-error-handling.md Retrieve the last error that occurred in a background goroutine associated with the LDAP connection using `conn.GetLastError()`. ```go // Check for background goroutine errors if bgErr := conn.GetLastError(); bgErr != nil { log.Printf("Background error detected: %v", bgErr) } ``` -------------------------------- ### Conn.StartTLS Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Sends the STARTTLS command and upgrades the connection to TLS. The connection must not already be TLS-encrypted. ```APIDOC ## Conn.StartTLS ### Description Sends the STARTTLS command and upgrades the connection to TLS. The connection must not already be TLS-encrypted. ### Method func (l *Conn) StartTLS(config *tls.Config) error ### Parameters #### Path Parameters - **config** (*tls.Config) - Required - TLS configuration ### Returns error ### Throws `ErrorNetwork` - if connection is already TLS or TLS negotiation fails ### Example ```go tlsConfig := &tls.Config{InsecureSkipVerify: false} err := conn.StartTLS(tlsConfig) if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Basic LDAP Authentication and Search in Go Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Connect to an LDAP server, bind with credentials, and perform a search for user attributes. Ensure the LDAP server is running and accessible. ```go package main import ( "fmt" "log" "github.com/go-ldap/ldap/v3" ) func main() { // Connect to LDAP server conn, err := ldap.DialURL("ldap://localhost:389") if err != nil { log.Fatal(err) } defer conn.Close() // Bind with credentials err = conn.Bind("cn=admin,dc=example,dc=org", "password") if err != nil { log.Fatal(err) } // Search searchReq := ldap.NewSearchRequest( "dc=example,dc=org", // Base DN ldap.ScopeWholeSubtree, // Scope ldap.NeverDerefAliases, // Dereference 0, 0, false, // Size, time limit, types only "(uid=john)", // Filter []string{"uid", "cn", "mail"}, // Attributes nil, // Controls ) result, err := conn.Search(searchReq) if err != nil { log.Fatal(err) } // Process results for _, entry := range result.Entries { fmt.Printf("DN: %s\n", entry.DN) fmt.Printf("UID: %s\n", entry.GetAttributeValue("uid")) fmt.Printf("CN: %s\n", entry.GetAttributeValue("cn")) fmt.Printf("Mail: %s\n", entry.GetAttributeValue("mail")) } } ``` -------------------------------- ### Using Controls with WhoAmI Extended Operation Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/07-extended-operations.md Demonstrates how to include LDAP controls, such as proxy authorization, with extended operations like WhoAmI. The result reflects the identity of the proxied user. ```go // WhoAmI with proxied authorization proxyControl := ldap.NewControlProxyAuthorization("cn=admin,dc=example,dc=org") result, err := conn.WhoAmI([]ldap.Control{proxyControl}) if err != nil { log.Fatal(err) } // Result reflects identity of proxied user log.Printf("Proxied as: %s", result.AuthzID) ``` -------------------------------- ### Control Interface Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/10-types-reference.md Defines the interface that all LDAP controls must implement, including methods for getting the control type, encoding, and string representation. ```go type Control interface { GetControlType() string Encode() *ber.Packet String() string } ``` -------------------------------- ### CompileFilter Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Converts a string representation of an LDAP filter into a BER-encoded packet. The filter string must start with '(' and adhere to LDAP filter syntax. ```APIDOC ## CompileFilter ### Description Converts a string representation of an LDAP filter into a BER-encoded packet. ### Method ```go func CompileFilter(filter string) (*ber.Packet, error) ``` ### Parameters #### Path Parameters - **filter** (string) - Required - LDAP filter string (must start with '(' ) ### Returns - **ber.Packet** - The compiled filter as a BER packet. - **error** - An error if the filter compilation fails. ### Throws - **ErrorFilterCompile** - If the filter does not start with '(' or has syntax errors. ### Request Example ```go packet, err := ldap.CompileFilter("(cn=John*)") if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### Get Raw Attribute Value Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Retrieves the first raw byte value for a given attribute name from an Entry. Useful for attributes with non-string values. ```go func (e *Entry) GetRawAttributeValue(attribute string) []byte ``` -------------------------------- ### Upgrade Connection to TLS Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Sends the STARTTLS command to upgrade the existing connection to a TLS-encrypted one. The connection must not already be TLS-encrypted. Handles TLS negotiation errors. ```go tlsConfig := &tls.Config{InsecureSkipVerify: false} err := conn.StartTLS(tlsConfig) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Get First Attribute Value Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Retrieves the first value for a given attribute name from an Entry. Returns an empty string if the attribute is not found. Case-sensitive. ```go func (e *Entry) GetAttributeValue(attribute string) string ``` -------------------------------- ### Using Multiple Controls Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Demonstrates how to create and use multiple LDAP controls in a search request. ```APIDOC ## Using Multiple Controls ### Description This example shows how to construct a search request with multiple controls, such as Paging and SortRequest. ### Code Example ```go controls := []ldap.Control{ ldap.NewControlPaging(500), ldap.NewControlSortRequest([]*ldap.SortKey{ {AttributeType: "cn", ReverseOrder: false}, }), } searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=person)", []string{"cn", "mail"}, controls, ) result, err := conn.Search(searchReq) ``` ``` -------------------------------- ### Use Manage DSA IT Control in Search Request Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Demonstrates how to include the Manage DSA IT control in a search request to handle referrals. ```go searchReq := ldap.NewSearchRequest( "cn=referral,dc=example,dc=org", ldap.ScopeBaseObject, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=*)", nil, []ldap.Control{ldap.NewControlManageDsaIT()}, ) result, err := conn.Search(searchReq) ``` -------------------------------- ### Get All Attribute Values (Case-Insensitive) Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Retrieves all values for a given attribute name, matching the attribute name case-insensitively. Returns an empty slice if the attribute is not found. ```go func (e *Entry) GetEqualFoldAttributeValues(attribute string) []string ``` -------------------------------- ### Enable Package-Level Logging in Go LDAP Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Configure a custom logger for package-level logging. Ensure 'log' and 'os' are imported. ```go import "log" customLog := log.New(os.Stdout, "[LDAP] ", log.LstdFlags) ldap.Logger(customLog) ``` -------------------------------- ### Get Last Recorded Error Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Retrieves the most recent error recorded by background goroutines, such as message processing or reading errors. Returns nil if no error has occurred. ```go if err := conn.GetLastError(); err != nil { log.Printf("Background error: %v", err) } ``` -------------------------------- ### Complete LDAP Authentication Flow in Go Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Connects to an LDAP server, performs a simple bind with credentials, and then unbinds. Ensure the LDAP server is running and accessible at the specified URL. ```go package main import ( "log" "github.com/go-ldap/ldap/v3" ) func main() { // Connect to LDAP server conn, err := ldap.DialURL("ldap://localhost:389") if err != nil { log.Fatal(err) } defer conn.Close() // Bind with credentials err = conn.Bind("cn=admin,dc=example,dc=org", "password") if err != nil { log.Fatal(err) } // Perform LDAP operations... // Unbind when done err = conn.Unbind() if err != nil { log.Fatal(err) } } ``` -------------------------------- ### WhoAmI Operation Execution Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/07-extended-operations.md Executes the WhoAmI extended operation to get the server's recognized identity for the current connection. Pass nil for controls if none are needed. ```go conn.Bind("cn=john,dc=example,dc=org", "password") result, err := conn.WhoAmI(nil) if err != nil { log.Fatal(err) } log.Printf("Authenticated as: %s", result.AuthzID) // Output: Authenticated as: dn:cn=john,dc=example,dc=org ``` -------------------------------- ### Build DN with Escaping Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Shows how to construct a DN string safely by escaping user-provided input using `ldap.EscapeDN` before formatting it into a DN string. It's crucial to validate the resulting DN by parsing it. ```go // When constructing DN strings with user input, escape properly userName := "John \"Admin\" Doe" newDN := fmt.Sprintf( "cn=%s,ou=users,dc=example,dc=org", ldap.EscapeDN(userName), ) // Result: cn=John \"Admin\" Doe,ou=users,dc=example,dc=org // Then parse to validate dn, err := ldap.ParseDN(newDN) if err != nil { log.Fatal("Invalid DN") } ``` -------------------------------- ### Compile LDAP Filter String to BER Packet Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/05-filters-dn.md Converts a string representation of an LDAP filter into a BER-encoded packet. The filter string must start with '(' and be syntactically correct. ```go packet, err := ldap.CompileFilter("(cn=John*)") if err != nil { log.Fatal(err) } ``` -------------------------------- ### Create SimpleBindRequest Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Factory function to create a new SimpleBindRequest. Pass nil for controls if none are required. ```go req := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=org", "password", nil) ``` -------------------------------- ### Use Async Search for Large Results Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md For potentially large result sets, utilize `conn.SearchAsync` with a context and a result channel buffer. This allows processing entries one at a time, preventing memory exhaustion and improving responsiveness. ```go // For potentially large result sets, use async search ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() result := conn.SearchAsync(ctx, searchReq, 500) for result.Next() { // Process one entry at a time entry := result.Entry() // ... work with entry } ``` -------------------------------- ### Initialize LDAP Connection Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Must be called after creating a Conn with NewConn to initialize necessary goroutines for message processing. ```go conn := ldap.NewConn(netConn, false) conn.Start() ``` -------------------------------- ### Get Attribute Value (Case-Insensitive) Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Retrieves the first value for a given attribute name, matching the attribute name case-insensitively using strings.EqualFold. Returns an empty string if the attribute is not found. ```go func (e *Entry) GetEqualFoldAttributeValue(attribute string) string ``` -------------------------------- ### Print Entry to Stdout Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Outputs a human-readable string representation of the Entry to standard output. ```go func (e *Entry) Print() ``` -------------------------------- ### Get TLS Connection State Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Retrieves the current TLS connection state if the connection is encrypted with TLS. Also returns a boolean indicating whether the connection is currently using TLS. ```go state, isTLS := conn.TLSConnectionState() if isTLS { fmt.Printf("TLS Version: %v\n", state.Version) fmt.Printf("Cipher: %v\n", state.CipherSuite) } ``` -------------------------------- ### Execute Content Synchronization Search (Syncrepl) Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Executes a content synchronization search using RFC 4533 Syncrepl. Returns changes asynchronously. Requires context, search request details, buffer size, sync mode, and a synchronization state cookie. ```go func (l *Conn) Syncrepl(ctx context.Context, searchRequest *SearchRequest, bufferSize int, mode ControlSyncRequestMode, cookie []byte, reloadHint bool) Response ``` -------------------------------- ### StartTLS Operation Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/07-extended-operations.md Upgrades an unencrypted LDAP connection to a secure TLS connection. ```APIDOC ## StartTLS Operation ### Description Sends the StartTLS command to upgrade the connection to TLS. ### Method `Conn.StartTLS` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```go // Connect without TLS conn, err := ldap.DialURL("ldap://localhost:389") if err != nil { log.Fatal(err) } // Upgrade to TLS tlsConfig := &tls.Config{ServerName: "ldap.example.com"} err = conn.StartTLS(tlsConfig) if err != nil { log.Fatal(err) } // Now connection is encrypted ``` ### Response #### Success Response None (operation modifies the connection state) #### Response Example None ``` -------------------------------- ### Pretty Print Entry with Indentation Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Outputs a formatted, human-readable string representation of the Entry to standard output, with specified indentation. ```go func (e *Entry) PrettyPrint(indent int) ``` -------------------------------- ### Use Constants for Search Scope and Dereference Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Use predefined constants like `ldap.ScopeWholeSubtree` and `ldap.NeverDerefAliases` instead of magic numbers for search scope and alias dereferencing to improve code readability and maintainability. ```go // Good - readable, no magic numbers searchReq := ldap.NewSearchRequest( baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, ...) ``` ```go // Bad - unclear what 2 and 0 mean searchReq := ldap.NewSearchRequest(baseDN, 2, 0, ...) ``` -------------------------------- ### Implementing Custom Extended Operations Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/07-extended-operations.md Demonstrates how to create and send a custom extended operation request to an LDAP server. This involves encoding a custom request value and handling the server's response. ```go package main import ( "log" "github.com/go-ldap/ldap/v3" ber "github.com/go-asn1-ber/asn1-ber" ) func main() { conn, _ := ldap.DialURL("ldap://localhost:389") defer conn.Close() conn.Bind("cn=admin,dc=example,dc=org", "password") // Create custom extended request customOID := "1.2.3.4.5.6.7.8.9" // Encode custom request value if needed value := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Request Value") value.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "custom data", "Data")) req := ldap.NewExtendedRequest(customOID, value) resp, err := conn.Extended(req) if err != nil { log.Fatal(err) } // Decode response value if resp.Value != nil { log.Printf("Response received: %v", resp.Value) } } ``` -------------------------------- ### SimpleBindResult Structure Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Represents the server's response to a simple bind operation, primarily containing any returned controls. ```go type SimpleBindResult struct { Controls []Control } ``` -------------------------------- ### Entry.PrettyPrint Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Outputs a formatted description with indentation. ```APIDOC ## Entry.PrettyPrint ### Description Outputs a formatted description with indentation. ### Method `PrettyPrint` (Go method on Entry) ### Parameters #### Method Parameters - **indent** (int) - Required - The indentation level for the output. ### Returns None ``` -------------------------------- ### Build Safe Distinguished Name (DN) Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/09-utility-functions.md Shows how to construct a valid Distinguished Name (DN) by escaping individual components. This is crucial for preventing errors and security issues when creating new entries or specifying paths. ```go func createUserDN(username string) string { // Escape components when building DN return fmt.Sprintf( "uid=%s,ou=users,dc=example,dc=org", ldap.EscapeDN(username), ) } ``` -------------------------------- ### Asynchronous Directory Synchronization (DirSyncAsync) Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Executes a directory synchronization search asynchronously, returning a Response channel. This is suitable for long-running operations where non-blocking behavior is desired. Requires a context for cancellation. ```go func (l *Conn) DirSyncAsync(ctx context.Context, searchRequest *SearchRequest, bufferSize int, flags, maxAttrCount int64, cookie []byte) Response ``` -------------------------------- ### Asynchronous LDAP Search with Context Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Employ `Conn.SearchAsync` for non-blocking searches, returning a channel to iterate over results. This method is ideal for scenarios where the application needs to remain responsive during the search. Ensure to use a `context.Context` for managing timeouts and cancellations. ```go ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defuncancel() searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=*)", []string{"cn"}, nil, ) result := conn.SearchAsync(ctx, searchReq, 100) for result.Next() { entry := result.Entry() if entry != nil { log.Printf("DN: %s\n", entry.DN) } } if err := result.Err(); err != nil { log.Fatal(err) } ``` -------------------------------- ### Perform Simple Bind Operation Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Executes a simple bind using the provided SimpleBindRequest. Handles potential errors such as invalid credentials or network issues. ```go req := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=org", "password", nil) result, err := conn.SimpleBind(req) if err != nil { log.Fatal(err) } fmt.Printf("Bind successful, controls: %v\n", result.Controls) ``` -------------------------------- ### StartTLS Operation for TLS Upgrade Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/07-extended-operations.md Upgrades an unencrypted LDAP connection to a TLS-encrypted connection. Requires a tls.Config for the TLS handshake. ```go // Connect without TLS conn, err := ldap.DialURL("ldap://localhost:389") if err != nil { log.Fatal(err) } // Upgrade to TLS tlsConfig := &tls.Config{ServerName: "ldap.example.com"} err = conn.StartTLS(tlsConfig) if err != nil { log.Fatal(err) } // Now connection is encrypted ``` -------------------------------- ### LDAP Search with Automatic Paging Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Utilize `Conn.SearchWithPaging` to perform searches that automatically handle result pagination. This method is recommended for retrieving large datasets, as it transparently manages paging controls, ensuring all results are fetched without manual intervention. ```go searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=person)", []string{"uid", "cn", "mail"}, nil, ) result, err := conn.SearchWithPaging(searchReq, 1000) // 1000 entries per page if err != nil { log.Fatal(err) } for _, entry := range result.Entries { log.Printf("DN: %s", entry.DN) } ``` -------------------------------- ### LDAP Simple Bind with Controls in Go Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Creates and executes a simple bind request with custom LDAP controls. This is useful for advanced authentication scenarios or server-specific requirements. Ensure `conn` is an active LDAP connection. ```go // Create bind request with controls req := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=org", "password", []ldap.Control{ // Add desired controls here }) result, err := conn.SimpleBind(req) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Entry.Print Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/03-search-operations.md Outputs a human-readable description of the entry to stdout. ```APIDOC ## Entry.Print ### Description Outputs a human-readable description of the entry to stdout. ### Method `Print` (Go method on Entry) ### Parameters None ### Returns None ``` -------------------------------- ### Go LDAP Per-Connection Timeout Management Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Shows how to set a timeout for all requests on a specific LDAP connection using SetTimeout. ```go // Per-connection timeout (applies to all requests) conn.SetTimeout(30 * time.Second) ``` -------------------------------- ### Dial LDAP Server via URL Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/01-connection-client.md Connects to the given LDAP URL, supporting ldap://, ldaps://, ldapi://, and cldap:// schemes. Optional configuration functions can be provided. ```go func DialURL(addr string, opts ...DialOpt) (*Conn, error) ``` ```go conn, err := ldap.DialURL("ldap://localhost:389") if err != nil { log.Fatal(err) } deffer conn.Close() ``` ```go // With TLS config tlsConfig := &tls.Config{InsecureSkipVerify: false} conn, err := ldap.DialURL("ldaps://localhost:636", ldap.DialWithTLSConfig(tlsConfig)) ``` -------------------------------- ### Go LDAP Global Default Timeout Management Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Illustrates setting the global default timeout for LDAP connections created with Dial or DialTLS. ```go // Global default (for Dial/DialTLS) ldap.DefaultTimeout = 60 * time.Second ``` -------------------------------- ### Create Manage DSA IT Control Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Provides a constructor function for creating a new Manage DSA IT control. ```go func NewControlManageDsaIT() *ControlManageDsaIT ``` -------------------------------- ### Execute LDAP Add Operation in Go Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/04-modify-operations.md Performs the LDAP Add operation to create a new directory entry using a prepared AddRequest. Handles potential errors like entry existence or access rights. ```go req := ldap.NewAddRequest("cn=john,dc=example,dc=org", nil) req.Attribute("objectClass", []string{"inetOrgPerson"}) req.Attribute("cn", []string{"John Doe"}) req.Attribute("sn", []string{"Doe"}) req.Attribute("userPassword", []string{"password123"}) err := conn.Add(req) if err != nil { log.Fatal(err) } ``` -------------------------------- ### NewSimpleBindRequest Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Creates a new SimpleBindRequest object with the provided username, password, and optional controls. ```APIDOC ## NewSimpleBindRequest ### Description Creates a new SimpleBindRequest with the given credentials. ### Parameters - **username** (string) - User DN or username - **password** (string) - User password - **controls** ([]Control) - Optional controls (pass nil for none) ### Returns - `*SimpleBindRequest` ### Example ```go req := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=org", "password", nil) ``` ``` -------------------------------- ### Asynchronous LDAP Search in Go Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Perform LDAP searches asynchronously to improve performance, especially with large result sets. Use a context for timeouts and a buffer for results. ```go ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) def cancel() result := conn.SearchAsync(ctx, searchReq, 100) // buffer 100 results for result.Next() { entry := result.Entry() // Process entry } if err := result.Err(); err != nil { log.Fatal(err) } ``` -------------------------------- ### NewControlDirSync Function Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Creates a new DirSync control. Use this to initiate or continue a directory synchronization process. ```go control := ldap.NewControlDirSync(ldap.DirSyncPublicDataOnly, 0, nil) searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, "(objectClass=*)", nil, []ldap.Control{control}, ) result, err := conn.DirSync(searchReq, ldap.DirSyncPublicDataOnly, 0, nil) ``` -------------------------------- ### Debug LDAP Packets from File Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/09-utility-functions.md Reads and prints LDAP protocol packets from a binary file for debugging purposes. ```go err := ldap.DebugBinaryFile("ldap-capture.bin") if err != nil { log.Fatal(err) } ``` -------------------------------- ### Custom Extended Operation with Raw BER Packet Handling Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/07-extended-operations.md Shows how to construct and execute a custom extended LDAP operation by manually building a BER packet. This is useful for operations without built-in support. The response value can then be parsed according to the operation's specification. ```go package main import ( "log" "github.com/go-ldap/ldap/v3" ber "github.com/go-asn1-ber/asn1-ber" ) func customExtendedOp(conn *ldap.Conn) error { // Build custom request value value := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "CustomValue") // Add operation-specific fields value.AppendChild(ber.NewString( ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "parameter1", "Parameter 1")) value.AppendChild(ber.NewInteger( ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 12345, "Parameter 2")) // Execute req := ldap.NewExtendedRequest("1.2.3.4.5", value) resp, err := conn.Extended(req) if err != nil { return err } // Decode response if resp.Value != nil { // Parse resp.Value.Children according to operation spec for _, child := range resp.Value.Children { log.Printf("Response field: %v", child.Value) } } return nil } ``` -------------------------------- ### Enable Per-Connection Debugging in Go LDAP Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Toggle detailed packet logging for a specific connection. Set `conn.Debug` to `true` to enable. ```go conn.Debug = true // Perform operations - detailed packet info will be logged conn.Debug = false ``` -------------------------------- ### Basic Error Handling in Go Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/08-error-handling.md Implement fundamental error checking after an operation. If an error occurs, log it and terminate the program. ```go result, err := conn.Search(searchReq) if err != nil { log.Fatal(err) } ``` -------------------------------- ### Convenience Simple Bind Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md A simplified function for performing a simple bind with just username and password. This method does not permit empty passwords. ```go err := conn.Bind("cn=admin,dc=example,dc=org", "password") if err != nil { log.Fatal(err) } ``` -------------------------------- ### Use Named Constants for Search Requests Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/09-utility-functions.md Employ named constants like `ldap.ScopeWholeSubtree` and `ldap.NeverDerefAliases` instead of magic numbers for improved readability and maintainability in `ldap.NewSearchRequest`. ```go // WRONG - magic numbers searchReq := ldap.NewSearchRequest(baseDN, 2, 0, 0, 0, false, filter, attrs, nil) // RIGHT - named constants searchReq := ldap.NewSearchRequest( baseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, filter, attrs, nil) ``` -------------------------------- ### Conn.Add Method Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/04-modify-operations.md Executes an AddRequest to create a new entry in the LDAP directory. Handles various potential errors during the operation. ```APIDOC ## Conn.Add Method ### Description Executes the given add request, creating a new entry. ### Parameters - **addRequest** (*AddRequest) - Required - Add request with DN and attributes ### Returns - **error** - An error if the operation fails. ### Throws - **ErrorNetwork, LDAPResultEntryAlreadyExists** - Entry with this DN already exists - **ErrorNetwork, LDAPResultNoSuchObject** - Parent entry does not exist - **ErrorNetwork, LDAPResultObjectClassViolation** - Attributes violate object class definition - **ErrorNetwork, LDAPResultConstraintViolation** - Values violate attribute constraints - **ErrorNetwork, LDAPResultInsufficientAccessRights** - Insufficient permissions to add ### Example ```go req := ldap.NewAddRequest("cn=john,dc=example,dc=org", nil) req.Attribute("objectClass", []string{"inetOrgPerson"}) req.Attribute("cn", []string{"John Doe"}) req.Attribute("sn", []string{"Doe"}) req.Attribute("userPassword", []string{"password123"}) err := conn.Add(req) if err != nil { log.Fatal(err) } ``` ``` -------------------------------- ### SimpleBindRequest Structure Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Defines the structure for a simple username/password bind request. The AllowEmptyPassword field can be set to true to permit unauthenticated binds. ```go type SimpleBindRequest struct { Username string Password string Controls []Control AllowEmptyPassword bool } ``` -------------------------------- ### Search LDAP Entries by Email Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/09-utility-functions.md Demonstrates how to safely search for LDAP entries based on an email address. Always escape user input when building filters to prevent injection vulnerabilities. ```go func searchByEmail(conn *ldap.Conn, email string) ([]*ldap.Entry, error) { // Always escape user input when building filters escapedEmail := ldap.EscapeFilter(email) searchReq := ldap.NewSearchRequest( "dc=example,dc=org", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, fmt.Sprintf("(mail=%s)", escapedEmail), []string{"uid", "cn", "mail"}, nil, ) result, err := conn.Search(searchReq) if err != nil { return nil, err } return result.Entries, nil } ``` -------------------------------- ### NewControlPaging Function Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/06-controls.md Creates a new Paging control with a specified page size. Use this when initiating a paginated search request. ```go func NewControlPaging(pagingSize uint32) *ControlPaging ``` -------------------------------- ### SimpleBindResult Structure Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Contains the server's response to a simple bind request, primarily including any controls returned by the server. ```APIDOC ## SimpleBindResult ### Description Contains the server's response to a simple bind request. ### Fields - **Controls** ([]Control) - Controls returned by the server ``` -------------------------------- ### Analyze Binary Packets with Go LDAP Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/00-readme.md Debug a captured LDAP binary packet file by providing its path to `ldap.DebugBinaryFile`. ```go // Debug a captured packet file ldap.DebugBinaryFile("ldap-capture.bin") ``` -------------------------------- ### SimpleBind Source: https://github.com/go-ldap/ldap/blob/master/_autodocs/02-bind-operations.md Performs the LDAP simple bind operation using the provided SimpleBindRequest. Handles authentication and returns the server's response or an error. ```APIDOC ## SimpleBind ### Description Performs the simple bind operation defined in the request. ### Parameters - **simpleBindRequest** (*SimpleBindRequest) - Bind request with credentials ### Returns - `*SimpleBindResult`, error ### Throws - **ErrorEmptyPassword**: Password is empty and AllowEmptyPassword is false - **ErrorNetwork, LDAPResultInvalidCredentials**: Invalid username or password - **ErrorNetwork, LDAPResultNoSuchObject**: User DN does not exist ### Example ```go req := ldap.NewSimpleBindRequest("cn=admin,dc=example,dc=org", "password", nil) result, err := conn.SimpleBind(req) if err != nil { log.Fatal(err) } fmt.Printf("Bind successful, controls: %v\n", result.Controls) ``` ```