From b302af88f67e54fd7606be4e7d702871007e76ca Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Tue, 13 Dec 2022 15:49:56 +0100 Subject: [PATCH] Add basic config setting for LDAP education backend require LDAP support for Education resources to be explicitly enabled. Default to a NOOP implementation if disabled. --- services/graph/pkg/config/config.go | 15 ++++ .../pkg/config/defaults/defaultconfig.go | 15 ++-- services/graph/pkg/identity/ldap.go | 8 +++ services/graph/pkg/identity/ldap_school.go | 32 ++++++++- services/graph/pkg/identity/noop_school.go | 71 +++++++++++++++++++ services/graph/pkg/service/v0/service.go | 7 +- 6 files changed, 137 insertions(+), 11 deletions(-) create mode 100644 services/graph/pkg/identity/noop_school.go diff --git a/services/graph/pkg/config/config.go b/services/graph/pkg/config/config.go index 012dd6163a..f3491e38a3 100644 --- a/services/graph/pkg/config/config.go +++ b/services/graph/pkg/config/config.go @@ -62,6 +62,21 @@ type LDAP struct { GroupObjectClass string `yaml:"group_objectclass" env:"LDAP_GROUP_OBJECTCLASS;GRAPH_LDAP_GROUP_OBJECTCLASS" desc:"The object class to use for groups in the default group search filter ('groupOfNames'). "` GroupNameAttribute string `yaml:"group_name_attribute" env:"LDAP_GROUP_SCHEMA_GROUPNAME;GRAPH_LDAP_GROUP_NAME_ATTRIBUTE" desc:"LDAP Attribute to use for the name of groups."` GroupIDAttribute string `yaml:"group_id_attribute" env:"LDAP_GROUP_SCHEMA_ID;GRAPH_LDAP_GROUP_ID_ATTRIBUTE" desc:"LDAP Attribute to use as the unique id for groups. This should be a stable globally unique ID like a UUID."` + + EducationResourcesEnabled bool `yaml:"education_resources_enabled" env:"LDAP_EDUCATION_RESOURCES_ENABLE;GRAPH_LDAP_EDUCATION_RESOURCES_ENABLED" desc:"enable LDAP support for managin education related resources"` + EducationConfig LDAPEducationConfig +} + +// LDAPEducationConfig represents the LDAP configuration for education related resources +type LDAPEducationConfig struct { + SchoolBaseDN string `yaml:"school_base_dn" env:"LDAP_SCHOOL_BASE_DN;GRAPH_LDAP_SCHOOL_BASE_DN" desc:"Search base DN for looking up LDAP schools."` + SchoolSearchScope string `yaml:"school_search_scope" env:"LDAP_SCHOOL_SCOPE;GRAPH_LDAP_SCHOOL_SEARCH_SCOPE" desc:"LDAP search scope to use when looking up schools. Supported scopes are 'base', 'one' and 'sub'."` + + SchoolFilter string `yaml:"school_filter" env:"LDAP_SCHOOL_FILTER;GRAPH_LDAP_SCHOOL_FILTER" desc:"LDAP filter to add to the default filters for school searches."` + SchoolObjectClass string `yaml:"school_objectclass" env:"LDAP_SCHOOL_OBJECTCLASS;GRAPH_LDAP_SCHOOL_OBJECTCLASS" desc:"The object class to use for schools in the default school search filter."` + + SchoolNameAttribute string `yaml:"school_name_attribute" env:"LDAP_SCHOOL_SCHEMA_SCHOOLNAME;GRAPH_LDAP_SCHOOL_NAME_ATTRIBUTE" desc:"LDAP Attribute to use for the name of schools."` + SchoolIDAttribute string `yaml:"school_id_attribute" env:"LDAP_SCHOOL_SCHEMA_ID;GRAPH_LDAP_SCHOOL_ID_ATTRIBUTE" desc:"LDAP Attribute to use as the unique id for schools. This should be a stable globally unique ID like a UUID."` } type Identity struct { diff --git a/services/graph/pkg/config/defaults/defaultconfig.go b/services/graph/pkg/config/defaults/defaultconfig.go index f238f21b21..84c0fc9493 100644 --- a/services/graph/pkg/config/defaults/defaultconfig.go +++ b/services/graph/pkg/config/defaults/defaultconfig.go @@ -55,13 +55,14 @@ func DefaultConfig() *config.Config { UserNameAttribute: "uid", // FIXME: switch this to some more widely available attribute by default // ideally this needs to be constant for the lifetime of a users - UserIDAttribute: "owncloudUUID", - GroupBaseDN: "ou=groups,o=libregraph-idm", - GroupSearchScope: "sub", - GroupFilter: "", - GroupObjectClass: "groupOfNames", - GroupNameAttribute: "cn", - GroupIDAttribute: "owncloudUUID", + UserIDAttribute: "owncloudUUID", + GroupBaseDN: "ou=groups,o=libregraph-idm", + GroupSearchScope: "sub", + GroupFilter: "", + GroupObjectClass: "groupOfNames", + GroupNameAttribute: "cn", + GroupIDAttribute: "owncloudUUID", + EducationResourcesEnabled: false, }, }, Events: config.Events{ diff --git a/services/graph/pkg/identity/ldap.go b/services/graph/pkg/identity/ldap.go index 99bbbbec8d..2256a46b28 100644 --- a/services/graph/pkg/identity/ldap.go +++ b/services/graph/pkg/identity/ldap.go @@ -40,6 +40,8 @@ type LDAP struct { groupScope int groupAttributeMap groupAttributeMap + educationConfig educationConfig + logger *log.Logger conn ldap.Client } @@ -90,6 +92,11 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD return nil, fmt.Errorf("error configuring group scope: %w", err) } + var educationConfig educationConfig + if educationConfig, err = newEducationConfig(config); err != nil { + return nil, fmt.Errorf("error setting up education resource config: %w", err) + } + return &LDAP{ useServerUUID: config.UseServerUUID, usePwModifyExOp: config.UsePasswordModExOp, @@ -103,6 +110,7 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD groupObjectClass: config.GroupObjectClass, groupScope: groupScope, groupAttributeMap: gam, + educationConfig: educationConfig, logger: logger, conn: lc, writeEnabled: config.WriteEnabled, diff --git a/services/graph/pkg/identity/ldap_school.go b/services/graph/pkg/identity/ldap_school.go index 3be98f069a..db365b92ac 100644 --- a/services/graph/pkg/identity/ldap_school.go +++ b/services/graph/pkg/identity/ldap_school.go @@ -2,12 +2,15 @@ package identity import ( "context" + "fmt" "net/url" + "github.com/go-ldap/ldap/v3" libregraph "github.com/owncloud/libre-graph-api-go" + "github.com/owncloud/ocis/v2/services/graph/pkg/config" ) -type schoolConfig struct { +type educationConfig struct { schoolBaseDN string schoolFilter string schoolObjectClass string @@ -16,14 +19,37 @@ type schoolConfig struct { } type schoolAttributeMap struct { - displayname string + displayName string schoolNumber string id string } +func defaultEducationConfig() educationConfig { + return educationConfig{ + schoolObjectClass: "ocEducationSchool", + schoolScope: ldap.ScopeWholeSubtree, + schoolAttributeMap: newSchoolAttributeMap(), + } +} + +func newEducationConfig(config config.LDAP) (educationConfig, error) { + if config.EducationResourcesEnabled { + var err error + eduCfg := defaultEducationConfig() + eduCfg.schoolBaseDN = config.EducationConfig.SchoolBaseDN + if config.EducationConfig.SchoolSearchScope != "" { + if eduCfg.schoolScope, err = stringToScope(config.EducationConfig.SchoolSearchScope); err != nil { + return educationConfig{}, fmt.Errorf("error configuring school search scope: %w", err) + } + } + return eduCfg, nil + } + return educationConfig{}, nil +} + func newSchoolAttributeMap() schoolAttributeMap { return schoolAttributeMap{ - displayname: "ou", + displayName: "ou", schoolNumber: "ocEducationSchoolNumber", id: "owncloudUUID", } diff --git a/services/graph/pkg/identity/noop_school.go b/services/graph/pkg/identity/noop_school.go new file mode 100644 index 0000000000..4bccf3590c --- /dev/null +++ b/services/graph/pkg/identity/noop_school.go @@ -0,0 +1,71 @@ +package identity + +import ( + "context" + "net/url" + + libregraph "github.com/owncloud/libre-graph-api-go" +) + +// NOOP is a dummy EducationBackend, doing nothing +type NOOP struct{} + +// CreateSchool creates the supplied school in the identity backend. +func (i *NOOP) CreateSchool(ctx context.Context, school libregraph.EducationSchool) (*libregraph.EducationSchool, error) { + return nil, errNotImplemented +} + +// DeleteSchool deletes a given school, identified by id +func (i *NOOP) DeleteSchool(ctx context.Context, id string) error { + return errNotImplemented +} + +// GetSchool implements the EducationBackend interface for the NOOP backend. +func (i *NOOP) GetSchool(ctx context.Context, nameOrID string, queryParam url.Values) (*libregraph.EducationSchool, error) { + return nil, errNotImplemented +} + +// GetSchools implements the EducationBackend interface for the NOOP backend. +func (i *NOOP) GetSchools(ctx context.Context, queryParam url.Values) ([]*libregraph.EducationSchool, error) { + return nil, errNotImplemented +} + +// GetSchoolMembers implements the EducationBackend interface for the NOOP backend. +func (i *NOOP) GetSchoolMembers(ctx context.Context, id string) ([]*libregraph.EducationUser, error) { + return nil, errNotImplemented +} + +// AddMembersToSchool adds new members (reference by a slice of IDs) to supplied school in the identity backend. +func (i *NOOP) AddMembersToSchool(ctx context.Context, schoolID string, memberID []string) error { + return errNotImplemented +} + +// RemoveMemberFromSchool removes a single member (by ID) from a school +func (i *NOOP) RemoveMemberFromSchool(ctx context.Context, schoolID string, memberID string) error { + return errNotImplemented +} + +// CreateEducationUser creates a given education user in the identity backend. +func (i *NOOP) CreateEducationUser(ctx context.Context, user libregraph.EducationUser) (*libregraph.EducationUser, error) { + return nil, errNotImplemented +} + +// DeleteEducationUser deletes a given educationuser, identified by username or id, from the backend +func (i *NOOP) DeleteEducationUser(ctx context.Context, nameOrID string) error { + return errNotImplemented +} + +// UpdateEducationUser applies changes to given education user, identified by username or id +func (i *NOOP) UpdateEducationUser(ctx context.Context, nameOrID string, user libregraph.EducationUser) (*libregraph.EducationUser, error) { + return nil, errNotImplemented +} + +// GetEducationUser implements the EducationBackend interface for the NOOP backend. +func (i *NOOP) GetEducationUser(ctx context.Context, nameOrID string, queryParam url.Values) (*libregraph.EducationUser, error) { + return nil, errNotImplemented +} + +// GetEducationUsers implements the EducationBackend interface for the NOOP backend. +func (i *NOOP) GetEducationUsers(ctx context.Context, queryParam url.Values) ([]*libregraph.EducationUser, error) { + return nil, errNotImplemented +} diff --git a/services/graph/pkg/service/v0/service.go b/services/graph/pkg/service/v0/service.go index ffdb1ce69e..daa3d9eaf7 100644 --- a/services/graph/pkg/service/v0/service.go +++ b/services/graph/pkg/service/v0/service.go @@ -146,7 +146,12 @@ func NewService(opts ...Option) Service { } svc.identityBackend = lb if options.IdentityEducationBackend == nil { - svc.identityEducationBackend = lb + if options.Config.Identity.LDAP.EducationResourcesEnabled { + svc.identityEducationBackend = lb + } else { + noop := &identity.NOOP{} + svc.identityEducationBackend = noop + } } default: options.Logger.Error().Msgf("Unknown Identity Backend: '%s'", options.Config.Identity.Backend)