diff --git a/main.go b/main.go index 3d5ba57..13d3da6 100644 --- a/main.go +++ b/main.go @@ -74,8 +74,6 @@ type State struct { login Login } -type Entry map[string][]string - var configFlag = flag.String("config", "./config.json", "Configuration file path") var resyncFlag = flag.Bool("resync", false, "Check and re-synchronize memberOf values before launch") diff --git a/read.go b/read.go index b36b966..7887c93 100644 --- a/read.go +++ b/read.go @@ -17,11 +17,14 @@ func (server *Server) getAttribute(dn string, attr string) ([]string, error) { return nil, err } + // List all attributes of the object, this is needed because the attribute we are + // looking for can exist with different cases than the one specified here pairs, _, err := server.kv.List(path+"/attribute=", &server.readOpts) if err != nil { return nil, err } + // Collect values for the attribute, case-insensitively values := []string{} for _, pair := range pairs { if strings.EqualFold(pair.Key, path+"/attribute="+attr) { diff --git a/util.go b/util.go index 30d7a67..cbb6b0f 100644 --- a/util.go +++ b/util.go @@ -11,6 +11,13 @@ import ( log "github.com/sirupsen/logrus" ) +// DNs ---- + +type dnComponent struct { + Type string + Value string +} + func dnToConsul(dn string) (string, error) { if strings.Contains(dn, "/") { return "", fmt.Errorf("DN %s contains a /", dn) @@ -45,6 +52,48 @@ func consulToDN(key string) (string, string, error) { return "", "", fmt.Errorf("Consul key %s does not end with attribute=something", key) } +func parseDN(dn string) ([]dnComponent, error) { + rdns := strings.Split(dn, ",") + + ret := []dnComponent{} + + for _, rdn := range rdns { + splits := strings.Split(rdn, "=") + if len(splits) != 2 { + return nil, fmt.Errorf("Wrong DN component: %s (expected type=value)", rdn) + } + ret = append(ret, dnComponent{ + Type: strings.ToLower(strings.TrimSpace(splits[0])), + Value: strings.ToLower(strings.TrimSpace(splits[1])), + }) + } + return ret, nil +} + +func unparseDN(path []dnComponent) string { + ret := "" + for _, c := range path { + if ret != "" { + ret = ret + "," + } + ret = ret + c.Type + "=" + c.Value + } + return ret +} + +func canonicalDN(dn string) (string, error) { + path, err := parseDN(dn) + if err != nil { + return "", err + } + + return unparseDN(path), nil +} + +// Values + +type Entry map[string][]string + func parseValue(value []byte) ([]string, error) { val := []string{} err := json.Unmarshal(value, &val) @@ -82,49 +131,6 @@ func parseConsulResult(data []*consul.KVPair) (map[string]Entry, error) { return aggregator, nil } -type DNComponent struct { - Type string - Value string -} - -func parseDN(dn string) ([]DNComponent, error) { - rdns := strings.Split(dn, ",") - - ret := []DNComponent{} - - for _, rdn := range rdns { - splits := strings.Split(rdn, "=") - if len(splits) != 2 { - return nil, fmt.Errorf("Wrong DN component: %s (expected type=value)", rdn) - } - ret = append(ret, DNComponent{ - Type: strings.ToLower(strings.TrimSpace(splits[0])), - Value: strings.ToLower(strings.TrimSpace(splits[1])), - }) - } - return ret, nil -} - -func unparseDN(path []DNComponent) string { - ret := "" - for _, c := range path { - if ret != "" { - ret = ret + "," - } - ret = ret + c.Type + "=" + c.Value - } - return ret -} - -func canonicalDN(dn string) (string, error) { - path, err := parseDN(dn) - if err != nil { - return "", err - } - - return unparseDN(path), nil -} - func checkRestrictedAttr(attr string) error { RESTRICTED_ATTRS := []string{ ATTR_MEMBEROF, diff --git a/write.go b/write.go index e4c7de1..482f971 100644 --- a/write.go +++ b/write.go @@ -19,7 +19,31 @@ func (server *Server) putAttributes(dn string, attrs Entry) error { return err } - for k, valuesNC := range attrs { + // Normalize attribute names: if we have several times the same attr + // but with different cases, put that in the same attr + normalized := make(Entry) + for k, values := range attrs { + found := false + for k2 := range normalized { + if strings.EqualFold(k, k2) { + normalized[k2] = append(normalized[k2], values...) + found = true + break + } + } + if !found { + normalized[k] = values + } + } + + // Retreieve previously existing attributes, which we will use to delete + // entries with the wrong case + previous_pairs, _, err := server.kv.List(prefix + "/attribute=", &server.readOpts) + if err != nil { + return err + } + + for k, valuesNC := range normalized { path := prefix + "/attribute=" + k // Trim spaces and remove empty values @@ -31,6 +55,16 @@ func (server *Server) putAttributes(dn string, attrs Entry) error { } } + // If previously existing pairs with the wrong case exist, delete them + for _, prev_pair := range previous_pairs { + if strings.EqualFold(prev_pair.Key, path) && prev_pair.Key != path { + _, err := server.kv.Delete(prev_pair.Key, nil) + if err != nil { + return err + } + } + } + // If we have zero values, delete associated k/v pair // Otherwise, write new values if len(values) == 0 {