Skip to content

Commit

Permalink
Match our Fork with go-ldap/ldap (#4)
Browse files Browse the repository at this point in the history
* unified request flow && external binding to LDAP (go-ldap#232)

* unified request flow && external binding to LDAP

* fix debug mode

* go.mod was added

* Prevent negative waitgroup panic by `Add`ing first. (go-ldap#237)

* Use github for module name. (go-ldap#239)

* Rename asn1 ber dependency. (go-ldap#243)

* Rename asn1.ber dependency.

* go mod tidy

* Update travic CI to new asn1 ber

* Update travis go_import_path

* Update README (go-ldap#245)

* Update go.mod (go-ldap#241)

I believe that this (plus a new tag) is what is necessary for native go modules support -- right now go modules complains that the version tag is >= v2 but the module doesn't claim to be a version >= v2.

* Versioned v3 according to Go wiki, maintaining backward compatibility (go-ldap#247)

* Moved v3 to subfolder to allow for versioning >2 with go modules. Reverted top level go.mod to fix backward compatibility

* Updated readme to include directions on Go Modules, including the rationale
  • Loading branch information
hahmadia authored Nov 25, 2019
1 parent fee0a36 commit ef4da40
Show file tree
Hide file tree
Showing 53 changed files with 5,797 additions and 351 deletions.
7 changes: 4 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,19 @@ go:
- "1.10.x"
- "1.11.x"
- "1.12.x"
- "1.13.x"
- tip

git:
depth: 1
depth: 1

matrix:
fast_finish: true
allow_failures:
- go: tip
go_import_path: gopkg.in/ldap.v3
go_import_path: github.com/go-ldap/ldap
install:
- go get gopkg.in/asn1-ber.v1
- go get github.com/go-asn1-ber/asn1-ber
- go get code.google.com/p/go.tools/cmd/cover || go get golang.org/x/tools/cmd/cover
- go get github.com/golang/lint/golint || go get golang.org/x/lint/golint || true
- go build -v ./...
Expand Down
37 changes: 22 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,8 @@
[![GoDoc](https://godoc.org/gopkg.in/ldap.v3?status.svg)](https://godoc.org/gopkg.in/ldap.v3)
[![GoDoc](https://godoc.org/github.com/go-ldap/ldap?status.svg)](https://godoc.org/github.com/go-ldap/ldap)
[![Build Status](https://travis-ci.org/go-ldap/ldap.svg)](https://travis-ci.org/go-ldap/ldap)

# Basic LDAP v3 functionality for the GO programming language.

## Install

For the latest version use:

go get gopkg.in/ldap.v3

Import the latest version with:

import "gopkg.in/ldap.v3"

## Required Libraries:

- gopkg.in/asn1-ber.v1

## Features:

- Connecting to LDAP server (non-TLS, TLS, STARTTLS)
Expand All @@ -34,6 +20,27 @@ Import the latest version with:
- search
- modify

## Go Modules:

`go get github.com/go-ldap/ldap/v3`

As go-ldap was v2+ when Go Modules came out, updating to Go Modules would be considered a breaking change.

To maintain backwards compatability, we ultimately decided to use subfolders (as v3 was already a branch).
Whilst this duplicates the code, we can move toward implementing a backwards-compatible versioning system that allows for code reuse.
The alternative would be to increment the version number, however we believe that this would confuse users as v3 is in line with LDAPv3 (RFC-4511)
https://tools.ietf.org/html/rfc4511


For more info, please visit the pull request that updated to modules.
https://github.com/go-ldap/ldap/pull/247

To install with `GOMODULE111=off`, use `go get github.com/go-ldap/ldap`
https://golang.org/cmd/go/#hdr-Legacy_GOPATH_go_get

As always, we are looking for contributors with great ideas on how to best move forward.


## Contributing:

Bug reports and pull requests are welcome!
Expand Down
53 changes: 17 additions & 36 deletions add.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@
package ldap

import (
"errors"
"log"

"gopkg.in/asn1-ber.v1"
ber "github.com/go-asn1-ber/asn1-ber"
)

// Attribute represents an LDAP attribute
Expand Down Expand Up @@ -45,20 +44,26 @@ type AddRequest struct {
Controls []Control
}

func (a AddRequest) encode() *ber.Packet {
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request")
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, a.DN, "DN"))
func (req *AddRequest) appendTo(envelope *ber.Packet) error {
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationAddRequest, nil, "Add Request")
pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.DN, "DN"))
attributes := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "Attributes")
for _, attribute := range a.Attributes {
for _, attribute := range req.Attributes {
attributes.AppendChild(attribute.encode())
}
request.AppendChild(attributes)
return request
pkt.AppendChild(attributes)

envelope.AppendChild(pkt)
if len(req.Controls) > 0 {
envelope.AppendChild(encodeControls(req.Controls))
}

return nil
}

// Attribute adds an attribute with the given type and values
func (a *AddRequest) Attribute(attrType string, attrVals []string) {
a.Attributes = append(a.Attributes, Attribute{Type: attrType, Vals: attrVals})
func (req *AddRequest) Attribute(attrType string, attrVals []string) {
req.Attributes = append(req.Attributes, Attribute{Type: attrType, Vals: attrVals})
}

// NewAddRequest returns an AddRequest for the given DN, with no attributes
Expand All @@ -72,39 +77,17 @@ func NewAddRequest(dn string, controls []Control) *AddRequest {

// Add performs the given AddRequest
func (l *Conn) Add(addRequest *AddRequest) 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"))
packet.AppendChild(addRequest.encode())
if len(addRequest.Controls) > 0 {
packet.AppendChild(encodeControls(addRequest.Controls))
}

l.Debug.PrintPacket(packet)

msgCtx, err := l.sendMessage(packet)
msgCtx, err := l.doRequest(addRequest)
if err != nil {
return err
}
defer l.finishMessage(msgCtx)

l.Debug.Printf("%d: waiting for response", msgCtx.id)
packetResponse, ok := <-msgCtx.responses
if !ok {
return NewError(ErrorNetwork, errors.New("ldap: response channel closed"))
}
packet, err = packetResponse.ReadPacket()
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
packet, err := l.readPacket(msgCtx)
if err != nil {
return err
}

if l.Debug {
if err := addLDAPDescriptions(packet); err != nil {
return err
}
ber.PrintPacket(packet)
}

if packet.Children[1].Tag == ApplicationAddResponse {
err := GetLDAPError(packet)
if err != nil {
Expand All @@ -113,7 +96,5 @@ func (l *Conn) Add(addRequest *AddRequest) error {
} else {
log.Printf("Unexpected Response: %d", packet.Children[1].Tag)
}

l.Debug.Printf("%d: returning", msgCtx.id)
return nil
}
83 changes: 50 additions & 33 deletions bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"errors"
"fmt"

"gopkg.in/asn1-ber.v1"
ber "github.com/go-asn1-ber/asn1-ber"
)

// SimpleBindRequest represents a username/password bind operation
Expand Down Expand Up @@ -35,13 +35,18 @@ func NewSimpleBindRequest(username string, password string, controls []Control)
}
}

func (bindRequest *SimpleBindRequest) encode() *ber.Packet {
request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
request.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, bindRequest.Username, "User Name"))
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, bindRequest.Password, "Password"))
func (req *SimpleBindRequest) appendTo(envelope *ber.Packet) error {
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, req.Username, "User Name"))
pkt.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, req.Password, "Password"))

return request
envelope.AppendChild(pkt)
if len(req.Controls) > 0 {
envelope.AppendChild(encodeControls(req.Controls))
}

return nil
}

// SimpleBind performs the simple bind operation defined in the given request
Expand All @@ -50,41 +55,17 @@ func (l *Conn) SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResu
return nil, NewError(ErrorEmptyPassword, errors.New("ldap: empty password not allowed by the client"))
}

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"))
encodedBindRequest := simpleBindRequest.encode()
packet.AppendChild(encodedBindRequest)
if len(simpleBindRequest.Controls) > 0 {
packet.AppendChild(encodeControls(simpleBindRequest.Controls))
}

if l.Debug {
ber.PrintPacket(packet)
}

msgCtx, err := l.sendMessage(packet)
msgCtx, err := l.doRequest(simpleBindRequest)
if err != nil {
return nil, err
}
defer l.finishMessage(msgCtx)

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)
packet, err := l.readPacket(msgCtx)
if err != nil {
return nil, err
}

if l.Debug {
if err = addLDAPDescriptions(packet); err != nil {
return nil, err
}
ber.PrintPacket(packet)
}

result := &SimpleBindResult{
Controls: make([]Control, 0),
}
Expand Down Expand Up @@ -133,3 +114,39 @@ func (l *Conn) UnauthenticatedBind(username string) error {
_, err := l.SimpleBind(req)
return err
}

var externalBindRequest = requestFunc(func(envelope *ber.Packet) error {
pkt := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationBindRequest, nil, "Bind Request")
pkt.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, 3, "Version"))
pkt.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "User Name"))

