Skip to content

Commit

Permalink
update, add Parse(), Apply()
Browse files Browse the repository at this point in the history
* Parse() wraps Unmarshal() to parse a string
* Apply() sends an *LDIF to the given ldap.Client to modify
  the server
... changes for go-ldap#54 already
included by commented
  • Loading branch information
vetinari committed Aug 4, 2016
1 parent f76f90f commit bdac54f
Show file tree
Hide file tree
Showing 5 changed files with 270 additions and 69 deletions.
67 changes: 67 additions & 0 deletions ldif/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
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)
}
/*
case entry.ModifyDN != nil:
if err := conn.ModifyDN(entry.ModifyDN); err != nil {
if continueOnErr {
log.Printf("ERROR: Failed to modify dn %s: %s", entry.ModifyDN.DN, err)
continue
}
return fmt.Errorf("failed to modify dn %s: %s", entry.ModifyDN.DN, err)
}
*/
}
}
return nil
}
26 changes: 22 additions & 4 deletions ldif/ldif.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package ldif

import (
"bufio"
"bytes"
"encoding/base64"
"errors"
"fmt"
Expand Down Expand Up @@ -60,6 +61,14 @@ var comment byte = '#'
var space byte = ' '
var spaces = string(space)

// Parse wraps Unmarshal to parse an LDIF from a string
func Parse(str string) (l *LDIF, err error) {
buf := bytes.NewBuffer([]byte(str))
l = &LDIF{}
err = Unmarshal(buf, l)
return
}

// Unmarshal parses the LDIF from the given io.Reader into the LDIF struct.
// The caller is responsible for closing the io.Reader if that is
// needed.
Expand Down Expand Up @@ -211,6 +220,7 @@ func (l *LDIF) parseLine(line string) (attr, val string, err error) {

if off > len(line)-2 {
err = errors.New("empty value")
// FIXME: this is allowed for some attributes
return
}

Expand All @@ -225,7 +235,6 @@ func (l *LDIF) parseLine(line string) (attr, val string, err error) {
case ':':
var n int
value := strings.TrimLeft(line[off+2:], spaces)
// fmt.Fprintf(os.Stderr, "LINE=%s\nVALUE=%s\n", line, value)
dec := make([]byte, base64.StdEncoding.DecodedLen(len([]byte(value))))
n, err = base64.StdEncoding.Decode(dec, []byte(value))
if err != nil {
Expand All @@ -239,15 +248,16 @@ func (l *LDIF) parseLine(line string) (attr, val string, err error) {
val = strings.TrimLeft(line[off+2:], spaces)
u, err = url.Parse(val)
if err != nil {
err = fmt.Errorf("failed to parse URL: %s", err)
return
}
if u.Scheme != "file" {
err = errors.New("unsupported URL scheme " + u.Scheme)
err = fmt.Errorf("unsupported URL scheme %s", u.Scheme)
return
}
data, err = ioutil.ReadFile(u.Path)
if err != nil {
err = errors.New("Failed to read " + u.Path + ": " + err.Error())
err = fmt.Errorf("failed to read %s: %s", u.Path, err)
return
}
val = string(data) // FIXME: safe?
Expand Down Expand Up @@ -306,4 +316,12 @@ func validAttr(attr string) error {
return nil
}

// vim: ts=4 sw=4 noexpandtab nolist
// AllEntries returns all *ldap.Entries in the LDIF
func (l *LDIF) AllEntries() (entries []*ldap.Entry) {
for _, entry := range l.Entries {
if entry.Entry != nil {
entries = append(entries, entry.Entry)
}
}
return entries
}
30 changes: 11 additions & 19 deletions ldif/ldif_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
package ldif_test

import (
"bytes"
"gopkg.in/ldap.v2/ldif"
"io/ioutil"
"os"
"testing"
)

func parseString(str string) (*ldif.LDIF, error) {
ex := bytes.NewBuffer([]byte(str))
l := &ldif.LDIF{}
err := ldif.Unmarshal(ex, l)
return l, err
}

var ldifRFC2849Example = `version: 1
dn: cn=Barbara Jensen, ou=Product Development, dc=airius, dc=com
objectclass: top
Expand All @@ -38,7 +30,7 @@ telephonenumber: +1 408 555 1212
`

func TestLDIFParseRFC2849Example(t *testing.T) {
l, err := parseString(ldifRFC2849Example)
l, err := ldif.Parse(ldifRFC2849Example)
if err != nil {
t.Errorf("Failed to parse RFC 2849 example: %s", err)
}
Expand All @@ -53,7 +45,7 @@ cn: Some User
`

func TestLDIFParseEmptyAttr(t *testing.T) {
_, err := parseString(ldifEmpty)
_, err := ldif.Parse(ldifEmpty)
if err == nil {
t.Errorf("Did not fail to parse empty attribute")
}
Expand All @@ -64,7 +56,7 @@ cn: Some User
`

func TestLDIFParseMissingDN(t *testing.T) {
_, err := parseString(ldifMissingDN)
_, err := ldif.Parse(ldifMissingDN)
if err == nil {
t.Errorf("Did not fail to parse missing DN attribute")
}
Expand All @@ -77,7 +69,7 @@ cn: Someone
`

func TestLDIFContinuation(t *testing.T) {
l, err := parseString(ldifContinuation)
l, err := ldif.Parse(ldifContinuation)
if err != nil {
t.Errorf("Failed to parse LDIF: %s", err)
}
Expand All @@ -92,7 +84,7 @@ sn:: U29tZSBPbmU=
`

func TestLDIFBase64(t *testing.T) {
l, err := parseString(ldifBase64)
l, err := ldif.Parse(ldifBase64)
if err != nil {
t.Errorf("Failed to parse LDIF: %s", err)
}
Expand All @@ -110,7 +102,7 @@ sn:: XXX-U29tZSBPbmU=
`

func TestLDIFBase64Broken(t *testing.T) {
_, err := parseString(ldifBase64Broken)
_, err := ldif.Parse(ldifBase64Broken)
if err == nil {
t.Errorf("Did not failed to parse broken base64")
}
Expand All @@ -122,7 +114,7 @@ sn:: U29tZSBPbmU=
`

func TestLDIFTrailingBlank(t *testing.T) {
_, err := parseString(ldifTrailingBlank)
_, err := ldif.Parse(ldifTrailingBlank)
if err != nil {
t.Errorf("Failed to parse LDIF: %s", err)
}
Expand All @@ -135,7 +127,7 @@ sn: someone
`

func TestLDIFComments(t *testing.T) {
l, err := parseString(ldifComments)
l, err := ldif.Parse(ldifComments)
if err != nil {
t.Errorf("Failed to parse LDIF: %s", err)
}
Expand All @@ -149,7 +141,7 @@ sn:someone
`

func TestLDIFNoSpace(t *testing.T) {
l, err := parseString(ldifNoSpace)
l, err := ldif.Parse(ldifNoSpace)
if err != nil {
t.Errorf("Failed to parse LDIF: %s", err)
}
Expand All @@ -163,7 +155,7 @@ sn: someone
`

func TestLDIFMultiSpace(t *testing.T) {
l, err := parseString(ldifMultiSpace)
l, err := ldif.Parse(ldifMultiSpace)
if err != nil {
t.Errorf("Failed to parse LDIF: %s", err)
}
Expand All @@ -180,7 +172,7 @@ func TestLDIFURL(t *testing.T) {
defer os.Remove(f.Name())
f.Write([]byte("TEST\n"))
f.Sync()
l, err := parseString("dn: uid=someone,dc=example,dc=org\ndescription:< file://" + f.Name() + "\n")
l, err := ldif.Parse("dn: uid=someone,dc=example,dc=org\ndescription:< file://" + f.Name() + "\n")
if err != nil {
t.Errorf("Failed to parse LDIF: %s", err)
}
Expand Down
Loading

0 comments on commit bdac54f

Please sign in to comment.