Implement Modify

This commit is contained in:
Alex 2020-01-19 22:21:05 +01:00
parent f9cb0552be
commit 7e4079b3d8

191
main.go
View file

@ -43,7 +43,7 @@ func consulToDN(pair *consul.KVPair) (string, string, []byte) {
}
dn = cpath + dn
}
return dn, "", nil
panic("Consul key " + pair.Key + " does not end with attribute=something")
}
func parseValue(value []byte) ([]string, error) {
@ -156,6 +156,7 @@ func main() {
routes.Add(gobottin.handleAdd)
routes.Compare(gobottin.handleCompare)
routes.Delete(gobottin.handleDelete)
routes.Modify(gobottin.handleModify)
ldapserver.Handle(routes)
// listen on 10389
@ -686,3 +687,191 @@ func (server *Server) handleDeleteInternal(state *State, r *message.DelRequest)
return ldap.LDAPResultSuccess, nil
}
func (server *Server) handleModify(s ldap.UserState, w ldap.ResponseWriter, m *ldap.Message) {
state := s.(*State)
r := m.GetModifyRequest()
code, err := server.handleModifyInternal(state, &r)
res := ldap.NewResponse(code)
if err != nil {
res.SetDiagnosticMessage(err.Error())
}
w.Write(message.ModifyResponse(res))
}
func (server *Server) handleModifyInternal(state *State, r *message.ModifyRequest) (int, error) {
dn := string(r.Object())
_, err := server.checkSuffix(dn, false)
if err != nil {
return ldap.LDAPResultInvalidDNSyntax, err
}
// TODO check user for permissions to write dn
// Retrieve previous values (by the way, check object exists)
items, _, err := server.kv.List(dnToConsul(dn) + "/attribute=", nil)
if err != nil {
return ldap.LDAPResultOperationsError, err
}
if len(items) == 0 {
return ldap.LDAPResultNoSuchObject, fmt.Errorf("Not found: %s", dn)
}
prevEntry := Entry{}
for _, item := range items {
itemDN, attr, val := consulToDN(item)
if itemDN != dn {
panic("itemDN != dn in handleModifyInternal")
}
vals, err := parseValue(val)
if err != nil {
return ldap.LDAPResultOperationsError, err
}
prevEntry[attr] = vals
}
// Keep track of group members added/deleted
addMembers, delMembers := []string{}, []string{}
// Produce new entry values to be saved
newEntry := Entry{}
for _, change := range r.Changes() {
attr := string(change.Modification().Type_())
values := change.Modification().Vals()
if change.Operation() == ldap.ModifyRequestChangeOperationAdd {
newEntry[attr] = prevEntry[attr]
for _, val := range values {
present := false
for _, prevVal := range newEntry[attr] {
if prevVal == string(val) {
present = true
break
}
}
if !present {
newEntry[attr] = append(newEntry[attr], string(val))
if strings.EqualFold(attr, "member") {
addMembers = append(addMembers, string(val))
}
}
}
} else if change.Operation() == ldap.ModifyRequestChangeOperationDelete {
if len(values) == 0 {
// Delete everything
newEntry[attr] = []string{}
if strings.EqualFold(attr, "member") {
delMembers = append(delMembers, prevEntry[attr]...)
}
} else {
// Delete only those specified
newEntry[attr] = []string{}
for _, prevVal := range prevEntry[attr] {
keep := true
for _, delVal := range values {
if string(delVal) == prevVal {
keep = false
break
}
}
if keep {
newEntry[attr] = append(newEntry[attr], prevVal)
} else {
if strings.EqualFold(attr, "member") {
delMembers = append(delMembers, prevVal)
}
}
}
}
} else if change.Operation() == ldap.ModifyRequestChangeOperationReplace {
newEntry[attr] = []string{}
for _, newVal := range values {
newEntry[attr] = append(newEntry[attr], string(newVal))
}
if strings.EqualFold(attr, "member") {
for _, newMem := range newEntry[attr] {
mustAdd := true
for _, prevMem := range prevEntry[attr] {
if prevMem == newMem {
mustAdd = false
break
}
}
if mustAdd {
addMembers = append(addMembers, newMem)
}
}
for _, prevMem := range prevEntry[attr] {
mustDel := true
for _, newMem := range newEntry[attr] {
if newMem == prevMem {
mustDel = false
break
}
}
if mustDel {
delMembers = append(delMembers, prevMem)
}
}
}
}
}
// Check that added members actually exist
for _, addMem := range addMembers {
exists, err := server.objectExists(addMem)
if err != nil {
return ldap.LDAPResultOperationsError, err
}
if !exists {
return ldap.LDAPResultNoSuchObject, fmt.Errorf(
"Cannot add member %s, it does not exist", addMem)
}
}
// Save the edited values
server.addElements(dn, newEntry)
// Update memberOf for added members and deleted members
for _, addMem := range addMembers {
memberOf, err := server.getAttribute(addMem, "memberOf")
if err != nil {
return ldap.LDAPResultOperationsError, err
}
if memberOf == nil {
memberOf = []string{}
}
memberOf = append(memberOf, dn)
err = server.addElements(addMem, Entry{"memberOf": memberOf})
if err != nil {
return ldap.LDAPResultOperationsError, err
}
}
for _, delMem := range delMembers {
memberOf, err := server.getAttribute(delMem, "memberOf")
if err != nil {
return ldap.LDAPResultOperationsError, err
}
if memberOf == nil {
memberOf = []string{}
}
newMemberOf := []string{}
for _, g := range memberOf {
if g != dn {
newMemberOf = append(newMemberOf, g)
}
}
err = server.addElements(delMem, Entry{"memberOf": newMemberOf})
if err != nil {
return ldap.LDAPResultOperationsError, err
}
}
return ldap.LDAPResultSuccess, nil
}