Remove code duplication for ldap entry membership.

This commit is contained in:
Daniel Swärd
2023-02-09 11:38:50 +01:00
parent 8e1a65fc29
commit 399e05b256
6 changed files with 75 additions and 81 deletions

View File

@@ -6,6 +6,7 @@ import (
"github.com/CiscoM31/godata"
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/go-ldap/ldap/v3"
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
)
@@ -40,6 +41,8 @@ type Backend interface {
AddMembersToGroup(ctx context.Context, groupID string, memberID []string) error
// RemoveMemberFromGroup removes a single member (by ID) from a group
RemoveMemberFromGroup(ctx context.Context, groupID string, memberID string) error
// RemoveEntryByDNAndAttributeFromEntry creates a request to remove a single member entry by attribute and DN from an ldap entry
RemoveEntryByDNAndAttributeFromEntry(entry *ldap.Entry, dn string, attribute string) (*ldap.ModifyRequest, error)
}
// EducationBackend defines the Interface for an EducationBackend implementation

View File

@@ -9,6 +9,7 @@ import (
cs3user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
"github.com/cs3org/reva/v2/pkg/rgrpc/todo/pool"
"github.com/go-ldap/ldap/v3"
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
@@ -207,6 +208,11 @@ func (i *CS3) RemoveMemberFromGroup(ctx context.Context, groupID string, memberI
return errorcode.New(errorcode.NotSupported, "not implemented")
}
// RemoveEntryByDNAndAttributeFromEntry implements the Backend Interface. It's currently not supported for the CS3 backend
func (i *CS3) RemoveEntryByDNAndAttributeFromEntry(entry *ldap.Entry, dn string, attribute string) (*ldap.ModifyRequest, error) {
return nil, errorcode.New(errorcode.NotSupported, "not implemented")
}
func createGroupModelFromCS3(g *cs3group.Group) *libregraph.Group {
if g.Id == nil {
g.Id = &cs3group.GroupId{}

View File

@@ -8,6 +8,7 @@ import (
"github.com/CiscoM31/godata"
"github.com/go-ldap/ldap/v3"
"github.com/gofrs/uuid"
"github.com/libregraph/idm/pkg/ldapdn"
libregraph "github.com/owncloud/libre-graph-api-go"
oldap "github.com/owncloud/ocis/v2/ocis-pkg/ldap"
"github.com/owncloud/ocis/v2/ocis-pkg/log"
@@ -179,7 +180,7 @@ func (i *LDAP) DeleteUser(ctx context.Context, nameOrID string) error {
for _, group := range groupEntries {
logger.Debug().Str("group", group.DN).Str("user", e.DN).Msg("Cleaning up group membership")
if mr, err := i.removeMemberFromGroupEntry(group, e.DN); err == nil {
if mr, err := i.RemoveEntryByDNAndAttributeFromEntry(group, e.DN, i.groupAttributeMap.member); err == nil {
if err = i.conn.Modify(mr); err != nil {
// Errors when deleting the memberships are only logged as warnings but not returned
// to the user as we already successfully deleted the users itself
@@ -608,3 +609,40 @@ func stringToScope(scope string) (int, error) {
}
return s, nil
}
// RemoveEntryByDNAndAttributeFromEntry creates a request to remove a single member entry by attribute and DN from an ldap entry
func (i *LDAP) RemoveEntryByDNAndAttributeFromEntry(entry *ldap.Entry, dn string, attribute string) (*ldap.ModifyRequest, error) {
nOldDN, err := ldapdn.ParseNormalize(dn)
if err != nil {
return nil, err
}
entries := entry.GetEqualFoldAttributeValues(attribute)
found := false
for _, entry := range entries {
if entry == "" {
continue
}
if nEntry, err := ldapdn.ParseNormalize(entry); err != nil {
// We couldn't parse the entry value as a DN. Let's keep it
// as it is but log a warning
i.logger.Warn().Str("entryDN", entry).Err(err).Msg("Couldn't parse DN")
continue
} else {
if nEntry == nOldDN {
found = true
}
}
}
if !found {
i.logger.Debug().Str("backend", "ldap").Str("entry", entry.DN).Str("target", dn).
Msg("The target is not an entry in the attribute list")
return nil, ErrNotFound
}
mr := ldap.ModifyRequest{DN: entry.DN}
if len(entries) == 1 {
mr.Add(attribute, []string{""})
}
mr.Delete(attribute, []string{dn})
return &mr, nil
}

View File

@@ -467,48 +467,9 @@ func (i *LDAP) RemoveTeacherFromEducationClass(ctx context.Context, classID stri
return err
}
if mr, err := i.removeTeacherFromClassEntry(class, teacher.DN); err == nil {
if mr, err := i.RemoveEntryByDNAndAttributeFromEntry(class, teacher.DN, i.educationConfig.classAttributeMap.teachers); err == nil {
return i.conn.Modify(mr)
}
return nil
}
// removeTeacherFromClassEntry creates an LDAP Modify request (not sending it)
// that would update the supplied entry to remove the specified teacher from the
// class
func (i *LDAP) removeTeacherFromClassEntry(class *ldap.Entry, teacherDN string) (*ldap.ModifyRequest, error) {
nOldTeacherDN, err := ldapdn.ParseNormalize(teacherDN)
if err != nil {
return nil, err
}
teachers := class.GetEqualFoldAttributeValues(i.educationConfig.classAttributeMap.teachers)
found := false
for _, teacher := range teachers {
if teacher == "" {
continue
}
if nTeacher, err := ldapdn.ParseNormalize(teacher); err != nil {
// We couldn't parse the teacher value as a DN. Let's keep it
// as it is but log a warning
i.logger.Warn().Str("teacherDN", teacher).Err(err).Msg("Couldn't parse DN")
continue
} else {
if nTeacher == nOldTeacherDN {
found = true
}
}
}
if !found {
i.logger.Debug().Str("backend", "ldap").Str("groupdn", class.DN).Str("teacher", teacherDN).
Msg("The target is not a teacher of the class")
return nil, ErrNotFound
}
mr := ldap.ModifyRequest{DN: class.DN}
if len(teachers) == 1 {
mr.Add(i.educationConfig.classAttributeMap.teachers, []string{""})
}
mr.Delete(i.educationConfig.classAttributeMap.teachers, []string{teacherDN})
return &mr, nil
}

View File

@@ -279,7 +279,7 @@ func (i *LDAP) RemoveMemberFromGroup(ctx context.Context, groupID string, member
}
logger.Debug().Str("backend", "ldap").Str("groupdn", ge.DN).Str("member", me.DN).Msg("remove member")
if mr, err := i.removeMemberFromGroupEntry(ge, me.DN); err == nil {
if mr, err := i.RemoveEntryByDNAndAttributeFromEntry(ge, me.DN, i.groupAttributeMap.member); err == nil {
return i.conn.Modify(mr)
}
return nil
@@ -413,45 +413,6 @@ func (i *LDAP) getLDAPGroupsByFilter(filter string, requestMembers, single bool)
return res.Entries, nil
}
// removeMemberFromGroupEntry creates an LDAP Modify request (not sending it)
// that would update the supplied entry to remove the specified member from the
// group
func (i *LDAP) removeMemberFromGroupEntry(group *ldap.Entry, memberDN string) (*ldap.ModifyRequest, error) {
nOldMemberDN, err := ldapdn.ParseNormalize(memberDN)
if err != nil {
return nil, err
}
members := group.GetEqualFoldAttributeValues(i.groupAttributeMap.member)
found := false
for _, member := range members {
if member == "" {
continue
}
if nMember, err := ldapdn.ParseNormalize(member); err != nil {
// We couldn't parse the member value as a DN. Let's keep it
// as it is but log a warning
i.logger.Warn().Str("memberDN", member).Err(err).Msg("Couldn't parse DN")
continue
} else {
if nMember == nOldMemberDN {
found = true
}
}
}
if !found {
i.logger.Debug().Str("backend", "ldap").Str("groupdn", group.DN).Str("member", memberDN).
Msg("The target is not a member of the group")
return nil, ErrNotFound
}
mr := ldap.ModifyRequest{DN: group.DN}
if len(members) == 1 {
mr.Add(i.groupAttributeMap.member, []string{""})
}
mr.Delete(i.groupAttributeMap.member, []string{memberDN})
return &mr, nil
}
func (i *LDAP) getGroupByDN(dn string) (*ldap.Entry, error) {
attrs := []string{
i.groupAttributeMap.id,

View File

@@ -7,6 +7,8 @@ import (
godata "github.com/CiscoM31/godata"
ldap "github.com/go-ldap/ldap/v3"
libregraph "github.com/owncloud/libre-graph-api-go"
mock "github.com/stretchr/testify/mock"
@@ -222,6 +224,29 @@ func (_m *Backend) GetUsers(ctx context.Context, oreq *godata.GoDataRequest) ([]
return r0, r1
}
// RemoveEntryByDNAndAttributeFromEntry provides a mock function with given fields: entry, dn, attribute
func (_m *Backend) RemoveEntryByDNAndAttributeFromEntry(entry *ldap.Entry, dn string, attribute string) (*ldap.ModifyRequest, error) {
ret := _m.Called(entry, dn, attribute)
var r0 *ldap.ModifyRequest
if rf, ok := ret.Get(0).(func(*ldap.Entry, string, string) *ldap.ModifyRequest); ok {
r0 = rf(entry, dn, attribute)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*ldap.ModifyRequest)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(*ldap.Entry, string, string) error); ok {
r1 = rf(entry, dn, attribute)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// RemoveMemberFromGroup provides a mock function with given fields: ctx, groupID, memberID
func (_m *Backend) RemoveMemberFromGroup(ctx context.Context, groupID string, memberID string) error {
ret := _m.Called(ctx, groupID, memberID)