diff --git a/services/graph/pkg/identity/backend.go b/services/graph/pkg/identity/backend.go index 2a2ccddb4a..d8a295d214 100644 --- a/services/graph/pkg/identity/backend.go +++ b/services/graph/pkg/identity/backend.go @@ -43,6 +43,8 @@ type Backend interface { 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) + // ExpandLDAPAttributeEntries reads an attribute from an ldap entry and expands to users + ExpandLDAPAttributeEntries(ctx context.Context, e *ldap.Entry, attribute string) ([]*ldap.Entry, error) } // EducationBackend defines the Interface for an EducationBackend implementation diff --git a/services/graph/pkg/identity/cs3.go b/services/graph/pkg/identity/cs3.go index e963b2fba2..b6d9f3b9b9 100644 --- a/services/graph/pkg/identity/cs3.go +++ b/services/graph/pkg/identity/cs3.go @@ -213,6 +213,11 @@ func (i *CS3) RemoveEntryByDNAndAttributeFromEntry(entry *ldap.Entry, dn string, return nil, errorcode.New(errorcode.NotSupported, "not implemented") } +// ExpandLDAPAttributeEntries implements the Backend Interface. It's currently not supported for the CS3 backend +func (i *CS3) ExpandLDAPAttributeEntries(ctx context.Context, e *ldap.Entry, attribute string) ([]*ldap.Entry, error) { + return nil, errorcode.New(errorcode.NotSupported, "not implemented") +} + func createGroupModelFromCS3(g *cs3group.Group) *libregraph.Group { if g.Id == nil { g.Id = &cs3group.GroupId{} diff --git a/services/graph/pkg/identity/ldap.go b/services/graph/pkg/identity/ldap.go index 8913e6299e..a18d7a55f1 100644 --- a/services/graph/pkg/identity/ldap.go +++ b/services/graph/pkg/identity/ldap.go @@ -646,3 +646,26 @@ func (i *LDAP) RemoveEntryByDNAndAttributeFromEntry(entry *ldap.Entry, dn string mr.Delete(attribute, []string{dn}) return &mr, nil } + +// ExpandLDAPAttributeEntries reads an attribute from an ldap entry and expands to users +func (i *LDAP) ExpandLDAPAttributeEntries(ctx context.Context, e *ldap.Entry, attribute string) ([]*ldap.Entry, error) { + logger := i.logger.SubloggerWithRequestID(ctx) + logger.Debug().Str("backend", "ldap").Msg("ExpandLDAPAttributeEntries") + result := []*ldap.Entry{} + + for _, entryDN := range e.GetEqualFoldAttributeValues(attribute) { + if entryDN == "" { + continue + } + logger.Debug().Str("entryDN", entryDN).Msg("lookup") + ue, err := i.getUserByDN(entryDN) + if err != nil { + // Ignore errors when reading a specific entry fails, just log them and continue + logger.Debug().Err(err).Str("entry", entryDN).Msg("error reading attribute member entry") + continue + } + result = append(result, ue) + } + + return result, nil +} diff --git a/services/graph/pkg/identity/ldap_education_class.go b/services/graph/pkg/identity/ldap_education_class.go index 8e4bad7f79..677c2ff70a 100644 --- a/services/graph/pkg/identity/ldap_education_class.go +++ b/services/graph/pkg/identity/ldap_education_class.go @@ -228,7 +228,7 @@ func (i *LDAP) GetEducationClassMembers(ctx context.Context, id string) ([]*libr return nil, err } - memberEntries, err := i.expandLDAPGroupMembers(ctx, e) + memberEntries, err := i.ExpandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) result := make([]*libregraph.EducationUser, 0, len(memberEntries)) if err != nil { return nil, err @@ -351,7 +351,7 @@ func (i *LDAP) GetEducationClassTeachers(ctx context.Context, classID string) ([ return nil, err } - teacherEntries, err := i.expandLDAPClassTeachers(ctx, class) + teacherEntries, err := i.ExpandLDAPAttributeEntries(ctx, class, i.educationConfig.classAttributeMap.teachers) result := make([]*libregraph.EducationUser, 0, len(teacherEntries)) if err != nil { return nil, err @@ -366,28 +366,6 @@ func (i *LDAP) GetEducationClassTeachers(ctx context.Context, classID string) ([ } -func (i *LDAP) expandLDAPClassTeachers(ctx context.Context, e *ldap.Entry) ([]*ldap.Entry, error) { - logger := i.logger.SubloggerWithRequestID(ctx) - logger.Debug().Str("backend", "ldap").Msg("expandLDAPClassTeachers") - result := []*ldap.Entry{} - - for _, teacherDN := range e.GetEqualFoldAttributeValues(i.educationConfig.classAttributeMap.teachers) { - if teacherDN == "" { - continue - } - logger.Debug().Str("teacherDN", teacherDN).Msg("lookup") - ue, err := i.getUserByDN(teacherDN) - if err != nil { - // Ignore errors when reading a specific teacher fails, just log them and continue - logger.Debug().Err(err).Str("teacher", teacherDN).Msg("error reading class teacher") - continue - } - result = append(result, ue) - } - - return result, nil -} - // AddTeacherToEducationclass adds a teacher (by ID) to class in the identity backend. func (i *LDAP) AddTeacherToEducationClass(ctx context.Context, classID string, teacherID string) error { logger := i.logger.SubloggerWithRequestID(ctx) diff --git a/services/graph/pkg/identity/ldap_group.go b/services/graph/pkg/identity/ldap_group.go index b572ddd93d..65e2986617 100644 --- a/services/graph/pkg/identity/ldap_group.go +++ b/services/graph/pkg/identity/ldap_group.go @@ -37,7 +37,7 @@ func (i *LDAP) GetGroup(ctx context.Context, nameOrID string, queryParam url.Val return nil, errorcode.New(errorcode.ItemNotFound, "not found") } if slices.Contains(sel, "members") || slices.Contains(exp, "members") { - members, err := i.expandLDAPGroupMembers(ctx, e) + members, err := i.ExpandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) if err != nil { return nil, err } @@ -115,7 +115,7 @@ func (i *LDAP) GetGroups(ctx context.Context, queryParam url.Values) ([]*libregr continue } if expandMembers { - members, err := i.expandLDAPGroupMembers(ctx, e) + members, err := i.ExpandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) if err != nil { return nil, err } @@ -142,7 +142,7 @@ func (i *LDAP) GetGroupMembers(ctx context.Context, groupID string) ([]*libregra return nil, err } - memberEntries, err := i.expandLDAPGroupMembers(ctx, e) + memberEntries, err := i.ExpandLDAPAttributeEntries(ctx, e, i.groupAttributeMap.member) result := make([]*libregraph.User, 0, len(memberEntries)) if err != nil { return nil, err @@ -323,28 +323,6 @@ func (i *LDAP) groupToLDAPAttrValues(group libregraph.Group) (map[string][]strin return attrs, nil } -func (i *LDAP) expandLDAPGroupMembers(ctx context.Context, e *ldap.Entry) ([]*ldap.Entry, error) { - logger := i.logger.SubloggerWithRequestID(ctx) - logger.Debug().Str("backend", "ldap").Msg("expandLDAPGroupMembers") - result := []*ldap.Entry{} - - for _, memberDN := range e.GetEqualFoldAttributeValues(i.groupAttributeMap.member) { - if memberDN == "" { - continue - } - logger.Debug().Str("memberDN", memberDN).Msg("lookup") - ue, err := i.getUserByDN(memberDN) - if err != nil { - // Ignore errors when reading a specific member fails, just log them and continue - logger.Debug().Err(err).Str("member", memberDN).Msg("error reading group member") - continue - } - result = append(result, ue) - } - - return result, nil -} - func (i *LDAP) getLDAPGroupByID(id string, requestMembers bool) (*ldap.Entry, error) { id = ldap.EscapeFilter(id) filter := fmt.Sprintf("(%s=%s)", i.groupAttributeMap.id, id) diff --git a/services/graph/pkg/identity/mocks/backend.go b/services/graph/pkg/identity/mocks/backend.go index 997b5a04fe..595a3db85b 100644 --- a/services/graph/pkg/identity/mocks/backend.go +++ b/services/graph/pkg/identity/mocks/backend.go @@ -109,6 +109,29 @@ func (_m *Backend) DeleteUser(ctx context.Context, nameOrID string) error { return r0 } +// ExpandLDAPAttributeEntries provides a mock function with given fields: ctx, e, attribute +func (_m *Backend) ExpandLDAPAttributeEntries(ctx context.Context, e *ldap.Entry, attribute string) ([]*ldap.Entry, error) { + ret := _m.Called(ctx, e, attribute) + + var r0 []*ldap.Entry + if rf, ok := ret.Get(0).(func(context.Context, *ldap.Entry, string) []*ldap.Entry); ok { + r0 = rf(ctx, e, attribute) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*ldap.Entry) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, *ldap.Entry, string) error); ok { + r1 = rf(ctx, e, attribute) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // GetGroup provides a mock function with given fields: ctx, nameOrID, queryParam func (_m *Backend) GetGroup(ctx context.Context, nameOrID string, queryParam url.Values) (*libregraph.Group, error) { ret := _m.Called(ctx, nameOrID, queryParam)