From 54f6f7da20d43f392c60b4aab6e0a37b1f01d1e2 Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Sun, 21 Feb 2016 16:33:17 +0100 Subject: [PATCH 1/8] add ModifyDN() - moddn/modrdn --- moddn.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 moddn.go diff --git a/moddn.go b/moddn.go new file mode 100644 index 00000000..e26f8df0 --- /dev/null +++ b/moddn.go @@ -0,0 +1,97 @@ +// File contains ModifyDN functionality +// +// https://tools.ietf.org/html/rfc4511 +// ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { +// entry LDAPDN, +// newrdn RelativeLDAPDN, +// deleteoldrdn BOOLEAN, +// newSuperior [0] LDAPDN OPTIONAL } +// +// +package ldap + +import ( + "errors" + "log" + + "gopkg.in/asn1-ber.v1" +) + +type ModifyDNRequest struct { + DN string + NewRDN string + DeleteOldRDN bool + NewSuperior string +} + +// set "newSup" to empty string for just renaming, to move w/o renaming the "rdn" must be the first +// RDN of the given DN +func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest { + return &ModifyDNRequest{ + DN: dn, + NewRDN: rdn, + DeleteOldRDN: delOld, + NewSuperior: newSup, + } +} + +func (m ModifyDNRequest) encode() *ber.Packet { + request := ber.Encode(ber.ClassApplication, ber.TypeConstructed, ApplicationModifyDNRequest, nil, "Modify DN Request") + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.DN, "DN")) + request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.NewRDN, "New RDN")) + request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, m.DeleteOldRDN, "Delete old RDN")) + if m.NewSuperior != "" { + // FIXME: do we need ber.TagEOC here or the context number? (in this case both are 0) ... and this + // moves the DN to the new base on OpenLDAP ;-) + request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior")) + } + return request +} + +// Rename the given DN and optionally move to another base (when the "newSup" argument +// to NewModifyDNRequest() is not ""). +func (l *Conn) ModifyDN(m *ModifyDNRequest) error { + messageID := l.nextMessageID() + packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(m.encode()) + + l.Debug.PrintPacket(packet) + + channel, err := l.sendMessage(packet) + if err != nil { + return err + } + if channel == nil { + return NewError(ErrorNetwork, errors.New("ldap: could not send message")) + } + defer l.finishMessage(messageID) + + l.Debug.Printf("%d: waiting for response", messageID) + packet = <-channel + l.Debug.Printf("%d: got response %p", messageID, packet) + if packet == nil { + return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + } + + if l.Debug { + if err := addLDAPDescriptions(packet); err != nil { + return err + } + ber.PrintPacket(packet) + } + + if packet.Children[1].Tag == ApplicationModifyDNResponse { + resultCode, resultDescription := getLDAPResultCode(packet) + if resultCode != 0 { + return NewError(resultCode, errors.New(resultDescription)) + } + } else { + log.Printf("Unexpected Response: %d", packet.Children[1].Tag) + } + + l.Debug.Printf("%d: returning", messageID) + return nil +} + +// vim: ts=4 sw=4 noexpandtab nolist From 834049a5485c4313df06e46b07c7062a0ebeee71 Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Mon, 14 Mar 2016 11:38:08 +0100 Subject: [PATCH 2/8] Update README --- README.md | 3 ++- moddn.go | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f49b4d6a..45217c84 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ Import the latest version with: - Add Requests / Responses - Delete Requests / Responses - Better Unicode support + - Modify DN Requests / Responses ## Examples: @@ -43,7 +44,7 @@ Import the latest version with: - [x] Add Requests / Responses - [x] Delete Requests / Responses - - [x] Modify DN Requests / Responses + - [ ] Modify DN Requests / Responses - [ ] Compare Requests / Responses - [ ] Implement Tests / Benchmarks diff --git a/moddn.go b/moddn.go index e26f8df0..20e4ff67 100644 --- a/moddn.go +++ b/moddn.go @@ -41,8 +41,6 @@ func (m ModifyDNRequest) encode() *ber.Packet { request.AppendChild(ber.NewString(ber.ClassUniversal, ber.TypePrimitive, ber.TagOctetString, m.NewRDN, "New RDN")) request.AppendChild(ber.NewBoolean(ber.ClassUniversal, ber.TypePrimitive, ber.TagBoolean, m.DeleteOldRDN, "Delete old RDN")) if m.NewSuperior != "" { - // FIXME: do we need ber.TagEOC here or the context number? (in this case both are 0) ... and this - // moves the DN to the new base on OpenLDAP ;-) request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior")) } return request From f0d509c869bb2b92ba6912772c5722174bd6ce15 Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Fri, 18 Mar 2016 16:29:39 +0100 Subject: [PATCH 3/8] add ModifyDN() to client --- client.go | 1 + 1 file changed, 1 insertion(+) diff --git a/client.go b/client.go index d3401f9e..e6227b65 100644 --- a/client.go +++ b/client.go @@ -14,6 +14,7 @@ type Client interface { Add(addRequest *AddRequest) error Del(delRequest *DelRequest) error Modify(modifyRequest *ModifyRequest) error + ModifyDN(modifyDNRequest *ModifyDNRequest) error Compare(dn, attribute, value string) (bool, error) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*PasswordModifyResult, error) From 81dd048ec5cee739658e010962f3383a40024196 Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Thu, 9 Jun 2016 08:43:05 +0200 Subject: [PATCH 4/8] update docs, changes needed for #57 --- moddn.go | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/moddn.go b/moddn.go index 20e4ff67..fef9d1fe 100644 --- a/moddn.go +++ b/moddn.go @@ -24,8 +24,18 @@ type ModifyDNRequest struct { NewSuperior string } -// set "newSup" to empty string for just renaming, to move w/o renaming the "rdn" must be the first -// RDN of the given DN +// NewModifyDNRequest creates a new request which can be passed to ModifyDN(). +// +// To move an object in the tree, set the "newSup" to the new parent entry DN. Use an +// empty string for just changing the object's RDN. +// +// For moving the object without renaming the "rdn" must be the first +// RDN of the given DN. +// +// A call like +// mdnReq := NewModifyDNRequest("uid=someone,dc=example,dc=org", "uid=newname", true, "") +// will setup the request to just rename uid=someone,dc=example,dc=org to +// uid=newname,dc=example,dc=org. func NewModifyDNRequest(dn string, rdn string, delOld bool, newSup string) *ModifyDNRequest { return &ModifyDNRequest{ DN: dn, @@ -66,7 +76,11 @@ func (l *Conn) ModifyDN(m *ModifyDNRequest) error { defer l.finishMessage(messageID) l.Debug.Printf("%d: waiting for response", messageID) - packet = <-channel + packetResponse, ok := <-channel + if !ok { + return NewError(ErrorNetwork, errors.New("ldap: channel closed")) + } + packet, err = packetResponse.ReadPacket() l.Debug.Printf("%d: got response %p", messageID, packet) if packet == nil { return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) @@ -91,5 +105,3 @@ func (l *Conn) ModifyDN(m *ModifyDNRequest) error { l.Debug.Printf("%d: returning", messageID) return nil } - -// vim: ts=4 sw=4 noexpandtab nolist From e4bd062255082f4731628efeb69e23906c86703d Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Sat, 23 Jul 2016 11:21:42 +0200 Subject: [PATCH 5/8] update to use msgCtx --- moddn.go | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/moddn.go b/moddn.go index fef9d1fe..1c70c886 100644 --- a/moddn.go +++ b/moddn.go @@ -1,4 +1,4 @@ -// File contains ModifyDN functionality +// Package ldap - moddn.go contains ModifyDN functionality // // https://tools.ietf.org/html/rfc4511 // ModifyDNRequest ::= [APPLICATION 12] SEQUENCE { @@ -17,6 +17,7 @@ import ( "gopkg.in/asn1-ber.v1" ) +// ModifyDNRequest holds the request to modify a DN type ModifyDNRequest struct { DN string NewRDN string @@ -56,34 +57,30 @@ func (m ModifyDNRequest) encode() *ber.Packet { return request } -// Rename the given DN and optionally move to another base (when the "newSup" argument +// ModifyDN renames the given DN and optionally move to another base (when the "newSup" argument // to NewModifyDNRequest() is not ""). func (l *Conn) ModifyDN(m *ModifyDNRequest) error { - messageID := l.nextMessageID() packet := ber.Encode(ber.ClassUniversal, ber.TypeConstructed, ber.TagSequence, nil, "LDAP Request") - packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, messageID, "MessageID")) + packet.AppendChild(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID, "MessageID")) packet.AppendChild(m.encode()) l.Debug.PrintPacket(packet) - channel, err := l.sendMessage(packet) + msgCtx, err := l.sendMessage(packet) if err != nil { return err } - if channel == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not send message")) - } - defer l.finishMessage(messageID) + defer l.finishMessage(msgCtx) - l.Debug.Printf("%d: waiting for response", messageID) - packetResponse, ok := <-channel + l.Debug.Printf("%d: waiting for response", msgCtx.id) + packetResponse, ok := <-msgCtx.responses if !ok { return NewError(ErrorNetwork, errors.New("ldap: channel closed")) } packet, err = packetResponse.ReadPacket() - l.Debug.Printf("%d: got response %p", messageID, packet) - if packet == nil { - return NewError(ErrorNetwork, errors.New("ldap: could not retrieve message")) + l.Debug.Printf("%d: got response %p", msgCtx.id, packet) + if err != nil { + return err } if l.Debug { @@ -102,6 +99,6 @@ func (l *Conn) ModifyDN(m *ModifyDNRequest) error { log.Printf("Unexpected Response: %d", packet.Children[1].Tag) } - l.Debug.Printf("%d: returning", messageID) + l.Debug.Printf("%d: returning", msgCtx.id) return nil } From 42e38fabac1735f9dac375b9ef245d182410ae2c Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Tue, 20 Sep 2016 19:29:16 +0200 Subject: [PATCH 6/8] fix missing comma, add moddn_test.go with examples --- moddn.go | 2 +- moddn_test.go | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 moddn_test.go diff --git a/moddn.go b/moddn.go index 1c70c886..5fafaef0 100644 --- a/moddn.go +++ b/moddn.go @@ -30,7 +30,7 @@ type ModifyDNRequest struct { // To move an object in the tree, set the "newSup" to the new parent entry DN. Use an // empty string for just changing the object's RDN. // -// For moving the object without renaming the "rdn" must be the first +// For moving the object without renaming, the "rdn" must be the first // RDN of the given DN. // // A call like diff --git a/moddn_test.go b/moddn_test.go new file mode 100644 index 00000000..9ce6ee42 --- /dev/null +++ b/moddn_test.go @@ -0,0 +1,72 @@ +package ldap_test + +import ( + "log" + + "gopkg.in/ldap.v2" +) + +func ExampleModDNRenameNoMove() { + conn, err := ldap.Dial("tcp", "ldap.example.org:389") + if err != nil { + log.Fatalf("Failed to connect: %s\n", err) + } + defer conn.Close() + + _, err = conn.SimpleBind(&ldap.SimpleBindRequest{ + Username: "uid=someone,ou=people,dc=example,dc=org", + Password: "MySecretPass", + }) + if err != nil { + log.Fatalf("Failed to bind: %s\n", err) + } + // just rename to uid=new,ou=people,dc=example,dc=org: + req := ldap.NewModifyDNRequest("uid=user,ou=people,dc=example,dc=org", "uid=new", true, "") + if err = conn.ModifyDN(req); err != nil { + log.Fatalf("Failed to call ModifyDN(): %s\n", err) + } +} + +func ExampleModDNRenameAndMove() { + conn, err := ldap.Dial("tcp", "ldap.example.org:389") + if err != nil { + log.Fatalf("Failed to connect: %s\n", err) + } + defer conn.Close() + + _, err = conn.SimpleBind(&ldap.SimpleBindRequest{ + Username: "uid=someone,ou=people,dc=example,dc=org", + Password: "MySecretPass", + }) + if err != nil { + log.Fatalf("Failed to bind: %s\n", err) + } + // rename to uid=new,ou=people,dc=example,dc=org and move to ou=users,dc=example,dc=org -> + // uid=new,ou=users,dc=example,dc=org + req := ldap.NewModifyDNRequest("uid=user,ou=people,dc=example,dc=org", "uid=new", true, "ou=users,dc=example,dc=org") + + if err = conn.ModifyDN(req); err != nil { + log.Fatalf("Failed to call ModifyDN(): %s\n", err) + } +} + +func ExampleModDNMove() { + conn, err := ldap.Dial("tcp", "ldap.example.org:389") + if err != nil { + log.Fatalf("Failed to connect: %s\n", err) + } + defer conn.Close() + + _, err = conn.SimpleBind(&ldap.SimpleBindRequest{ + Username: "uid=someone,ou=people,dc=example,dc=org", + Password: "MySecretPass", + }) + if err != nil { + log.Fatalf("Failed to bind: %s\n", err) + } + // move to ou=users,dc=example,dc=org -> uid=user,ou=users,dc=example,dc=org + req := ldap.NewModifyDNRequest("uid=user,ou=people,dc=example,dc=org", "uid=user", true, "ou=users,dc=example,dc=org") + if err = conn.ModifyDN(req); err != nil { + log.Fatalf("Failed to call ModifyDN(): %s\n", err) + } +} From ccbe1160f82508b2f573db6beb10cc4272a9ac6b Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Tue, 20 Sep 2016 19:57:21 +0200 Subject: [PATCH 7/8] rename example functions to match the conventions for godoc --- moddn_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/moddn_test.go b/moddn_test.go index 9ce6ee42..f4af41aa 100644 --- a/moddn_test.go +++ b/moddn_test.go @@ -6,7 +6,8 @@ import ( "gopkg.in/ldap.v2" ) -func ExampleModDNRenameNoMove() { +// ExampleConn_ModifyDN_renameNoMove shows how to rename an entry without moving it +func ExampleConn_ModifyDN_renameNoMove() { conn, err := ldap.Dial("tcp", "ldap.example.org:389") if err != nil { log.Fatalf("Failed to connect: %s\n", err) @@ -27,7 +28,8 @@ func ExampleModDNRenameNoMove() { } } -func ExampleModDNRenameAndMove() { +// ExampleConn_ModifyDN_renameAndMove shows how to rename an entry and moving it to a new base +func ExampleConn_ModifyDN_renameAndMove() { conn, err := ldap.Dial("tcp", "ldap.example.org:389") if err != nil { log.Fatalf("Failed to connect: %s\n", err) @@ -50,7 +52,8 @@ func ExampleModDNRenameAndMove() { } } -func ExampleModDNMove() { +// ExampleConn_ModifyDN_moveOnly shows how to move an entry to a new base without renaming the RDN +func ExampleConn_ModifyDN_moveOnly() { conn, err := ldap.Dial("tcp", "ldap.example.org:389") if err != nil { log.Fatalf("Failed to connect: %s\n", err) From 9dfc2bf272719f24df4feed68455eecfb21dcefe Mon Sep 17 00:00:00 2001 From: Hanno Hecker Date: Sat, 26 Nov 2016 08:47:09 +0100 Subject: [PATCH 8/8] add missing parens --- moddn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moddn.go b/moddn.go index 5fafaef0..7065b814 100644 --- a/moddn.go +++ b/moddn.go @@ -61,7 +61,7 @@ func (m ModifyDNRequest) encode() *ber.Packet { // to NewModifyDNRequest() is not ""). func (l *Conn) ModifyDN(m *ModifyDNRequest) 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(ber.NewInteger(ber.ClassUniversal, ber.TypePrimitive, ber.TagInteger, l.nextMessageID(), "MessageID")) packet.AppendChild(m.encode()) l.Debug.PrintPacket(packet)