From 99f27e569d8305128957aa0e2af29c92c71e912f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Jul 2023 06:05:31 +0000 Subject: [PATCH] Bump github.com/go-ldap/ldap/v3 Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.5-0.20230327113050-32d292ef5ded to 3.4.5. - [Release notes](https://github.com/go-ldap/ldap/releases) - [Commits](https://github.com/go-ldap/ldap/commits/v3.4.5) --- updated-dependencies: - dependency-name: github.com/go-ldap/ldap/v3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/go-ldap/ldap/v3/add.go | 4 +- vendor/github.com/go-ldap/ldap/v3/bind.go | 7 +- vendor/github.com/go-ldap/ldap/v3/client.go | 4 +- vendor/github.com/go-ldap/ldap/v3/compare.go | 3 +- vendor/github.com/go-ldap/ldap/v3/conn.go | 64 ++++++++++---- vendor/github.com/go-ldap/ldap/v3/control.go | 93 ++++++++++++++++++++ vendor/github.com/go-ldap/ldap/v3/del.go | 4 +- vendor/github.com/go-ldap/ldap/v3/moddn.go | 4 +- vendor/github.com/go-ldap/ldap/v3/modify.go | 4 +- vendor/github.com/go-ldap/ldap/v3/search.go | 93 +++++++++++++++++++- vendor/modules.txt | 2 +- 13 files changed, 252 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index 8a86f5fc39..5db8ca2c91 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.2 - github.com/go-ldap/ldap/v3 v3.4.5-0.20230327113050-32d292ef5ded + github.com/go-ldap/ldap/v3 v3.4.5 github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3 github.com/go-micro/plugins/v4/client/grpc v1.2.0 github.com/go-micro/plugins/v4/events/natsjs v1.2.0 diff --git a/go.sum b/go.sum index 64ad7b032c..390666734a 100644 --- a/go.sum +++ b/go.sum @@ -757,8 +757,8 @@ github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-kit/log v0.2.1 h1:MRVx0/zhvdseW+Gza6N9rVzU/IVzaeE1SFI4raAhmBU= github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= github.com/go-ldap/ldap/v3 v3.1.7/go.mod h1:5Zun81jBTabRaI8lzN7E1JjyEl1g6zI6u9pd8luAK4Q= -github.com/go-ldap/ldap/v3 v3.4.5-0.20230327113050-32d292ef5ded h1:DCi4j5aIjsT27tSluBdFlDkYvHnNSxwnua+hjt+1wtk= -github.com/go-ldap/ldap/v3 v3.4.5-0.20230327113050-32d292ef5ded/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= +github.com/go-ldap/ldap/v3 v3.4.5 h1:ekEKmaDrpvR2yf5Nc/DClsGG9lAmdDixe44mLzlW5r8= +github.com/go-ldap/ldap/v3 v3.4.5/go.mod h1:bMGIq3AGbytbaMwf8wdv5Phdxz0FWHTIYMSzyrYgnQs= github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3 h1:sfz1YppV05y4sYaW7kXZtrocU/+vimnIWt4cxAYh7+o= github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3/go.mod h1:ZXFhGda43Z2TVbfGZefXyMJzsDHhCh0go3bZUcwTx7o= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= diff --git a/vendor/github.com/go-ldap/ldap/v3/add.go b/vendor/github.com/go-ldap/ldap/v3/add.go index c3101b7628..ab32b0b6b4 100644 --- a/vendor/github.com/go-ldap/ldap/v3/add.go +++ b/vendor/github.com/go-ldap/ldap/v3/add.go @@ -1,6 +1,7 @@ package ldap import ( + "fmt" ber "github.com/go-asn1-ber/asn1-ber" ) @@ -61,7 +62,6 @@ func NewAddRequest(dn string, controls []Control) *AddRequest { DN: dn, Controls: controls, } - } // Add performs the given AddRequest @@ -83,7 +83,7 @@ func (l *Conn) Add(addRequest *AddRequest) error { return err } } else { - logger.Printf("Unexpected Response: %d", packet.Children[1].Tag) + return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag) } return nil } diff --git a/vendor/github.com/go-ldap/ldap/v3/bind.go b/vendor/github.com/go-ldap/ldap/v3/bind.go index 9a87d02774..a37f8e2c73 100644 --- a/vendor/github.com/go-ldap/ldap/v3/bind.go +++ b/vendor/github.com/go-ldap/ldap/v3/bind.go @@ -261,7 +261,7 @@ func parseParams(str string) (map[string]string, error) { var state int for i := 0; i <= len(str); i++ { switch state { - case 0: //reading key + case 0: // reading key if i == len(str) { return nil, fmt.Errorf("syntax error on %d", i) } @@ -270,7 +270,7 @@ func parseParams(str string) (map[string]string, error) { continue } state = 1 - case 1: //reading value + case 1: // reading value if i == len(str) { m[key] = value break @@ -289,7 +289,7 @@ func parseParams(str string) (map[string]string, error) { default: value += string(str[i]) } - case 2: //inside quotes + case 2: // inside quotes if i == len(str) { return nil, fmt.Errorf("syntax error on %d", i) } @@ -651,7 +651,6 @@ func (l *Conn) GSSAPIBindRequest(client GSSAPIClient, req *GSSAPIBindRequest) er } func (l *Conn) saslBindTokenExchange(reqControls []Control, reqToken []byte) ([]byte, error) { - // Construct LDAP Bind request with GSSAPI SASL mechanism. envelope := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") envelope.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) diff --git a/vendor/github.com/go-ldap/ldap/v3/client.go b/vendor/github.com/go-ldap/ldap/v3/client.go index f0312aff9a..b438d254b2 100644 --- a/vendor/github.com/go-ldap/ldap/v3/client.go +++ b/vendor/github.com/go-ldap/ldap/v3/client.go @@ -9,7 +9,8 @@ import ( type Client interface { Start() StartTLS(*tls.Config) error - Close() + Close() error + GetLastError() error IsClosing() bool SetTimeout(time.Duration) TLSConnectionState() (tls.ConnectionState, bool) @@ -32,4 +33,5 @@ type Client interface { Search(*SearchRequest) (*SearchResult, error) SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error) + DirSync(searchRequest *SearchRequest, flags, maxAttrCount int64, cookie []byte) (*SearchResult, error) } diff --git a/vendor/github.com/go-ldap/ldap/v3/compare.go b/vendor/github.com/go-ldap/ldap/v3/compare.go index cd43e4c53d..a1cd760b34 100644 --- a/vendor/github.com/go-ldap/ldap/v3/compare.go +++ b/vendor/github.com/go-ldap/ldap/v3/compare.go @@ -34,7 +34,8 @@ func (l *Conn) Compare(dn, attribute, value string) (bool, error) { msgCtx, err := l.doRequest(&CompareRequest{ DN: dn, Attribute: attribute, - Value: value}) + Value: value, + }) if err != nil { return false, err } diff --git a/vendor/github.com/go-ldap/ldap/v3/conn.go b/vendor/github.com/go-ldap/ldap/v3/conn.go index 858224af0d..3ed8088312 100644 --- a/vendor/github.com/go-ldap/ldap/v3/conn.go +++ b/vendor/github.com/go-ldap/ldap/v3/conn.go @@ -2,6 +2,7 @@ package ldap import ( "bufio" + "context" "crypto/tls" "errors" "fmt" @@ -60,13 +61,21 @@ type messageContext struct { // sendResponse should only be called within the processMessages() loop which // is also responsible for closing the responses channel. -func (msgCtx *messageContext) sendResponse(packet *PacketResponse) { +func (msgCtx *messageContext) sendResponse(packet *PacketResponse, timeout time.Duration) { + timeoutCtx := context.Background() + if timeout > 0 { + var cancelFunc context.CancelFunc + timeoutCtx, cancelFunc = context.WithTimeout(context.Background(), timeout) + defer cancelFunc() + } select { case msgCtx.responses <- packet: // Successfully sent packet to message handler. case <-msgCtx.done: // The request handler is done and will not receive more // packets. + case <-timeoutCtx.Done(): + // The timeout was reached before the packet was sent. } } @@ -102,6 +111,8 @@ type Conn struct { wgClose sync.WaitGroup outstandingRequests uint messageMutex sync.Mutex + + err error } var _ Client = &Conn{} @@ -238,7 +249,7 @@ func DialURL(addr string, opts ...DialOpt) (*Conn, error) { // NewConn returns a new Conn using conn for network I/O. func NewConn(conn net.Conn, isTLS bool) *Conn { - return &Conn{ + l := &Conn{ conn: conn, chanConfirm: make(chan struct{}), chanMessageID: make(chan int64), @@ -247,11 +258,12 @@ func NewConn(conn net.Conn, isTLS bool) *Conn { requestTimeout: 0, isTLS: isTLS, } + l.wgClose.Add(1) + return l } // Start initializes goroutines to read responses and process messages func (l *Conn) Start() { - l.wgClose.Add(1) go l.reader() go l.processMessages() } @@ -267,24 +279,36 @@ func (l *Conn) setClosing() bool { } // Close closes the connection. -func (l *Conn) Close() { +func (l *Conn) Close() (err error) { l.messageMutex.Lock() defer l.messageMutex.Unlock() if l.setClosing() { l.Debug.Printf("Sending quit message and waiting for confirmation") l.chanMessage <- &messagePacket{Op: MessageQuit} - <-l.chanConfirm + + timeoutCtx := context.Background() + if l.requestTimeout > 0 { + var cancelFunc context.CancelFunc + timeoutCtx, cancelFunc = context.WithTimeout(timeoutCtx, time.Duration(l.requestTimeout)) + defer cancelFunc() + } + select { + case <-l.chanConfirm: + // Confirmation was received. + case <-timeoutCtx.Done(): + // The timeout was reached before confirmation was received. + } + close(l.chanMessage) l.Debug.Printf("Closing network connection") - if err := l.conn.Close(); err != nil { - logger.Println(err) - } - + err = l.conn.Close() l.wgClose.Done() } l.wgClose.Wait() + + return err } // SetTimeout sets the time after a request is sent that a MessageTimeout triggers @@ -300,6 +324,12 @@ func (l *Conn) nextMessageID() int64 { return 0 } +// GetLastError returns the last recorded error from goroutines like processMessages and reader. +// // Only the last recorded error will be returned. +func (l *Conn) GetLastError() error { + return l.err +} + // StartTLS sends the command to start a TLS session and then creates a new TLS Client func (l *Conn) StartTLS(config *tls.Config) error { if l.isTLS { @@ -448,13 +478,13 @@ func (l *Conn) sendProcessMessage(message *messagePacket) bool { func (l *Conn) processMessages() { defer func() { if err := recover(); err != nil { - logger.Printf("ldap: recovered panic in processMessages: %v", err) + l.err = fmt.Errorf("ldap: recovered panic in processMessages: %v", err) } for messageID, msgCtx := range l.messageContexts { // If we are closing due to an error, inform anyone who // is waiting about the error. if l.IsClosing() && l.closeErr.Load() != nil { - msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}) + msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}, time.Duration(l.requestTimeout)) } l.Debug.Printf("Closing channel for MessageID %d", messageID) close(msgCtx.responses) @@ -482,7 +512,7 @@ func (l *Conn) processMessages() { _, err := l.conn.Write(buf) if err != nil { l.Debug.Printf("Error Sending Message: %s", err.Error()) - message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)}) + message.Context.sendResponse(&PacketResponse{Error: fmt.Errorf("unable to send request: %s", err)}, time.Duration(l.requestTimeout)) close(message.Context.responses) break } @@ -497,7 +527,7 @@ func (l *Conn) processMessages() { timer := time.NewTimer(time.Duration(l.requestTimeout)) defer func() { if err := recover(); err != nil { - logger.Printf("ldap: recovered panic in RequestTimeout: %v", err) + l.err = fmt.Errorf("ldap: recovered panic in RequestTimeout: %v", err) } timer.Stop() @@ -517,9 +547,9 @@ func (l *Conn) processMessages() { case MessageResponse: l.Debug.Printf("Receiving message %d", message.MessageID) if msgCtx, ok := l.messageContexts[message.MessageID]; ok { - msgCtx.sendResponse(&PacketResponse{message.Packet, nil}) + msgCtx.sendResponse(&PacketResponse{message.Packet, nil}, time.Duration(l.requestTimeout)) } else { - logger.Printf("Received unexpected message %d, %v", message.MessageID, l.IsClosing()) + l.err = fmt.Errorf("ldap: received unexpected message %d, %v", message.MessageID, l.IsClosing()) l.Debug.PrintPacket(message.Packet) } case MessageTimeout: @@ -527,7 +557,7 @@ func (l *Conn) processMessages() { // All reads will return immediately if msgCtx, ok := l.messageContexts[message.MessageID]; ok { l.Debug.Printf("Receiving message timeout for %d", message.MessageID) - msgCtx.sendResponse(&PacketResponse{message.Packet, NewError(ErrorNetwork, errors.New("ldap: connection timed out"))}) + msgCtx.sendResponse(&PacketResponse{message.Packet, NewError(ErrorNetwork, errors.New("ldap: connection timed out"))}, time.Duration(l.requestTimeout)) delete(l.messageContexts, message.MessageID) close(msgCtx.responses) } @@ -546,7 +576,7 @@ func (l *Conn) reader() { cleanstop := false defer func() { if err := recover(); err != nil { - logger.Printf("ldap: recovered panic in reader: %v", err) + l.err = fmt.Errorf("ldap: recovered panic in reader: %v", err) } if !cleanstop { l.Close() diff --git a/vendor/github.com/go-ldap/ldap/v3/control.go b/vendor/github.com/go-ldap/ldap/v3/control.go index 7dd0da0df7..0be697e220 100644 --- a/vendor/github.com/go-ldap/ldap/v3/control.go +++ b/vendor/github.com/go-ldap/ldap/v3/control.go @@ -34,6 +34,16 @@ const ( ControlTypeMicrosoftShowDeleted = "1.2.840.113556.1.4.417" // ControlTypeMicrosoftServerLinkTTL - https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/f4f523a8-abc0-4b3a-a471-6b2fef135481?redirectedfrom=MSDN ControlTypeMicrosoftServerLinkTTL = "1.2.840.113556.1.4.2309" + // ControlTypeDirSync - Active Directory DirSync - https://msdn.microsoft.com/en-us/library/aa366978(v=vs.85).aspx + ControlTypeDirSync = "1.2.840.113556.1.4.841" +) + +// Flags for DirSync control +const ( + DirSyncIncrementalValues int64 = 2147483648 + DirSyncPublicDataOnly int64 = 8192 + DirSyncAncestorsFirstOrder int64 = 2048 + DirSyncObjectSecurity int64 = 1 ) // ControlTypeMap maps controls to text descriptions @@ -47,6 +57,7 @@ var ControlTypeMap = map[string]string{ ControlTypeMicrosoftServerLinkTTL: "Return TTL-DNs for link values with associated expiry times - Microsoft", ControlTypeServerSideSorting: "Server Side Sorting Request - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)", ControlTypeServerSideSortingResult: "Server Side Sorting Results - LDAP Control Extension for Server Side Sorting of Search Results (RFC2891)", + ControlTypeDirSync: "DirSync", } // Control defines an interface controls provide to encode and describe themselves @@ -501,6 +512,31 @@ func DecodeControl(packet *ber.Packet) (Control, error) { return NewControlServerSideSorting(value) case ControlTypeServerSideSortingResult: return NewControlServerSideSortingResult(value) + case ControlTypeDirSync: + value.Description += " (DirSync)" + c := new(ControlDirSync) + if value.Value != nil { + valueChildren, err := ber.DecodePacketErr(value.Data.Bytes()) + if err != nil { + return nil, err + } + value.Data.Truncate(0) + value.Value = nil + value.AppendChild(valueChildren) + } + value = value.Children[0] + if len(value.Children) != 3 { // also on initial creation, Cookie is an empty string + return nil, fmt.Errorf("invalid number of children in dirSync control") + } + value.Description = "DirSync Control Value" + value.Children[0].Description = "Flags" + value.Children[1].Description = "MaxAttrCnt" + value.Children[2].Description = "Cookie" + c.Flags = value.Children[0].Value.(int64) + c.MaxAttrCnt = value.Children[1].Value.(int64) + c.Cookie = value.Children[2].Data.Bytes() + value.Children[2].Value = c.Cookie + return c, nil default: c := new(ControlString) c.ControlType = ControlType @@ -572,6 +608,62 @@ func encodeControls(controls []Control) *ber.Packet { return packet } +// ControlDirSync implements the control described in https://msdn.microsoft.com/en-us/library/aa366978(v=vs.85).aspx +type ControlDirSync struct { + Flags int64 + MaxAttrCnt int64 + Cookie []byte +} + +// NewControlDirSync returns a dir sync control +func NewControlDirSync(flags int64, maxAttrCount int64, cookie []byte) *ControlDirSync { + return &ControlDirSync{ + Flags: flags, + MaxAttrCnt: maxAttrCount, + Cookie: cookie, + } +} + +// GetControlType returns the OID +func (c *ControlDirSync) GetControlType() string { + return ControlTypeDirSync +} + +// String returns a human-readable description +func (c *ControlDirSync) String() string { + return fmt.Sprintf("ControlType: %s (%q), Criticality: true, ControlValue: Flags: %d, MaxAttrCnt: %d", ControlTypeMap[ControlTypeDirSync], ControlTypeDirSync, c.Flags, c.MaxAttrCnt) +} + +// Encode returns the ber packet representation +func (c *ControlDirSync) Encode() *ber.Packet { + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Control") + packet.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, ControlTypeDirSync, "Control Type ("+ControlTypeMap[ControlTypeDirSync]+")")) + packet.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, true, "Criticality")) // must be true always + + val := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, nil, "Control Value (DirSync)") + + seq := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "DirSync Control Value") + seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.Flags), "Flags")) + seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.MaxAttrCnt), "MaxAttrCount")) + + cookie := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "Cookie") + if len(c.Cookie) != 0 { + cookie.Value = c.Cookie + cookie.Data.Write(c.Cookie) + } + seq.AppendChild(cookie) + + val.AppendChild(seq) + + packet.AppendChild(val) + return packet +} + +// SetCookie stores the given cookie in the dirSync control +func (c *ControlDirSync) SetCookie(cookie []byte) { + c.Cookie = cookie +} + // ControlServerSideSorting type SortKey struct { @@ -740,6 +832,7 @@ type ControlServerSideSortingResult struct { func (control *ControlServerSideSortingResult) GetControlType() string { return ControlTypeServerSideSortingResult } + func (c *ControlServerSideSortingResult) Encode() *ber.Packet { packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "SortResult sequence") sortResult := ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagEnumerated, int64(c.Result), "SortResult") diff --git a/vendor/github.com/go-ldap/ldap/v3/del.go b/vendor/github.com/go-ldap/ldap/v3/del.go index bac0dfb795..62306951d9 100644 --- a/vendor/github.com/go-ldap/ldap/v3/del.go +++ b/vendor/github.com/go-ldap/ldap/v3/del.go @@ -1,6 +1,7 @@ package ldap import ( + "fmt" ber "github.com/go-asn1-ber/asn1-ber" ) @@ -51,7 +52,8 @@ func (l *Conn) Del(delRequest *DelRequest) error { return err } } else { - logger.Printf("Unexpected Response: %d", packet.Children[1].Tag) + return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag) } + return nil } diff --git a/vendor/github.com/go-ldap/ldap/v3/moddn.go b/vendor/github.com/go-ldap/ldap/v3/moddn.go index 14a2ff76c7..84a6488e42 100644 --- a/vendor/github.com/go-ldap/ldap/v3/moddn.go +++ b/vendor/github.com/go-ldap/ldap/v3/moddn.go @@ -1,6 +1,7 @@ package ldap import ( + "fmt" ber "github.com/go-asn1-ber/asn1-ber" ) @@ -94,7 +95,8 @@ func (l *Conn) ModifyDN(m *ModifyDNRequest) error { return err } } else { - logger.Printf("Unexpected Response: %d", packet.Children[1].Tag) + return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag) } + return nil } diff --git a/vendor/github.com/go-ldap/ldap/v3/modify.go b/vendor/github.com/go-ldap/ldap/v3/modify.go index 0260969aa7..0e5013601f 100644 --- a/vendor/github.com/go-ldap/ldap/v3/modify.go +++ b/vendor/github.com/go-ldap/ldap/v3/modify.go @@ -2,6 +2,7 @@ package ldap import ( "errors" + "fmt" ber "github.com/go-asn1-ber/asn1-ber" ) @@ -126,8 +127,9 @@ func (l *Conn) Modify(modifyRequest *ModifyRequest) error { return err } } else { - logger.Printf("Unexpected Response: %d", packet.Children[1].Tag) + return fmt.Errorf("ldap: unexpected response: %d", packet.Children[1].Tag) } + return nil } diff --git a/vendor/github.com/go-ldap/ldap/v3/search.go b/vendor/github.com/go-ldap/ldap/v3/search.go index 66a76856de..9c0ccd0717 100644 --- a/vendor/github.com/go-ldap/ldap/v3/search.go +++ b/vendor/github.com/go-ldap/ldap/v3/search.go @@ -7,6 +7,7 @@ import ( "sort" "strconv" "strings" + "time" ber "github.com/go-asn1-ber/asn1-ber" ) @@ -185,9 +186,9 @@ func readTag(f reflect.StructField) (string, bool) { // Unmarshal parses the Entry in the value pointed to by i // // Currently, this methods only supports struct fields of type -// string, []string, int, int64 or []byte. Other field types will not be -// regarded. If the field type is a string or int but multiple attribute -// values are returned, the first value will be used to fill the field. +// string, []string, int, int64, []byte, *DN, []*DN or time.Time. Other field types +// will not be regarded. If the field type is a string or int but multiple +// attribute values are returned, the first value will be used to fill the field. // // Example: // @@ -216,12 +217,22 @@ func readTag(f reflect.StructField) (string, bool) { // // values. // Data []byte `ldap:"data"` // +// // Time is parsed with the generalizedTime spec into a time.Time +// Created time.Time `ldap:"createdTimestamp"` +// +// // *DN is parsed with the ParseDN +// Owner *ldap.DN `ldap:"owner"` +// +// // []*DN is parsed with the ParseDN +// Children []*ldap.DN `ldap:"children"` +// // // This won't work, as the field is not of type string. For this // // to work, you'll have to temporarily store the result in string // // (or string array) and convert it to the desired type afterwards. // UserAccountControl uint32 `ldap:"userPrincipalName"` // } // user := UserEntry{} +// // if err := result.Unmarshal(&user); err != nil { // // ... // } @@ -275,8 +286,28 @@ func (e *Entry) Unmarshal(i interface{}) (err error) { return fmt.Errorf("ldap: could not parse value '%s' into int field", values[0]) } fv.SetInt(intVal) + case time.Time: + t, err := ber.ParseGeneralizedTime([]byte(values[0])) + if err != nil { + return fmt.Errorf("ldap: could not parse value '%s' into time.Time field", values[0]) + } + fv.Set(reflect.ValueOf(t)) + case *DN: + dn, err := ParseDN(values[0]) + if err != nil { + return fmt.Errorf("ldap: could not parse value '%s' into *ldap.DN field", values[0]) + } + fv.Set(reflect.ValueOf(dn)) + case []*DN: + for _, item := range values { + dn, err := ParseDN(item) + if err != nil { + return fmt.Errorf("ldap: could not parse value '%s' into *ldap.DN field", item) + } + fv.Set(reflect.Append(fv, reflect.ValueOf(dn))) + } default: - return fmt.Errorf("ldap: expected field to be of type string, []string, int, int64 or []byte, got %v", ft.Type) + return fmt.Errorf("ldap: expected field to be of type string, []string, int, int64, []byte, *DN, []*DN or time.Time, got %v", ft.Type) } } return @@ -553,3 +584,57 @@ func unpackAttributes(children []*ber.Packet) []*EntryAttribute { return entries } + +// DirSync does a Search with dirSync Control. +func (l *Conn) DirSync(searchRequest *SearchRequest, flags int64, maxAttrCount int64, cookie []byte) (*SearchResult, error) { + var dirSyncControl *ControlDirSync + + control := FindControl(searchRequest.Controls, ControlTypeDirSync) + if control == nil { + dirSyncControl = NewControlDirSync(flags, maxAttrCount, cookie) + searchRequest.Controls = append(searchRequest.Controls, dirSyncControl) + } else { + castControl, ok := control.(*ControlDirSync) + if !ok { + return nil, fmt.Errorf("Expected DirSync control to be of type *ControlDirSync, got %v", control) + } + if castControl.Flags != flags { + return nil, fmt.Errorf("flags given in search request (%d) conflicts with flags given in search call (%d)", castControl.Flags, flags) + } + if castControl.MaxAttrCnt != maxAttrCount { + return nil, fmt.Errorf("MaxAttrCnt given in search request (%d) conflicts with maxAttrCount given in search call (%d)", castControl.MaxAttrCnt, maxAttrCount) + } + dirSyncControl = castControl + } + searchResult := new(SearchResult) + result, err := l.Search(searchRequest) + l.Debug.Printf("Looking for result...") + if err != nil { + return searchResult, err + } + if result == nil { + return searchResult, NewError(ErrorNetwork, errors.New("ldap: packet not received")) + } + + searchResult.Entries = append(searchResult.Entries, result.Entries...) + searchResult.Referrals = append(searchResult.Referrals, result.Referrals...) + searchResult.Controls = append(searchResult.Controls, result.Controls...) + + l.Debug.Printf("Looking for DirSync Control...") + dirSyncResult := FindControl(result.Controls, ControlTypeDirSync) + if dirSyncResult == nil { + dirSyncControl = nil + l.Debug.Printf("Could not find dirSyncControl control. Breaking...") + return searchResult, nil + } + + cookie = dirSyncResult.(*ControlDirSync).Cookie + if len(cookie) == 0 { + dirSyncControl = nil + l.Debug.Printf("Could not find cookie. Breaking...") + return searchResult, nil + } + dirSyncControl.SetCookie(cookie) + + return searchResult, nil +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 4ed9b8ef11..0cb8cfa8ca 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -862,7 +862,7 @@ github.com/go-jose/go-jose/v3/json ## explicit; go 1.17 github.com/go-kit/log github.com/go-kit/log/level -# github.com/go-ldap/ldap/v3 v3.4.5-0.20230327113050-32d292ef5ded +# github.com/go-ldap/ldap/v3 v3.4.5 ## explicit; go 1.14 github.com/go-ldap/ldap/v3 # github.com/go-ldap/ldif v0.0.0-20200320164324-fd88d9b715b3