diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index cce3aa894..e869686cb 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -61,6 +61,10 @@ var ( Name: "admin-filter", Usage: "An LDAP filter specifying if a user should be given administrator privileges.", }, + cli.BoolFlag{ + Name: "allow-deactivate-all", + Usage: "Allow empty search results to deactivate all users.", + }, cli.StringFlag{ Name: "username-attribute", Usage: "The attribute of the user’s LDAP record containing the user name.", @@ -231,6 +235,9 @@ func parseLdapConfig(c *cli.Context, config *models.LDAPConfig) error { if c.IsSet("admin-filter") { config.Source.AdminFilter = c.String("admin-filter") } + if c.IsSet("allow-deactivate-all") { + config.Source.AllowDeactivateAll = c.Bool("allow-deactivate-all") + } return nil } diff --git a/models/user.go b/models/user.go index 9ddd262ae..7e3fce5f7 100644 --- a/models/user.go +++ b/models/user.go @@ -1760,6 +1760,15 @@ func SyncExternalUsers(ctx context.Context) { continue } + if len(sr) == 0 { + if !s.LDAP().AllowDeactivateAll { + log.Error("LDAP search found no entries but did not report an error. Refusing to deactivate all users") + continue + } else { + log.Warn("LDAP search found no entries but did not report an error. All users will be deactivated as per settings") + } + } + for _, su := range sr { select { case <-ctx.Done(): diff --git a/modules/auth/auth_form.go b/modules/auth/auth_form.go index c838590c1..a30ebb75e 100644 --- a/modules/auth/auth_form.go +++ b/modules/auth/auth_form.go @@ -30,6 +30,7 @@ type AuthenticationForm struct { SearchPageSize int Filter string AdminFilter string + AllowDeactivateAll bool IsActive bool IsSyncEnabled bool SMTPAuth string diff --git a/modules/auth/ldap/ldap.go b/modules/auth/ldap/ldap.go index ed83a77e1..7f0d2c93f 100644 --- a/modules/auth/ldap/ldap.go +++ b/modules/auth/ldap/ldap.go @@ -47,6 +47,7 @@ type Source struct { Filter string // Query filter to validate entry AdminFilter string // Query filter to check if user is admin Enabled bool // if this source is disabled + AllowDeactivateAll bool // Allow an empty search response to deactivate all users from this source } // SearchResult : user data diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 320d60648..5e4d94531 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1826,6 +1826,7 @@ auths.attribute_surname = Surname Attribute auths.attribute_mail = Email Attribute auths.attribute_ssh_public_key = Public SSH Key Attribute auths.attributes_in_bind = Fetch Attributes in Bind DN Context +auths.allow_deactivate_all = Allow an empty search result to deactivate all users auths.use_paged_search = Use Paged Search auths.search_page_size = Page Size auths.filter = User Filter diff --git a/routers/admin/auths.go b/routers/admin/auths.go index 8a16e36bf..4fa76df44 100644 --- a/routers/admin/auths.go +++ b/routers/admin/auths.go @@ -130,6 +130,7 @@ func parseLDAPConfig(form auth.AuthenticationForm) *models.LDAPConfig { SearchPageSize: pageSize, Filter: form.Filter, AdminFilter: form.AdminFilter, + AllowDeactivateAll: form.AllowDeactivateAll, Enabled: true, }, } diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index d1a614b1f..3f515bbf4 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -112,6 +112,12 @@ {{end}} +