Skip to content
Merged
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
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@
Utilities for working with ldif data
# ldif

Utilities for working with ldif data. This implements most of RFC 2849.

## Change Entries

Support for moddn / modrdn changes is missing (in Unmarshal and
Marshal) - gopkg.in/ldap.v2 does not support it currently

## Controls
Only simple controls without control value are supported, currently
just
Manage DSA IT - oid: 2.16.840.1.113730.3.4.2

## URLs

URL schemes in an LDIF like
jpegPhoto;binary:< file:///usr/share/photos/someone.jpg
are only supported for the "file" scheme like in the example above
57 changes: 57 additions & 0 deletions apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package ldif

import (
"fmt"
"log"

"gopkg.in/ldap.v2"
)

// Apply sends the LDIF entries to the server and does the changes as
// given by the entries.
//
// All *ldap.Entry are converted to an *ldap.AddRequest.
//
// By default, it returns on the first error. To continue with applying the
// LDIF, set the continueOnErr argument to true - in this case the errors
// are logged with log.Printf()
func (l *LDIF) Apply(conn ldap.Client, continueOnErr bool) error {
for _, entry := range l.Entries {
switch {
case entry.Entry != nil:
add := ldap.NewAddRequest(entry.Entry.DN)
for _, attr := range entry.Entry.Attributes {
add.Attribute(attr.Name, attr.Values)
}
entry.Add = add
fallthrough
case entry.Add != nil:
if err := conn.Add(entry.Add); err != nil {
if continueOnErr {
log.Printf("ERROR: Failed to add %s: %s", entry.Add.DN, err)
continue
}
return fmt.Errorf("failed to add %s: %s", entry.Add.DN, err)
}

case entry.Del != nil:
if err := conn.Del(entry.Del); err != nil {
if continueOnErr {
log.Printf("ERROR: Failed to delete %s: %s", entry.Del.DN, err)
continue
}
return fmt.Errorf("failed to delete %s: %s", entry.Del.DN, err)
}

case entry.Modify != nil:
if err := conn.Modify(entry.Modify); err != nil {
if continueOnErr {
log.Printf("ERROR: Failed to modify %s: %s", entry.Modify.DN, err)
continue
}
return fmt.Errorf("failed to modify %s: %s", entry.Modify.DN, err)
}
}
}
return nil
}
91 changes: 91 additions & 0 deletions changes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package ldif_test

import (
"testing"

"github.com/go-ldap/ldif"
)

var ldifRFC2849Example6 = `version: 1
# Add a new entry
dn: cn=Fiona Jensen, ou=Marketing, dc=airius, dc=com
changetype: add
objectclass: top
objectclass: person
objectclass: organizationalPerson
cn: Fiona Jensen
sn: Jensen
uid: fiona
telephonenumber: +1 408 555 1212
# jpegphoto:< file:///usr/local/directory/photos/fiona.jpg

# Delete an existing entry
dn: cn=Robert Jensen, ou=Marketing, dc=airius, dc=com
changetype: delete

# Modify an entry's relative distinguished name
#dn: cn=Paul Jensen, ou=Product Development, dc=airius, dc=com
#changetype: modrdn
#newrdn: cn=Paula Jensen
#deleteoldrdn: 1

# Rename an entry and move all of its children to a new location in
# the directory tree (only implemented by LDAPv3 servers).
#dn: ou=PD Accountants, ou=Product Development, dc=airius, dc=com
#changetype: modrdn
#newrdn: ou=Product Development Accountants
#deleteoldrdn: 0
#newsuperior: ou=Accounting, dc=airius, dc=com

# Modify an entry: add an additional value to the postaladdress
# attribute, completely delete the description attribute, replace
# the telephonenumber attribute with two values, and delete a specific
# value from the facsimiletelephonenumber attribute
dn: cn=Paula Jensen, ou=Product Development, dc=airius, dc=com
changetype: modify
add: postaladdress
postaladdress: 123 Anystreet $ Sunnyvale, CA $ 94086
-
# the example in the RFC has an empty line here, I don't think that's allowed...
delete: description
-
replace: telephonenumber
telephonenumber: +1 408 555 1234
telephonenumber: +1 408 555 5678
-
delete: facsimiletelephonenumber
facsimiletelephonenumber: +1 408 555 9876
-

# Modify an entry: replace the postaladdress attribute with an empty
# set of values (which will cause the attribute to be removed), and
# delete the entire description attribute. Note that the first will
# always succeed, while the second will only succeed if at least
# one value for the description attribute is present.
dn: cn=Ingrid Jensen, ou=Product Support, dc=airius, dc=com
changetype: modify
replace: postaladdress
-
delete: description
-
`

func TestLDIFParseRFC2849Example6(t *testing.T) {
l, err := ldif.Parse(ldifRFC2849Example6)
if err != nil {
t.Errorf("Failed to parse RFC 2849 example #6: %s", err)
}
if len(l.Entries) != 4 { // != 6
t.Errorf("invalid number of entries parsed: %d", len(l.Entries))
}
if l.Entries[3].Modify == nil {
t.Errorf("last entry not a modify request")
}
if l.Entries[3].Modify.DeleteAttributes[0].Type != "description" {
t.Errorf("RFC 2849 example 6: no deletion of description in last entry")
}
if l.Entries[2].Modify.ReplaceAttributes[0].Type != "telephonenumber" &&
l.Entries[2].Modify.ReplaceAttributes[0].Vals[1] != "+1 408 555 5678" {
t.Errorf("RFC 2849 example 6: no replacing of telephonenumber")
}
}
Loading