diff --git a/api/v1alpha1/controllerconfig_types.go b/api/v1alpha1/controllerconfig_types.go index 717f330e..fe9b0e2a 100644 --- a/api/v1alpha1/controllerconfig_types.go +++ b/api/v1alpha1/controllerconfig_types.go @@ -36,6 +36,7 @@ import ( // userSearchFilter: "(objectClass=person)" // emailAttribute: "mail" // attributes: ["uid", "mail"] +// bindUserName: "foobar" // googleDriveConfig: # optional, required for googleDrive source type // maxRetries: 3 // concurrentFolders: 5 @@ -133,6 +134,9 @@ type LDAPConfig struct { // Attributes is the list of LDAP attributes to retrieve. // +optional Attributes []string `json:"attributes,omitempty"` + // BindUserName is the username for the LDAP server. Password is fetched from the secret specified in the SecretRef field. + // +optional + BindUserName string `json:"bindUserName,omitempty"` } // ControllerConfigStatus defines the observed state of ControllerConfig. diff --git a/config/crd/bases/operator.dataverse.redhat.com_controllerconfigs.yaml b/config/crd/bases/operator.dataverse.redhat.com_controllerconfigs.yaml index 4aae9997..4633e5f3 100644 --- a/config/crd/bases/operator.dataverse.redhat.com_controllerconfigs.yaml +++ b/config/crd/bases/operator.dataverse.redhat.com_controllerconfigs.yaml @@ -81,6 +81,11 @@ spec: baseUserDN: description: BaseUserDN is the base DN for user searches. type: string + bindUserName: + description: BindUserName is the username for the LDAP server. + Password is fetched from the secret specified in the SecretRef + field. + type: string emailAttribute: description: EmailAttribute is the LDAP attribute containing user email addresses (e.g., "mail"). diff --git a/config/samples/operator_v1alpha1_controllerconfig.yaml b/config/samples/operator_v1alpha1_controllerconfig.yaml index a3faa384..667651db 100644 --- a/config/samples/operator_v1alpha1_controllerconfig.yaml +++ b/config/samples/operator_v1alpha1_controllerconfig.yaml @@ -21,6 +21,7 @@ spec: # userSearchFilter: "(objectClass=person)" # emailAttribute: "mail" # attributes: ["uid", "mail"] + # bindUserName: "foobar" # Optional: Google Drive controller-level settings (required when using googleDrive source type) # googleDriveConfig: # maxRetries: 3 diff --git a/internal/controller/controllerconfig_controller.go b/internal/controller/controllerconfig_controller.go index 1837bcde..2a5f6c8e 100644 --- a/internal/controller/controllerconfig_controller.go +++ b/internal/controller/controllerconfig_controller.go @@ -142,6 +142,10 @@ func (r *ControllerConfigReconciler) Reconcile(ctx context.Context, req ctrl.Req // initialize LDAP client and cache if configured if config.Spec.LDAPConfig != nil && config.Spec.LDAPConfig.Server != "" { ldapCfg := *config.Spec.LDAPConfig + + // fetch LDAP password from secret if provided + ldapPassword := string(secret.Data["LDAP_PASSWORD"]) + lc, err := ldap.InitLDAP(ldap.Config{ Server: ldapCfg.Server, GroupDN: ldapCfg.GroupDN, @@ -150,6 +154,8 @@ func (r *ControllerConfigReconciler) Reconcile(ctx context.Context, req ctrl.Req UserSearchFilter: ldapCfg.UserSearchFilter, EmailAttribute: ldapCfg.EmailAttribute, Attributes: ldapCfg.Attributes, + BindUserName: ldapCfg.BindUserName, + BindPassword: ldapPassword, }) if err != nil { logger.Error(err, "failed to initialize LDAP client, will retry") diff --git a/pkg/gdrive/ldap/client.go b/pkg/gdrive/ldap/client.go index dea5a912..05cb8052 100644 --- a/pkg/gdrive/ldap/client.go +++ b/pkg/gdrive/ldap/client.go @@ -42,6 +42,9 @@ type Config struct { EmailAttribute string `yaml:"emailAttribute" json:"emailAttribute"` // Attributes is the list of LDAP attributes to retrieve. Attributes []string `yaml:"attributes" json:"attributes"` + + BindUserName string `yaml:"bindUserName" json:"bindUserName"` + BindPassword string `yaml:"bindPassword" json:"bindPassword"` } // DefaultConfig returns a Config with generic LDAP defaults. @@ -57,6 +60,7 @@ func DefaultConfig() Config { type LDAPConnClient interface { IsClosing() bool Search(*ldap.SearchRequest) (*ldap.SearchResult, error) + Bind(username, password string) error UnauthenticatedBind(username string) error } @@ -71,6 +75,8 @@ type LDAPConn struct { userSearchFilter string emailAttribute string attributes []string + bindUserName string + bindPassword string } // Client defines the interface for LDAP operations used by the gdrive package. @@ -87,11 +93,19 @@ func InitLDAP(config Config) (Client, error) { return nil, fmt.Errorf("failed to connect to LDAP server %s: %w", config.Server, err) } - // Perform anonymous bind - err = ldapConn.UnauthenticatedBind("") - if err != nil { - _ = ldapConn.Close() - return nil, fmt.Errorf("failed to bind LDAP connection: %w", err) + if config.BindUserName != "" && config.BindPassword != "" { + err = ldapConn.Bind(config.BindUserName, config.BindPassword) + if err != nil { + _ = ldapConn.Close() + return nil, fmt.Errorf("failed to bind LDAP connection: %w", err) + } + } else { + // Perform anonymous bind + err = ldapConn.UnauthenticatedBind("") + if err != nil { + _ = ldapConn.Close() + return nil, fmt.Errorf("failed to bind LDAP connection: %w", err) + } } emailAttr := config.EmailAttribute @@ -108,6 +122,8 @@ func InitLDAP(config Config) (Client, error) { userSearchFilter: config.UserSearchFilter, emailAttribute: emailAttr, attributes: config.Attributes, + bindUserName: config.BindUserName, + bindPassword: config.BindPassword, }, nil } @@ -120,10 +136,19 @@ func (l *LDAPConn) getConn() LDAPConnClient { if err != nil { return nil } - err = newConn.UnauthenticatedBind("") - if err != nil { - _ = newConn.Close() - return nil + + if l.bindUserName != "" && l.bindPassword != "" { + err = newConn.Bind(l.bindUserName, l.bindPassword) + if err != nil { + _ = newConn.Close() + return nil + } + } else { + err = newConn.UnauthenticatedBind("") + if err != nil { + _ = newConn.Close() + return nil + } } l.conn = newConn } diff --git a/pkg/unstructured/source.go b/pkg/unstructured/source.go index 61e33b50..8ff7854e 100644 --- a/pkg/unstructured/source.go +++ b/pkg/unstructured/source.go @@ -362,10 +362,13 @@ func (g *GDriveSource) SyncFilesToFilestore(ctx context.Context, fs *filestore.F if stored { logger.Info("stored gdrive file", "fileID", record.FileID, "fileName", record.FileName) - mu.Lock() - storedFiles = append(storedFiles, file) - mu.Unlock() } + + // still append the file to the storedFiles list, + mu.Lock() + storedFiles = append(storedFiles, file) + mu.Unlock() + return nil }) }