Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add ModifyDN() - moddn/modrdn #54

Closed
wants to merge 17 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Import the latest version with:
- Modify Requests / Responses
- Add Requests / Responses
- Delete Requests / Responses
- Modify DN Requests / Responses

## Examples:

Expand Down
1 change: 1 addition & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,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)
Expand Down
104 changes: 104 additions & 0 deletions moddn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Package ldap - moddn.go 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"
)

// ModifyDNRequest holds the request to modify a DN
type ModifyDNRequest struct {
DN string
NewRDN string
DeleteOldRDN bool
NewSuperior string
}

// 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 {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future documentation clarity (godoc) it wouldn't hurt to have 3 short examples:

  1. Rename without move
  2. Rename with move
  3. Move only

Or just actual Example functions in a moddn_test.go file? (https://blog.golang.org/examples)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

made an moddn_test.go with the 3 examples

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 != "" {
request.AppendChild(ber.NewString(ber.ClassContext, ber.TypePrimitive, 0, m.NewSuperior, "New Superior"))
}
return request
}

// 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 {
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(m.encode())

l.Debug.PrintPacket(packet)

msgCtx, err := l.sendMessage(packet)
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: channel closed"))
}
packet, err = packetResponse.ReadPacket()
l.Debug.Printf("%d: got response %p", msgCtx.id, packet)
if err != nil {
return err
}

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", msgCtx.id)
return nil
}
75 changes: 75 additions & 0 deletions moddn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package ldap_test

import (
"log"

"gopkg.in/ldap.v2"
)

// 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)
}
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)
}
}

// 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)
}
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)
}
}

// 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)
}
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)
}
}