A cloud-native LDAP server backed by a Consul datastore
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.7 KiB

package main
import (
"sort"
)
func (server *Server) memberOfAdd(member string, group string) {
// Retreive previous memberOf value
memberGroups, err := server.getAttribute(member, ATTR_MEMBEROF)
if err != nil {
server.logger.Warnf("Could not add %s to memberOf of %s: %s", group, member, err)
return
}
// Return early if group is already in memberOf
for _, g := range memberGroups {
if g == group {
server.logger.Warnf("Inconsistency detected, %s was memberOf %s at a time when it didn't exist! (not an issue anymore)",
member, group)
return
}
}
// Add group to memberOf
memberGroups = append(memberGroups, group)
err = server.putAttributes(member, Entry{
ATTR_MEMBEROF: memberGroups,
})
if err != nil {
server.logger.Warnf("Could not add %s to memberOf of %s: %s", group, member, err)
}
}
func (server *Server) memberOfRemove(member string, group string) {
// Retreive previous memberOf value
memberOf, err := server.getAttribute(member, ATTR_MEMBEROF)
if err != nil || memberOf == nil {
server.logger.Warnf("Could not remove %s from memberOf of %s: %s", group, member, err)
return
}
// Filter out group
newMemberOf := []string{}
for _, g := range memberOf {
if g != group {
newMemberOf = append(newMemberOf, g)
}
}
// Return early if group already not in memberOf
if len(newMemberOf) == len(memberOf) {
server.logger.Warnf("Inconsistency detected, %s was not memberOf %s at a time when it should have been! (not an issue anymore)",
member, group)
return
}
// Update value of memberOf
err = server.putAttributes(member, Entry{
ATTR_MEMBEROF: newMemberOf,
})
if err != nil {
server.logger.Warnf("Could not remove %s from memberOf of %s: %s", group, member, err)
}
}
func (server *Server) memberOfResync() error {
server.logger.Warnf("Starting resync of member/memberOf values")
// Load the whole LDAP database
basePath, err := dnToConsul(server.config.Suffix)
if err != nil {
return err
}
data, _, err := server.kv.List(basePath, &server.readOpts)
if err != nil {
return err
}
entries, err := parseConsulResult(data)
if err != nil {
return err
}
// Check member values for all objects, and remove deleted objects
// Calculate new memberOf sets for all objects
newMemberOf := make(map[string][]string)
for dn := range entries {
newMemberOf[dn] = []string{}
}
for dn, entry := range entries {
member, ok := entry[ATTR_MEMBER]
if !ok {
continue
}
keepMember := []string{}
for _, mem := range member {
if _, exists := entries[mem]; exists {
keepMember = append(keepMember, mem)
newMemberOf[mem] = append(newMemberOf[mem], dn)
} else {
server.logger.Warnf("Fixing: %s had as member %s which doesn't exist", dn, mem)
}
}
if len(keepMember) != len(member) {
server.logger.Warnf("Writing new member list for %s", dn)
err = server.putAttributes(dn, Entry{
ATTR_MEMBER: keepMember,
})
if err != nil {
return err
}
}
}
// Write updated memberOf values
for dn, newMemberOfV := range newMemberOf {
prevMemberOf := []string{}
if v, ok := entries[dn][ATTR_MEMBEROF]; ok {
prevMemberOf = v
}
different := (len(prevMemberOf) != len(newMemberOfV))
if !different {
sort.Strings(newMemberOfV)
sort.Strings(prevMemberOf)
for i := range newMemberOfV {
if newMemberOfV[i] != prevMemberOf[i] {
different = true
break
}
}
}
if different {
server.logger.Warnf("Fixing memberOf for %s (%d -> %d)",
dn, len(prevMemberOf), len(newMemberOfV))
err = server.putAttributes(dn, Entry{
ATTR_MEMBEROF: newMemberOfV,
})
if err != nil {
return err
}
}
}
server.logger.Warnf("Done resyncing member/memberOf values")
return nil
}