Initial QSfera import
This commit is contained in:
+144
@@ -0,0 +1,144 @@
|
||||
package ldapentry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"golang.org/x/text/cases"
|
||||
)
|
||||
|
||||
func ApplyModify(old *ldap.Entry, mod *ldap.ModifyRequest) (newEntry *ldap.Entry, err error) {
|
||||
oldDN, err := ldap.ParseDN(old.DN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rdn := oldDN.RDNs[0]
|
||||
modDN, err := ldap.ParseDN(mod.DN)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// This shouldn't happen if we ge here (TM)
|
||||
if !oldDN.EqualFold(modDN) {
|
||||
return nil, ldap.NewError(ldap.LDAPResultUnwillingToPerform, errors.New("DNs do not match"))
|
||||
}
|
||||
|
||||
casefold := cases.Fold()
|
||||
newEntry = ldap.NewEntry(old.DN, map[string][]string{})
|
||||
newEntry.Attributes = old.Attributes
|
||||
for _, c := range mod.Changes {
|
||||
nType := casefold.String(c.Modification.Type)
|
||||
switch c.Operation {
|
||||
case ldap.AddAttribute:
|
||||
newValues := entryApplyModAdd(newEntry.GetEqualFoldAttributeValues(nType), c.Modification.Vals)
|
||||
newEntry.Attributes = entryReplaceValues(newEntry.Attributes, c.Modification.Type, newValues)
|
||||
|
||||
case ldap.ReplaceAttribute:
|
||||
// Modifies on RDN attributes need special care to make sure that the rdn Value is not removed
|
||||
for _, rdnAttr := range rdn.Attributes {
|
||||
if nType == casefold.String(rdnAttr.Type) {
|
||||
rdnPresent := false
|
||||
nRdnVal := casefold.String(rdnAttr.Value)
|
||||
for _, newVal := range c.Modification.Vals {
|
||||
if nRdnVal == casefold.String(newVal) {
|
||||
rdnPresent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !rdnPresent {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotAllowedOnRDN, errors.New(""))
|
||||
}
|
||||
}
|
||||
}
|
||||
newEntry.Attributes = entryReplaceValues(newEntry.Attributes, c.Modification.Type, c.Modification.Vals)
|
||||
case ldap.DeleteAttribute:
|
||||
for _, rdnAttr := range rdn.Attributes {
|
||||
// Modifies on RDN attributes need special care
|
||||
if nType == casefold.String(rdnAttr.Type) {
|
||||
if len(c.Modification.Vals) == 0 {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotAllowedOnRDN, errors.New(""))
|
||||
}
|
||||
nRdnVal := casefold.String(rdnAttr.Value)
|
||||
for _, delVal := range c.Modification.Vals {
|
||||
if nRdnVal == casefold.String(delVal) {
|
||||
return nil, ldap.NewError(ldap.LDAPResultNotAllowedOnRDN, errors.New(""))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
newValues := entryApplyModDelete(old.GetEqualFoldAttributeValues(nType), c.Modification.Vals)
|
||||
newEntry.Attributes = entryReplaceValues(newEntry.Attributes, c.Modification.Type, newValues)
|
||||
}
|
||||
}
|
||||
return newEntry, nil
|
||||
}
|
||||
|
||||
func entryReplaceValues(ea []*ldap.EntryAttribute, attrType string, newValues []string) (updatedAttrs []*ldap.EntryAttribute) {
|
||||
casefold := cases.Fold()
|
||||
nType := casefold.String(attrType)
|
||||
updated := false
|
||||
for _, attr := range ea {
|
||||
if casefold.String(attr.Name) == nType {
|
||||
updated = true
|
||||
if len(newValues) == 0 {
|
||||
continue
|
||||
}
|
||||
updatedAttrs = append(updatedAttrs, ldap.NewEntryAttribute(attr.Name, newValues))
|
||||
} else {
|
||||
updatedAttrs = append(updatedAttrs, attr)
|
||||
}
|
||||
}
|
||||
if !updated {
|
||||
if len(newValues) != 0 {
|
||||
updatedAttrs = append(updatedAttrs, ldap.NewEntryAttribute(attrType, newValues))
|
||||
}
|
||||
}
|
||||
return updatedAttrs
|
||||
}
|
||||
|
||||
func entryApplyModAdd(curVals, addVals []string) (newVals []string) {
|
||||
newVals = curVals
|
||||
casefold := cases.Fold()
|
||||
for _, newVal := range addVals {
|
||||
present := false
|
||||
for _, val := range curVals {
|
||||
if casefold.String(newVal) == casefold.String(val) {
|
||||
present = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !present {
|
||||
newVals = append(newVals, newVal)
|
||||
}
|
||||
}
|
||||
return newVals
|
||||
}
|
||||
|
||||
func entryApplyModDelete(curVals, delVals []string) (newVals []string) {
|
||||
casefold := cases.Fold()
|
||||
if len(delVals) == 0 {
|
||||
return []string{}
|
||||
}
|
||||
for _, curVal := range curVals {
|
||||
nCurVal := casefold.String(curVal)
|
||||
keep := true
|
||||
for _, del := range delVals {
|
||||
if nCurVal == casefold.String(del) {
|
||||
keep = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if keep {
|
||||
newVals = append(newVals, curVal)
|
||||
}
|
||||
}
|
||||
return newVals
|
||||
}
|
||||
|
||||
func EntryFromAddRequest(add *ldap.AddRequest) *ldap.Entry {
|
||||
attrs := map[string][]string{}
|
||||
|
||||
for _, a := range add.Attributes {
|
||||
attrs[a.Type] = a.Vals
|
||||
}
|
||||
return ldap.NewEntry(add.DN, attrs)
|
||||
}
|
||||
Reference in New Issue
Block a user