Implement Modify
This commit is contained in:
parent
f9cb0552be
commit
7e4079b3d8
1 changed files with 190 additions and 1 deletions
191
main.go
191
main.go
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue