From bc9f81cc2361c535f2a0b9b05a13f9d7804cafa6 Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Wed, 14 Dec 2022 14:51:20 +0100 Subject: [PATCH] LDAP Support for Delete School --- services/graph/pkg/identity/ldap_school.go | 67 ++++++++++++++++++- .../graph/pkg/identity/ldap_school_test.go | 39 +++++++++++ 2 files changed, 105 insertions(+), 1 deletion(-) diff --git a/services/graph/pkg/identity/ldap_school.go b/services/graph/pkg/identity/ldap_school.go index 3d256aa51e..d4fa0e5762 100644 --- a/services/graph/pkg/identity/ldap_school.go +++ b/services/graph/pkg/identity/ldap_school.go @@ -102,7 +102,21 @@ func (i *LDAP) CreateSchool(ctx context.Context, school libregraph.EducationScho // DeleteSchool deletes a given school, identified by id func (i *LDAP) DeleteSchool(ctx context.Context, id string) error { - return errNotImplemented + logger := i.logger.SubloggerWithRequestID(ctx) + logger.Debug().Str("backend", "ldap").Msg("DeleteSchool") + if !i.writeEnabled { + return errReadOnly + } + e, err := i.getSchoolByID(id) + if err != nil { + return err + } + + dr := ldap.DelRequest{DN: e.DN} + if err = i.conn.Del(&dr); err != nil { + return err + } + return nil } // GetSchool implements the EducationBackend interface for the LDAP backend. @@ -144,6 +158,57 @@ func (i *LDAP) getSchoolByDN(dn string) (*ldap.Entry, error) { return i.getEntryByDN(dn, attrs, filter) } +func (i *LDAP) getSchoolByID(id string) (*ldap.Entry, error) { + id = ldap.EscapeFilter(id) + filter := fmt.Sprintf("(%s=%s)", i.educationConfig.schoolAttributeMap.id, id) + return i.getSchoolByFilter(filter) +} + +func (i *LDAP) getSchoolByFilter(filter string) (*ldap.Entry, error) { + filter = fmt.Sprintf("(&%s(objectClass=%s)%s)", + i.educationConfig.schoolFilter, + i.educationConfig.schoolObjectClass, + filter, + ) + searchRequest := ldap.NewSearchRequest( + i.educationConfig.schoolBaseDN, + i.educationConfig.schoolScope, + ldap.NeverDerefAliases, 1, 0, false, + filter, + []string{ + i.educationConfig.schoolAttributeMap.displayName, + i.educationConfig.schoolAttributeMap.id, + i.educationConfig.schoolAttributeMap.schoolNumber, + }, + nil, + ) + i.logger.Debug().Str("backend", "ldap"). + Str("base", searchRequest.BaseDN). + Str("filter", searchRequest.Filter). + Int("scope", searchRequest.Scope). + Int("sizelimit", searchRequest.SizeLimit). + Interface("attributes", searchRequest.Attributes). + Msg("getSchoolByFilter") + res, err := i.conn.Search(searchRequest) + + if err != nil { + var errmsg string + if lerr, ok := err.(*ldap.Error); ok { + if lerr.ResultCode == ldap.LDAPResultSizeLimitExceeded { + errmsg = fmt.Sprintf("too many results searching for school '%s'", filter) + i.logger.Debug().Str("backend", "ldap").Err(lerr). + Str("schoolfilter", filter).Msg("too many results searching for school") + } + } + return nil, errorcode.New(errorcode.ItemNotFound, errmsg) + } + if len(res.Entries) == 0 { + return nil, errNotFound + } + + return res.Entries[0], nil +} + func (i *LDAP) createSchoolModelFromLDAP(e *ldap.Entry) *libregraph.EducationSchool { if e == nil { return nil diff --git a/services/graph/pkg/identity/ldap_school_test.go b/services/graph/pkg/identity/ldap_school_test.go index 0c3853d69a..2fa33907bf 100644 --- a/services/graph/pkg/identity/ldap_school_test.go +++ b/services/graph/pkg/identity/ldap_school_test.go @@ -68,3 +68,42 @@ func TestCreateSchool(t *testing.T) { assert.Equal(t, res_school.GetId(), school.GetId()) assert.Equal(t, res_school.GetSchoolNumber(), school.GetSchoolNumber()) } + +func TestDeleteSchool(t *testing.T) { + lm := &mocks.Client{} + sr1 := &ldap.SearchRequest{ + BaseDN: "", + Scope: 2, + SizeLimit: 1, + Filter: "(&(objectClass=ocEducationSchool)(owncloudUUID=abcd-defg))", + Attributes: []string{"ou", "owncloudUUID", "ocEducationSchoolNumber"}, + Controls: []ldap.Control(nil), + } + sr2 := &ldap.SearchRequest{ + BaseDN: "", + Scope: 2, + SizeLimit: 1, + Filter: "(&(objectClass=ocEducationSchool)(owncloudUUID=xxxx-xxxx))", + Attributes: []string{"ou", "owncloudUUID", "ocEducationSchoolNumber"}, + Controls: []ldap.Control(nil), + } + lm.On("Search", sr1).Return(&ldap.SearchResult{Entries: []*ldap.Entry{schoolEntry}}, nil) + lm.On("Search", sr2).Return(&ldap.SearchResult{Entries: []*ldap.Entry{}}, nil) + dr1 := &ldap.DelRequest{ + DN: "ou=Test School", + } + lm.On("Del", dr1).Return(nil) + b, err := getMockedBackend(lm, eduConfig, &logger) + assert.Nil(t, err) + + err = b.DeleteSchool(context.Background(), "abcd-defg") + lm.AssertNumberOfCalls(t, "Search", 1) + lm.AssertNumberOfCalls(t, "Del", 1) + assert.Nil(t, err) + + err = b.DeleteSchool(context.Background(), "xxxx-xxxx") + lm.AssertNumberOfCalls(t, "Search", 2) + lm.AssertNumberOfCalls(t, "Del", 1) + assert.NotNil(t, err) + assert.Equal(t, "itemNotFound", err.Error()) +}