From f6c8cd5ea8c0cb9450b8792d8bb46a8fee5074c4 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Tue, 21 Jan 2025 18:03:30 +0100 Subject: [PATCH] allow LDAP users (and linked peers) to be automatically re-enabled (#345) --- README.md | 1 + docs/documentation/configuration/overview.md | 4 +++ internal/app/users/ldap_helper.go | 4 +++ internal/app/users/user_manager.go | 29 +++++++++++++++----- internal/config/auth.go | 8 ++++-- 5 files changed, 36 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1d826d2..d937b47 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ The following configuration options are available: | login_filter | auth/ldap | | LDAP filters for users that should be allowed to log in. {{login_identifier}} will be replaced with the login username. | | admin_group | auth/ldap | | Users in this group are marked as administrators. | | disable_missing | auth/ldap | | If synchronization is enabled, missing LDAP users will be disabled in WireGuard Portal. | +| auto_re_enable | auth/ldap | | If auto re-enable is true, users that where disabled because they were missing will be re-enabled once they are found again. | | sync_filter | auth/ldap | | LDAP filters for users that should be synchronized to WireGuard Portal. | | sync_interval | auth/ldap | | The time interval after which users will be synchronized from LDAP. Empty value or `0` disables synchronization. | | registration_enabled | auth/ldap | | If registration is enabled, new user accounts will created in WireGuard Portal. | diff --git a/docs/documentation/configuration/overview.md b/docs/documentation/configuration/overview.md index 432898a..61b66b6 100644 --- a/docs/documentation/configuration/overview.md +++ b/docs/documentation/configuration/overview.md @@ -444,6 +444,10 @@ Below are the properties for each LDAP provider entry inside `auth.ldap`: - **Default:** *(empty)* - **Description:** If `true`, any user **not** found in LDAP (during sync) is disabled in WireGuard Portal. +#### `auto_re_enable` +- **Default:** *(empty)* +- **Description:** If `true`, users that where disabled because they were missing (see `disable_missing`) will be re-enabled once they are found again. + #### `registration_enabled` - **Default:** *(empty)* - **Description:** If `true`, new user accounts are created in WireGuard Portal upon first login. diff --git a/internal/app/users/ldap_helper.go b/internal/app/users/ldap_helper.go index 32db6e1..dfd75b6 100644 --- a/internal/app/users/ldap_helper.go +++ b/internal/app/users/ldap_helper.go @@ -71,5 +71,9 @@ func userChangedInLdap(dbUser, ldapUser *domain.User) bool { return true } + if dbUser.ProviderName != ldapUser.ProviderName { + return true + } + return false } diff --git a/internal/app/users/user_manager.go b/internal/app/users/user_manager.go index 2a90581..7fdc090 100644 --- a/internal/app/users/user_manager.go +++ b/internal/app/users/user_manager.go @@ -469,7 +469,7 @@ func (m Manager) synchronizeLdapUsers(ctx context.Context, provider *config.Ldap logrus.Tracef("fetched %d raw ldap users from provider %s...", len(rawUsers), provider.ProviderName) // Update existing LDAP users - err = m.updateLdapUsers(ctx, provider.ProviderName, rawUsers, &provider.FieldMap, provider.ParsedAdminGroupDN) + err = m.updateLdapUsers(ctx, provider, rawUsers, &provider.FieldMap, provider.ParsedAdminGroupDN) if err != nil { return err } @@ -487,13 +487,13 @@ func (m Manager) synchronizeLdapUsers(ctx context.Context, provider *config.Ldap func (m Manager) updateLdapUsers( ctx context.Context, - providerName string, + provider *config.LdapProvider, rawUsers []internal.RawLdapUser, fields *config.LdapFields, adminGroupDN *ldap.DN, ) error { for _, rawUser := range rawUsers { - user, err := convertRawLdapUser(providerName, rawUser, fields, adminGroupDN) + user, err := convertRawLdapUser(provider.ProviderName, rawUser, fields, adminGroupDN) if err != nil && !errors.Is(err, domain.ErrNotFound) { return fmt.Errorf("failed to convert LDAP data for %v: %w", rawUser["dn"], err) } @@ -506,17 +506,27 @@ func (m Manager) updateLdapUsers( tctx, cancel := context.WithTimeout(ctx, 30*time.Second) tctx = domain.SetUserInfo(tctx, domain.SystemAdminContextUserInfo()) + // create new user if existingUser == nil { err := m.NewUser(tctx, user) if err != nil { cancel() return fmt.Errorf("create error for user id %s: %w", user.Identifier, err) } + + cancel() + return nil } - if existingUser != nil && existingUser.Source == domain.UserSourceLdap && userChangedInLdap(existingUser, - user) { - + // update existing user + if provider.AutoReEnable && existingUser.DisabledReason == domain.DisabledReasonLdapMissing { + user.Disabled = nil + user.DisabledReason = "" + } else { + user.Disabled = existingUser.Disabled + user.DisabledReason = existingUser.DisabledReason + } + if existingUser.Source == domain.UserSourceLdap && userChangedInLdap(existingUser, user) { err := m.users.SaveUser(tctx, user.Identifier, func(u *domain.User) (*domain.User, error) { u.UpdatedAt = time.Now() u.UpdatedBy = domain.CtxSystemLdapSyncer @@ -528,7 +538,8 @@ func (m Manager) updateLdapUsers( u.Phone = user.Phone u.Department = user.Department u.IsAdmin = user.IsAdmin - u.Disabled = user.Disabled + u.Disabled = nil + u.DisabledReason = "" return u, nil }) @@ -536,6 +547,10 @@ func (m Manager) updateLdapUsers( cancel() return fmt.Errorf("update error for user id %s: %w", user.Identifier, err) } + + if existingUser.IsDisabled() && !user.IsDisabled() { + m.bus.Publish(app.TopicUserEnabled, *user) + } } cancel() diff --git a/internal/config/auth.go b/internal/config/auth.go index 9a61847..f044e80 100644 --- a/internal/config/auth.go +++ b/internal/config/auth.go @@ -114,9 +114,11 @@ type LdapProvider struct { ParsedAdminGroupDN *ldap.DN `yaml:"-"` // If DisableMissing is true, missing users will be deactivated - DisableMissing bool `yaml:"disable_missing"` - SyncFilter string `yaml:"sync_filter"` - SyncInterval time.Duration `yaml:"sync_interval"` + DisableMissing bool `yaml:"disable_missing"` + // If AutoReEnable is true, users that where disabled because they were missing will be re-enabled once they are found again + AutoReEnable bool `yaml:"auto_re_enable"` + SyncFilter string `yaml:"sync_filter"` + SyncInterval time.Duration `yaml:"sync_interval"` // If RegistrationEnabled is set to true, wg-portal will create new users that do not exist in the database. RegistrationEnabled bool `yaml:"registration_enabled"`