mirror of
https://github.com/h44z/wg-portal.git
synced 2026-09-03 21:36:44 +00:00
fix(ldap): do not create interfaces from interface_filter entries (#746)
updateInterfaceLdapFilters saved the matched users with SaveInterface, which creates the interface when it is missing. On first start that panics. The sync runs immediately (main.go:85) and the importer later (main.go:116), so the sync creates a stub row for every interface_filter key, and the importer, which snapshotted the interface list before its device round-trips, then fails with "interface already exists". The window is GetInterfaces plus GetPeers, so a directory on localhost loses the race and a slower one hides it. The stub rows are wrong anyway. They have no backend, so a typo in an interface_filter key quietly created an interface attached to no controller. Look the interface up and skip with a warning when it is absent. The filter is applied on the next sync once the importer has created it. A lookup error that is not ErrNotFound also skips. Signed-off-by: clark-ja <37738506+clark-ja@users.noreply.github.com>
This commit is contained in:
@@ -311,30 +311,55 @@ func (m Manager) updateInterfaceLdapFilters(
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
}
|
||||
m.applyInterfaceLdapFilter(ctx, ifaceId, provider.ProviderName, matchedUserIds)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// applyInterfaceLdapFilter stores the users an LDAP filter matched onto an
|
||||
// existing interface.
|
||||
//
|
||||
// It deliberately does not create the interface. SaveInterface would, which is
|
||||
// wrong twice over: an interface_filter entry is a statement about who may use
|
||||
// an interface, not a reason to bring one into existence, and the row it
|
||||
// creates has no backend. It also races the startup importer, which snapshots
|
||||
// the interface list before its device round-trips and then fails with
|
||||
// "interface already exists" once it finds the row.
|
||||
func (m Manager) applyInterfaceLdapFilter(
|
||||
ctx context.Context,
|
||||
ifaceId domain.InterfaceIdentifier,
|
||||
providerName string,
|
||||
matchedUserIds []domain.UserIdentifier,
|
||||
) {
|
||||
if _, err := m.interfaces.GetInterface(ctx, ifaceId); err != nil {
|
||||
if errors.Is(err, domain.ErrNotFound) {
|
||||
slog.Warn("skipping interface filter for unknown interface",
|
||||
"interface", ifaceId, "provider", providerName)
|
||||
} else {
|
||||
slog.Error("failed to look up interface for ldap filter",
|
||||
"interface", ifaceId, "provider", providerName, "error", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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[providerName] = matchedUserIds
|
||||
return i, nil
|
||||
})
|
||||
if err != nil {
|
||||
slog.Error("failed to save interface ldap allowed users",
|
||||
"interface", ifaceId, "provider", providerName, "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
slog.Debug("updated interface ldap allowed users",
|
||||
"interface", ifaceId, "provider", providerName, "matched_count", len(matchedUserIds))
|
||||
}
|
||||
|
||||
func ldapUserIdentifier(rawUser map[string]any, field string) domain.UserIdentifier {
|
||||
identifier := internal.MapDefaultString(rawUser, field, "")
|
||||
identifier = domain.SanitizeIdentifier(identifier, 256)
|
||||
|
||||
Reference in New Issue
Block a user