44 "context"
55 "errors"
66 "fmt"
7+ "slices"
78 "time"
89
910 "github.com/go-ldap/ldap/v3"
@@ -49,10 +50,9 @@ const (
4950)
5051
5152var (
52- errNotSet = errors .New ("attribute not set" )
53- errSchoolNameExists = errorcode .New (errorcode .NameAlreadyExists , "A school with that name is already present" )
54- errSchoolNumberExists = errorcode .New (errorcode .NameAlreadyExists , "A school with that number is already present" )
55- errSchoolExternalIdExists = errorcode .New (errorcode .NameAlreadyExists , "A school with that external id is already present" )
53+ errNotSet = errors .New ("attribute not set" )
54+ errSchoolNameExists = errorcode .New (errorcode .NameAlreadyExists , "A school with that name is already present" )
55+ errSchoolNumberExists = errorcode .New (errorcode .NameAlreadyExists , "A school with that number is already present" )
5656)
5757
5858func defaultEducationConfig () educationConfig {
@@ -136,21 +136,6 @@ func (i *LDAP) CreateEducationSchool(ctx context.Context, school libregraph.Educ
136136 }
137137 }
138138
139- // Check that the school external id is not already used
140- if school .HasExternalId () {
141- _ , err := i .getSchoolByExternalId (school .GetExternalId ())
142- switch {
143- case err == nil :
144- logger .Debug ().Err (errSchoolExternalIdExists ).Str ("externalId" , school .GetExternalId ()).Msg ("duplicate school external id" )
145- return nil , errSchoolExternalIdExists
146- case errors .Is (err , ErrNotFound ):
147- break
148- default :
149- logger .Error ().Err (err ).Str ("externalId" , school .GetExternalId ()).Msg ("error looking up school by external id" )
150- return nil , errorcode .New (errorcode .GeneralException , "error looking up school by external id" )
151- }
152- }
153-
154139 attributeTypeAndValue := ldap.AttributeTypeAndValue {
155140 Type : i .educationConfig .schoolAttributeMap .displayName ,
156141 Value : school .GetDisplayName (),
@@ -299,14 +284,14 @@ func (i *LDAP) updateSchoolProperties(ctx context.Context, dn string, currentSch
299284}
300285
301286// UpdateEducationSchool updates the supplied school in the identity backend
302- func (i * LDAP ) UpdateEducationSchool (ctx context.Context , numberOrIDOrExternalID string , school libregraph.EducationSchool ) (* libregraph.EducationSchool , error ) {
287+ func (i * LDAP ) UpdateEducationSchool (ctx context.Context , numberOrID string , school libregraph.EducationSchool ) (* libregraph.EducationSchool , error ) {
303288 logger := i .logger .SubloggerWithRequestID (ctx )
304289 logger .Debug ().Str ("backend" , "ldap" ).Msg ("UpdateEducationSchool" )
305290 if ! i .writeEnabled {
306291 return nil , ErrReadOnly
307292 }
308293
309- e , err := i .getSchoolByNumberOrIDOrExternalID ( numberOrIDOrExternalID )
294+ e , err := i .getSchoolByNumberOrID ( numberOrID )
310295 if err != nil {
311296 return nil , err
312297 }
@@ -329,7 +314,7 @@ func (i *LDAP) UpdateEducationSchool(ctx context.Context, numberOrIDOrExternalID
329314 }
330315
331316 // Read back school from LDAP
332- e , err = i .getSchoolByNumberOrIDOrExternalID (i .getID (e ))
317+ e , err = i .getSchoolByNumberOrID (i .getID (e ))
333318 if err != nil {
334319 return nil , err
335320 }
@@ -343,7 +328,7 @@ func (i *LDAP) DeleteEducationSchool(ctx context.Context, id string) error {
343328 if ! i .writeEnabled {
344329 return ErrReadOnly
345330 }
346- e , err := i .getSchoolByNumberOrIDOrExternalID (id )
331+ e , err := i .getSchoolByNumberOrID (id )
347332 if err != nil {
348333 return err
349334 }
@@ -358,10 +343,10 @@ func (i *LDAP) DeleteEducationSchool(ctx context.Context, id string) error {
358343}
359344
360345// GetEducationSchool implements the EducationBackend interface for the LDAP backend.
361- func (i * LDAP ) GetEducationSchool (ctx context.Context , numberOrIDOrExternalID string ) (* libregraph.EducationSchool , error ) {
346+ func (i * LDAP ) GetEducationSchool (ctx context.Context , numberOrID string ) (* libregraph.EducationSchool , error ) {
362347 logger := i .logger .SubloggerWithRequestID (ctx )
363348 logger .Debug ().Str ("backend" , "ldap" ).Msg ("GetEducationSchool" )
364- e , err := i .getSchoolByNumberOrIDOrExternalID ( numberOrIDOrExternalID )
349+ e , err := i .getSchoolByNumberOrID ( numberOrID )
365350 if err != nil {
366351 return nil , err
367352 }
@@ -371,13 +356,36 @@ func (i *LDAP) GetEducationSchool(ctx context.Context, numberOrIDOrExternalID st
371356
372357// GetEducationSchools implements the EducationBackend interface for the LDAP backend.
373358func (i * LDAP ) GetEducationSchools (ctx context.Context ) ([]* libregraph.EducationSchool , error ) {
374- var filter string
375- filter = fmt .Sprintf ("(objectClass=%s)" , i .educationConfig .schoolObjectClass )
376-
359+ filter := fmt .Sprintf ("(objectClass=%s)" , i .educationConfig .schoolObjectClass )
377360 if i .educationConfig .schoolFilter != "" {
378361 filter = fmt .Sprintf ("(&%s%s)" , i .educationConfig .schoolFilter , filter )
379362 }
363+ return i .searchEducationSchools (ctx , filter )
364+ }
365+
366+ // FilterEducationSchoolsByAttribute implements the EducationBackend interface for the LDAP backend.
367+ func (i * LDAP ) FilterEducationSchoolsByAttribute (ctx context.Context , attr , value string ) ([]* libregraph.EducationSchool , error ) {
368+ logger := i .logger .SubloggerWithRequestID (ctx ).With ().Str ("func" , "FilterEducationSchoolsByAttribute" ).Logger ()
369+ logger .Debug ().Str ("backend" , "ldap" ).Str ("attribute" , attr ).Str ("value" , value ).Msg ("" )
370+
371+ var ldapAttr string
372+ switch attr {
373+ case "externalId" :
374+ ldapAttr = i .educationConfig .schoolAttributeMap .externalId
375+ default :
376+ return nil , errorcode .New (errorcode .InvalidRequest , fmt .Sprintf ("filtering by attribute '%s' is not supported" , attr ))
377+ }
378+ filter := fmt .Sprintf ("(&%s(objectClass=%s)(%s=%s))" ,
379+ i .educationConfig .schoolFilter ,
380+ i .educationConfig .schoolObjectClass ,
381+ ldap .EscapeFilter (ldapAttr ),
382+ ldap .EscapeFilter (value ),
383+ )
384+ return i .searchEducationSchools (ctx , filter )
385+ }
380386
387+ // searchEducationSchools builds and executes an LDAP search for education schools and converts the results to EducationSchool models.
388+ func (i * LDAP ) searchEducationSchools (ctx context.Context , filter string ) ([]* libregraph.EducationSchool , error ) {
381389 searchRequest := ldap .NewSearchRequest (
382390 i .educationConfig .schoolBaseDN ,
383391 i .educationConfig .schoolScope ,
@@ -386,13 +394,15 @@ func (i *LDAP) GetEducationSchools(ctx context.Context) ([]*libregraph.Education
386394 i .getEducationSchoolAttrTypes (),
387395 nil ,
388396 )
389- i .logger .Debug ().Str ("backend" , "ldap" ).
397+ logger := i .logger .SubloggerWithRequestID (ctx )
398+ logger .Debug ().Str ("backend" , "ldap" ).
390399 Str ("base" , searchRequest .BaseDN ).
391400 Str ("filter" , searchRequest .Filter ).
392401 Int ("scope" , searchRequest .Scope ).
393402 Int ("sizelimit" , searchRequest .SizeLimit ).
394403 Interface ("attributes" , searchRequest .Attributes ).
395- Msg ("GetEducationSchools" )
404+ Msg ("searchEducationSchools" )
405+
396406 res , err := i .conn .Search (searchRequest )
397407 if err != nil {
398408 return nil , errorcode .New (errorcode .ItemNotFound , err .Error ())
@@ -436,11 +446,11 @@ func (i *LDAP) GetEducationSchoolUsers(ctx context.Context, schoolNumberOrID str
436446}
437447
438448// AddUsersToEducationSchool adds new members (reference by a slice of IDs) to supplied school in the identity backend.
439- func (i * LDAP ) AddUsersToEducationSchool (ctx context.Context , schoolNumberOrIDOrExternalID string , memberIDs []string ) error {
449+ func (i * LDAP ) AddUsersToEducationSchool (ctx context.Context , schoolNumberOrID string , memberIDs []string ) error {
440450 logger := i .logger .SubloggerWithRequestID (ctx )
441451 logger .Debug ().Str ("backend" , "ldap" ).Msg ("AddUsersToEducationSchool" )
442452
443- schoolEntry , err := i .getSchoolByNumberOrIDOrExternalID ( schoolNumberOrIDOrExternalID )
453+ schoolEntry , err := i .getSchoolByNumberOrID ( schoolNumberOrID )
444454 if err != nil {
445455 return err
446456 }
@@ -462,32 +472,31 @@ func (i *LDAP) AddUsersToEducationSchool(ctx context.Context, schoolNumberOrIDOr
462472 }
463473
464474 for _ , userEntry := range userEntries {
465- currentSchools := userEntry .GetEqualFoldAttributeValues (i .educationConfig .memberOfSchoolAttribute )
466- found := false
467- for _ , currentSchool := range currentSchools {
468- if currentSchool == schoolID {
469- found = true
470- break
471- }
472- }
473- if ! found {
474- mr := ldap.ModifyRequest {DN : userEntry .DN }
475- mr .Add (i .educationConfig .memberOfSchoolAttribute , []string {schoolID })
476- if err := i .conn .Modify (& mr ); err != nil {
477- return err
478- }
475+ if err := i .addEntryToSchool (userEntry , schoolID ); err != nil {
476+ return err
479477 }
480478 }
481479
482480 return nil
483481}
484482
483+ // addEntryToSchool adds the schoolID to the entry's memberOfSchool attribute if not already present.
484+ func (i * LDAP ) addEntryToSchool (entry * ldap.Entry , schoolID string ) error {
485+ currentSchools := entry .GetEqualFoldAttributeValues (i .educationConfig .memberOfSchoolAttribute )
486+ if slices .Contains (currentSchools , schoolID ) {
487+ return nil
488+ }
489+ mr := ldap.ModifyRequest {DN : entry .DN }
490+ mr .Add (i .educationConfig .memberOfSchoolAttribute , []string {schoolID })
491+ return i .conn .Modify (& mr )
492+ }
493+
485494// RemoveUserFromEducationSchool removes a single member (by ID) from a school
486- func (i * LDAP ) RemoveUserFromEducationSchool (ctx context.Context , schoolNumberOrIDOrExternalID string , memberID string ) error {
495+ func (i * LDAP ) RemoveUserFromEducationSchool (ctx context.Context , schoolNumberOrID string , memberID string ) error {
487496 logger := i .logger .SubloggerWithRequestID (ctx )
488497 logger .Debug ().Str ("backend" , "ldap" ).Msg ("RemoveUserFromEducationSchool" )
489498
490- schoolEntry , err := i .getSchoolByNumberOrIDOrExternalID ( schoolNumberOrIDOrExternalID )
499+ schoolEntry , err := i .getSchoolByNumberOrID ( schoolNumberOrID )
491500 if err != nil {
492501 return err
493502 }
@@ -542,12 +551,12 @@ func (i *LDAP) GetEducationSchoolClasses(ctx context.Context, schoolNumberOrID s
542551}
543552
544553func (i * LDAP ) getEducationSchoolEntries (
545- schoolNumberOrIDOrExternalID , filter , objectClass , baseDN string ,
554+ schoolNumberOrID , filter , objectClass , baseDN string ,
546555 scope int ,
547556 attributes []string ,
548557 logger log.Logger ,
549558) ([]* ldap.Entry , error ) {
550- schoolEntry , err := i .getSchoolByNumberOrIDOrExternalID ( schoolNumberOrIDOrExternalID )
559+ schoolEntry , err := i .getSchoolByNumberOrID ( schoolNumberOrID )
551560 if err != nil {
552561 return nil , err
553562 }
@@ -584,11 +593,11 @@ func (i *LDAP) getEducationSchoolEntries(
584593}
585594
586595// AddClassesToEducationSchool adds new members (reference by a slice of IDs) to supplied school in the identity backend.
587- func (i * LDAP ) AddClassesToEducationSchool (ctx context.Context , schoolNumberOrIDOrExternalID string , memberIDs []string ) error {
596+ func (i * LDAP ) AddClassesToEducationSchool (ctx context.Context , schoolNumberOrID string , memberIDs []string ) error {
588597 logger := i .logger .SubloggerWithRequestID (ctx )
589598 logger .Debug ().Str ("backend" , "ldap" ).Msg ("AddClassesToEducationSchool" )
590599
591- schoolEntry , err := i .getSchoolByNumberOrIDOrExternalID ( schoolNumberOrIDOrExternalID )
600+ schoolEntry , err := i .getSchoolByNumberOrID ( schoolNumberOrID )
592601 if err != nil {
593602 return err
594603 }
@@ -610,32 +619,20 @@ func (i *LDAP) AddClassesToEducationSchool(ctx context.Context, schoolNumberOrID
610619 }
611620
612621 for _ , classEntry := range classEntries {
613- currentSchools := classEntry .GetEqualFoldAttributeValues (i .educationConfig .memberOfSchoolAttribute )
614- found := false
615- for _ , currentSchool := range currentSchools {
616- if currentSchool == schoolID {
617- found = true
618- break
619- }
620- }
621- if ! found {
622- mr := ldap.ModifyRequest {DN : classEntry .DN }
623- mr .Add (i .educationConfig .memberOfSchoolAttribute , []string {schoolID })
624- if err := i .conn .Modify (& mr ); err != nil {
625- return err
626- }
622+ if err := i .addEntryToSchool (classEntry , schoolID ); err != nil {
623+ return err
627624 }
628625 }
629626
630627 return nil
631628}
632629
633630// RemoveClassFromEducationSchool removes a single member (by ID) from a school
634- func (i * LDAP ) RemoveClassFromEducationSchool (ctx context.Context , schoolNumberOrIDOrExternalID string , memberID string ) error {
631+ func (i * LDAP ) RemoveClassFromEducationSchool (ctx context.Context , schoolNumberOrID string , memberID string ) error {
635632 logger := i .logger .SubloggerWithRequestID (ctx )
636633 logger .Debug ().Str ("backend" , "ldap" ).Msg ("RemoveClassFromEducationSchool" )
637634
638- schoolEntry , err := i .getSchoolByNumberOrIDOrExternalID ( schoolNumberOrIDOrExternalID )
635+ schoolEntry , err := i .getSchoolByNumberOrID ( schoolNumberOrID )
639636 if err != nil {
640637 return err
641638 }
@@ -673,16 +670,14 @@ func (i *LDAP) getSchoolByDN(dn string) (*ldap.Entry, error) {
673670 return i .getEntryByDN (dn , i .getEducationSchoolAttrTypes (), filter )
674671}
675672
676- func (i * LDAP ) getSchoolByNumberOrIDOrExternalID ( numberOrIDOrExternalID string ) (* ldap.Entry , error ) {
677- numberOrIDOrExternalID = ldap .EscapeFilter (numberOrIDOrExternalID )
673+ func (i * LDAP ) getSchoolByNumberOrID ( numberOrID string ) (* ldap.Entry , error ) {
674+ numberOrID = ldap .EscapeFilter (numberOrID )
678675 filter := fmt .Sprintf (
679- "(|(%s=%s)(%s=%s)(%s=%s) )" ,
676+ "(|(%s=%s)(%s=%s))" ,
680677 i .educationConfig .schoolAttributeMap .id ,
681- numberOrIDOrExternalID ,
678+ numberOrID ,
682679 i .educationConfig .schoolAttributeMap .schoolNumber ,
683- numberOrIDOrExternalID ,
684- i .educationConfig .schoolAttributeMap .externalId ,
685- numberOrIDOrExternalID ,
680+ numberOrID ,
686681 )
687682 return i .getSchoolByFilter (filter )
688683}
@@ -697,16 +692,6 @@ func (i *LDAP) getSchoolByNumber(schoolNumber string) (*ldap.Entry, error) {
697692 return i .getSchoolByFilter (filter )
698693}
699694
700- func (i * LDAP ) getSchoolByExternalId (schoolExternalId string ) (* ldap.Entry , error ) {
701- schoolExternalId = ldap .EscapeFilter (schoolExternalId )
702- filter := fmt .Sprintf (
703- "(%s=%s)" ,
704- i .educationConfig .schoolAttributeMap .externalId ,
705- schoolExternalId ,
706- )
707- return i .getSchoolByFilter (filter )
708- }
709-
710695func (i * LDAP ) getSchoolByFilter (filter string ) (* ldap.Entry , error ) {
711696 filter = fmt .Sprintf ("(&%s(objectClass=%s)%s)" ,
712697 i .educationConfig .schoolFilter ,
@@ -820,6 +805,7 @@ func (i *LDAP) getEducationSchoolAttrTypes() []string {
820805 return []string {
821806 i .educationConfig .schoolAttributeMap .displayName ,
822807 i .educationConfig .schoolAttributeMap .id ,
808+ i .educationConfig .schoolAttributeMap .externalId ,
823809 i .educationConfig .schoolAttributeMap .schoolNumber ,
824810 i .educationConfig .schoolAttributeMap .terminationDate ,
825811 }
0 commit comments