saslAuth := ber.Encode(ber.ClassContext, ber.TypeConstructed, 3, "", "authentication")
saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "EXTERNAL", "SASL Mech"))
saslAuth.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, "", "SASL Cred"))

pkt.AppendChild(saslAuth)

envelope.AppendChild(pkt)

return nil
})

// ExternalBind performs SASL/EXTERNAL authentication.
//
// Use ldap.DialURL("ldapi://") to connect to the Unix socket before ExternalBind.
//
// See https://tools.ietf.org/html/rfc4422#appendix-A
func (l *Conn) ExternalBind() error {
msgCtx, err := l.doRequest(externalBindRequest)
if err != nil {
return err
}
defer l.finishMessage(msgCtx)

packet, err := l.readPacket(msgCtx)
if err != nil {
return err
}

return GetLDAPError(packet)
}
18 changes: 10 additions & 8 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,23 @@ import (
// Client knows how to interact with an LDAP server
type Client interface {
Start()
StartTLS(config *tls.Config) error
StartTLS(*tls.Config) error
Close()
SetTimeout(time.Duration)

Bind(username, password string) error
SimpleBind(simpleBindRequest *SimpleBindRequest) (*SimpleBindResult, error)
UnauthenticatedBind(username string) error
SimpleBind(*SimpleBindRequest) (*SimpleBindResult, error)
ExternalBind() error

Add(addRequest *AddRequest) error
Del(delRequest *DelRequest) error
Modify(modifyRequest *ModifyRequest) error
ModifyDN(modifyDNRequest *ModifyDNRequest) error
Add(*AddRequest) error
Del(*DelRequest) error
Modify(*ModifyRequest) error
ModifyDN(*ModifyDNRequest) error

Compare(dn, attribute, value string) (bool, error)
PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error)
PasswordModify(*PasswordModifyRequest) (*PasswordModifyResult, error)

Search(searchRequest *SearchRequest) (*SearchResult, error)
Search(*SearchRequest) (*SearchResult, error)
SearchWithPaging(searchRequest *SearchRequest, pagingSize uint32) (*SearchResult, error)
}
Loading

0 comments on commit ef4da40

Please sign in to comment.