Refactor & add case normalization logic to putAttributes

This commit is contained in:
Alex 2021-03-09 19:00:45 +01:00
parent 1a20a64eff
commit 99d8955ab3
4 changed files with 87 additions and 46 deletions

View file

@ -74,8 +74,6 @@ type State struct {
login Login login Login
} }
type Entry map[string][]string
var configFlag = flag.String("config", "./config.json", "Configuration file path") var configFlag = flag.String("config", "./config.json", "Configuration file path")
var resyncFlag = flag.Bool("resync", false, "Check and re-synchronize memberOf values before launch") var resyncFlag = flag.Bool("resync", false, "Check and re-synchronize memberOf values before launch")

View file

@ -17,11 +17,14 @@ func (server *Server) getAttribute(dn string, attr string) ([]string, error) {
return nil, err 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) pairs, _, err := server.kv.List(path+"/attribute=", &server.readOpts)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Collect values for the attribute, case-insensitively
values := []string{} values := []string{}
for _, pair := range pairs { for _, pair := range pairs {
if strings.EqualFold(pair.Key, path+"/attribute="+attr) { if strings.EqualFold(pair.Key, path+"/attribute="+attr) {

92
util.go
View file

@ -11,6 +11,13 @@ import (
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
// DNs ----
type dnComponent struct {
Type string
Value string
}
func dnToConsul(dn string) (string, error) { func dnToConsul(dn string) (string, error) {
if strings.Contains(dn, "/") { if strings.Contains(dn, "/") {
return "", fmt.Errorf("DN %s contains a /", 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) 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) { func parseValue(value []byte) ([]string, error) {
val := []string{} val := []string{}
err := json.Unmarshal(value, &val) err := json.Unmarshal(value, &val)
@ -82,49 +131,6 @@ func parseConsulResult(data []*consul.KVPair) (map[string]Entry, error) {
return aggregator, nil 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 { func checkRestrictedAttr(attr string) error {
RESTRICTED_ATTRS := []string{ RESTRICTED_ATTRS := []string{
ATTR_MEMBEROF, ATTR_MEMBEROF,

View file

@ -19,7 +19,31 @@ func (server *Server) putAttributes(dn string, attrs Entry) error {
return err 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 path := prefix + "/attribute=" + k
// Trim spaces and remove empty values // 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 // If we have zero values, delete associated k/v pair
// Otherwise, write new values // Otherwise, write new values
if len(values) == 0 { if len(values) == 0 {