Skip to content

Commit

Permalink
feat: add extended requests
Browse files Browse the repository at this point in the history
  • Loading branch information
cpuschma committed Apr 23, 2024
1 parent 17409dc commit 9fd2332
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 0 deletions.
1 change: 1 addition & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Client interface {
Modify(*ModifyRequest) error
ModifyDN(*ModifyDNRequest) error
ModifyWithResult(*ModifyRequest) (*ModifyResult, error)
Extended(*ExtendedRequest) (*ExtendResponse, error)

Compare(dn, attribute, value string) (bool, error)
PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error)
Expand Down
73 changes: 73 additions & 0 deletions extend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ldap

import (
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
)

// ExtendedRequest TODO
// See: https://www.rfc-editor.org/rfc/rfc4511#section-4.12
type ExtendedRequest struct {
Name string
Value string
}

func NewExtendedRequest(name, value string) *ExtendedRequest {
return &ExtendedRequest{
Name: name,
Value: value,
}
}

func (er ExtendedRequest) appendTo(envelope *ber.Packet) error {
// ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
// requestName [0] LDAPOID,
// requestValue [1] OCTET STRING OPTIONAL }
//
// Despite the RFC documentation stating otherwise, the requestName field needs to be
// of class application and type EOC, otherwise the directory server will terminate
// the connection right away (tested against OpenLDAP, Active Directory).
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Extend Request")
pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, ber.TagEOC, er.Name, "Extension Name"))
if er.Value != "" {
pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, er.Value, "Extension Value"))
}
envelope.AppendChild(pkt)
return nil
}

type ExtendResponse struct {
Name string
Value string
}

func (l *Conn) Extended(er *ExtendedRequest) (*ExtendResponse, error) {
msgCtx, err := l.doRequest(er)
if err != nil {
return nil, err
}
defer l.finishMessage(msgCtx)

// ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
// COMPONENTS OF LDAPResult,
// responseName [10] LDAPOID OPTIONAL,
// responseValue [11] OCTET STRING OPTIONAL }
packet, err := l.readPacket(msgCtx)
if err != nil {
return nil, err
}
if len(packet.Children) < 2 || len(packet.Children[1].Children) < 4 {
return nil, fmt.Errorf(
"ldap: malformed extended response: expected 4 children, got: %d",
len(packet.Children),
)
}

response := new(ExtendResponse)
response.Name = packet.Children[1].Children[3].Data.String()
if len(packet.Children) == 4 {
response.Value = packet.Children[1].Children[4].Data.String()
}

return response, nil
}
1 change: 1 addition & 0 deletions v3/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Client interface {
Modify(*ModifyRequest) error
ModifyDN(*ModifyDNRequest) error
ModifyWithResult(*ModifyRequest) (*ModifyResult, error)
Extended(*ExtendedRequest) (*ExtendResponse, error)

Compare(dn, attribute, value string) (bool, error)
PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error)
Expand Down
73 changes: 73 additions & 0 deletions v3/extend.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package ldap

import (
"fmt"
ber "github.com/go-asn1-ber/asn1-ber"
)

// ExtendedRequest TODO
// See: https://www.rfc-editor.org/rfc/rfc4511#section-4.12
type ExtendedRequest struct {
Name string
Value string
}

func NewExtendedRequest(name, value string) *ExtendedRequest {
return &ExtendedRequest{
Name: name,
Value: value,
}
}

func (er ExtendedRequest) appendTo(envelope *ber.Packet) error {
// ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
// requestName [0] LDAPOID,
// requestValue [1] OCTET STRING OPTIONAL }
//
// Despite the RFC documentation stating otherwise, the requestName field needs to be
// of class application and type EOC, otherwise the directory server will terminate
// the connection right away (tested against OpenLDAP, Active Directory).
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationExtendedRequest, nil, "Extend Request")
pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, ber.TagEOC, er.Name, "Extension Name"))
if er.Value != "" {
pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, er.Value, "Extension Value"))
}
envelope.AppendChild(pkt)
return nil
}

type ExtendResponse struct {
Name string
Value string
}

func (l *Conn) Extended(er *ExtendedRequest) (*ExtendResponse, error) {
msgCtx, err := l.doRequest(er)
if err != nil {
return nil, err
}
defer l.finishMessage(msgCtx)

// ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
// COMPONENTS OF LDAPResult,
// responseName [10] LDAPOID OPTIONAL,
// responseValue [11] OCTET STRING OPTIONAL }
packet, err := l.readPacket(msgCtx)
if err != nil {
return nil, err
}
if len(packet.Children) < 2 || len(packet.Children[1].Children) < 4 {
return nil, fmt.Errorf(
"ldap: malformed extended response: expected 4 children, got: %d",
len(packet.Children),
)
}

response := new(ExtendResponse)
response.Name = packet.Children[1].Children[3].Data.String()
if len(packet.Children) == 4 {
response.Value = packet.Children[1].Children[4].Data.String()
}

return response, nil
}

0 comments on commit 9fd2332

Please sign in to comment.