From eee0d123e418a3d1091ceb0f05ff0e31f1cc876c Mon Sep 17 00:00:00 2001 From: Pascal Fischer <32096965+pascal-fischer@users.noreply.github.com> Date: Thu, 27 Feb 2025 12:17:07 +0100 Subject: [PATCH] [management] add flow settings and credentials (#3389) --- client/cmd/testutil_test.go | 4 +- client/internal/engine_test.go | 4 +- client/internal/pkce_auth.go | 2 +- client/server/server_test.go | 5 +- go.mod | 2 +- go.sum | 4 +- management/client/client_test.go | 7 +- management/cmd/management.go | 8 +- management/server/account.go | 117 +++----------- management/server/account/account.go | 19 --- .../account/account_manager_interface.go | 146 ++++++++++++++++++ management/server/account_test.go | 12 +- management/server/dns_test.go | 3 +- management/server/ephemeral.go | 5 +- management/server/ephemeral_test.go | 7 +- management/server/groups/manager.go | 6 +- management/server/grpcserver.go | 29 ++-- management/server/http/api/openapi.yml | 4 + management/server/http/api/types.gen.go | 3 + management/server/http/handler.go | 11 +- .../handlers/accounts/accounts_handler.go | 30 ++-- .../accounts/accounts_handler_test.go | 6 + .../http/handlers/dns/dns_settings_handler.go | 10 +- .../http/handlers/dns/nameservers_handler.go | 8 +- .../http/handlers/events/events_handler.go | 8 +- .../http/handlers/groups/groups_handler.go | 8 +- .../server/http/handlers/networks/handler.go | 8 +- .../http/handlers/peers/peers_handler.go | 8 +- .../handlers/policies/geolocations_handler.go | 8 +- .../handlers/policies/policies_handler.go | 8 +- .../policies/posture_checks_handler.go | 8 +- .../http/handlers/routes/routes_handler.go | 8 +- .../handlers/setup_keys/setupkeys_handler.go | 9 +- .../server/http/handlers/users/pat_handler.go | 8 +- .../http/handlers/users/users_handler.go | 8 +- .../http/testing/testing_tools/tools.go | 14 +- management/server/integrated_validator.go | 17 +- .../integrations/extra_settings/manager.go | 12 ++ .../integrated_validator/interface.go | 11 +- management/server/management_proto_test.go | 9 +- management/server/management_test.go | 3 +- management/server/mock_server/account_mock.go | 25 ++- management/server/nameserver_test.go | 3 +- management/server/networks/manager.go | 6 +- .../server/networks/resources/manager.go | 6 +- management/server/networks/routers/manager.go | 6 +- management/server/peer.go | 55 +++---- management/server/peer_test.go | 15 +- management/server/permissions/manager.go | 3 +- management/server/route_test.go | 3 +- management/server/settings/manager.go | 106 +++++++++++-- management/server/status/error.go | 6 + management/server/store/sql_store.go | 3 +- management/server/token_mgr.go | 6 + management/server/types/settings.go | 24 ++- 55 files changed, 547 insertions(+), 327 deletions(-) delete mode 100644 management/server/account/account.go create mode 100644 management/server/account/account_manager_interface.go create mode 100644 management/server/integrations/extra_settings/manager.go diff --git a/client/cmd/testutil_test.go b/client/cmd/testutil_test.go index 4c06a7da0..30ba79056 100644 --- a/client/cmd/testutil_test.go +++ b/client/cmd/testutil_test.go @@ -90,13 +90,13 @@ func startManagement(t *testing.T, config *mgmt.Config, testFile string) (*grpc. metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) require.NoError(t, err) - accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock()) + accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) if err != nil { t.Fatal(err) } secretsManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay) - mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settings.NewManager(store), peersUpdateManager, secretsManager, nil, nil, nil) + mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settings.NewManagerMock(), peersUpdateManager, secretsManager, nil, nil, nil) if err != nil { t.Fatal(err) } diff --git a/client/internal/engine_test.go b/client/internal/engine_test.go index 9de1da28d..60f07cbec 100644 --- a/client/internal/engine_test.go +++ b/client/internal/engine_test.go @@ -1434,13 +1434,13 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) require.NoError(t, err) - accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock()) + accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) if err != nil { return nil, "", err } secretsManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay) - mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settings.NewManager(store), peersUpdateManager, secretsManager, nil, nil, nil) + mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settings.NewManagerMock(), peersUpdateManager, secretsManager, nil, nil, nil) if err != nil { return nil, "", err } diff --git a/client/internal/pkce_auth.go b/client/internal/pkce_auth.go index 6f714889f..ac6734b0c 100644 --- a/client/internal/pkce_auth.go +++ b/client/internal/pkce_auth.go @@ -37,7 +37,7 @@ type PKCEAuthProviderConfig struct { RedirectURLs []string // UseIDToken indicates if the id token should be used for authentication UseIDToken bool - //ClientCertPair is used for mTLS authentication to the IDP + // ClientCertPair is used for mTLS authentication to the IDP ClientCertPair *tls.Certificate } diff --git a/client/server/server_test.go b/client/server/server_test.go index 0c0f32fec..0a8285ee7 100644 --- a/client/server/server_test.go +++ b/client/server/server_test.go @@ -10,7 +10,6 @@ import ( "go.opentelemetry.io/otel" "github.com/netbirdio/management-integrations/integrations" - log "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/grpc/keepalive" @@ -129,13 +128,13 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) require.NoError(t, err) - accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock()) + accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) if err != nil { return nil, "", err } secretsManager := server.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay) - mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settings.NewManager(store), peersUpdateManager, secretsManager, nil, nil, nil) + mgmtServer, err := server.NewServer(context.Background(), config, accountManager, settings.NewManagerMock(), peersUpdateManager, secretsManager, nil, nil, nil) if err != nil { return nil, "", err } diff --git a/go.mod b/go.mod index 81fa32a3c..4c948c007 100644 --- a/go.mod +++ b/go.mod @@ -60,7 +60,7 @@ require ( github.com/miekg/dns v1.1.59 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nadoo/ipset v0.5.0 - github.com/netbirdio/management-integrations/integrations v0.0.0-20250225104154-5648068fab25 + github.com/netbirdio/management-integrations/integrations v0.0.0-20250226165736-0ac3dc443266 github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20241010133937-e0df50df217d github.com/okta/okta-sdk-golang/v2 v2.18.0 github.com/oschwald/maxminddb-golang v1.12.0 diff --git a/go.sum b/go.sum index 51851a942..23a7b8aac 100644 --- a/go.sum +++ b/go.sum @@ -529,8 +529,8 @@ github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944 h1:TDtJKmM6S github.com/netbirdio/go-netroute v0.0.0-20240611143515-f59b0e1d3944/go.mod h1:sHA6TRxjQ6RLbnI+3R4DZo2Eseg/iKiPRfNmcuNySVQ= github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e h1:PURA50S8u4mF6RrkYYCAvvPCixhqqEiEy3Ej6avh04c= github.com/netbirdio/ice/v3 v3.0.0-20240315174635-e72a50fcb64e/go.mod h1:YMLU7qbKfVjmEv7EoZPIVEI+kNYxWCdPK3VS0BU+U4Q= -github.com/netbirdio/management-integrations/integrations v0.0.0-20250225104154-5648068fab25 h1:OLpyWEHa/d6M8N8sUk5nq5+yYfkBc38NwmsQe5jUBao= -github.com/netbirdio/management-integrations/integrations v0.0.0-20250225104154-5648068fab25/go.mod h1:qaApwbKpiX1vknyXb5x49qnQNBx8X67E1Pvn5sJ6gQU= +github.com/netbirdio/management-integrations/integrations v0.0.0-20250226165736-0ac3dc443266 h1:z7yibtn9dqDpT/UhLYY5bF4ELK5H06d4iaUoteRCfwE= +github.com/netbirdio/management-integrations/integrations v0.0.0-20250226165736-0ac3dc443266/go.mod h1:smsjbLWt5BUYXRKFwbBvUvembwYYXxryY+EHXKnG5KQ= github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9axERMVN63dqyFqnvuD+EMJHzM7mNGON8= github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20241010133937-e0df50df217d h1:bRq5TKgC7Iq20pDiuC54yXaWnAVeS5PdGpSokFTlR28= diff --git a/management/client/client_test.go b/management/client/client_test.go index 73427b38a..5625885f4 100644 --- a/management/client/client_test.go +++ b/management/client/client_test.go @@ -10,14 +10,13 @@ import ( "github.com/stretchr/testify/require" + "github.com/netbirdio/netbird/client/system" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/telemetry" - "github.com/netbirdio/netbird/client/system" - log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" @@ -73,13 +72,13 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) { metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) require.NoError(t, err) - accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock()) + accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) if err != nil { t.Fatal(err) } secretsManager := mgmt.NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay) - mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settings.NewManager(store), peersUpdateManager, secretsManager, nil, nil, nil) + mgmtServer, err := mgmt.NewServer(context.Background(), config, accountManager, settings.NewManagerMock(), peersUpdateManager, secretsManager, nil, nil, nil) if err != nil { t.Fatal(err) } diff --git a/management/cmd/management.go b/management/cmd/management.go index ad3850957..9f8fa2fcb 100644 --- a/management/cmd/management.go +++ b/management/cmd/management.go @@ -34,7 +34,6 @@ import ( "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/realip" "github.com/netbirdio/management-integrations/integrations" - "github.com/netbirdio/netbird/management/server/peers" "github.com/netbirdio/netbird/encryption" @@ -203,13 +202,14 @@ var ( } userManager := users.NewManager(store) - settingsManager := settings.NewManager(store) + extraSettingsManager := integrations.NewManager() + settingsManager := settings.NewManager(store, userManager, extraSettingsManager) permissionsManager := permissions.NewManager(userManager, settingsManager) peersManager := peers.NewManager(store, permissionsManager) proxyController := integrations.NewController(store) accountManager, err := server.BuildManager(ctx, store, peersUpdateManager, idpManager, mgmtSingleAccModeDomain, - dnsDomain, eventStore, geo, userDeleteFromIDPEnabled, integratedPeerValidator, appMetrics, proxyController) + dnsDomain, eventStore, geo, userDeleteFromIDPEnabled, integratedPeerValidator, appMetrics, proxyController, settingsManager) if err != nil { return fmt.Errorf("failed to build default manager: %v", err) } @@ -276,7 +276,7 @@ var ( routersManager := routers.NewManager(store, permissionsManager, accountManager) networksManager := networks.NewManager(store, permissionsManager, resourcesManager, routersManager, accountManager) - httpAPIHandler, err := nbhttp.NewAPIHandler(ctx, accountManager, networksManager, resourcesManager, routersManager, groupsManager, geo, authManager, appMetrics, integratedPeerValidator, proxyController, permissionsManager, peersManager) + httpAPIHandler, err := nbhttp.NewAPIHandler(ctx, accountManager, networksManager, resourcesManager, routersManager, groupsManager, geo, authManager, appMetrics, integratedPeerValidator, proxyController, permissionsManager, peersManager, settingsManager) if err != nil { return fmt.Errorf("failed creating HTTP API handler: %v", err) diff --git a/management/server/account.go b/management/server/account.go index 80821ce91..eb4f0cf38 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -6,7 +6,6 @@ import ( "fmt" "math/rand" "net" - "net/netip" "reflect" "regexp" "slices" @@ -22,7 +21,7 @@ import ( "golang.org/x/exp/maps" nbdns "github.com/netbirdio/netbird/dns" - "github.com/netbirdio/netbird/management/domain" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/geolocation" @@ -31,6 +30,7 @@ import ( "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/posture" + "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/telemetry" @@ -49,104 +49,11 @@ const ( type userLoggedInOnce bool -type ExternalCacheManager cache.CacheInterface[*idp.UserData] - func cacheEntryExpiration() time.Duration { r := rand.Intn(int(CacheExpirationMax.Milliseconds()-CacheExpirationMin.Milliseconds())) + int(CacheExpirationMin.Milliseconds()) return time.Duration(r) * time.Millisecond } -type AccountManager interface { - GetOrCreateAccountByUser(ctx context.Context, userId, domain string) (*types.Account, error) - GetAccount(ctx context.Context, accountID string) (*types.Account, error) - CreateSetupKey(ctx context.Context, accountID string, keyName string, keyType types.SetupKeyType, expiresIn time.Duration, - autoGroups []string, usageLimit int, userID string, ephemeral bool, allowExtraDNSLabels bool) (*types.SetupKey, error) - SaveSetupKey(ctx context.Context, accountID string, key *types.SetupKey, userID string) (*types.SetupKey, error) - CreateUser(ctx context.Context, accountID, initiatorUserID string, key *types.UserInfo) (*types.UserInfo, error) - DeleteUser(ctx context.Context, accountID, initiatorUserID string, targetUserID string) error - DeleteRegularUsers(ctx context.Context, accountID, initiatorUserID string, targetUserIDs []string, userInfos map[string]*types.UserInfo) error - InviteUser(ctx context.Context, accountID string, initiatorUserID string, targetUserID string) error - ListSetupKeys(ctx context.Context, accountID, userID string) ([]*types.SetupKey, error) - SaveUser(ctx context.Context, accountID, initiatorUserID string, update *types.User) (*types.UserInfo, error) - SaveOrAddUser(ctx context.Context, accountID, initiatorUserID string, update *types.User, addIfNotExists bool) (*types.UserInfo, error) - SaveOrAddUsers(ctx context.Context, accountID, initiatorUserID string, updates []*types.User, addIfNotExists bool) ([]*types.UserInfo, error) - GetSetupKey(ctx context.Context, accountID, userID, keyID string) (*types.SetupKey, error) - GetAccountByID(ctx context.Context, accountID string, userID string) (*types.Account, error) - AccountExists(ctx context.Context, accountID string) (bool, error) - GetAccountIDByUserID(ctx context.Context, userID, domain string) (string, error) - GetAccountIDFromUserAuth(ctx context.Context, userAuth nbcontext.UserAuth) (string, string, error) - DeleteAccount(ctx context.Context, accountID, userID string) error - GetUserByID(ctx context.Context, id string) (*types.User, error) - GetUserFromUserAuth(ctx context.Context, userAuth nbcontext.UserAuth) (*types.User, error) - ListUsers(ctx context.Context, accountID string) ([]*types.User, error) - GetPeers(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) - MarkPeerConnected(ctx context.Context, peerKey string, connected bool, realIP net.IP, accountID string) error - DeletePeer(ctx context.Context, accountID, peerID, userID string) error - UpdatePeer(ctx context.Context, accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) - GetNetworkMap(ctx context.Context, peerID string) (*types.NetworkMap, error) - GetPeerNetwork(ctx context.Context, peerID string) (*types.Network, error) - AddPeer(ctx context.Context, setupKey, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) - CreatePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenName string, expiresIn int) (*types.PersonalAccessTokenGenerated, error) - DeletePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) error - GetPAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) (*types.PersonalAccessToken, error) - GetAllPATs(ctx context.Context, accountID string, initiatorUserID string, targetUserID string) ([]*types.PersonalAccessToken, error) - GetUsersFromAccount(ctx context.Context, accountID, userID string) (map[string]*types.UserInfo, error) - GetGroup(ctx context.Context, accountId, groupID, userID string) (*types.Group, error) - GetAllGroups(ctx context.Context, accountID, userID string) ([]*types.Group, error) - GetGroupByName(ctx context.Context, groupName, accountID string) (*types.Group, error) - SaveGroup(ctx context.Context, accountID, userID string, group *types.Group) error - SaveGroups(ctx context.Context, accountID, userID string, newGroups []*types.Group) error - DeleteGroup(ctx context.Context, accountId, userId, groupID string) error - DeleteGroups(ctx context.Context, accountId, userId string, groupIDs []string) error - GroupAddPeer(ctx context.Context, accountId, groupID, peerID string) error - GroupDeletePeer(ctx context.Context, accountId, groupID, peerID string) error - GetPeerGroups(ctx context.Context, accountID, peerID string) ([]*types.Group, error) - GetPolicy(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error) - SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy) (*types.Policy, error) - DeletePolicy(ctx context.Context, accountID, policyID, userID string) error - ListPolicies(ctx context.Context, accountID, userID string) ([]*types.Policy, error) - GetRoute(ctx context.Context, accountID string, routeID route.ID, userID string) (*route.Route, error) - CreateRoute(ctx context.Context, accountID string, prefix netip.Prefix, networkType route.NetworkType, domains domain.List, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups, accessControlGroupIDs []string, enabled bool, userID string, keepRoute bool) (*route.Route, error) - SaveRoute(ctx context.Context, accountID, userID string, route *route.Route) error - DeleteRoute(ctx context.Context, accountID string, routeID route.ID, userID string) error - ListRoutes(ctx context.Context, accountID, userID string) ([]*route.Route, error) - GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) - CreateNameServerGroup(ctx context.Context, accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string, searchDomainsEnabled bool) (*nbdns.NameServerGroup, error) - SaveNameServerGroup(ctx context.Context, accountID, userID string, nsGroupToSave *nbdns.NameServerGroup) error - DeleteNameServerGroup(ctx context.Context, accountID, nsGroupID, userID string) error - ListNameServerGroups(ctx context.Context, accountID string, userID string) ([]*nbdns.NameServerGroup, error) - GetDNSDomain() string - StoreEvent(ctx context.Context, initiatorID, targetID, accountID string, activityID activity.ActivityDescriber, meta map[string]any) - GetEvents(ctx context.Context, accountID, userID string) ([]*activity.Event, error) - GetDNSSettings(ctx context.Context, accountID string, userID string) (*types.DNSSettings, error) - SaveDNSSettings(ctx context.Context, accountID string, userID string, dnsSettingsToSave *types.DNSSettings) error - GetPeer(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error) - UpdateAccountSettings(ctx context.Context, accountID, userID string, newSettings *types.Settings) (*types.Account, error) - LoginPeer(ctx context.Context, login PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) // used by peer gRPC API - SyncPeer(ctx context.Context, sync PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) // used by peer gRPC API - GetAllConnectedPeers() (map[string]struct{}, error) - HasConnectedChannel(peerID string) bool - GetExternalCacheManager() ExternalCacheManager - GetPostureChecks(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error) - SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error) - DeletePostureChecks(ctx context.Context, accountID, postureChecksID, userID string) error - ListPostureChecks(ctx context.Context, accountID, userID string) ([]*posture.Checks, error) - GetIdpManager() idp.Manager - UpdateIntegratedValidatorGroups(ctx context.Context, accountID string, userID string, groups []string) error - GroupValidation(ctx context.Context, accountId string, groups []string) (bool, error) - GetValidatedPeers(ctx context.Context, accountID string) (map[string]struct{}, error) - SyncAndMarkPeer(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) - OnPeerDisconnected(ctx context.Context, accountID string, peerPubKey string) error - SyncPeerMeta(ctx context.Context, peerPubKey string, meta nbpeer.PeerSystemMeta) error - FindExistingPostureCheck(accountID string, checks *posture.ChecksDefinition) (*posture.Checks, error) - GetAccountIDForPeerKey(ctx context.Context, peerKey string) (string, error) - GetAccountSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) - DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error - UpdateAccountPeers(ctx context.Context, accountID string) - BuildUserInfosForAccount(ctx context.Context, accountID, initiatorUserID string, accountUsers []*types.User) (map[string]*types.UserInfo, error) - SyncUserJWTGroups(ctx context.Context, userAuth nbcontext.UserAuth) error -} - type DefaultAccountManager struct { Store store.Store // cacheMux and cacheLoading helps to make sure that only a single cache reload runs at a time per accountID @@ -156,7 +63,7 @@ type DefaultAccountManager struct { peersUpdateManager *PeersUpdateManager idpManager idp.Manager cacheManager cache.CacheInterface[[]*idp.UserData] - externalCacheManager ExternalCacheManager + externalCacheManager account.ExternalCacheManager ctx context.Context eventStore activity.Store geo geolocation.Geolocation @@ -164,6 +71,7 @@ type DefaultAccountManager struct { requestBuffer *AccountRequestBuffer proxyController port_forwarding.Controller + settingsManager settings.Manager // singleAccountMode indicates whether the instance has a single account. // If true, then every new user will end up under the same account. @@ -249,6 +157,7 @@ func BuildManager( integratedPeerValidator integrated_validator.IntegratedValidator, metrics telemetry.AppMetrics, proxyController port_forwarding.Controller, + settingsManager settings.Manager, ) (*DefaultAccountManager, error) { start := time.Now() defer func() { @@ -272,6 +181,7 @@ func BuildManager( metrics: metrics, requestBuffer: NewAccountRequestBuffer(ctx, store), proxyController: proxyController, + settingsManager: settingsManager, } accountsCounter, err := store.GetAccountsCounter(ctx) if err != nil { @@ -317,7 +227,7 @@ func BuildManager( return am, nil } -func (am *DefaultAccountManager) GetExternalCacheManager() ExternalCacheManager { +func (am *DefaultAccountManager) GetExternalCacheManager() account.ExternalCacheManager { return am.externalCacheManager } @@ -406,6 +316,11 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco return nil, err } + err = am.settingsManager.UpdateExtraSettings(ctx, accountID, newSettings.Extra) + if err != nil { + return nil, err + } + if updateAccountPeers { go am.UpdateAccountPeers(ctx, accountID) } @@ -1476,7 +1391,7 @@ func (am *DefaultAccountManager) SyncAndMarkPeer(ctx context.Context, accountID peerUnlock := am.Store.AcquireWriteLockByUID(ctx, peerPubKey) defer peerUnlock() - peer, netMap, postureChecks, err := am.SyncPeer(ctx, PeerSync{WireGuardPubKey: peerPubKey, Meta: meta}, accountID) + peer, netMap, postureChecks, err := am.SyncPeer(ctx, account.PeerSync{WireGuardPubKey: peerPubKey, Meta: meta}, accountID) if err != nil { return nil, nil, nil, fmt.Errorf("error syncing peer: %w", err) } @@ -1516,7 +1431,7 @@ func (am *DefaultAccountManager) SyncPeerMeta(ctx context.Context, peerPubKey st unlockPeer := am.Store.AcquireWriteLockByUID(ctx, peerPubKey) defer unlockPeer() - _, _, _, err = am.SyncPeer(ctx, PeerSync{WireGuardPubKey: peerPubKey, Meta: meta, UpdateAccountPeers: true}, accountID) + _, _, _, err = am.SyncPeer(ctx, account.PeerSync{WireGuardPubKey: peerPubKey, Meta: meta, UpdateAccountPeers: true}, accountID) if err != nil { return mapError(ctx, err) } @@ -1685,3 +1600,7 @@ func separateGroups(autoGroups []string, allGroups []*types.Group) ([]string, ma return newAutoGroups, jwtAutoGroups } + +func (am *DefaultAccountManager) GetStore() store.Store { + return am.Store +} diff --git a/management/server/account/account.go b/management/server/account/account.go deleted file mode 100644 index 40f032fbe..000000000 --- a/management/server/account/account.go +++ /dev/null @@ -1,19 +0,0 @@ -package account - -type ExtraSettings struct { - // PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator - PeerApprovalEnabled bool - - // IntegratedValidatorGroups list of group IDs to be used with integrated approval configurations - IntegratedValidatorGroups []string `gorm:"serializer:json"` -} - -// Copy copies the ExtraSettings struct -func (e *ExtraSettings) Copy() *ExtraSettings { - var cpGroup []string - - return &ExtraSettings{ - PeerApprovalEnabled: e.PeerApprovalEnabled, - IntegratedValidatorGroups: append(cpGroup, e.IntegratedValidatorGroups...), - } -} diff --git a/management/server/account/account_manager_interface.go b/management/server/account/account_manager_interface.go new file mode 100644 index 000000000..f0e20a9d8 --- /dev/null +++ b/management/server/account/account_manager_interface.go @@ -0,0 +1,146 @@ +package account + +import ( + "context" + "net" + "net/netip" + "time" + + "github.com/eko/gocache/v3/cache" + + nbdns "github.com/netbirdio/netbird/dns" + "github.com/netbirdio/netbird/management/domain" + "github.com/netbirdio/netbird/management/server/activity" + nbcontext "github.com/netbirdio/netbird/management/server/context" + "github.com/netbirdio/netbird/management/server/idp" + nbpeer "github.com/netbirdio/netbird/management/server/peer" + "github.com/netbirdio/netbird/management/server/posture" + "github.com/netbirdio/netbird/management/server/store" + "github.com/netbirdio/netbird/management/server/types" + "github.com/netbirdio/netbird/route" +) + +type ExternalCacheManager cache.CacheInterface[*idp.UserData] + +// nolint +type AccountManager interface { + GetOrCreateAccountByUser(ctx context.Context, userId, domain string) (*types.Account, error) + GetAccount(ctx context.Context, accountID string) (*types.Account, error) + CreateSetupKey(ctx context.Context, accountID string, keyName string, keyType types.SetupKeyType, expiresIn time.Duration, + autoGroups []string, usageLimit int, userID string, ephemeral bool, allowExtraDNSLabels bool) (*types.SetupKey, error) + SaveSetupKey(ctx context.Context, accountID string, key *types.SetupKey, userID string) (*types.SetupKey, error) + CreateUser(ctx context.Context, accountID, initiatorUserID string, key *types.UserInfo) (*types.UserInfo, error) + DeleteUser(ctx context.Context, accountID, initiatorUserID string, targetUserID string) error + DeleteRegularUsers(ctx context.Context, accountID, initiatorUserID string, targetUserIDs []string, userInfos map[string]*types.UserInfo) error + InviteUser(ctx context.Context, accountID string, initiatorUserID string, targetUserID string) error + ListSetupKeys(ctx context.Context, accountID, userID string) ([]*types.SetupKey, error) + SaveUser(ctx context.Context, accountID, initiatorUserID string, update *types.User) (*types.UserInfo, error) + SaveOrAddUser(ctx context.Context, accountID, initiatorUserID string, update *types.User, addIfNotExists bool) (*types.UserInfo, error) + SaveOrAddUsers(ctx context.Context, accountID, initiatorUserID string, updates []*types.User, addIfNotExists bool) ([]*types.UserInfo, error) + GetSetupKey(ctx context.Context, accountID, userID, keyID string) (*types.SetupKey, error) + GetAccountByID(ctx context.Context, accountID string, userID string) (*types.Account, error) + AccountExists(ctx context.Context, accountID string) (bool, error) + GetAccountIDByUserID(ctx context.Context, userID, domain string) (string, error) + GetAccountIDFromUserAuth(ctx context.Context, userAuth nbcontext.UserAuth) (string, string, error) + DeleteAccount(ctx context.Context, accountID, userID string) error + GetUserByID(ctx context.Context, id string) (*types.User, error) + GetUserFromUserAuth(ctx context.Context, userAuth nbcontext.UserAuth) (*types.User, error) + ListUsers(ctx context.Context, accountID string) ([]*types.User, error) + GetPeers(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) + MarkPeerConnected(ctx context.Context, peerKey string, connected bool, realIP net.IP, accountID string) error + DeletePeer(ctx context.Context, accountID, peerID, userID string) error + UpdatePeer(ctx context.Context, accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) + GetNetworkMap(ctx context.Context, peerID string) (*types.NetworkMap, error) + GetPeerNetwork(ctx context.Context, peerID string) (*types.Network, error) + AddPeer(ctx context.Context, setupKey, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) + CreatePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenName string, expiresIn int) (*types.PersonalAccessTokenGenerated, error) + DeletePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) error + GetPAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) (*types.PersonalAccessToken, error) + GetAllPATs(ctx context.Context, accountID string, initiatorUserID string, targetUserID string) ([]*types.PersonalAccessToken, error) + GetUsersFromAccount(ctx context.Context, accountID, userID string) (map[string]*types.UserInfo, error) + GetGroup(ctx context.Context, accountId, groupID, userID string) (*types.Group, error) + GetAllGroups(ctx context.Context, accountID, userID string) ([]*types.Group, error) + GetGroupByName(ctx context.Context, groupName, accountID string) (*types.Group, error) + SaveGroup(ctx context.Context, accountID, userID string, group *types.Group) error + SaveGroups(ctx context.Context, accountID, userID string, newGroups []*types.Group) error + DeleteGroup(ctx context.Context, accountId, userId, groupID string) error + DeleteGroups(ctx context.Context, accountId, userId string, groupIDs []string) error + GroupAddPeer(ctx context.Context, accountId, groupID, peerID string) error + GroupDeletePeer(ctx context.Context, accountId, groupID, peerID string) error + GetPeerGroups(ctx context.Context, accountID, peerID string) ([]*types.Group, error) + GetPolicy(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error) + SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy) (*types.Policy, error) + DeletePolicy(ctx context.Context, accountID, policyID, userID string) error + ListPolicies(ctx context.Context, accountID, userID string) ([]*types.Policy, error) + GetRoute(ctx context.Context, accountID string, routeID route.ID, userID string) (*route.Route, error) + CreateRoute(ctx context.Context, accountID string, prefix netip.Prefix, networkType route.NetworkType, domains domain.List, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups, accessControlGroupIDs []string, enabled bool, userID string, keepRoute bool) (*route.Route, error) + SaveRoute(ctx context.Context, accountID, userID string, route *route.Route) error + DeleteRoute(ctx context.Context, accountID string, routeID route.ID, userID string) error + ListRoutes(ctx context.Context, accountID, userID string) ([]*route.Route, error) + GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) + CreateNameServerGroup(ctx context.Context, accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string, searchDomainsEnabled bool) (*nbdns.NameServerGroup, error) + SaveNameServerGroup(ctx context.Context, accountID, userID string, nsGroupToSave *nbdns.NameServerGroup) error + DeleteNameServerGroup(ctx context.Context, accountID, nsGroupID, userID string) error + ListNameServerGroups(ctx context.Context, accountID string, userID string) ([]*nbdns.NameServerGroup, error) + GetDNSDomain() string + StoreEvent(ctx context.Context, initiatorID, targetID, accountID string, activityID activity.ActivityDescriber, meta map[string]any) + GetEvents(ctx context.Context, accountID, userID string) ([]*activity.Event, error) + GetDNSSettings(ctx context.Context, accountID string, userID string) (*types.DNSSettings, error) + SaveDNSSettings(ctx context.Context, accountID string, userID string, dnsSettingsToSave *types.DNSSettings) error + GetPeer(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error) + UpdateAccountSettings(ctx context.Context, accountID, userID string, newSettings *types.Settings) (*types.Account, error) + LoginPeer(ctx context.Context, login PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) // used by peer gRPC API + SyncPeer(ctx context.Context, sync PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) // used by peer gRPC API + GetAllConnectedPeers() (map[string]struct{}, error) + HasConnectedChannel(peerID string) bool + GetExternalCacheManager() ExternalCacheManager + GetPostureChecks(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error) + SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error) + DeletePostureChecks(ctx context.Context, accountID, postureChecksID, userID string) error + ListPostureChecks(ctx context.Context, accountID, userID string) ([]*posture.Checks, error) + GetIdpManager() idp.Manager + UpdateIntegratedValidatorGroups(ctx context.Context, accountID string, userID string, groups []string) error + GroupValidation(ctx context.Context, accountId string, groups []string) (bool, error) + GetValidatedPeers(ctx context.Context, accountID string) (map[string]struct{}, error) + SyncAndMarkPeer(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) + OnPeerDisconnected(ctx context.Context, accountID string, peerPubKey string) error + SyncPeerMeta(ctx context.Context, peerPubKey string, meta nbpeer.PeerSystemMeta) error + FindExistingPostureCheck(accountID string, checks *posture.ChecksDefinition) (*posture.Checks, error) + GetAccountIDForPeerKey(ctx context.Context, peerKey string) (string, error) + GetAccountSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) + DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error + UpdateAccountPeers(ctx context.Context, accountID string) + BuildUserInfosForAccount(ctx context.Context, accountID, initiatorUserID string, accountUsers []*types.User) (map[string]*types.UserInfo, error) + SyncUserJWTGroups(ctx context.Context, userAuth nbcontext.UserAuth) error + GetStore() store.Store +} + +// PeerSync used as a data object between the gRPC API and AccountManager on Sync request. +type PeerSync struct { + // WireGuardPubKey is a peers WireGuard public key + WireGuardPubKey string + // Meta is the system information passed by peer, must be always present + Meta nbpeer.PeerSystemMeta + // UpdateAccountPeers indicate updating account peers, + // which occurs when the peer's metadata is updated + UpdateAccountPeers bool +} + +// PeerLogin used as a data object between the gRPC API and AccountManager on Login request. +type PeerLogin struct { + // WireGuardPubKey is a peers WireGuard public key + WireGuardPubKey string + // SSHKey is a peer's ssh key. Can be empty (e.g., old version do not provide it, or this feature is disabled) + SSHKey string + // Meta is the system information passed by peer, must be always present. + Meta nbpeer.PeerSystemMeta + // UserID indicates that JWT was used to log in, and it was valid. Can be empty when SetupKey is used or auth is not required. + UserID string + // SetupKey references to a server.SetupKey to log in. Can be empty when UserID is used or auth is not required. + SetupKey string + // ConnectionIP is the real IP of the peer + ConnectionIP net.IP + + // ExtraDNSLabels is a list of extra DNS labels that the peer wants to use + ExtraDNSLabels []string +} diff --git a/management/server/account_test.go b/management/server/account_test.go index 9a6828940..7c11048a4 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -13,7 +13,9 @@ import ( "testing" "time" + nbAccount "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" + "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/util" resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types" @@ -36,7 +38,7 @@ import ( "github.com/netbirdio/netbird/route" ) -func verifyCanAddPeerToAccount(t *testing.T, manager AccountManager, account *types.Account, userID string) { +func verifyCanAddPeerToAccount(t *testing.T, manager nbAccount.AccountManager, account *types.Account, userID string) { t.Helper() peer := &nbpeer.Peer{ Key: "BhRPtynAAYRDy08+q4HTMsos8fs4plTP4NOSh7C1ry8=", @@ -1403,7 +1405,7 @@ func TestAccountManager_DeletePeer(t *testing.T) { assert.Equal(t, peer.IP.String(), fmt.Sprint(ev.Meta["ip"])) } -func getEvent(t *testing.T, accountID string, manager AccountManager, eventType activity.Activity) *activity.Event { +func getEvent(t *testing.T, accountID string, manager nbAccount.AccountManager, eventType activity.Activity) *activity.Event { t.Helper() for { select { @@ -2809,7 +2811,7 @@ func createManager(t TB) (*DefaultAccountManager, error) { return nil, err } - manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) if err != nil { return nil, err } @@ -3024,7 +3026,7 @@ func BenchmarkLoginPeer_ExistingPeer(b *testing.B) { b.ResetTimer() start := time.Now() for i := 0; i < b.N; i++ { - _, _, _, err := manager.LoginPeer(context.Background(), PeerLogin{ + _, _, _, err := manager.LoginPeer(context.Background(), nbAccount.PeerLogin{ WireGuardPubKey: account.Peers["peer-1"].Key, SSHKey: "someKey", Meta: nbpeer.PeerSystemMeta{Hostname: strconv.Itoa(i)}, @@ -3099,7 +3101,7 @@ func BenchmarkLoginPeer_NewPeer(b *testing.B) { b.ResetTimer() start := time.Now() for i := 0; i < b.N; i++ { - _, _, _, err := manager.LoginPeer(context.Background(), PeerLogin{ + _, _, _, err := manager.LoginPeer(context.Background(), nbAccount.PeerLogin{ WireGuardPubKey: "some-new-key" + strconv.Itoa(i), SSHKey: "someKey", Meta: nbpeer.PeerSystemMeta{Hostname: strconv.Itoa(i)}, diff --git a/management/server/dns_test.go b/management/server/dns_test.go index 3318dbaed..6b2f73151 100644 --- a/management/server/dns_test.go +++ b/management/server/dns_test.go @@ -12,6 +12,7 @@ import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" + "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/telemetry" "github.com/netbirdio/netbird/management/server/types" @@ -209,7 +210,7 @@ func createDNSManager(t *testing.T) (*DefaultAccountManager, error) { metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) require.NoError(t, err) - return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) } func createDNSStore(t *testing.T) (store.Store, error) { diff --git a/management/server/ephemeral.go b/management/server/ephemeral.go index 3d6d01434..52ab450d7 100644 --- a/management/server/ephemeral.go +++ b/management/server/ephemeral.go @@ -7,6 +7,7 @@ import ( log "github.com/sirupsen/logrus" + nbAccount "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/store" @@ -34,7 +35,7 @@ type ephemeralPeer struct { // automatically. Inactivity means the peer disconnected from the Management server. type EphemeralManager struct { store store.Store - accountManager AccountManager + accountManager nbAccount.AccountManager headPeer *ephemeralPeer tailPeer *ephemeralPeer @@ -43,7 +44,7 @@ type EphemeralManager struct { } // NewEphemeralManager instantiate new EphemeralManager -func NewEphemeralManager(store store.Store, accountManager AccountManager) *EphemeralManager { +func NewEphemeralManager(store store.Store, accountManager nbAccount.AccountManager) *EphemeralManager { return &EphemeralManager{ store: store, accountManager: accountManager, diff --git a/management/server/ephemeral_test.go b/management/server/ephemeral_test.go index df8fe98c3..76e60f2c6 100644 --- a/management/server/ephemeral_test.go +++ b/management/server/ephemeral_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + nbAccount "github.com/netbirdio/netbird/management/server/account" nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/types" @@ -27,7 +28,7 @@ func (s *MockStore) GetAllEphemeralPeers(_ context.Context, _ store.LockingStren } type MocAccountManager struct { - AccountManager + nbAccount.AccountManager store *MockStore } @@ -36,6 +37,10 @@ func (a MocAccountManager) DeletePeer(_ context.Context, accountID, peerID, user return nil //nolint:nil } +func (a MocAccountManager) GetStore() store.Store { + return a.store +} + func TestNewManager(t *testing.T) { startTime := time.Now() timeNow = func() time.Time { diff --git a/management/server/groups/manager.go b/management/server/groups/manager.go index cfc7ee57b..d5431be7b 100644 --- a/management/server/groups/manager.go +++ b/management/server/groups/manager.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - s "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/permissions" @@ -24,13 +24,13 @@ type Manager interface { type managerImpl struct { store store.Store permissionsManager permissions.Manager - accountManager s.AccountManager + accountManager account.AccountManager } type mockManager struct { } -func NewManager(store store.Store, permissionsManager permissions.Manager, accountManager s.AccountManager) Manager { +func NewManager(store store.Store, permissionsManager permissions.Manager, accountManager account.AccountManager) Manager { return &managerImpl{ store: store, permissionsManager: permissionsManager, diff --git a/management/server/grpcserver.go b/management/server/grpcserver.go index 9f77fd242..4e72bd96f 100644 --- a/management/server/grpcserver.go +++ b/management/server/grpcserver.go @@ -12,6 +12,7 @@ import ( pb "github.com/golang/protobuf/proto" // nolint "github.com/golang/protobuf/ptypes/timestamp" "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/realip" + "github.com/netbirdio/management-integrations/integrations" log "github.com/sirupsen/logrus" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" "google.golang.org/grpc/codes" @@ -20,6 +21,8 @@ import ( "github.com/netbirdio/netbird/encryption" "github.com/netbirdio/netbird/management/proto" + "github.com/netbirdio/netbird/management/server/account" + "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/auth" nbContext "github.com/netbirdio/netbird/management/server/context" nbpeer "github.com/netbirdio/netbird/management/server/peer" @@ -32,7 +35,7 @@ import ( // GRPCServer an instance of a Management gRPC API server type GRPCServer struct { - accountManager AccountManager + accountManager account.AccountManager settingsManager settings.Manager wgKey wgtypes.Key proto.UnimplementedManagementServiceServer @@ -49,7 +52,7 @@ type GRPCServer struct { func NewServer( ctx context.Context, config *Config, - accountManager AccountManager, + accountManager account.AccountManager, settingsManager settings.Manager, peersUpdateManager *PeersUpdateManager, secretsManager SecretsManager, @@ -457,7 +460,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p sshKey = loginReq.GetPeerKeys().GetSshPubKey() } - peer, netMap, postureChecks, err := s.accountManager.LoginPeer(ctx, PeerLogin{ + peer, netMap, postureChecks, err := s.accountManager.LoginPeer(ctx, account.PeerLogin{ WireGuardPubKey: peerKey.String(), SSHKey: string(sshKey), Meta: extractPeerMeta(ctx, loginReq.GetMeta()), @@ -486,7 +489,7 @@ func (s *GRPCServer) Login(ctx context.Context, req *proto.EncryptedMessage) (*p // if peer has reached this point then it has logged in loginResp := &proto.LoginResponse{ - NetbirdConfig: toNetbirdConfig(s.config, nil, relayToken), + NetbirdConfig: toNetbirdConfig(s.config, nil, relayToken, nil), PeerConfig: toPeerConfig(peer, netMap.Network, s.accountManager.GetDNSDomain(), false), Checks: toProtocolChecks(ctx, postureChecks), } @@ -544,7 +547,7 @@ func ToResponseProto(configProto Protocol) proto.HostConfig_Protocol { } } -func toNetbirdConfig(config *Config, turnCredentials *Token, relayToken *Token) *proto.NetbirdConfig { +func toNetbirdConfig(config *Config, turnCredentials *Token, relayToken *Token, extraSettings *types.ExtraSettings) *proto.NetbirdConfig { if config == nil { return nil } @@ -592,7 +595,7 @@ func toNetbirdConfig(config *Config, turnCredentials *Token, relayToken *Token) } } - return &proto.NetbirdConfig{ + nbConfig := &proto.NetbirdConfig{ Stuns: stuns, Turns: turns, Signal: &proto.HostConfig{ @@ -601,6 +604,10 @@ func toNetbirdConfig(config *Config, turnCredentials *Token, relayToken *Token) }, Relay: relayCfg, } + + integrations.ExtendNetBirdConfig(nbConfig, extraSettings) + + return nbConfig } func toPeerConfig(peer *nbpeer.Peer, network *types.Network, dnsName string, dnsResolutionOnRoutingPeerEnabled bool) *proto.PeerConfig { @@ -614,10 +621,10 @@ func toPeerConfig(peer *nbpeer.Peer, network *types.Network, dnsName string, dns } } -func toSyncResponse(ctx context.Context, config *Config, peer *nbpeer.Peer, turnCredentials *Token, relayCredentials *Token, networkMap *types.NetworkMap, dnsName string, checks []*posture.Checks, dnsCache *DNSConfigCache, dnsResolutionOnRoutingPeerEnbled bool) *proto.SyncResponse { +func toSyncResponse(ctx context.Context, config *Config, peer *nbpeer.Peer, turnCredentials *Token, relayCredentials *Token, networkMap *types.NetworkMap, dnsName string, checks []*posture.Checks, dnsCache *DNSConfigCache, dnsResolutionOnRoutingPeerEnabled bool, extraSettings *types.ExtraSettings) *proto.SyncResponse { response := &proto.SyncResponse{ - NetbirdConfig: toNetbirdConfig(config, turnCredentials, relayCredentials), - PeerConfig: toPeerConfig(peer, networkMap.Network, dnsName, dnsResolutionOnRoutingPeerEnbled), + NetbirdConfig: toNetbirdConfig(config, turnCredentials, relayCredentials, extraSettings), + PeerConfig: toPeerConfig(peer, networkMap.Network, dnsName, dnsResolutionOnRoutingPeerEnabled), NetworkMap: &proto.NetworkMap{ Serial: networkMap.Network.CurrentSerial(), Routes: toProtocolRoutes(networkMap.Routes), @@ -693,12 +700,12 @@ func (s *GRPCServer) sendInitialSync(ctx context.Context, peerKey wgtypes.Key, p } } - settings, err := s.settingsManager.GetSettings(ctx, peer.AccountID, peer.UserID) + settings, err := s.settingsManager.GetSettings(ctx, peer.AccountID, activity.SystemInitiator) if err != nil { return status.Errorf(codes.Internal, "error handling request") } - plainResp := toSyncResponse(ctx, s.config, peer, turnToken, relayToken, networkMap, s.accountManager.GetDNSDomain(), postureChecks, nil, settings.RoutingPeerDNSResolutionEnabled) + plainResp := toSyncResponse(ctx, s.config, peer, turnToken, relayToken, networkMap, s.accountManager.GetDNSDomain(), postureChecks, nil, settings.RoutingPeerDNSResolutionEnabled, settings.Extra) encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, plainResp) if err != nil { diff --git a/management/server/http/api/openapi.yml b/management/server/http/api/openapi.yml index ab4f7c0ba..622af5ba0 100644 --- a/management/server/http/api/openapi.yml +++ b/management/server/http/api/openapi.yml @@ -106,6 +106,10 @@ components: description: (Cloud only) Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. type: boolean example: true + network_traffic_logs_enabled: + description: Enables or disables network traffic logs. If enabled, all network traffic logs from peers will be stored. + type: boolean + example: true AccountRequest: type: object properties: diff --git a/management/server/http/api/types.gen.go b/management/server/http/api/types.gen.go index fc5d3d707..c94028dbb 100644 --- a/management/server/http/api/types.gen.go +++ b/management/server/http/api/types.gen.go @@ -230,6 +230,9 @@ type Account struct { // AccountExtraSettings defines model for AccountExtraSettings. type AccountExtraSettings struct { + // NetworkTrafficLogsEnabled Enables or disables network traffic logs. If enabled, all network traffic logs from peers will be stored. + NetworkTrafficLogsEnabled *bool `json:"network_traffic_logs_enabled,omitempty"` + // PeerApprovalEnabled (Cloud only) Enables or disables peer approval globally. If enabled, all peers added will be in pending state until approved by an admin. PeerApprovalEnabled *bool `json:"peer_approval_enabled,omitempty"` } diff --git a/management/server/http/handler.go b/management/server/http/handler.go index f4c4bc763..6a3cfae70 100644 --- a/management/server/http/handler.go +++ b/management/server/http/handler.go @@ -10,10 +10,12 @@ import ( "github.com/netbirdio/management-integrations/integrations" + "github.com/netbirdio/netbird/management/server/account" + "github.com/netbirdio/netbird/management/server/settings" + "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" "github.com/netbirdio/netbird/management/server/permissions" - s "github.com/netbirdio/netbird/management/server" "github.com/netbirdio/netbird/management/server/auth" "github.com/netbirdio/netbird/management/server/geolocation" nbgroups "github.com/netbirdio/netbird/management/server/groups" @@ -41,7 +43,7 @@ const apiPrefix = "/api" // NewAPIHandler creates the Management service HTTP API handler registering all the available endpoints. func NewAPIHandler( ctx context.Context, - accountManager s.AccountManager, + accountManager account.AccountManager, networksManager nbnetworks.Manager, resourceManager resources.Manager, routerManager routers.Manager, @@ -53,6 +55,7 @@ func NewAPIHandler( proxyController port_forwarding.Controller, permissionsManager permissions.Manager, peersManager nbpeers.Manager, + settingsManager settings.Manager, ) (http.Handler, error) { authMiddleware := middleware.NewAuthMiddleware( @@ -73,11 +76,11 @@ func NewAPIHandler( router.Use(metricsMiddleware.Handler, corsMiddleware.Handler, authMiddleware.Handler, acMiddleware.Handler) - if _, err := integrations.RegisterHandlers(ctx, prefix, router, accountManager, integratedValidator, appMetrics.GetMeter(), permissionsManager, peersManager, proxyController); err != nil { + if _, err := integrations.RegisterHandlers(ctx, prefix, router, accountManager, integratedValidator, appMetrics.GetMeter(), permissionsManager, peersManager, proxyController, settingsManager); err != nil { return nil, fmt.Errorf("register integrations endpoints: %w", err) } - accounts.AddEndpoints(accountManager, router) + accounts.AddEndpoints(accountManager, settingsManager, router) peers.AddEndpoints(accountManager, router) users.AddEndpoints(accountManager, router) setup_keys.AddEndpoints(accountManager, router) diff --git a/management/server/http/handlers/accounts/accounts_handler.go b/management/server/http/handlers/accounts/accounts_handler.go index bc0054a7f..b76d28094 100644 --- a/management/server/http/handlers/accounts/accounts_handler.go +++ b/management/server/http/handlers/accounts/accounts_handler.go @@ -7,31 +7,33 @@ import ( "github.com/gorilla/mux" - "github.com/netbirdio/netbird/management/server" "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" + "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/types" ) // handler is a handler that handles the server.Account HTTP endpoints type handler struct { - accountManager server.AccountManager + accountManager account.AccountManager + settingsManager settings.Manager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { - accountsHandler := newHandler(accountManager) +func AddEndpoints(accountManager account.AccountManager, settingsManager settings.Manager, router *mux.Router) { + accountsHandler := newHandler(accountManager, settingsManager) router.HandleFunc("/accounts/{accountId}", accountsHandler.updateAccount).Methods("PUT", "OPTIONS") router.HandleFunc("/accounts/{accountId}", accountsHandler.deleteAccount).Methods("DELETE", "OPTIONS") router.HandleFunc("/accounts", accountsHandler.getAllAccounts).Methods("GET", "OPTIONS") } // newHandler creates a new handler HTTP handler -func newHandler(accountManager server.AccountManager) *handler { +func newHandler(accountManager account.AccountManager, settingsManager settings.Manager) *handler { return &handler{ - accountManager: accountManager, + accountManager: accountManager, + settingsManager: settingsManager, } } @@ -45,7 +47,7 @@ func (h *handler) getAllAccounts(w http.ResponseWriter, r *http.Request) { accountID, userID := userAuth.AccountId, userAuth.UserId - settings, err := h.accountManager.GetAccountSettings(r.Context(), accountID, userID) + settings, err := h.settingsManager.GetSettings(r.Context(), accountID, userID) if err != nil { util.WriteError(r.Context(), err, w) return @@ -89,7 +91,14 @@ func (h *handler) updateAccount(w http.ResponseWriter, r *http.Request) { } if req.Settings.Extra != nil { - settings.Extra = &account.ExtraSettings{PeerApprovalEnabled: *req.Settings.Extra.PeerApprovalEnabled} + flowEnabled := false + if req.Settings.Extra.NetworkTrafficLogsEnabled != nil { + flowEnabled = *req.Settings.Extra.NetworkTrafficLogsEnabled + } + settings.Extra = &types.ExtraSettings{ + PeerApprovalEnabled: *req.Settings.Extra.PeerApprovalEnabled, + FlowEnabled: flowEnabled, + } } if req.Settings.JwtGroupsEnabled != nil { @@ -163,7 +172,10 @@ func toAccountResponse(accountID string, settings *types.Settings) *api.Account } if settings.Extra != nil { - apiSettings.Extra = &api.AccountExtraSettings{PeerApprovalEnabled: &settings.Extra.PeerApprovalEnabled} + apiSettings.Extra = &api.AccountExtraSettings{ + PeerApprovalEnabled: &settings.Extra.PeerApprovalEnabled, + NetworkTrafficLogsEnabled: &settings.Extra.FlowEnabled, + } } return &api.Account{ diff --git a/management/server/http/handlers/accounts/accounts_handler_test.go b/management/server/http/handlers/accounts/accounts_handler_test.go index a8d57a13f..61ab4ef8a 100644 --- a/management/server/http/handlers/accounts/accounts_handler_test.go +++ b/management/server/http/handlers/accounts/accounts_handler_test.go @@ -16,11 +16,16 @@ import ( nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/mock_server" + "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/types" ) func initAccountsTestData(account *types.Account) *handler { + settingsMock := settings.NewManagerMock() + settingsMock.GetSettingsFunc = func(ctx context.Context, accountID string, userID string) (*types.Settings, error) { + return account.Settings, nil + } return &handler{ accountManager: &mock_server.MockAccountManager{ GetAccountSettingsFunc: func(ctx context.Context, accountID string, userID string) (*types.Settings, error) { @@ -41,6 +46,7 @@ func initAccountsTestData(account *types.Account) *handler { return accCopy, nil }, }, + settingsManager: settingsMock, } } diff --git a/management/server/http/handlers/dns/dns_settings_handler.go b/management/server/http/handlers/dns/dns_settings_handler.go index 6ff938369..85be8e707 100644 --- a/management/server/http/handlers/dns/dns_settings_handler.go +++ b/management/server/http/handlers/dns/dns_settings_handler.go @@ -7,7 +7,7 @@ import ( "github.com/gorilla/mux" log "github.com/sirupsen/logrus" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" @@ -16,22 +16,22 @@ import ( // dnsSettingsHandler is a handler that returns the DNS settings of the account type dnsSettingsHandler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, router *mux.Router) { addDNSSettingEndpoint(accountManager, router) addDNSNameserversEndpoint(accountManager, router) } -func addDNSSettingEndpoint(accountManager server.AccountManager, router *mux.Router) { +func addDNSSettingEndpoint(accountManager account.AccountManager, router *mux.Router) { dnsSettingsHandler := newDNSSettingsHandler(accountManager) router.HandleFunc("/dns/settings", dnsSettingsHandler.getDNSSettings).Methods("GET", "OPTIONS") router.HandleFunc("/dns/settings", dnsSettingsHandler.updateDNSSettings).Methods("PUT", "OPTIONS") } // newDNSSettingsHandler returns a new instance of dnsSettingsHandler handler -func newDNSSettingsHandler(accountManager server.AccountManager) *dnsSettingsHandler { +func newDNSSettingsHandler(accountManager account.AccountManager) *dnsSettingsHandler { return &dnsSettingsHandler{accountManager: accountManager} } diff --git a/management/server/http/handlers/dns/nameservers_handler.go b/management/server/http/handlers/dns/nameservers_handler.go index 33d070477..0bba95988 100644 --- a/management/server/http/handlers/dns/nameservers_handler.go +++ b/management/server/http/handlers/dns/nameservers_handler.go @@ -9,7 +9,7 @@ import ( log "github.com/sirupsen/logrus" nbdns "github.com/netbirdio/netbird/dns" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" @@ -18,10 +18,10 @@ import ( // nameserversHandler is the nameserver group handler of the account type nameserversHandler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func addDNSNameserversEndpoint(accountManager server.AccountManager, router *mux.Router) { +func addDNSNameserversEndpoint(accountManager account.AccountManager, router *mux.Router) { nameserversHandler := newNameserversHandler(accountManager) router.HandleFunc("/dns/nameservers", nameserversHandler.getAllNameservers).Methods("GET", "OPTIONS") router.HandleFunc("/dns/nameservers", nameserversHandler.createNameserverGroup).Methods("POST", "OPTIONS") @@ -31,7 +31,7 @@ func addDNSNameserversEndpoint(accountManager server.AccountManager, router *mux } // newNameserversHandler returns a new instance of nameserversHandler handler -func newNameserversHandler(accountManager server.AccountManager) *nameserversHandler { +func newNameserversHandler(accountManager account.AccountManager) *nameserversHandler { return &nameserversHandler{accountManager: accountManager} } diff --git a/management/server/http/handlers/events/events_handler.go b/management/server/http/handlers/events/events_handler.go index 0fb2295a8..984201ac0 100644 --- a/management/server/http/handlers/events/events_handler.go +++ b/management/server/http/handlers/events/events_handler.go @@ -8,7 +8,7 @@ import ( "github.com/gorilla/mux" log "github.com/sirupsen/logrus" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" @@ -17,16 +17,16 @@ import ( // handler HTTP handler type handler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, router *mux.Router) { eventsHandler := newHandler(accountManager) router.HandleFunc("/events", eventsHandler.getAllEvents).Methods("GET", "OPTIONS") } // newHandler creates a new events handler -func newHandler(accountManager server.AccountManager) *handler { +func newHandler(accountManager account.AccountManager) *handler { return &handler{accountManager: accountManager} } diff --git a/management/server/http/handlers/groups/groups_handler.go b/management/server/http/handlers/groups/groups_handler.go index 2d0b8bdbd..012987994 100644 --- a/management/server/http/handlers/groups/groups_handler.go +++ b/management/server/http/handlers/groups/groups_handler.go @@ -7,10 +7,10 @@ import ( "github.com/gorilla/mux" log "github.com/sirupsen/logrus" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" nbpeer "github.com/netbirdio/netbird/management/server/peer" - "github.com/netbirdio/netbird/management/server" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" "github.com/netbirdio/netbird/management/server/status" @@ -19,10 +19,10 @@ import ( // handler is a handler that returns groups of the account type handler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, router *mux.Router) { groupsHandler := newHandler(accountManager) router.HandleFunc("/groups", groupsHandler.getAllGroups).Methods("GET", "OPTIONS") router.HandleFunc("/groups", groupsHandler.createGroup).Methods("POST", "OPTIONS") @@ -32,7 +32,7 @@ func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { } // newHandler creates a new groups handler -func newHandler(accountManager server.AccountManager) *handler { +func newHandler(accountManager account.AccountManager) *handler { return &handler{ accountManager: accountManager, } diff --git a/management/server/http/handlers/networks/handler.go b/management/server/http/handlers/networks/handler.go index bb6b97267..319b8ca45 100644 --- a/management/server/http/handlers/networks/handler.go +++ b/management/server/http/handlers/networks/handler.go @@ -9,7 +9,7 @@ import ( "github.com/gorilla/mux" log "github.com/sirupsen/logrus" - s "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/groups" "github.com/netbirdio/netbird/management/server/http/api" @@ -28,12 +28,12 @@ type handler struct { networksManager networks.Manager resourceManager resources.Manager routerManager routers.Manager - accountManager s.AccountManager + accountManager account.AccountManager groupsManager groups.Manager } -func AddEndpoints(networksManager networks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager groups.Manager, accountManager s.AccountManager, router *mux.Router) { +func AddEndpoints(networksManager networks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager groups.Manager, accountManager account.AccountManager, router *mux.Router) { addRouterEndpoints(routerManager, router) addResourceEndpoints(resourceManager, groupsManager, router) @@ -45,7 +45,7 @@ func AddEndpoints(networksManager networks.Manager, resourceManager resources.Ma router.HandleFunc("/networks/{networkId}", networksHandler.deleteNetwork).Methods("DELETE", "OPTIONS") } -func newHandler(networksManager networks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager groups.Manager, accountManager s.AccountManager) *handler { +func newHandler(networksManager networks.Manager, resourceManager resources.Manager, routerManager routers.Manager, groupsManager groups.Manager, accountManager account.AccountManager) *handler { return &handler{ networksManager: networksManager, resourceManager: resourceManager, diff --git a/management/server/http/handlers/peers/peers_handler.go b/management/server/http/handlers/peers/peers_handler.go index 2336d16cf..4bf6e4830 100644 --- a/management/server/http/handlers/peers/peers_handler.go +++ b/management/server/http/handlers/peers/peers_handler.go @@ -9,7 +9,7 @@ import ( "github.com/gorilla/mux" log "github.com/sirupsen/logrus" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/groups" "github.com/netbirdio/netbird/management/server/http/api" @@ -21,10 +21,10 @@ import ( // Handler is a handler that returns peers of the account type Handler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, router *mux.Router) { peersHandler := NewHandler(accountManager) router.HandleFunc("/peers", peersHandler.GetAllPeers).Methods("GET", "OPTIONS") router.HandleFunc("/peers/{peerId}", peersHandler.HandlePeer). @@ -33,7 +33,7 @@ func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { } // NewHandler creates a new peers Handler -func NewHandler(accountManager server.AccountManager) *Handler { +func NewHandler(accountManager account.AccountManager) *Handler { return &Handler{ accountManager: accountManager, } diff --git a/management/server/http/handlers/policies/geolocations_handler.go b/management/server/http/handlers/policies/geolocations_handler.go index c4868f879..818230e44 100644 --- a/management/server/http/handlers/policies/geolocations_handler.go +++ b/management/server/http/handlers/policies/geolocations_handler.go @@ -6,7 +6,7 @@ import ( "github.com/gorilla/mux" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/geolocation" "github.com/netbirdio/netbird/management/server/http/api" @@ -20,18 +20,18 @@ var ( // geolocationsHandler is a handler that returns locations. type geolocationsHandler struct { - accountManager server.AccountManager + accountManager account.AccountManager geolocationManager geolocation.Geolocation } -func addLocationsEndpoint(accountManager server.AccountManager, locationManager geolocation.Geolocation, router *mux.Router) { +func addLocationsEndpoint(accountManager account.AccountManager, locationManager geolocation.Geolocation, router *mux.Router) { locationHandler := newGeolocationsHandlerHandler(accountManager, locationManager) router.HandleFunc("/locations/countries", locationHandler.getAllCountries).Methods("GET", "OPTIONS") router.HandleFunc("/locations/countries/{country}/cities", locationHandler.getCitiesByCountry).Methods("GET", "OPTIONS") } // newGeolocationsHandlerHandler creates a new Geolocations handler -func newGeolocationsHandlerHandler(accountManager server.AccountManager, geolocationManager geolocation.Geolocation) *geolocationsHandler { +func newGeolocationsHandlerHandler(accountManager account.AccountManager, geolocationManager geolocation.Geolocation) *geolocationsHandler { return &geolocationsHandler{ accountManager: accountManager, geolocationManager: geolocationManager, diff --git a/management/server/http/handlers/policies/policies_handler.go b/management/server/http/handlers/policies/policies_handler.go index 63fc8a03b..b76f5b1bd 100644 --- a/management/server/http/handlers/policies/policies_handler.go +++ b/management/server/http/handlers/policies/policies_handler.go @@ -7,7 +7,7 @@ import ( "github.com/gorilla/mux" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/geolocation" "github.com/netbirdio/netbird/management/server/http/api" @@ -18,10 +18,10 @@ import ( // handler is a handler that returns policy of the account type handler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, locationManager geolocation.Geolocation, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, locationManager geolocation.Geolocation, router *mux.Router) { policiesHandler := newHandler(accountManager) router.HandleFunc("/policies", policiesHandler.getAllPolicies).Methods("GET", "OPTIONS") router.HandleFunc("/policies", policiesHandler.createPolicy).Methods("POST", "OPTIONS") @@ -32,7 +32,7 @@ func AddEndpoints(accountManager server.AccountManager, locationManager geolocat } // newHandler creates a new policies handler -func newHandler(accountManager server.AccountManager) *handler { +func newHandler(accountManager account.AccountManager) *handler { return &handler{ accountManager: accountManager, } diff --git a/management/server/http/handlers/policies/posture_checks_handler.go b/management/server/http/handlers/policies/posture_checks_handler.go index e6e58da58..be099d7f2 100644 --- a/management/server/http/handlers/policies/posture_checks_handler.go +++ b/management/server/http/handlers/policies/posture_checks_handler.go @@ -6,7 +6,7 @@ import ( "github.com/gorilla/mux" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/geolocation" "github.com/netbirdio/netbird/management/server/http/api" @@ -17,11 +17,11 @@ import ( // postureChecksHandler is a handler that returns posture checks of the account. type postureChecksHandler struct { - accountManager server.AccountManager + accountManager account.AccountManager geolocationManager geolocation.Geolocation } -func addPostureCheckEndpoint(accountManager server.AccountManager, locationManager geolocation.Geolocation, router *mux.Router) { +func addPostureCheckEndpoint(accountManager account.AccountManager, locationManager geolocation.Geolocation, router *mux.Router) { postureCheckHandler := newPostureChecksHandler(accountManager, locationManager) router.HandleFunc("/posture-checks", postureCheckHandler.getAllPostureChecks).Methods("GET", "OPTIONS") router.HandleFunc("/posture-checks", postureCheckHandler.createPostureCheck).Methods("POST", "OPTIONS") @@ -32,7 +32,7 @@ func addPostureCheckEndpoint(accountManager server.AccountManager, locationManag } // newPostureChecksHandler creates a new PostureChecks handler -func newPostureChecksHandler(accountManager server.AccountManager, geolocationManager geolocation.Geolocation) *postureChecksHandler { +func newPostureChecksHandler(accountManager account.AccountManager, geolocationManager geolocation.Geolocation) *postureChecksHandler { return &postureChecksHandler{ accountManager: accountManager, geolocationManager: geolocationManager, diff --git a/management/server/http/handlers/routes/routes_handler.go b/management/server/http/handlers/routes/routes_handler.go index 0f0d24780..d6aa52c5e 100644 --- a/management/server/http/handlers/routes/routes_handler.go +++ b/management/server/http/handlers/routes/routes_handler.go @@ -9,7 +9,7 @@ import ( "github.com/gorilla/mux" "github.com/netbirdio/netbird/management/domain" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" @@ -21,10 +21,10 @@ const failedToConvertRoute = "failed to convert route to response: %v" // handler is the routes handler of the account type handler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, router *mux.Router) { routesHandler := newHandler(accountManager) router.HandleFunc("/routes", routesHandler.getAllRoutes).Methods("GET", "OPTIONS") router.HandleFunc("/routes", routesHandler.createRoute).Methods("POST", "OPTIONS") @@ -34,7 +34,7 @@ func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { } // newHandler returns a new instance of routes handler -func newHandler(accountManager server.AccountManager) *handler { +func newHandler(accountManager account.AccountManager) *handler { return &handler{ accountManager: accountManager, } diff --git a/management/server/http/handlers/setup_keys/setupkeys_handler.go b/management/server/http/handlers/setup_keys/setupkeys_handler.go index 8095f43b0..bebbe1f16 100644 --- a/management/server/http/handlers/setup_keys/setupkeys_handler.go +++ b/management/server/http/handlers/setup_keys/setupkeys_handler.go @@ -3,13 +3,12 @@ package setup_keys import ( "context" "encoding/json" - "net/http" "time" "github.com/gorilla/mux" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" @@ -19,10 +18,10 @@ import ( // handler is a handler that returns a list of setup keys of the account type handler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, router *mux.Router) { keysHandler := newHandler(accountManager) router.HandleFunc("/setup-keys", keysHandler.getAllSetupKeys).Methods("GET", "OPTIONS") router.HandleFunc("/setup-keys", keysHandler.createSetupKey).Methods("POST", "OPTIONS") @@ -32,7 +31,7 @@ func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { } // newHandler creates a new setup key handler -func newHandler(accountManager server.AccountManager) *handler { +func newHandler(accountManager account.AccountManager) *handler { return &handler{ accountManager: accountManager, } diff --git a/management/server/http/handlers/users/pat_handler.go b/management/server/http/handlers/users/pat_handler.go index 84fbef93e..ba8fcd3ed 100644 --- a/management/server/http/handlers/users/pat_handler.go +++ b/management/server/http/handlers/users/pat_handler.go @@ -6,7 +6,7 @@ import ( "github.com/gorilla/mux" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" @@ -16,10 +16,10 @@ import ( // patHandler is the nameserver group handler of the account type patHandler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func addUsersTokensEndpoint(accountManager server.AccountManager, router *mux.Router) { +func addUsersTokensEndpoint(accountManager account.AccountManager, router *mux.Router) { tokenHandler := newPATsHandler(accountManager) router.HandleFunc("/users/{userId}/tokens", tokenHandler.getAllTokens).Methods("GET", "OPTIONS") router.HandleFunc("/users/{userId}/tokens", tokenHandler.createToken).Methods("POST", "OPTIONS") @@ -28,7 +28,7 @@ func addUsersTokensEndpoint(accountManager server.AccountManager, router *mux.Ro } // newPATsHandler creates a new patHandler HTTP handler -func newPATsHandler(accountManager server.AccountManager) *patHandler { +func newPATsHandler(accountManager account.AccountManager) *patHandler { return &patHandler{ accountManager: accountManager, } diff --git a/management/server/http/handlers/users/users_handler.go b/management/server/http/handlers/users/users_handler.go index 3869f21f0..6dcd4ea69 100644 --- a/management/server/http/handlers/users/users_handler.go +++ b/management/server/http/handlers/users/users_handler.go @@ -8,21 +8,21 @@ import ( "github.com/gorilla/mux" log "github.com/sirupsen/logrus" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/http/api" "github.com/netbirdio/netbird/management/server/http/util" "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/types" - "github.com/netbirdio/netbird/management/server" nbcontext "github.com/netbirdio/netbird/management/server/context" ) // handler is a handler that returns users of the account type handler struct { - accountManager server.AccountManager + accountManager account.AccountManager } -func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { +func AddEndpoints(accountManager account.AccountManager, router *mux.Router) { userHandler := newHandler(accountManager) router.HandleFunc("/users", userHandler.getAllUsers).Methods("GET", "OPTIONS") router.HandleFunc("/users/{userId}", userHandler.updateUser).Methods("PUT", "OPTIONS") @@ -33,7 +33,7 @@ func AddEndpoints(accountManager server.AccountManager, router *mux.Router) { } // newHandler creates a new UsersHandler HTTP handler -func newHandler(accountManager server.AccountManager) *handler { +func newHandler(accountManager account.AccountManager) *handler { return &handler{ accountManager: accountManager, } diff --git a/management/server/http/testing/testing_tools/tools.go b/management/server/http/testing/testing_tools/tools.go index a74299fa0..37b9a3023 100644 --- a/management/server/http/testing/testing_tools/tools.go +++ b/management/server/http/testing/testing_tools/tools.go @@ -15,7 +15,13 @@ import ( "time" "github.com/golang-jwt/jwt" + "github.com/netbirdio/management-integrations/integrations" + + "github.com/netbirdio/netbird/management/server/account" + "github.com/netbirdio/netbird/management/server/settings" + "github.com/netbirdio/netbird/management/server/users" + "github.com/stretchr/testify/assert" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" @@ -88,7 +94,7 @@ type PerformanceMetrics struct { MaxMsPerOpCICD float64 } -func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *server.UpdateMessage, validateUpdate bool) (http.Handler, server.AccountManager, chan struct{}) { +func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *server.UpdateMessage, validateUpdate bool) (http.Handler, account.AccountManager, chan struct{}) { store, cleanup, err := store.NewTestStoreFromSQL(context.Background(), sqlFile, t.TempDir()) if err != nil { t.Fatalf("Failed to create test store: %v", err) @@ -117,7 +123,9 @@ func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *serve geoMock := &geolocation.Mock{} validatorMock := server.MocIntegratedValidator{} proxyController := integrations.NewController(store) - am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController) + userManager := users.NewManager(store) + settingsManager := settings.NewManager(store, userManager, integrations.NewManager()) + am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager) if err != nil { t.Fatalf("Failed to create manager: %v", err) } @@ -138,7 +146,7 @@ func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *serve permissionsManagerMock := permissions.NewManagerMock() peersManager := peers.NewManager(store, permissionsManagerMock) - apiHandler, err := nbhttp.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManagerMock, peersManager) + apiHandler, err := nbhttp.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManagerMock, peersManager, settingsManager) if err != nil { t.Fatalf("Failed to create API handler: %v", err) } diff --git a/management/server/integrated_validator.go b/management/server/integrated_validator.go index b95ea1699..ef77bf10c 100644 --- a/management/server/integrated_validator.go +++ b/management/server/integrated_validator.go @@ -6,7 +6,6 @@ import ( log "github.com/sirupsen/logrus" - "github.com/netbirdio/netbird/management/server/account" nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/types" @@ -43,12 +42,12 @@ func (am *DefaultAccountManager) UpdateIntegratedValidatorGroups(ctx context.Con return err } - var extra *account.ExtraSettings + var extra *types.ExtraSettings if a.Settings.Extra != nil { extra = a.Settings.Extra } else { - extra = &account.ExtraSettings{} + extra = &types.ExtraSettings{} a.Settings.Extra = extra } extra.IntegratedValidatorGroups = groups @@ -104,21 +103,21 @@ func (am *DefaultAccountManager) GetValidatedPeers(ctx context.Context, accountI } type MocIntegratedValidator struct { - ValidatePeerFunc func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *account.ExtraSettings) (*nbpeer.Peer, bool, error) + ValidatePeerFunc func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) } -func (a MocIntegratedValidator) ValidateExtraSettings(_ context.Context, newExtraSettings *account.ExtraSettings, oldExtraSettings *account.ExtraSettings, peers map[string]*nbpeer.Peer, userID string, accountID string) error { +func (a MocIntegratedValidator) ValidateExtraSettings(_ context.Context, newExtraSettings *types.ExtraSettings, oldExtraSettings *types.ExtraSettings, peers map[string]*nbpeer.Peer, userID string, accountID string) error { return nil } -func (a MocIntegratedValidator) ValidatePeer(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *account.ExtraSettings) (*nbpeer.Peer, bool, error) { +func (a MocIntegratedValidator) ValidatePeer(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) { if a.ValidatePeerFunc != nil { return a.ValidatePeerFunc(context.Background(), update, peer, userID, accountID, dnsDomain, peersGroup, extraSettings) } return update, false, nil } -func (a MocIntegratedValidator) GetValidatedPeers(accountID string, groups []*types.Group, peers []*nbpeer.Peer, extraSettings *account.ExtraSettings) (map[string]struct{}, error) { +func (a MocIntegratedValidator) GetValidatedPeers(accountID string, groups []*types.Group, peers []*nbpeer.Peer, extraSettings *types.ExtraSettings) (map[string]struct{}, error) { validatedPeers := make(map[string]struct{}) for _, peer := range peers { validatedPeers[peer.ID] = struct{}{} @@ -126,11 +125,11 @@ func (a MocIntegratedValidator) GetValidatedPeers(accountID string, groups []*ty return validatedPeers, nil } -func (MocIntegratedValidator) PreparePeer(_ context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *account.ExtraSettings) *nbpeer.Peer { +func (MocIntegratedValidator) PreparePeer(_ context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings) *nbpeer.Peer { return peer } -func (MocIntegratedValidator) IsNotValidPeer(_ context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *account.ExtraSettings) (bool, bool, error) { +func (MocIntegratedValidator) IsNotValidPeer(_ context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings) (bool, bool, error) { return false, false, nil } diff --git a/management/server/integrations/extra_settings/manager.go b/management/server/integrations/extra_settings/manager.go new file mode 100644 index 000000000..f471b228f --- /dev/null +++ b/management/server/integrations/extra_settings/manager.go @@ -0,0 +1,12 @@ +package extra_settings + +import ( + "context" + + "github.com/netbirdio/netbird/management/server/types" +) + +type Manager interface { + GetExtraSettings(ctx context.Context, accountID string) (*types.ExtraSettings, error) + UpdateExtraSettings(ctx context.Context, accountID string, extraSettings *types.ExtraSettings) error +} diff --git a/management/server/integrations/integrated_validator/interface.go b/management/server/integrations/integrated_validator/interface.go index ff179e3c0..083baa65e 100644 --- a/management/server/integrations/integrated_validator/interface.go +++ b/management/server/integrations/integrated_validator/interface.go @@ -3,18 +3,17 @@ package integrated_validator import ( "context" - "github.com/netbirdio/netbird/management/server/account" nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/types" ) // IntegratedValidator interface exists to avoid the circle dependencies type IntegratedValidator interface { - ValidateExtraSettings(ctx context.Context, newExtraSettings *account.ExtraSettings, oldExtraSettings *account.ExtraSettings, peers map[string]*nbpeer.Peer, userID string, accountID string) error - ValidatePeer(ctx context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *account.ExtraSettings) (*nbpeer.Peer, bool, error) - PreparePeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *account.ExtraSettings) *nbpeer.Peer - IsNotValidPeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *account.ExtraSettings) (bool, bool, error) - GetValidatedPeers(accountID string, groups []*types.Group, peers []*nbpeer.Peer, extraSettings *account.ExtraSettings) (map[string]struct{}, error) + ValidateExtraSettings(ctx context.Context, newExtraSettings *types.ExtraSettings, oldExtraSettings *types.ExtraSettings, peers map[string]*nbpeer.Peer, userID string, accountID string) error + ValidatePeer(ctx context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) + PreparePeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings) *nbpeer.Peer + IsNotValidPeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings) (bool, bool, error) + GetValidatedPeers(accountID string, groups []*types.Group, peers []*nbpeer.Peer, extraSettings *types.ExtraSettings) (map[string]struct{}, error) PeerDeleted(ctx context.Context, accountID, peerID string) error SetPeerInvalidationListener(fn func(accountID string)) Stop(ctx context.Context) diff --git a/management/server/management_proto_test.go b/management/server/management_proto_test.go index c838c4a27..529a3b57f 100644 --- a/management/server/management_proto_test.go +++ b/management/server/management_proto_test.go @@ -22,6 +22,7 @@ import ( "github.com/netbirdio/netbird/encryption" "github.com/netbirdio/netbird/formatter" mgmtProto "github.com/netbirdio/netbird/management/proto" + nbAccount "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" "github.com/netbirdio/netbird/management/server/settings" @@ -431,7 +432,7 @@ func startManagementForTest(t *testing.T, testFile string, config *Config) (*grp require.NoError(t, err) accountManager, err := BuildManager(ctx, store, peersUpdateManager, nil, "", "netbird.selfhosted", - eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) if err != nil { cleanup() @@ -441,7 +442,7 @@ func startManagementForTest(t *testing.T, testFile string, config *Config) (*grp secretsManager := NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig, config.Relay) ephemeralMgr := NewEphemeralManager(store, accountManager) - mgmtServer, err := NewServer(context.Background(), config, accountManager, settings.NewManager(store), peersUpdateManager, secretsManager, nil, ephemeralMgr, nil) + mgmtServer, err := NewServer(context.Background(), config, accountManager, settings.NewManagerMock(), peersUpdateManager, secretsManager, nil, ephemeralMgr, nil) if err != nil { return nil, nil, "", cleanup, err } @@ -740,7 +741,7 @@ func Test_LoginPerformance(t *testing.T) { NetbirdVersion: "", } - peerLogin := PeerLogin{ + peerLogin := nbAccount.PeerLogin{ WireGuardPubKey: key.String(), SSHKey: "random", Meta: extractPeerMeta(context.Background(), meta), @@ -765,7 +766,7 @@ func Test_LoginPerformance(t *testing.T) { messageCalls = append(messageCalls, login) mu.Unlock() - go func(peerLogin PeerLogin, counterStart *int32) { + go func(peerLogin nbAccount.PeerLogin, counterStart *int32) { defer wgPeer.Done() _, _, _, err = am.LoginPeer(context.Background(), peerLogin) if err != nil { diff --git a/management/server/management_test.go b/management/server/management_test.go index 838065e49..f64735b40 100644 --- a/management/server/management_test.go +++ b/management/server/management_test.go @@ -191,6 +191,7 @@ func startServer( server.MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), + settings.NewManagerMock(), ) if err != nil { t.Fatalf("failed creating an account manager: %v", err) @@ -201,7 +202,7 @@ func startServer( context.Background(), config, accountManager, - settings.NewManager(str), + settings.NewManagerMock(), peersUpdateManager, secretsManager, nil, diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go index 5564aab01..e23d198b6 100644 --- a/management/server/mock_server/account_mock.go +++ b/management/server/mock_server/account_mock.go @@ -11,17 +11,18 @@ import ( nbdns "github.com/netbirdio/netbird/dns" "github.com/netbirdio/netbird/management/domain" - "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" nbcontext "github.com/netbirdio/netbird/management/server/context" "github.com/netbirdio/netbird/management/server/idp" nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/posture" + "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/types" "github.com/netbirdio/netbird/route" ) -var _ server.AccountManager = (*MockAccountManager)(nil) +var _ account.AccountManager = (*MockAccountManager)(nil) type MockAccountManager struct { GetOrCreateAccountByUserFunc func(ctx context.Context, userId, domain string) (*types.Account, error) @@ -89,12 +90,12 @@ type MockAccountManager struct { SaveDNSSettingsFunc func(ctx context.Context, accountID, userID string, dnsSettingsToSave *types.DNSSettings) error GetPeerFunc func(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error) UpdateAccountSettingsFunc func(ctx context.Context, accountID, userID string, newSettings *types.Settings) (*types.Account, error) - LoginPeerFunc func(ctx context.Context, login server.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) - SyncPeerFunc func(ctx context.Context, sync server.PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) + LoginPeerFunc func(ctx context.Context, login account.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) + SyncPeerFunc func(ctx context.Context, sync account.PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) InviteUserFunc func(ctx context.Context, accountID string, initiatorUserID string, targetUserEmail string) error GetAllConnectedPeersFunc func() (map[string]struct{}, error) HasConnectedChannelFunc func(peerID string) bool - GetExternalCacheManagerFunc func() server.ExternalCacheManager + GetExternalCacheManagerFunc func() account.ExternalCacheManager GetPostureChecksFunc func(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error) SavePostureChecksFunc func(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error) DeletePostureChecksFunc func(ctx context.Context, accountID, postureChecksID, userID string) error @@ -110,6 +111,7 @@ type MockAccountManager struct { GetAccountSettingsFunc func(ctx context.Context, accountID string, userID string) (*types.Settings, error) DeleteSetupKeyFunc func(ctx context.Context, accountID, userID, keyID string) error BuildUserInfosForAccountFunc func(ctx context.Context, accountID, initiatorUserID string, accountUsers []*types.User) (map[string]*types.UserInfo, error) + GetStoreFunc func() store.Store } func (am *MockAccountManager) UpdateAccountPeers(ctx context.Context, accountID string) { @@ -661,7 +663,7 @@ func (am *MockAccountManager) UpdateAccountSettings(ctx context.Context, account } // LoginPeer mocks LoginPeer of the AccountManager interface -func (am *MockAccountManager) LoginPeer(ctx context.Context, login server.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { +func (am *MockAccountManager) LoginPeer(ctx context.Context, login account.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { if am.LoginPeerFunc != nil { return am.LoginPeerFunc(ctx, login) } @@ -669,7 +671,7 @@ func (am *MockAccountManager) LoginPeer(ctx context.Context, login server.PeerLo } // SyncPeer mocks SyncPeer of the AccountManager interface -func (am *MockAccountManager) SyncPeer(ctx context.Context, sync server.PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { +func (am *MockAccountManager) SyncPeer(ctx context.Context, sync account.PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { if am.SyncPeerFunc != nil { return am.SyncPeerFunc(ctx, sync, accountID) } @@ -700,7 +702,7 @@ func (am *MockAccountManager) StoreEvent(ctx context.Context, initiatorID, targe } // GetExternalCacheManager mocks GetExternalCacheManager of the AccountManager interface -func (am *MockAccountManager) GetExternalCacheManager() server.ExternalCacheManager { +func (am *MockAccountManager) GetExternalCacheManager() account.ExternalCacheManager { if am.GetExternalCacheManagerFunc() != nil { return am.GetExternalCacheManagerFunc() } @@ -838,3 +840,10 @@ func (am *MockAccountManager) BuildUserInfosForAccount(ctx context.Context, acco func (am *MockAccountManager) SyncUserJWTGroups(ctx context.Context, userAuth nbcontext.UserAuth) error { return status.Errorf(codes.Unimplemented, "method SyncUserJWTGroups is not implemented") } + +func (am *MockAccountManager) GetStore() store.Store { + if am.GetStoreFunc != nil { + return am.GetStoreFunc() + } + return nil +} diff --git a/management/server/nameserver_test.go b/management/server/nameserver_test.go index 064a645d7..3b63a1ad9 100644 --- a/management/server/nameserver_test.go +++ b/management/server/nameserver_test.go @@ -13,6 +13,7 @@ import ( "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" nbpeer "github.com/netbirdio/netbird/management/server/peer" + "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/telemetry" "github.com/netbirdio/netbird/management/server/types" @@ -772,7 +773,7 @@ func createNSManager(t *testing.T) (*DefaultAccountManager, error) { metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) require.NoError(t, err) - return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) } func createNSStore(t *testing.T) (store.Store, error) { diff --git a/management/server/networks/manager.go b/management/server/networks/manager.go index 51205f1e9..43f0ed0f8 100644 --- a/management/server/networks/manager.go +++ b/management/server/networks/manager.go @@ -6,7 +6,7 @@ import ( "github.com/rs/xid" - s "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/networks/resources" "github.com/netbirdio/netbird/management/server/networks/routers" @@ -26,7 +26,7 @@ type Manager interface { type managerImpl struct { store store.Store - accountManager s.AccountManager + accountManager account.AccountManager permissionsManager permissions.Manager resourcesManager resources.Manager routersManager routers.Manager @@ -35,7 +35,7 @@ type managerImpl struct { type mockManager struct { } -func NewManager(store store.Store, permissionsManager permissions.Manager, resourceManager resources.Manager, routersManager routers.Manager, accountManager s.AccountManager) Manager { +func NewManager(store store.Store, permissionsManager permissions.Manager, resourceManager resources.Manager, routersManager routers.Manager, accountManager account.AccountManager) Manager { return &managerImpl{ store: store, permissionsManager: permissionsManager, diff --git a/management/server/networks/resources/manager.go b/management/server/networks/resources/manager.go index 5b542d886..8cf09e561 100644 --- a/management/server/networks/resources/manager.go +++ b/management/server/networks/resources/manager.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - s "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/groups" "github.com/netbirdio/netbird/management/server/networks/resources/types" @@ -31,13 +31,13 @@ type managerImpl struct { store store.Store permissionsManager permissions.Manager groupsManager groups.Manager - accountManager s.AccountManager + accountManager account.AccountManager } type mockManager struct { } -func NewManager(store store.Store, permissionsManager permissions.Manager, groupsManager groups.Manager, accountManager s.AccountManager) Manager { +func NewManager(store store.Store, permissionsManager permissions.Manager, groupsManager groups.Manager, accountManager account.AccountManager) Manager { return &managerImpl{ store: store, permissionsManager: permissionsManager, diff --git a/management/server/networks/routers/manager.go b/management/server/networks/routers/manager.go index 3b32810a2..793efcf4f 100644 --- a/management/server/networks/routers/manager.go +++ b/management/server/networks/routers/manager.go @@ -7,7 +7,7 @@ import ( "github.com/rs/xid" - s "github.com/netbirdio/netbird/management/server" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/networks/routers/types" networkTypes "github.com/netbirdio/netbird/management/server/networks/types" @@ -29,13 +29,13 @@ type Manager interface { type managerImpl struct { store store.Store permissionsManager permissions.Manager - accountManager s.AccountManager + accountManager account.AccountManager } type mockManager struct { } -func NewManager(store store.Store, permissionsManager permissions.Manager, accountManager s.AccountManager) Manager { +func NewManager(store store.Store, permissionsManager permissions.Manager, accountManager account.AccountManager) Manager { return &managerImpl{ store: store, permissionsManager: permissionsManager, diff --git a/management/server/peer.go b/management/server/peer.go index 1e05137fd..0554032ad 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -16,6 +16,7 @@ import ( "golang.org/x/exp/maps" "github.com/netbirdio/netbird/management/domain" + "github.com/netbirdio/netbird/management/server/account" "github.com/netbirdio/netbird/management/server/geolocation" "github.com/netbirdio/netbird/management/server/idp" @@ -29,36 +30,6 @@ import ( "github.com/netbirdio/netbird/management/server/status" ) -// PeerSync used as a data object between the gRPC API and AccountManager on Sync request. -type PeerSync struct { - // WireGuardPubKey is a peers WireGuard public key - WireGuardPubKey string - // Meta is the system information passed by peer, must be always present - Meta nbpeer.PeerSystemMeta - // UpdateAccountPeers indicate updating account peers, - // which occurs when the peer's metadata is updated - UpdateAccountPeers bool -} - -// PeerLogin used as a data object between the gRPC API and AccountManager on Login request. -type PeerLogin struct { - // WireGuardPubKey is a peers WireGuard public key - WireGuardPubKey string - // SSHKey is a peer's ssh key. Can be empty (e.g., old version do not provide it, or this feature is disabled) - SSHKey string - // Meta is the system information passed by peer, must be always present. - Meta nbpeer.PeerSystemMeta - // UserID indicates that JWT was used to log in, and it was valid. Can be empty when SetupKey is used or auth is not required. - UserID string - // SetupKey references to a server.SetupKey to log in. Can be empty when UserID is used or auth is not required. - SetupKey string - // ConnectionIP is the real IP of the peer - ConnectionIP net.IP - - // ExtraDNSLabels is a list of extra DNS labels that the peer wants to use - ExtraDNSLabels []string -} - // GetPeers returns a list of peers under the given account filtering out peers that do not belong to a user if // the current user is not an admin. func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID, nameFilter, ipFilter string) ([]*nbpeer.Peer, error) { @@ -702,7 +673,7 @@ func getFreeIP(ctx context.Context, transaction store.Store, accountID string) ( } // SyncPeer checks whether peer is eligible for receiving NetworkMap (authenticated) and returns its NetworkMap if eligible -func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { +func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync account.PeerSync, accountID string) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { start := time.Now() defer func() { log.WithContext(ctx).Debugf("SyncPeer: took %v", time.Since(start)) @@ -777,7 +748,7 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync PeerSync, ac return am.getValidatedPeerWithMap(ctx, peerNotValid, accountID, peer) } -func (am *DefaultAccountManager) handlePeerLoginNotFound(ctx context.Context, login PeerLogin, err error) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { +func (am *DefaultAccountManager) handlePeerLoginNotFound(ctx context.Context, login account.PeerLogin, err error) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { if errStatus, ok := status.FromError(err); ok && errStatus.Type() == status.NotFound { // we couldn't find this peer by its public key which can mean that peer hasn't been registered yet. // Try registering it. @@ -797,7 +768,7 @@ func (am *DefaultAccountManager) handlePeerLoginNotFound(ctx context.Context, lo // LoginPeer logs in or registers a peer. // If peer doesn't exist the function checks whether a setup key or a user is present and registers a new peer if so. -func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { +func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login account.PeerLogin) (*nbpeer.Peer, *types.NetworkMap, []*posture.Checks, error) { accountID, err := am.Store.GetAccountIDByPeerPubKey(ctx, login.WireGuardPubKey) if err != nil { return am.handlePeerLoginNotFound(ctx, login, err) @@ -987,7 +958,7 @@ func processPeerPostureChecks(ctx context.Context, transaction store.Store, poli // The NetBird client doesn't have a way to check if the peer needs login besides sending a login request // with no JWT token and usually no setup-key. As the client can send up to two login request to check if it is expired // and before starting the engine, we do the checks without an account lock to avoid piling up requests. -func (am *DefaultAccountManager) checkIFPeerNeedsLoginWithoutLock(ctx context.Context, accountID string, login PeerLogin) error { +func (am *DefaultAccountManager) checkIFPeerNeedsLoginWithoutLock(ctx context.Context, accountID string, login account.PeerLogin) error { peer, err := am.Store.GetPeerByPeerPubKey(ctx, store.LockingStrengthShare, login.WireGuardPubKey) if err != nil { return err @@ -1230,7 +1201,13 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account remotePeerNetworkMap.Merge(proxyNetworkMap) } - update := toSyncResponse(ctx, nil, p, nil, nil, remotePeerNetworkMap, am.GetDNSDomain(), postureChecks, dnsCache, account.Settings.RoutingPeerDNSResolutionEnabled) + extraSetting, err := am.settingsManager.GetExtraSettings(ctx, accountID) + if err != nil { + log.WithContext(ctx).Errorf("failed to get flow enabled status: %v", err) + return + } + + update := toSyncResponse(ctx, nil, p, nil, nil, remotePeerNetworkMap, am.GetDNSDomain(), postureChecks, dnsCache, account.Settings.RoutingPeerDNSResolutionEnabled, extraSetting) am.peersUpdateManager.SendUpdate(ctx, p.ID, &UpdateMessage{Update: update, NetworkMap: remotePeerNetworkMap}) }(peer) } @@ -1293,7 +1270,13 @@ func (am *DefaultAccountManager) UpdateAccountPeer(ctx context.Context, accountI remotePeerNetworkMap.Merge(proxyNetworkMap) } - update := toSyncResponse(ctx, nil, peer, nil, nil, remotePeerNetworkMap, am.GetDNSDomain(), postureChecks, dnsCache, account.Settings.RoutingPeerDNSResolutionEnabled) + extraSettings, err := am.settingsManager.GetExtraSettings(ctx, peer.AccountID) + if err != nil { + log.WithContext(ctx).Errorf("failed to get extra settings: %v", err) + return + } + + update := toSyncResponse(ctx, nil, peer, nil, nil, remotePeerNetworkMap, am.GetDNSDomain(), postureChecks, dnsCache, account.Settings.RoutingPeerDNSResolutionEnabled, extraSettings) am.peersUpdateManager.SendUpdate(ctx, peer.ID, &UpdateMessage{Update: update, NetworkMap: remotePeerNetworkMap}) } diff --git a/management/server/peer_test.go b/management/server/peer_test.go index 843910597..666a048a4 100644 --- a/management/server/peer_test.go +++ b/management/server/peer_test.go @@ -13,13 +13,14 @@ import ( "testing" "time" - nbAccount "github.com/netbirdio/netbird/management/server/account" "github.com/rs/xid" log "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.zx2c4.com/wireguard/wgctrl/wgtypes" + "github.com/netbirdio/netbird/management/server/settings" + "github.com/netbirdio/netbird/management/server/integrations/port_forwarding" "github.com/netbirdio/netbird/management/server/util" @@ -1107,7 +1108,7 @@ func TestToSyncResponse(t *testing.T) { } dnsCache := &DNSConfigCache{} - response := toSyncResponse(context.Background(), config, peer, turnRelayToken, turnRelayToken, networkMap, dnsName, checks, dnsCache, true) + response := toSyncResponse(context.Background(), config, peer, turnRelayToken, turnRelayToken, networkMap, dnsName, checks, dnsCache, true, nil) assert.NotNil(t, response) // assert peer config @@ -1211,7 +1212,7 @@ func Test_RegisterPeerByUser(t *testing.T) { metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) assert.NoError(t, err) - am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) assert.NoError(t, err) existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b" @@ -1275,7 +1276,7 @@ func Test_RegisterPeerBySetupKey(t *testing.T) { metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) assert.NoError(t, err) - am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) assert.NoError(t, err) existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b" @@ -1342,7 +1343,7 @@ func Test_RegisterPeerRollbackOnFailure(t *testing.T) { metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) assert.NoError(t, err) - am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) assert.NoError(t, err) existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b" @@ -1531,7 +1532,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) { }) t.Run("validator requires update", func(t *testing.T) { - requireUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *nbAccount.ExtraSettings) (*nbpeer.Peer, bool, error) { + requireUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) { return update, true, nil } @@ -1553,7 +1554,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) { }) t.Run("validator requires no update", func(t *testing.T) { - requireNoUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *nbAccount.ExtraSettings) (*nbpeer.Peer, bool, error) { + requireNoUpdateFunc := func(_ context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) { return update, false, nil } diff --git a/management/server/permissions/manager.go b/management/server/permissions/manager.go index 320aad027..0345405fe 100644 --- a/management/server/permissions/manager.go +++ b/management/server/permissions/manager.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/netbirdio/netbird/management/server/activity" "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/types" "github.com/netbirdio/netbird/management/server/users" @@ -71,7 +72,7 @@ func (m *managerImpl) ValidateUserPermissions(ctx context.Context, accountID, us } func (m *managerImpl) validateRegularUserPermissions(ctx context.Context, accountID, userID string, module Module, operation Operation) (bool, error) { - settings, err := m.settingsManager.GetSettings(ctx, accountID, userID) + settings, err := m.settingsManager.GetSettings(ctx, accountID, activity.SystemInitiator) if err != nil { return false, fmt.Errorf("failed to get settings: %w", err) } diff --git a/management/server/route_test.go b/management/server/route_test.go index c5a5f2040..65f5428de 100644 --- a/management/server/route_test.go +++ b/management/server/route_test.go @@ -20,6 +20,7 @@ import ( routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types" networkTypes "github.com/netbirdio/netbird/management/server/networks/types" nbpeer "github.com/netbirdio/netbird/management/server/peer" + "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/telemetry" "github.com/netbirdio/netbird/management/server/types" @@ -1257,7 +1258,7 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) { metrics, err := telemetry.NewDefaultAppMetrics(context.Background()) require.NoError(t, err) - return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock()) + return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settings.NewManagerMock()) } func createRouterStore(t *testing.T) (store.Store, error) { diff --git a/management/server/settings/manager.go b/management/server/settings/manager.go index 37bc9f549..0bf0f63b3 100644 --- a/management/server/settings/manager.go +++ b/management/server/settings/manager.go @@ -2,36 +2,124 @@ package settings import ( "context" + "fmt" + "github.com/netbirdio/netbird/management/server/activity" + "github.com/netbirdio/netbird/management/server/integrations/extra_settings" + "github.com/netbirdio/netbird/management/server/status" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/types" + "github.com/netbirdio/netbird/management/server/users" ) type Manager interface { + GetExtraSettingsManager() extra_settings.Manager GetSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) + GetExtraSettings(ctx context.Context, accountID string) (*types.ExtraSettings, error) + UpdateExtraSettings(ctx context.Context, accountID string, extraSettings *types.ExtraSettings) error } type managerImpl struct { - store store.Store + store store.Store + extraSettingsManager extra_settings.Manager + userManager users.Manager } -type managerMock struct { +type ManagerMock struct { + GetSettingsFunc func(ctx context.Context, accountID, userID string) (*types.Settings, error) } -func NewManager(store store.Store) Manager { +func NewManager(store store.Store, userManager users.Manager, extraSettingsManager extra_settings.Manager) Manager { return &managerImpl{ - store: store, + store: store, + extraSettingsManager: extraSettingsManager, + userManager: userManager, } } -func (m *managerImpl) GetSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) { - return m.store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID) +func (m *managerImpl) GetExtraSettingsManager() extra_settings.Manager { + return m.extraSettingsManager } -func NewManagerMock() Manager { - return &managerMock{} +func (m *managerImpl) GetSettings(ctx context.Context, accountID, userID string) (*types.Settings, error) { + if userID != activity.SystemInitiator { + user, err := m.userManager.GetUser(ctx, userID) + if err != nil { + return nil, fmt.Errorf("get user: %w", err) + } + + if user.AccountID != accountID || (!user.HasAdminPower() && !user.IsServiceUser) { + return nil, status.Errorf(status.PermissionDenied, "the user has no permission to access account data") + } + } + + extraSettings, err := m.extraSettingsManager.GetExtraSettings(ctx, accountID) + if err != nil { + return nil, fmt.Errorf("get extra settings: %w", err) + } + + settings, err := m.store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID) + if err != nil { + return nil, fmt.Errorf("get account settings: %w", err) + } + + // Once we migrate the peer approval to settings manager this merging is obsolete + if settings.Extra != nil { + settings.Extra.FlowEnabled = extraSettings.FlowEnabled + } + + return settings, nil } -func (m *managerMock) GetSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) { +func (m *managerImpl) GetExtraSettings(ctx context.Context, accountID string) (*types.ExtraSettings, error) { + extraSettings, err := m.extraSettingsManager.GetExtraSettings(ctx, accountID) + if err != nil { + return nil, fmt.Errorf("get extra settings: %w", err) + } + + settings, err := m.store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID) + if err != nil { + return nil, fmt.Errorf("get account settings: %w", err) + } + + // Once we migrate the peer approval to settings manager this merging is obsolete + if settings.Extra == nil { + settings.Extra = &types.ExtraSettings{} + } + + settings.Extra.FlowEnabled = extraSettings.FlowEnabled + + return settings.Extra, nil +} + +func (m *managerImpl) UpdateExtraSettings(ctx context.Context, accountID string, extraSettings *types.ExtraSettings) error { + return m.extraSettingsManager.UpdateExtraSettings(ctx, accountID, extraSettings) +} + +func NewManagerMock() *ManagerMock { + return &ManagerMock{} +} + +func (m *ManagerMock) GetExtraSettingsManager() extra_settings.Manager { + return nil +} + +func (m *ManagerMock) GetSettings(ctx context.Context, accountID, userID string) (*types.Settings, error) { + if m.GetSettingsFunc != nil { + return m.GetSettingsFunc(ctx, accountID, userID) + } + return &types.Settings{}, nil } + +func (m *ManagerMock) SetGetSettingsFunc(f func(ctx context.Context, accountID, userID string) (*types.Settings, error)) { + m.GetSettingsFunc = f +} + +func (m *ManagerMock) GetExtraSettings(ctx context.Context, accountID string) (*types.ExtraSettings, error) { + return &types.ExtraSettings{}, nil +} + +func (m *ManagerMock) UpdateExtraSettings(ctx context.Context, accountID string, extraSettings *types.ExtraSettings) error { + return nil +} diff --git a/management/server/status/error.go b/management/server/status/error.go index 96b103183..adf7e060c 100644 --- a/management/server/status/error.go +++ b/management/server/status/error.go @@ -40,6 +40,8 @@ const ( // Type is a type of the Error type Type int32 +var ErrExtraSettingsNotFound = fmt.Errorf("extra settings not found") + // Error is an internal error type Error struct { ErrorType Type @@ -206,3 +208,7 @@ func NewOwnerDeletePermissionError() error { func NewPATNotFoundError(patID string) error { return Errorf(NotFound, "PAT: %s not found", patID) } + +func NewExtraSettingsNotFoundError() error { + return ErrExtraSettingsNotFound +} diff --git a/management/server/store/sql_store.go b/management/server/store/sql_store.go index 1dae3999b..4d455f23d 100644 --- a/management/server/store/sql_store.go +++ b/management/server/store/sql_store.go @@ -26,7 +26,6 @@ import ( "github.com/netbirdio/netbird/management/server/util" nbdns "github.com/netbirdio/netbird/dns" - "github.com/netbirdio/netbird/management/server/account" resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types" routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types" networkTypes "github.com/netbirdio/netbird/management/server/networks/types" @@ -95,7 +94,7 @@ func NewSqlStore(ctx context.Context, db *gorm.DB, storeEngine Engine, metrics t err = db.AutoMigrate( &types.SetupKey{}, &nbpeer.Peer{}, &types.User{}, &types.PersonalAccessToken{}, &types.Group{}, &types.Account{}, &types.Policy{}, &types.PolicyRule{}, &route.Route{}, &nbdns.NameServerGroup{}, - &installation{}, &account.ExtraSettings{}, &posture.Checks{}, &nbpeer.NetworkAddress{}, + &installation{}, &types.ExtraSettings{}, &posture.Checks{}, &nbpeer.NetworkAddress{}, &networkTypes.Network{}, &routerTypes.NetworkRouter{}, &resourceTypes.NetworkResource{}, ) if err != nil { diff --git a/management/server/token_mgr.go b/management/server/token_mgr.go index ec8aae47e..7217b543f 100644 --- a/management/server/token_mgr.go +++ b/management/server/token_mgr.go @@ -11,6 +11,8 @@ import ( log "github.com/sirupsen/logrus" + "github.com/netbirdio/management-integrations/integrations" + "github.com/netbirdio/netbird/management/proto" auth "github.com/netbirdio/netbird/relay/auth/hmac" authv2 "github.com/netbirdio/netbird/relay/auth/hmac/v2" @@ -216,6 +218,8 @@ func (m *TimeBasedAuthSecretsManager) pushNewTURNAndRelayTokens(ctx context.Cont } } + integrations.ExtendNetBirdConfig(update.NetbirdConfig, nil) + log.WithContext(ctx).Debugf("sending new TURN credentials to peer %s", peerID) m.updateManager.SendUpdate(ctx, peerID, &UpdateMessage{Update: update}) } @@ -238,6 +242,8 @@ func (m *TimeBasedAuthSecretsManager) pushNewRelayTokens(ctx context.Context, pe }, } + integrations.ExtendNetBirdConfig(update.NetbirdConfig, nil) + log.WithContext(ctx).Debugf("sending new relay credentials to peer %s", peerID) m.updateManager.SendUpdate(ctx, peerID, &UpdateMessage{Update: update}) } diff --git a/management/server/types/settings.go b/management/server/types/settings.go index 0ce5a6133..77adca5ad 100644 --- a/management/server/types/settings.go +++ b/management/server/types/settings.go @@ -2,8 +2,6 @@ package types import ( "time" - - "github.com/netbirdio/netbird/management/server/account" ) // Settings represents Account settings structure that can be modified via API and Dashboard @@ -42,7 +40,7 @@ type Settings struct { RoutingPeerDNSResolutionEnabled bool // Extra is a dictionary of Account settings - Extra *account.ExtraSettings `gorm:"embedded;embeddedPrefix:extra_"` + Extra *ExtraSettings `gorm:"embedded;embeddedPrefix:extra_"` } // Copy copies the Settings struct @@ -66,3 +64,23 @@ func (s *Settings) Copy() *Settings { } return settings } + +type ExtraSettings struct { + // PeerApprovalEnabled enables or disables the need for peers bo be approved by an administrator + PeerApprovalEnabled bool + + // IntegratedValidatorGroups list of group IDs to be used with integrated approval configurations + IntegratedValidatorGroups []string `gorm:"serializer:json"` + + FlowEnabled bool `gorm:"-"` +} + +// Copy copies the ExtraSettings struct +func (e *ExtraSettings) Copy() *ExtraSettings { + var cpGroup []string + + return &ExtraSettings{ + PeerApprovalEnabled: e.PeerApprovalEnabled, + IntegratedValidatorGroups: append(cpGroup, e.IntegratedValidatorGroups...), + } +}