build(deps): bump github.com/go-ldap/ldap/v3 from 3.4.12 to 3.4.13

Bumps [github.com/go-ldap/ldap/v3](https://github.com/go-ldap/ldap) from 3.4.12 to 3.4.13.
- [Release notes](https://github.com/go-ldap/ldap/releases)
- [Commits](https://github.com/go-ldap/ldap/compare/v3.4.12...v3.4.13)

---
updated-dependencies:
- dependency-name: github.com/go-ldap/ldap/v3
  dependency-version: 3.4.13
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2026-04-07 14:06:25 +02:00
committed by Ralf Haferkamp
parent 87a9660157
commit 9123e88f10
29 changed files with 1042 additions and 369 deletions
+11 -1
View File
@@ -1,6 +1,7 @@
package ldap
import (
"encoding/binary"
"fmt"
"strconv"
@@ -880,7 +881,16 @@ func (c *ControlDirSync) Encode() *ber.Packet {
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"))
// Note: Active Directory expects a 4-byte unsigned integer for flags, but ASN.1 uses signed integers by default.
// As a result, the BER encoder may encode flags as a 5-byte signed integer; we force 4-byte encoding here.
flagsPacket := ber.Encode(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, nil, "Flags")
flagsPacket.Value = int64(c.Flags)
flagsBytes := make([]byte, 4)
binary.BigEndian.PutUint32(flagsBytes, uint32(c.Flags))
flagsPacket.Data.Write(flagsBytes)
seq.AppendChild(flagsPacket)
seq.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, int64(c.MaxAttrCount), "MaxAttrCount"))
seq.AppendChild(cookie)
val.AppendChild(seq)
+7
View File
@@ -210,6 +210,10 @@ func GetLDAPError(packet *ber.Packet) error {
}
if response.ClassType == ber.ClassApplication && response.TagType == ber.TypeConstructed && len(response.Children) >= 3 {
if ber.Type(response.Children[0].Tag) == ber.Type(ber.TagInteger) || ber.Type(response.Children[0].Tag) == ber.Type(ber.TagEnumerated) {
if response.Children[0].Value == nil {
return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid result code in packet"), Packet: packet}
}
resultCode := uint16(response.Children[0].Value.(int64))
if resultCode == 0 { // No error
return nil
@@ -217,6 +221,9 @@ func GetLDAPError(packet *ber.Packet) error {
if ber.Type(response.Children[1].Tag) == ber.Type(ber.TagOctetString) &&
ber.Type(response.Children[2].Tag) == ber.Type(ber.TagOctetString) {
if response.Children[1].Value == nil {
return &Error{ResultCode: ErrorNetwork, Err: fmt.Errorf("Invalid matchedDN in packet"), Packet: packet}
}
return &Error{
ResultCode: resultCode,
MatchedDN: response.Children[1].Value.(string),
+12 -7
View File
@@ -76,18 +76,27 @@ func (l *Conn) Extended(er *ExtendedRequest) (*ExtendedResponse, error) {
return nil, err
}
if len(packet.Children[1].Children) < 4 {
extResp := packet.Children[1]
if len(extResp.Children) < 3 {
return nil, fmt.Errorf(
"ldap: malformed extended response: expected 4 children, got %d",
"ldap: malformed extended response: expected at least 3 children, got %d",
len(packet.Children),
)
}
response := &ExtendedResponse{
Name: packet.Children[1].Children[3].Data.String(),
Controls: make([]Control, 0),
}
for _, child := range extResp.Children {
switch child.Tag {
case ber.TagEnumerated:
response.Name = child.Data.String()
case ber.TagEmbeddedPDV:
response.Value = child
}
}
if len(packet.Children) == 3 {
for _, child := range packet.Children[2].Children {
decodedChild, decodeErr := DecodeControl(child)
@@ -98,9 +107,5 @@ func (l *Conn) Extended(er *ExtendedRequest) (*ExtendedResponse, error) {
}
}
if len(packet.Children[1].Children) == 5 {
response.Value = packet.Children[1].Children[4]
}
return response, nil
}
+130
View File
@@ -0,0 +1,130 @@
package ldap
import (
"errors"
"fmt"
"strings"
)
var ErrEmptyPostalAddress = errors.New("ldap: postal address cannot be empty")
// PostalAddress represents an RFC 4517 Postal Address
// A postal address is a sequence of strings of one or more arbitrary UCS
// characters, which form the lines of the address.
type PostalAddress struct {
lines []string
}
// NewPostalAddress creates a new PostalAddress by copying non-empty lines from the provided slice of strings.
func NewPostalAddress(lines []string) (*PostalAddress, error) {
copiedLines := make([]string, 0, len(lines))
for _, line := range lines {
if line == "" {
continue
}
copiedLines = append(copiedLines, line)
}
if len(copiedLines) == 0 {
return nil, ErrEmptyPostalAddress
}
return &PostalAddress{lines: copiedLines}, nil
}
// Lines returns a copy of the address lines as a slice of strings.
func (p *PostalAddress) Lines() []string {
copiedLines := make([]string, len(p.lines))
copy(copiedLines, p.lines)
return copiedLines
}
// String returns the postal address as a single string, with lines joined by newline characters.
func (p *PostalAddress) String() string {
return strings.Join(p.lines, "\n")
}
// Escape encodes special characters in the PostalAddress lines as per RFC 4517 and appends a `$` at the end of each line.
func (p *PostalAddress) Escape() string {
builder := &strings.Builder{}
for _, line := range p.lines {
for _, char := range line {
switch char {
case '\\':
builder.WriteString("\\5C")
case '$':
builder.WriteString("\\24")
default:
builder.WriteRune(char)
}
}
builder.WriteRune('$')
}
return builder.String()
}
// ParsePostalAddress parses an RFC 4517 escaped postal address string into a PostalAddress object or returns an error.
func ParsePostalAddress(escaped string) (*PostalAddress, error) {
lines := strings.Split(escaped, "$")
parsedLines := make([]string, 0, len(lines))
const totalEscapeLen = 3
for _, line := range lines {
if line == "" {
// Skip empty lines
continue
}
builder := &strings.Builder{}
for i := 0; i < len(line); i++ {
char := line[i]
if char == '\\' && i+totalEscapeLen <= len(line) {
escapeSeq := line[i+1 : i+totalEscapeLen]
switch escapeSeq {
case "5C", "5c":
builder.WriteRune('\\')
i += 2
case "24":
builder.WriteRune('$')
i += 2
default:
return nil, fmt.Errorf("invalid escape sequence: \\%s at position %d", escapeSeq, i)
}
} else if char == '\\' {
return nil, fmt.Errorf("incomplete escape sequence at position %d", i)
} else {
builder.WriteByte(char)
}
}
parsedLines = append(parsedLines, builder.String())
}
if len(parsedLines) == 0 {
return nil, ErrEmptyPostalAddress
}
return &PostalAddress{lines: parsedLines}, nil
}
// Equal compares the current PostalAddress with another PostalAddress and returns true if they are identical.
func (p *PostalAddress) Equal(other *PostalAddress) bool {
if p == other {
return true
}
if p == nil || other == nil {
return false
}
if len(p.lines) != len(other.lines) {
return false
}
for i := range p.lines {
if p.lines[i] != other.lines[i] {
return false
}
}
return true
}
+1 -1
View File
@@ -623,7 +623,7 @@ func (l *Conn) Search(searchRequest *SearchRequest) (*SearchResult, error) {
// SearchAsync performs a search request and returns all search results asynchronously.
// This means you get all results until an error happens (or the search successfully finished),
// e.g. for size / time limited requests all are recieved until the limit is reached.
// e.g. for size / time limited requests all are received until the limit is reached.
// To stop the search, call cancel function of the context.
func (l *Conn) SearchAsync(
ctx context.Context, searchRequest *SearchRequest, bufferSize int) Response {
+4 -72
View File
@@ -4,88 +4,20 @@ package ldap
//
// https://tools.ietf.org/html/rfc4532
import (
"errors"
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
)
type whoAmIRequest bool
// WhoAmIResult is returned by the WhoAmI() call
type WhoAmIResult struct {
AuthzID string
}
func (r whoAmIRequest) encode() (*ber.Packet, error) {
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Who Am I? Extended Operation")
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, ControlTypeWhoAmI, "Extended Request Name: Who Am I? OID"))
return request, nil
}
// WhoAmI returns the authzId the server thinks we are, you may pass controls
// like a Proxied Authorization control
func (l *Conn) WhoAmI(controls []Control) (*WhoAmIResult, error) {
packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request")
packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID"))
req := whoAmIRequest(true)
encodedWhoAmIRequest, err := req.encode()
if err != nil {
return nil, err
}
packet.AppendChild(encodedWhoAmIRequest)
if len(controls) != 0 {
packet.AppendChild(encodeControls(controls))
}
l.Debug.PrintPacket(packet)
msgCtx, err := l.sendMessage(packet)
if err != nil {
return nil, err
}
defer l.finishMessage(msgCtx)
result := &WhoAmIResult{}
l.Debug.Printf("%d: waiting for response", msgCtx.id)
packetResponse, ok := <-msgCtx.responses
if !ok {
return nil, NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
}
packet, err = packetResponse.ReadPacket()
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
extendedRequest := NewExtendedRequest(ControlTypeWhoAmI, nil)
extendedRequest.Controls = controls
resp, err := l.Extended(extendedRequest)
if err != nil {
return nil, err
}
if packet == nil {
return nil, NewError(ErrorNetwork, errors.New("ldap: could not retrieve message"))
}
if l.Debug {
if err := addLDAPDescriptions(packet); err != nil {
return nil, err
}
ber.PrintPacket(packet)
}
if packet.Children[1].Tag == ApplicationExtendedResponse {
if err := GetLDAPError(packet); err != nil {
return nil, err
}
} else {
return nil, NewError(ErrorUnexpectedResponse, fmt.Errorf("Unexpected Response: %d", packet.Children[1].Tag))
}
extendedResponse := packet.Children[1]
for _, child := range extendedResponse.Children {
if child.Tag == 11 {
result.AuthzID = ber.DecodeString(child.Data.Bytes())
}
}
return result, nil
return &WhoAmIResult{AuthzID: resp.Value.Data.String()}, nil
}