mirror of
https://github.com/h44z/wg-portal.git
synced 2026-03-24 00:56:26 +00:00
feat: Implement LDAP interface-specific provisioning filters (#642)
* Implement LDAP filter-based access control for interface provisioning * test: add unit tests for LDAP interface filtering logic * smaller improvements / cleanup --------- Co-authored-by: jc <37738506+theguy147@users.noreply.github.com> Co-authored-by: Christoph Haas <christoph.h@sprinternet.at>
This commit is contained in:
@@ -90,6 +90,12 @@ func (m Manager) synchronizeLdapUsers(ctx context.Context, provider *config.Ldap
|
||||
}
|
||||
}
|
||||
|
||||
// Update interface allowed users based on LDAP filters
|
||||
err = m.updateInterfaceLdapFilters(ctx, conn, provider)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -237,3 +243,59 @@ func (m Manager) disableMissingLdapUsers(
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m Manager) updateInterfaceLdapFilters(
|
||||
ctx context.Context,
|
||||
conn *ldap.Conn,
|
||||
provider *config.LdapProvider,
|
||||
) error {
|
||||
if len(provider.InterfaceFilter) == 0 {
|
||||
return nil // nothing to do if no interfaces are configured for this provider
|
||||
}
|
||||
|
||||
for ifaceName, groupFilter := range provider.InterfaceFilter {
|
||||
ifaceId := domain.InterfaceIdentifier(ifaceName)
|
||||
|
||||
// Combined filter: user must match the provider's base SyncFilter AND the interface's LdapGroupFilter
|
||||
combinedFilter := fmt.Sprintf("(&(%s)(%s))", provider.SyncFilter, groupFilter)
|
||||
|
||||
rawUsers, err := internal.LdapFindAllUsers(conn, provider.BaseDN, combinedFilter, &provider.FieldMap)
|
||||
if err != nil {
|
||||
slog.Error("failed to find users for interface filter",
|
||||
"interface", ifaceId,
|
||||
"provider", provider.ProviderName,
|
||||
"error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
matchedUserIds := make([]domain.UserIdentifier, 0, len(rawUsers))
|
||||
for _, rawUser := range rawUsers {
|
||||
userId := domain.UserIdentifier(internal.MapDefaultString(rawUser, provider.FieldMap.UserIdentifier, ""))
|
||||
if userId != "" {
|
||||
matchedUserIds = append(matchedUserIds, userId)
|
||||
}
|
||||
}
|
||||
|
||||
// Save the interface
|
||||
err = m.interfaces.SaveInterface(ctx, ifaceId, func(i *domain.Interface) (*domain.Interface, error) {
|
||||
if i.LdapAllowedUsers == nil {
|
||||
i.LdapAllowedUsers = make(map[string][]domain.UserIdentifier)
|
||||
}
|
||||
i.LdapAllowedUsers[provider.ProviderName] = matchedUserIds
|
||||
return i, nil
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("failed to save interface ldap allowed users",
|
||||
"interface", ifaceId,
|
||||
"provider", provider.ProviderName,
|
||||
"error", err)
|
||||
} else {
|
||||
slog.Debug("updated interface ldap allowed users",
|
||||
"interface", ifaceId,
|
||||
"provider", provider.ProviderName,
|
||||
"matched_count", len(matchedUserIds))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -39,6 +39,11 @@ type PeerDatabaseRepo interface {
|
||||
GetUserPeers(ctx context.Context, id domain.UserIdentifier) ([]domain.Peer, error)
|
||||
}
|
||||
|
||||
type InterfaceDatabaseRepo interface {
|
||||
// SaveInterface saves the interface with the given identifier.
|
||||
SaveInterface(ctx context.Context, id domain.InterfaceIdentifier, updateFunc func(i *domain.Interface) (*domain.Interface, error)) error
|
||||
}
|
||||
|
||||
type EventBus interface {
|
||||
// Publish sends a message to the message bus.
|
||||
Publish(topic string, args ...any)
|
||||
@@ -50,22 +55,27 @@ type EventBus interface {
|
||||
type Manager struct {
|
||||
cfg *config.Config
|
||||
|
||||
bus EventBus
|
||||
users UserDatabaseRepo
|
||||
peers PeerDatabaseRepo
|
||||
bus EventBus
|
||||
users UserDatabaseRepo
|
||||
peers PeerDatabaseRepo
|
||||
interfaces InterfaceDatabaseRepo
|
||||
}
|
||||
|
||||
// NewUserManager creates a new user manager instance.
|
||||
func NewUserManager(cfg *config.Config, bus EventBus, users UserDatabaseRepo, peers PeerDatabaseRepo) (
|
||||
*Manager,
|
||||
error,
|
||||
) {
|
||||
func NewUserManager(
|
||||
cfg *config.Config,
|
||||
bus EventBus,
|
||||
users UserDatabaseRepo,
|
||||
peers PeerDatabaseRepo,
|
||||
interfaces InterfaceDatabaseRepo,
|
||||
) (*Manager, error) {
|
||||
m := &Manager{
|
||||
cfg: cfg,
|
||||
bus: bus,
|
||||
|
||||
users: users,
|
||||
peers: peers,
|
||||
users: users,
|
||||
peers: peers,
|
||||
interfaces: interfaces,
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user