Implement LDAP backend for CreateSchool

This commit is contained in:
Ralf Haferkamp
2022-12-14 12:16:33 +01:00
committed by Ralf Haferkamp
parent b302af88f6
commit ad1355d032
3 changed files with 148 additions and 2 deletions

View File

@@ -2,12 +2,16 @@ package identity
import (
"context"
"errors"
"fmt"
"net/url"
"github.com/go-ldap/ldap/v3"
"github.com/gofrs/uuid"
libregraph "github.com/owncloud/libre-graph-api-go"
oldap "github.com/owncloud/ocis/v2/ocis-pkg/ldap"
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
"github.com/owncloud/ocis/v2/services/graph/pkg/service/v0/errorcode"
)
type educationConfig struct {
@@ -57,7 +61,43 @@ func newSchoolAttributeMap() schoolAttributeMap {
// CreateSchool creates the supplied school in the identity backend.
func (i *LDAP) CreateSchool(ctx context.Context, school libregraph.EducationSchool) (*libregraph.EducationSchool, error) {
return nil, errNotImplemented
logger := i.logger.SubloggerWithRequestID(ctx)
logger.Debug().Str("backend", "ldap").Msg("CreateSchool")
if !i.writeEnabled {
return nil, errReadOnly
}
dn := fmt.Sprintf("%s=%s,%s",
i.educationConfig.schoolAttributeMap.displayName,
oldap.EscapeDNAttributeValue(school.GetDisplayName()),
i.educationConfig.schoolBaseDN,
)
ar := ldap.NewAddRequest(dn, nil)
ar.Attribute(i.educationConfig.schoolAttributeMap.displayName, []string{school.GetDisplayName()})
ar.Attribute(i.educationConfig.schoolAttributeMap.schoolNumber, []string{school.GetSchoolNumber()})
if !i.useServerUUID {
ar.Attribute(i.educationConfig.schoolAttributeMap.id, []string{uuid.Must(uuid.NewV4()).String()})
}
objectClasses := []string{"organizationalUnit", i.educationConfig.schoolObjectClass, "top"}
ar.Attribute("objectClass", objectClasses)
if err := i.conn.Add(ar); err != nil {
var lerr *ldap.Error
logger.Debug().Err(err).Msg("error adding school")
if errors.As(err, &lerr) {
if lerr.ResultCode == ldap.LDAPResultEntryAlreadyExists {
err = errorcode.New(errorcode.NameAlreadyExists, lerr.Error())
}
}
return nil, err
}
// Read back school from LDAP to get the generated UUID
e, err := i.getSchoolByDN(ar.DN)
if err != nil {
return nil, err
}
return i.createSchoolModelFromLDAP(e), nil
}
// DeleteSchool deletes a given school, identified by id
@@ -89,3 +129,37 @@ func (i *LDAP) AddMembersToSchool(ctx context.Context, schoolID string, memberID
func (i *LDAP) RemoveMemberFromSchool(ctx context.Context, schoolID string, memberID string) error {
return errNotImplemented
}
func (i *LDAP) getSchoolByDN(dn string) (*ldap.Entry, error) {
attrs := []string{
i.educationConfig.schoolAttributeMap.displayName,
i.educationConfig.schoolAttributeMap.id,
i.educationConfig.schoolAttributeMap.schoolNumber,
}
filter := fmt.Sprintf("(objectClass=%s)", i.educationConfig.schoolObjectClass)
if i.educationConfig.schoolFilter != "" {
filter = fmt.Sprintf("(&%s(%s))", filter, i.educationConfig.schoolFilter)
}
return i.getEntryByDN(dn, attrs, filter)
}
func (i *LDAP) createSchoolModelFromLDAP(e *ldap.Entry) *libregraph.EducationSchool {
if e == nil {
return nil
}
displayName := e.GetEqualFoldAttributeValue(i.educationConfig.schoolAttributeMap.displayName)
id := e.GetEqualFoldAttributeValue(i.educationConfig.schoolAttributeMap.id)
schoolNumber := e.GetEqualFoldAttributeValue(i.educationConfig.schoolAttributeMap.schoolNumber)
if id != "" && displayName != "" && schoolNumber != "" {
school := libregraph.NewEducationSchool()
school.SetDisplayName(displayName)
school.SetSchoolNumber(schoolNumber)
school.SetId(id)
return school
}
i.logger.Warn().Str("dn", e.DN).Str("id", id).Str("displayName", displayName).Str("schoolNumber", schoolNumber).Msg("Invalid School. Missing required attribute")
return nil
}

View File

@@ -0,0 +1,70 @@
package identity
import (
"context"
"testing"
"github.com/go-ldap/ldap/v3"
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/v2/services/graph/mocks"
"github.com/owncloud/ocis/v2/services/graph/pkg/config"
"github.com/test-go/testify/assert"
"github.com/test-go/testify/mock"
)
var eduConfig = config.LDAP{
UserBaseDN: "ou=people,dc=test",
UserObjectClass: "inetOrgPerson",
UserSearchScope: "sub",
UserFilter: "",
UserDisplayNameAttribute: "displayname",
UserIDAttribute: "entryUUID",
UserEmailAttribute: "mail",
UserNameAttribute: "uid",
GroupBaseDN: "ou=groups,dc=test",
GroupObjectClass: "groupOfNames",
GroupSearchScope: "sub",
GroupFilter: "",
GroupNameAttribute: "cn",
GroupIDAttribute: "entryUUID",
WriteEnabled: true,
EducationResourcesEnabled: true,
}
var schoolEntry = ldap.NewEntry("ou=Test School",
map[string][]string{
"ou": {"Test School"},
"ocEducationSchoolNumber": {"0123"},
"owncloudUUID": {"abcd-defg"},
})
func TestCreateSchool(t *testing.T) {
lm := &mocks.Client{}
lm.On("Add", mock.Anything).
Return(nil)
lm.On("Search", mock.Anything).
Return(
&ldap.SearchResult{
Entries: []*ldap.Entry{schoolEntry},
},
nil)
b, err := getMockedBackend(lm, eduConfig, &logger)
assert.Nil(t, err)
assert.NotEqual(t, "", b.educationConfig.schoolObjectClass)
school := libregraph.NewEducationSchool()
school.SetDisplayName("Test School")
school.SetSchoolNumber("0123")
school.SetId("abcd-defg")
res_school, err := b.CreateSchool(context.Background(), *school)
lm.AssertNumberOfCalls(t, "Add", 1)
lm.AssertNumberOfCalls(t, "Search", 1)
assert.Nil(t, err)
assert.NotNil(t, res_school)
assert.Equal(t, res_school.GetDisplayName(), school.GetDisplayName())
assert.Equal(t, res_school.GetId(), school.GetId())
assert.Equal(t, res_school.GetSchoolNumber(), school.GetSchoolNumber())
}

View File

@@ -14,7 +14,7 @@ import (
)
func getMockedBackend(l ldap.Client, lc config.LDAP, logger *log.Logger) (*LDAP, error) {
return NewLDAPBackend(l, lconfig, logger)
return NewLDAPBackend(l, lc, logger)
}
var lconfig = config.LDAP{
@@ -33,6 +33,8 @@ var lconfig = config.LDAP{
GroupFilter: "",
GroupNameAttribute: "cn",
GroupIDAttribute: "entryUUID",
WriteEnabled: true,
}
var userEntry = ldap.NewEntry("uid=user",