Compare commits

...

9 Commits

Author SHA1 Message Date
Pascal Fischer
93c0172c8a Merge remote-tracking branch 'origin/fix/export-mgmt-config-url' into deploy/permissions-account 2025-03-25 11:45:41 +01:00
Maycon Santos
dc8aac6549 move relay config and management config path to types
this helps avoid circular import cycle through all the code
2025-03-24 23:05:11 +01:00
Pascal Fischer
80d1aa4516 export management config path 2025-03-24 17:55:21 +01:00
Pedro Costa
865d89a142 bump integrations mod 2025-03-21 18:12:00 +00:00
Pedro Costa
47fd423bb8 reduce fillEventsWithUserInfo cognitive complexity 2025-03-21 18:12:00 +00:00
Pedro Maia Costa
1df01a1ebf [management] create account by private domain (#3485) 2025-03-21 18:12:00 +00:00
Pedro Costa
abaffbcc2d [misc] apply feedback 2025-03-21 18:12:00 +00:00
Pedro Maia Costa
1763a953f4 [management] activity external user info (#3461) 2025-03-21 18:12:00 +00:00
Pedro Costa
f9f47b0ad8 [management] permission manager validate account access 2025-03-21 18:12:00 +00:00
38 changed files with 650 additions and 239 deletions

View File

@@ -12,6 +12,7 @@ import (
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -90,13 +91,13 @@ func startManagement(t *testing.T, config *mgmt.Config, testFile string) (*grpc.
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
if err != nil {
t.Fatal(err)
}

View File

@@ -49,6 +49,7 @@ import (
"github.com/netbirdio/netbird/management/server"
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -1403,7 +1404,7 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
config := &server.Config{
Stuns: []*server.Host{},
TURNConfig: &server.TURNConfig{},
Relay: &server.Relay{
Relay: &types.Relay{
Addresses: []string{"127.0.0.1:1234"},
CredentialsTTL: util.Duration{Duration: time.Hour},
Secret: "222222222222222222",
@@ -1438,6 +1439,8 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
@@ -1446,7 +1449,7 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
Return(&types.Settings{}, nil).
AnyTimes()
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
if err != nil {
return nil, "", err
}

View File

@@ -10,17 +10,19 @@ import (
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel"
"github.com/netbirdio/management-integrations/integrations"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
"github.com/netbirdio/management-integrations/integrations"
"github.com/netbirdio/netbird/client/internal"
"github.com/netbirdio/netbird/client/internal/peer"
mgmtProto "github.com/netbirdio/netbird/management/proto"
"github.com/netbirdio/netbird/management/server"
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -129,11 +131,12 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
if err != nil {
return nil, "", err
}

2
go.mod
View File

@@ -62,7 +62,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-20250320152138-69b93e4ef939
github.com/netbirdio/management-integrations/integrations v0.0.0-20250320160856-bef8efa19fbd
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

4
go.sum
View File

@@ -490,8 +490,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-20250320152138-69b93e4ef939 h1:OsLDdb6ekNaCVSyD+omhio2DECfEqLjCA1zo4HrgGqU=
github.com/netbirdio/management-integrations/integrations v0.0.0-20250320152138-69b93e4ef939/go.mod h1:3LvBPnW+i06K9fQr1SYwsbhvnxQHtIC8vvO4PjLmmy0=
github.com/netbirdio/management-integrations/integrations v0.0.0-20250320160856-bef8efa19fbd h1:rL4HSb/QhrEumuWkS4xirtHJgU0DsCbyfQS/MtGecK8=
github.com/netbirdio/management-integrations/integrations v0.0.0-20250320160856-bef8efa19fbd/go.mod h1:xFLzZcnjDssptPZUGj4ux4uIO75xM43GrTUwIKwFJHQ=
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=

View File

@@ -14,6 +14,7 @@ import (
"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/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -74,6 +75,7 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
@@ -87,7 +89,7 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
Return(&types.Settings{}, nil).
AnyTimes()
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
if err != nil {
t.Fatal(err)
}

View File

@@ -34,7 +34,9 @@ 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/management/server/types"
"github.com/netbirdio/netbird/encryption"
"github.com/netbirdio/netbird/formatter/hook"
@@ -50,7 +52,6 @@ import (
"github.com/netbirdio/netbird/management/server/networks"
"github.com/netbirdio/netbird/management/server/networks/resources"
"github.com/netbirdio/netbird/management/server/networks/routers"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -101,9 +102,9 @@ var (
// detect whether user specified a port
userPort := cmd.Flag("port").Changed
config, err = loadMgmtConfig(ctx, mgmtConfig)
config, err = loadMgmtConfig(ctx, types.MgmtConfigPath)
if err != nil {
return fmt.Errorf("failed reading provided config file: %s: %v", mgmtConfig, err)
return fmt.Errorf("failed reading provided config file: %s: %v", types.MgmtConfigPath, err)
}
if cmd.Flag(idpSignKeyRefreshEnabledFlagName).Changed {
@@ -183,7 +184,7 @@ var (
if config.DataStoreEncryptionKey != key {
log.WithContext(ctx).Infof("update config with activity store key")
config.DataStoreEncryptionKey = key
err := updateMgmtConfig(ctx, mgmtConfig, config)
err := updateMgmtConfig(ctx, types.MgmtConfigPath, config)
if err != nil {
return fmt.Errorf("failed to write out store encryption key: %s", err)
}
@@ -204,12 +205,11 @@ var (
userManager := users.NewManager(store)
extraSettingsManager := integrations.NewManager(eventStore)
settingsManager := settings.NewManager(store, userManager, extraSettingsManager)
permissionsManager := permissions.NewManager(userManager, settingsManager)
permissionsManager := integrations.InitPermissionsManager(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, settingsManager)
dnsDomain, eventStore, geo, userDeleteFromIDPEnabled, integratedPeerValidator, appMetrics, proxyController, settingsManager, permissionsManager)
if err != nil {
return fmt.Errorf("failed to build default manager: %v", err)
}
@@ -636,7 +636,7 @@ func handleRebrand(cmd *cobra.Command) error {
}
}
}
if mgmtConfig == defaultMgmtConfig {
if types.MgmtConfigPath == defaultMgmtConfig {
if migrateToNetbird(oldDefaultMgmtConfig, defaultMgmtConfig) {
cmd.Printf("will copy Config dir %s and its content to %s\n", oldDefaultMgmtConfigDir, defaultMgmtConfigDir)
err = cpDir(oldDefaultMgmtConfigDir, defaultMgmtConfigDir)

View File

@@ -7,6 +7,7 @@ import (
"github.com/spf13/cobra"
"github.com/netbirdio/netbird/management/server/types"
"github.com/netbirdio/netbird/version"
)
@@ -19,7 +20,6 @@ const (
var (
dnsDomain string
mgmtDataDir string
mgmtConfig string
logLevel string
logFile string
disableMetrics bool
@@ -56,7 +56,7 @@ func init() {
mgmtCmd.Flags().IntVar(&mgmtPort, "port", 80, "server port to listen on (defaults to 443 if TLS is enabled, 80 otherwise")
mgmtCmd.Flags().IntVar(&mgmtMetricsPort, "metrics-port", 9090, "metrics endpoint http port. Metrics are accessible under host:metrics-port/metrics")
mgmtCmd.Flags().StringVar(&mgmtDataDir, "datadir", defaultMgmtDataDir, "server data directory location")
mgmtCmd.Flags().StringVar(&mgmtConfig, "config", defaultMgmtConfig, "Netbird config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
mgmtCmd.Flags().StringVar(&types.MgmtConfigPath, "config", defaultMgmtConfig, "Netbird config file location. Config params specified via command line (e.g. datadir) have a precedence over configuration from this file")
mgmtCmd.Flags().StringVar(&mgmtLetsencryptDomain, "letsencrypt-domain", "", "a domain to issue Let's Encrypt certificate for. Enables TLS using Let's Encrypt. Will fetch and renew certificate, and run the server with TLS")
mgmtCmd.Flags().StringVar(&mgmtSingleAccModeDomain, "single-account-mode-domain", defaultSingleAccModeDomain, "Enables single account mode. This means that all the users will be under the same account grouped by the specified domain. If the installation has more than one account, the property is ineffective. Enabled by default with the default domain "+defaultSingleAccModeDomain)
mgmtCmd.Flags().BoolVar(&disableSingleAccMode, "disable-single-account-mode", false, "If set to true, disables single account mode. The --single-account-mode-domain property will be ignored and every new user will have a separate NetBird account.")

View File

@@ -29,6 +29,7 @@ import (
"github.com/netbirdio/netbird/management/server/integrations/integrated_validator"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
nbpeer "github.com/netbirdio/netbird/management/server/peer"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/posture"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/status"
@@ -89,6 +90,8 @@ type DefaultAccountManager struct {
integratedPeerValidator integrated_validator.IntegratedValidator
metrics telemetry.AppMetrics
permissionsManager permissions.Manager
}
// getJWTGroupsChanges calculates the changes needed to sync a user's JWT groups.
@@ -156,6 +159,7 @@ func BuildManager(
metrics telemetry.AppMetrics,
proxyController port_forwarding.Controller,
settingsManager settings.Manager,
permissionsManager permissions.Manager,
) (*DefaultAccountManager, error) {
start := time.Now()
defer func() {
@@ -180,6 +184,7 @@ func BuildManager(
requestBuffer: NewAccountRequestBuffer(ctx, store),
proxyController: proxyController,
settingsManager: settingsManager,
permissionsManager: permissionsManager,
}
accountsCounter, err := store.GetAccountsCounter(ctx)
if err != nil {
@@ -508,10 +513,6 @@ func (am *DefaultAccountManager) DeleteAccount(ctx context.Context, accountID, u
return err
}
if !user.HasAdminPower() {
return status.Errorf(status.PermissionDenied, "user is not allowed to delete account")
}
if user.Role != types.UserRoleOwner {
return status.Errorf(status.PermissionDenied, "user is not allowed to delete account. Only account owner can delete account")
}
@@ -1027,8 +1028,8 @@ func (am *DefaultAccountManager) GetAccountByID(ctx context.Context, accountID s
return nil, err
}
if user.AccountID != accountID {
return nil, status.Errorf(status.PermissionDenied, "the user has no permission to access account data")
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
return am.Store.GetAccount(ctx, accountID)
@@ -1061,8 +1062,8 @@ func (am *DefaultAccountManager) GetAccountIDFromUserAuth(ctx context.Context, u
return accountID, user.Id, nil
}
if user.AccountID != accountID {
return "", "", status.Errorf(status.PermissionDenied, "user %s is not part of the account %s", userAuth.UserId, accountID)
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return "", "", err
}
if !user.IsServiceUser && userAuth.Invited {
@@ -1521,7 +1522,11 @@ func (am *DefaultAccountManager) GetAccountSettings(ctx context.Context, account
return nil, err
}
if user.AccountID != accountID || (!user.HasAdminPower() && !user.IsServiceUser) {
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if !user.HasAdminPower() && !user.IsServiceUser {
return nil, status.Errorf(status.PermissionDenied, "the user has no permission to access account data")
}
@@ -1606,3 +1611,113 @@ func separateGroups(autoGroups []string, allGroups []*types.Group) ([]string, ma
func (am *DefaultAccountManager) GetStore() store.Store {
return am.Store
}
// Creates account by private domain.
// Expects domain value to be a valid and a private dns domain.
func (am *DefaultAccountManager) CreateAccountByPrivateDomain(ctx context.Context, initiatorId, domain string) (*types.Account, error) {
cancel := am.Store.AcquireGlobalLock(ctx)
defer cancel()
domain = strings.ToLower(domain)
count, err := am.Store.CountAccountsByPrivateDomain(ctx, domain)
if err != nil {
return nil, err
}
if count > 0 {
return nil, status.Errorf(status.InvalidArgument, "account with private domain already exists")
}
// retry twice for new ID clashes
for range 2 {
accountId := xid.New().String()
exists, err := am.Store.AccountExists(ctx, store.LockingStrengthShare, accountId)
if err != nil || exists {
continue
}
network := types.NewNetwork()
peers := make(map[string]*nbpeer.Peer)
users := make(map[string]*types.User)
routes := make(map[route.ID]*route.Route)
setupKeys := map[string]*types.SetupKey{}
nameServersGroups := make(map[string]*nbdns.NameServerGroup)
dnsSettings := types.DNSSettings{
DisabledManagementGroups: make([]string, 0),
}
newAccount := &types.Account{
Id: accountId,
CreatedAt: time.Now().UTC(),
SetupKeys: setupKeys,
Network: network,
Peers: peers,
Users: users,
// @todo check if using the MSP owner id here is ok
CreatedBy: initiatorId,
Domain: domain,
DomainCategory: types.PrivateCategory,
IsDomainPrimaryAccount: false,
Routes: routes,
NameServerGroups: nameServersGroups,
DNSSettings: dnsSettings,
Settings: &types.Settings{
PeerLoginExpirationEnabled: true,
PeerLoginExpiration: types.DefaultPeerLoginExpiration,
GroupsPropagationEnabled: true,
RegularUsersViewBlocked: true,
PeerInactivityExpirationEnabled: false,
PeerInactivityExpiration: types.DefaultPeerInactivityExpiration,
RoutingPeerDNSResolutionEnabled: true,
},
}
if err := newAccount.AddAllGroup(); err != nil {
return nil, status.Errorf(status.Internal, "failed to add all group to new account by private domain")
}
if err := am.Store.SaveAccount(ctx, newAccount); err != nil {
log.WithContext(ctx).Errorf("failed to save new account %s by private domain: %v", newAccount.Id, err)
return nil, err
}
am.StoreEvent(ctx, initiatorId, newAccount.Id, accountId, activity.AccountCreated, nil)
return newAccount, nil
}
return nil, status.Errorf(status.Internal, "failed to create new account by private domain")
}
func (am *DefaultAccountManager) UpdateToPrimaryAccount(ctx context.Context, accountId string) (*types.Account, error) {
account, err := am.Store.GetAccount(ctx, accountId)
if err != nil {
return nil, err
}
if account.IsDomainPrimaryAccount {
return account, nil
}
// additional check to ensure there is only one account for this domain at the time of update
count, err := am.Store.CountAccountsByPrivateDomain(ctx, account.Domain)
if err != nil {
return nil, err
}
if count > 1 {
return nil, status.Errorf(status.Internal, "more than one account exists with the same private domain")
}
account.IsDomainPrimaryAccount = true
if err := am.Store.SaveAccount(ctx, account); err != nil {
log.WithContext(ctx).Errorf("failed to update primary account %s by private domain: %v", account.Id, err)
return nil, status.Errorf(status.Internal, "failed to update primary account %s by private domain", account.Id)
}
return account, nil
}

View File

@@ -111,4 +111,6 @@ type Manager interface {
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
CreateAccountByPrivateDomain(ctx context.Context, initiatorId, domain string) (*types.Account, error)
UpdateToPrimaryAccount(ctx context.Context, accountId string) (*types.Account, error)
}

View File

@@ -17,6 +17,7 @@ import (
nbAccount "github.com/netbirdio/netbird/management/server/account"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/util"
@@ -2815,6 +2816,8 @@ func createManager(t TB) (*DefaultAccountManager, error) {
return nil, err
}
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
@@ -2828,7 +2831,7 @@ func createManager(t TB) (*DefaultAccountManager, error) {
Return(false, nil).
AnyTimes()
manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
if err != nil {
return nil, err
}
@@ -3150,3 +3153,51 @@ func BenchmarkLoginPeer_NewPeer(b *testing.B) {
})
}
}
func Test_CreateAccountByPrivateDomain(t *testing.T) {
manager, err := createManager(t)
if err != nil {
t.Fatal(err)
return
}
ctx := context.Background()
initiatorId := "test-user"
domain := "example.com"
account, err := manager.CreateAccountByPrivateDomain(ctx, initiatorId, domain)
assert.NoError(t, err)
assert.False(t, account.IsDomainPrimaryAccount)
assert.Equal(t, domain, account.Domain)
assert.Equal(t, types.PrivateCategory, account.DomainCategory)
assert.Equal(t, initiatorId, account.CreatedBy)
assert.Equal(t, 1, len(account.Groups))
assert.Equal(t, 0, len(account.Users))
assert.Equal(t, 0, len(account.SetupKeys))
// retry should fail
_, err = manager.CreateAccountByPrivateDomain(ctx, initiatorId, domain)
assert.Error(t, err)
}
func Test_UpdateToPrimaryAccount(t *testing.T) {
manager, err := createManager(t)
if err != nil {
t.Fatal(err)
return
}
ctx := context.Background()
initiatorId := "test-user"
domain := "example.com"
account, err := manager.CreateAccountByPrivateDomain(ctx, initiatorId, domain)
assert.NoError(t, err)
assert.False(t, account.IsDomainPrimaryAccount)
// retry should fail
account, err = manager.UpdateToPrimaryAccount(ctx, account.Id)
assert.NoError(t, err)
assert.True(t, account.IsDomainPrimaryAccount)
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/netbirdio/netbird/management/server/idp"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/types"
"github.com/netbirdio/netbird/util"
)
@@ -34,7 +35,7 @@ const (
type Config struct {
Stuns []*Host
TURNConfig *TURNConfig
Relay *Relay
Relay *types.Relay
Signal *Host
Datadir string
@@ -76,12 +77,6 @@ type TURNConfig struct {
Turns []*Host
}
type Relay struct {
Addresses []string
CredentialsTTL util.Duration
Secret string
}
// HttpServerConfig is a config of the HTTP Management service server
type HttpServerConfig struct {
LetsEncryptDomain string

View File

@@ -67,8 +67,8 @@ func (am *DefaultAccountManager) GetDNSSettings(ctx context.Context, accountID s
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -89,8 +89,8 @@ func (am *DefaultAccountManager) SaveDNSSettings(ctx context.Context, accountID
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
if !user.HasAdminPower() {

View File

@@ -13,6 +13,7 @@ import (
nbdns "github.com/netbirdio/netbird/dns"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -210,13 +211,14 @@ func createDNSManager(t *testing.T) (*DefaultAccountManager, error) {
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
}
func createDNSStore(t *testing.T) (store.Store, error) {

View File

@@ -10,6 +10,8 @@ import (
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/status"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/types"
)
func isEnabled() bool {
@@ -19,16 +21,12 @@ func isEnabled() bool {
// GetEvents returns a list of activity events of an account
func (am *DefaultAccountManager) GetEvents(ctx context.Context, accountID, userID string) ([]*activity.Event, error) {
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
defer unlock()
account, err := am.Store.GetAccount(ctx, accountID)
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
if err != nil {
return nil, err
}
user, err := account.FindUser(userID)
if err != nil {
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
@@ -58,6 +56,11 @@ func (am *DefaultAccountManager) GetEvents(ctx context.Context, accountID, userI
filtered = append(filtered, event)
}
err = am.fillEventsWithUserInfo(ctx, events, accountID, user)
if err != nil {
return nil, err
}
return filtered, nil
}
@@ -79,3 +82,156 @@ func (am *DefaultAccountManager) StoreEvent(ctx context.Context, initiatorID, ta
}()
}
}
type eventUserInfo struct {
email string
name string
accountId string
}
func (am *DefaultAccountManager) fillEventsWithUserInfo(ctx context.Context, events []*activity.Event, accountId string, user *types.User) error {
eventUserInfo, err := am.getEventsUserInfo(ctx, events, accountId, user)
if err != nil {
return err
}
for _, event := range events {
if !fillEventInitiatorInfo(eventUserInfo, event) {
log.WithContext(ctx).Warnf("failed to resolve user info for initiator: %s", event.InitiatorID)
}
fillEventTargetInfo(eventUserInfo, event)
}
return nil
}
func (am *DefaultAccountManager) getEventsUserInfo(ctx context.Context, events []*activity.Event, accountId string, user *types.User) (map[string]eventUserInfo, error) {
accountUsers, err := am.Store.GetAccountUsers(ctx, store.LockingStrengthShare, accountId)
if err != nil {
return nil, err
}
// @note check whether using a external initiator user here is an issue
userInfos, err := am.BuildUserInfosForAccount(ctx, accountId, user.Id, accountUsers)
if err != nil {
return nil, err
}
eventUserInfos := make(map[string]eventUserInfo)
for i, k := range userInfos {
eventUserInfos[i] = eventUserInfo{
email: k.Email,
name: k.Name,
accountId: accountId,
}
}
externalUserIds := []string{}
for _, event := range events {
if _, ok := eventUserInfos[event.InitiatorID]; ok {
continue
}
if event.InitiatorID == activity.SystemInitiator ||
event.InitiatorID == accountId ||
event.Activity == activity.PeerAddedWithSetupKey {
// @todo other events to be excluded if never initiated by a user
continue
}
externalUserIds = append(externalUserIds, event.InitiatorID)
}
if len(externalUserIds) == 0 {
return eventUserInfos, nil
}
return am.getEventsExternalUserInfo(ctx, externalUserIds, eventUserInfos, user)
}
func (am *DefaultAccountManager) getEventsExternalUserInfo(ctx context.Context, externalUserIds []string, eventUserInfos map[string]eventUserInfo, user *types.User) (map[string]eventUserInfo, error) {
externalAccountId := ""
fetched := make(map[string]struct{})
externalUsers := []*types.User{}
for _, id := range externalUserIds {
if _, ok := fetched[id]; ok {
continue
}
externalUser, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, id)
if err != nil {
// @todo consider logging
continue
}
if externalAccountId != "" && externalAccountId != externalUser.AccountID {
return nil, fmt.Errorf("multiple external user accounts in events")
}
if externalAccountId == "" {
externalAccountId = externalUser.AccountID
}
fetched[id] = struct{}{}
externalUsers = append(externalUsers, externalUser)
}
// if we couldn't determine an account, return what we have
if externalAccountId == "" {
log.WithContext(ctx).Warnf("failed to determine external user account from users: %v", externalUserIds)
return eventUserInfos, nil
}
externalUserInfos, err := am.BuildUserInfosForAccount(ctx, externalAccountId, user.Id, externalUsers)
if err != nil {
return nil, err
}
for i, k := range externalUserInfos {
eventUserInfos[i] = eventUserInfo{
email: k.Email,
name: k.Name,
accountId: externalAccountId,
}
}
return eventUserInfos, nil
}
func fillEventTargetInfo(eventUserInfo map[string]eventUserInfo, event *activity.Event) {
userInfo, ok := eventUserInfo[event.TargetID]
if !ok {
return
}
if event.Meta == nil {
event.Meta = make(map[string]any)
}
event.Meta["email"] = userInfo.email
event.Meta["username"] = userInfo.name
}
func fillEventInitiatorInfo(eventUserInfo map[string]eventUserInfo, event *activity.Event) bool {
userInfo, ok := eventUserInfo[event.InitiatorID]
if !ok {
return false
}
if event.InitiatorEmail == "" {
event.InitiatorEmail = userInfo.email
}
if event.InitiatorName == "" {
event.InitiatorName = userInfo.name
}
if event.AccountID != userInfo.accountId {
if event.Meta == nil {
event.Meta = make(map[string]any)
}
event.Meta["external"] = true
}
return true
}

View File

@@ -35,8 +35,8 @@ func (am *DefaultAccountManager) CheckGroupPermissions(ctx context.Context, acco
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
if user.IsRegularUser() {
@@ -83,8 +83,8 @@ func (am *DefaultAccountManager) SaveGroups(ctx context.Context, accountID, user
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
if user.IsRegularUser() {
@@ -215,8 +215,8 @@ func (am *DefaultAccountManager) DeleteGroups(ctx context.Context, accountID, us
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
if user.IsRegularUser() {

View File

@@ -1,7 +1,6 @@
package events
import (
"context"
"fmt"
"net/http"
@@ -47,66 +46,15 @@ func (h *handler) getAllEvents(w http.ResponseWriter, r *http.Request) {
util.WriteError(r.Context(), err, w)
return
}
events := make([]*api.Event, len(accountEvents))
for i, e := range accountEvents {
events[i] = toEventResponse(e)
}
err = h.fillEventsWithUserInfo(r.Context(), events, accountID, userID)
if err != nil {
util.WriteError(r.Context(), err, w)
return
}
util.WriteJSONObject(r.Context(), w, events)
}
func (h *handler) fillEventsWithUserInfo(ctx context.Context, events []*api.Event, accountId, userId string) error {
// build email, name maps based on users
userInfos, err := h.accountManager.GetUsersFromAccount(ctx, accountId, userId)
if err != nil {
log.WithContext(ctx).Errorf("failed to get users from account: %s", err)
return err
}
emails := make(map[string]string)
names := make(map[string]string)
for _, ui := range userInfos {
emails[ui.ID] = ui.Email
names[ui.ID] = ui.Name
}
var ok bool
for _, event := range events {
// fill initiator
if event.InitiatorEmail == "" {
event.InitiatorEmail, ok = emails[event.InitiatorId]
if !ok {
log.WithContext(ctx).Warnf("failed to resolve email for initiator: %s", event.InitiatorId)
}
}
if event.InitiatorName == "" {
// here to allowed to be empty because in the first release we did not store the name
event.InitiatorName = names[event.InitiatorId]
}
// fill target meta
email, ok := emails[event.TargetId]
if !ok {
continue
}
event.Meta["email"] = email
username, ok := names[event.TargetId]
if !ok {
continue
}
event.Meta["username"] = username
}
return nil
}
func toEventResponse(event *activity.Event) *api.Event {
meta := make(map[string]string)
if event.Meta != nil {

View File

@@ -16,19 +16,18 @@ import (
"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"
"github.com/netbirdio/management-integrations/integrations"
"github.com/netbirdio/netbird/management/server/peers"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/users"
"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/auth"
nbcontext "github.com/netbirdio/netbird/management/server/context"
@@ -125,7 +124,8 @@ func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *serve
proxyController := integrations.NewController(store)
userManager := users.NewManager(store)
settingsManager := settings.NewManager(store, userManager, integrations.NewManager(&activity.InMemoryEventStore{}))
am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager)
permissionsManagerMock := permissions.NewManagerMock()
am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager, permissionsManagerMock)
if err != nil {
t.Fatalf("Failed to create manager: %v", err)
}
@@ -143,7 +143,6 @@ func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *serve
resourcesManagerMock := resources.NewManagerMock()
routersManagerMock := routers.NewManagerMock()
groupsManagerMock := groups.NewManagerMock()
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, settingsManager)

View File

@@ -25,6 +25,7 @@ import (
mgmtProto "github.com/netbirdio/netbird/management/proto"
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -431,6 +432,8 @@ func startManagementForTest(t *testing.T, testFile string, config *Config) (*grp
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
@@ -441,7 +444,7 @@ func startManagementForTest(t *testing.T, testFile string, config *Config) (*grp
Return(&types.Settings{}, nil)
accountManager, err := BuildManager(ctx, store, peersUpdateManager, nil, "", "netbird.selfhosted",
eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
if err != nil {
cleanup()

View File

@@ -24,6 +24,7 @@ import (
"github.com/netbirdio/netbird/management/server"
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -194,6 +195,7 @@ func startServer(
Return(&types.Settings{}, nil).
AnyTimes()
permissionsManagerMock := permissions.NewManagerMock()
accountManager, err := server.BuildManager(
context.Background(),
str,
@@ -208,6 +210,7 @@ func startServer(
metrics,
port_forwarding.NewControllerMock(),
settingsMockManager,
permissionsManagerMock,
)
if err != nil {
t.Fatalf("failed creating an account manager: %v", err)

View File

@@ -112,6 +112,8 @@ type MockAccountManager struct {
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
CreateAccountByPrivateDomainFunc func(ctx context.Context, initiatorId, domain string) (*types.Account, error)
UpdateToPrimaryAccountFunc func(ctx context.Context, accountId string) (*types.Account, error)
}
func (am *MockAccountManager) UpdateAccountPeers(ctx context.Context, accountID string) {
@@ -847,3 +849,17 @@ func (am *MockAccountManager) GetStore() store.Store {
}
return nil
}
func (am *MockAccountManager) CreateAccountByPrivateDomain(ctx context.Context, initiatorId, domain string) (*types.Account, error) {
if am.CreateAccountByPrivateDomainFunc != nil {
return am.CreateAccountByPrivateDomainFunc(ctx, initiatorId, domain)
}
return nil, status.Errorf(codes.Unimplemented, "method CreateAccountByPrivateDomain is not implemented")
}
func (am *MockAccountManager) UpdateToPrimaryAccount(ctx context.Context, accountId string) (*types.Account, error) {
if am.UpdateToPrimaryAccountFunc != nil {
return am.UpdateToPrimaryAccountFunc(ctx, accountId)
}
return nil, status.Errorf(codes.Unimplemented, "method UpdateToPrimaryAccount is not implemented")
}

View File

@@ -25,8 +25,8 @@ func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, account
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -46,8 +46,8 @@ func (am *DefaultAccountManager) CreateNameServerGroup(ctx context.Context, acco
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
newNSGroup := &nbdns.NameServerGroup{
@@ -108,8 +108,8 @@ func (am *DefaultAccountManager) SaveNameServerGroup(ctx context.Context, accoun
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
var updateAccountPeers bool
@@ -159,8 +159,8 @@ func (am *DefaultAccountManager) DeleteNameServerGroup(ctx context.Context, acco
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
var nsGroup *nbdns.NameServerGroup
@@ -203,8 +203,8 @@ func (am *DefaultAccountManager) ListNameServerGroups(ctx context.Context, accou
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {

View File

@@ -14,6 +14,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/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -774,11 +775,12 @@ func createNSManager(t *testing.T) (*DefaultAccountManager, error) {
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
}
func createNSStore(t *testing.T) (store.Store, error) {

View File

@@ -37,8 +37,8 @@ func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
@@ -188,8 +188,8 @@ func (am *DefaultAccountManager) UpdatePeer(ctx context.Context, accountID, user
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
var peer *nbpeer.Peer
@@ -321,8 +321,8 @@ func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peer
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
}
@@ -1099,8 +1099,8 @@ func (am *DefaultAccountManager) GetPeer(ctx context.Context, accountID, peerID,
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)

View File

@@ -20,9 +20,10 @@ import (
"github.com/stretchr/testify/require"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
"github.com/netbirdio/netbird/management/server/util"
resourceTypes "github.com/netbirdio/netbird/management/server/networks/resources/types"
@@ -1217,7 +1218,8 @@ func Test_RegisterPeerByUser(t *testing.T) {
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
permissionsManagerMock := permissions.NewManagerMock()
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
assert.NoError(t, err)
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
@@ -1285,7 +1287,8 @@ func Test_RegisterPeerBySetupKey(t *testing.T) {
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
permissionsManagerMock := permissions.NewManagerMock()
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
assert.NoError(t, err)
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
@@ -1356,7 +1359,8 @@ func Test_RegisterPeerRollbackOnFailure(t *testing.T) {
t.Cleanup(ctrl.Finish)
settingsMockManager := settings.NewMockManager(ctrl)
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
permissionsManagerMock := permissions.NewManagerMock()
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
assert.NoError(t, err)
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"

View File

@@ -7,6 +7,7 @@ import (
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/status"
"github.com/netbirdio/netbird/management/server/types"
"github.com/netbirdio/netbird/management/server/users"
)
@@ -28,6 +29,7 @@ const (
type Manager interface {
ValidateUserPermissions(ctx context.Context, accountID, userID string, module Module, operation Operation) (bool, error)
ValidateAccountAccess(ctx context.Context, accountID string, user *types.User) error
}
type managerImpl struct {
@@ -52,11 +54,11 @@ func (m *managerImpl) ValidateUserPermissions(ctx context.Context, accountID, us
}
if user == nil {
return false, errors.New("user not found")
return false, status.NewUserNotFoundError(userID)
}
if user.AccountID != accountID {
return false, errors.New("user does not belong to account")
if err := m.ValidateAccountAccess(ctx, accountID, user); err != nil {
return false, err
}
switch user.Role {
@@ -91,6 +93,13 @@ func (m *managerImpl) validateRegularUserPermissions(ctx context.Context, accoun
return false, nil
}
func (m *managerImpl) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User) error {
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
}
return nil
}
func NewManagerMock() Manager {
return &managerMock{}
}
@@ -101,3 +110,11 @@ func (m *managerMock) ValidateUserPermissions(ctx context.Context, accountID, us
}
return false, nil
}
func (m *managerMock) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User) error {
// @note managers explicitly checked this, so should the mock
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
}
return nil
}

View File

@@ -22,8 +22,8 @@ func (am *DefaultAccountManager) GetPolicy(ctx context.Context, accountID, polic
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -43,8 +43,8 @@ func (am *DefaultAccountManager) SavePolicy(ctx context.Context, accountID, user
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -100,8 +100,8 @@ func (am *DefaultAccountManager) DeletePolicy(ctx context.Context, accountID, po
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
if user.IsRegularUser() {
@@ -148,8 +148,8 @@ func (am *DefaultAccountManager) ListPolicies(ctx context.Context, accountID, us
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {

View File

@@ -22,8 +22,8 @@ func (am *DefaultAccountManager) GetPostureChecks(ctx context.Context, accountID
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if !user.HasAdminPower() {
@@ -43,8 +43,8 @@ func (am *DefaultAccountManager) SavePostureChecks(ctx context.Context, accountI
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if !user.HasAdminPower() {
@@ -99,8 +99,8 @@ func (am *DefaultAccountManager) DeletePostureChecks(ctx context.Context, accoun
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
if !user.HasAdminPower() {
@@ -141,8 +141,8 @@ func (am *DefaultAccountManager) ListPostureChecks(ctx context.Context, accountI
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if !user.HasAdminPower() {

View File

@@ -25,7 +25,11 @@ func (am *DefaultAccountManager) GetRoute(ctx context.Context, accountID string,
return nil, err
}
if !user.IsAdminOrServiceUser() || user.AccountID != accountID {
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if !user.IsAdminOrServiceUser() {
return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view Network Routes")
}
@@ -342,7 +346,11 @@ func (am *DefaultAccountManager) ListRoutes(ctx context.Context, accountID, user
return nil, err
}
if !user.IsAdminOrServiceUser() || user.AccountID != accountID {
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if !user.IsAdminOrServiceUser() {
return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view Network Routes")
}

View File

@@ -21,6 +21,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/permissions"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/telemetry"
@@ -1259,6 +1260,7 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
require.NoError(t, err)
permissionsManagerMock := permissions.NewManagerMock()
ctrl := gomock.NewController(t)
t.Cleanup(ctrl.Finish)
@@ -1281,7 +1283,7 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
AnyTimes().
Return(&types.ExtraSettings{}, nil)
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager)
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
}
func createRouterStore(t *testing.T) (store.Store, error) {

View File

@@ -61,8 +61,8 @@ func (am *DefaultAccountManager) CreateSetupKey(ctx context.Context, accountID s
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -118,8 +118,8 @@ func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID str
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -180,8 +180,8 @@ func (am *DefaultAccountManager) ListSetupKeys(ctx context.Context, accountID, u
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -198,8 +198,8 @@ func (am *DefaultAccountManager) GetSetupKey(ctx context.Context, accountID, use
return nil, err
}
if user.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return nil, err
}
if user.IsRegularUser() {
@@ -226,8 +226,8 @@ func (am *DefaultAccountManager) DeleteSetupKey(ctx context.Context, accountID,
return err
}
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user); err != nil {
return err
}
if user.IsRegularUser() {

View File

@@ -2194,3 +2194,17 @@ func (s *SqlStore) GetPeerByIP(ctx context.Context, lockStrength LockingStrength
return &peer, nil
}
func (s *SqlStore) CountAccountsByPrivateDomain(ctx context.Context, domain string) (int64, error) {
var count int64
result := s.db.Model(&types.Account{}).
Where("domain = ? AND domain_category = ?",
strings.ToLower(domain), types.PrivateCategory,
).Count(&count)
if result.Error != nil {
log.WithContext(ctx).Errorf("failed to count accounts by private domain %s: %s", domain, result.Error)
return 0, status.Errorf(status.Internal, "failed to count accounts by private domain")
}
return count, nil
}

View File

@@ -69,6 +69,7 @@ type Store interface {
DeleteAccount(ctx context.Context, account *types.Account) error
UpdateAccountDomainAttributes(ctx context.Context, accountID string, domain string, category string, isPrimaryDomain bool) error
SaveDNSSettings(ctx context.Context, lockStrength LockingStrength, accountID string, settings *types.DNSSettings) error
CountAccountsByPrivateDomain(ctx context.Context, domain string) (int64, error)
GetUserByPATID(ctx context.Context, lockStrength LockingStrength, patID string) (*types.User, error)
GetUserByUserID(ctx context.Context, lockStrength LockingStrength, userID string) (*types.User, error)

View File

@@ -13,6 +13,7 @@ import (
"github.com/netbirdio/netbird/management/proto"
"github.com/netbirdio/netbird/management/server/settings"
"github.com/netbirdio/netbird/management/server/types"
auth "github.com/netbirdio/netbird/relay/auth/hmac"
authv2 "github.com/netbirdio/netbird/relay/auth/hmac/v2"
@@ -33,7 +34,7 @@ type SecretsManager interface {
type TimeBasedAuthSecretsManager struct {
mux sync.Mutex
turnCfg *TURNConfig
relayCfg *Relay
relayCfg *types.Relay
turnHmacToken *auth.TimedHMAC
relayHmacToken *authv2.Generator
updateManager *PeersUpdateManager
@@ -44,7 +45,7 @@ type TimeBasedAuthSecretsManager struct {
type Token auth.Token
func NewTimeBasedAuthSecretsManager(updateManager *PeersUpdateManager, turnCfg *TURNConfig, relayCfg *Relay, settingsManager settings.Manager) *TimeBasedAuthSecretsManager {
func NewTimeBasedAuthSecretsManager(updateManager *PeersUpdateManager, turnCfg *TURNConfig, relayCfg *types.Relay, settingsManager settings.Manager) *TimeBasedAuthSecretsManager {
mgr := &TimeBasedAuthSecretsManager{
updateManager: updateManager,
turnCfg: turnCfg,

View File

@@ -31,7 +31,7 @@ func TestTimeBasedAuthSecretsManager_GenerateCredentials(t *testing.T) {
secret := "some_secret"
peersManager := NewPeersUpdateManager(nil)
rc := &Relay{
rc := &types.Relay{
Addresses: []string{"localhost:0"},
CredentialsTTL: ttl,
Secret: secret,
@@ -81,7 +81,7 @@ func TestTimeBasedAuthSecretsManager_SetupRefresh(t *testing.T) {
peer := "some_peer"
updateChannel := peersManager.CreateChannel(context.Background(), peer)
rc := &Relay{
rc := &types.Relay{
Addresses: []string{"localhost:0"},
CredentialsTTL: ttl,
Secret: secret,
@@ -184,7 +184,7 @@ func TestTimeBasedAuthSecretsManager_CancelRefresh(t *testing.T) {
peersManager := NewPeersUpdateManager(nil)
peer := "some_peer"
rc := &Relay{
rc := &types.Relay{
Addresses: []string{"localhost:0"},
CredentialsTTL: ttl,
Secret: secret,

View File

@@ -0,0 +1,13 @@
package types
import "github.com/netbirdio/netbird/util"
// MgmtConfigPath Config path of the Management service
var MgmtConfigPath string
// Relay configuration type
type Relay struct {
Addresses []string
CredentialsTTL util.Duration
Secret string
}

View File

@@ -30,8 +30,8 @@ func (am *DefaultAccountManager) createServiceUser(ctx context.Context, accountI
return nil, err
}
if initiatorUser.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return nil, err
}
if !initiatorUser.HasAdminPower() {
@@ -93,8 +93,8 @@ func (am *DefaultAccountManager) inviteNewUser(ctx context.Context, accountID, u
return nil, err
}
if initiatorUser.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return nil, err
}
inviterID := userID
@@ -228,8 +228,8 @@ func (am *DefaultAccountManager) DeleteUser(ctx context.Context, accountID, init
return err
}
if initiatorUser.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return err
}
if !initiatorUser.HasAdminPower() {
@@ -290,8 +290,8 @@ func (am *DefaultAccountManager) InviteUser(ctx context.Context, accountID strin
return err
}
if initiatorUser.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return err
}
// check if the user is already registered with this ID
@@ -338,8 +338,8 @@ func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string
return nil, err
}
if initiatorUser.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return nil, err
}
targetUser, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, targetUserID)
@@ -376,8 +376,8 @@ func (am *DefaultAccountManager) DeletePAT(ctx context.Context, accountID string
return err
}
if initiatorUser.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return err
}
if initiatorUserID != targetUserID && initiatorUser.IsRegularUser() {
@@ -411,8 +411,8 @@ func (am *DefaultAccountManager) GetPAT(ctx context.Context, accountID string, i
return nil, err
}
if initiatorUser.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return nil, err
}
if initiatorUserID != targetUserID && initiatorUser.IsRegularUser() {
@@ -429,8 +429,8 @@ func (am *DefaultAccountManager) GetAllPATs(ctx context.Context, accountID strin
return nil, err
}
if initiatorUser.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return nil, err
}
if initiatorUserID != targetUserID && initiatorUser.IsRegularUser() {
@@ -476,8 +476,8 @@ func (am *DefaultAccountManager) SaveOrAddUsers(ctx context.Context, accountID,
return nil, err
}
if initiatorUser.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return nil, err
}
if !initiatorUser.HasAdminPower() || initiatorUser.IsBlocked() {
@@ -705,6 +705,7 @@ func (am *DefaultAccountManager) getUserInfo(ctx context.Context, user *types.Us
// validateUserUpdate validates the update operation for a user.
func validateUserUpdate(groupsMap map[string]*types.Group, initiatorUser, oldUser, update *types.User) error {
// @todo double check these
if initiatorUser.HasAdminPower() && initiatorUser.Id == update.Id && oldUser.Blocked != update.Blocked {
return status.Errorf(status.PermissionDenied, "admins can't block or unblock themselves")
}
@@ -790,8 +791,8 @@ func (am *DefaultAccountManager) GetUsersFromAccount(ctx context.Context, accoun
return nil, err
}
if initiatorUser.AccountID != accountID {
return nil, status.NewUserNotPartOfAccountError()
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return nil, err
}
return am.BuildUserInfosForAccount(ctx, accountID, initiatorUserID, accountUsers)
@@ -967,6 +968,10 @@ func (am *DefaultAccountManager) DeleteRegularUsers(ctx context.Context, account
return err
}
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, initiatorUser); err != nil {
return err
}
if !initiatorUser.HasAdminPower() {
return status.NewAdminPermissionError()
}

View File

@@ -13,6 +13,7 @@ import (
nbcache "github.com/netbirdio/netbird/management/server/cache"
nbcontext "github.com/netbirdio/netbird/management/server/context"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/util"
nbpeer "github.com/netbirdio/netbird/management/server/peer"
@@ -59,9 +60,11 @@ func TestUser_CreatePAT_ForSameUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: s,
eventStore: &activity.InMemoryEventStore{},
Store: s,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
pat, err := am.CreatePAT(context.Background(), mockAccountID, mockUserID, mockUserID, mockTokenName, mockExpiresIn)
@@ -107,9 +110,11 @@ func TestUser_CreatePAT_ForDifferentUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
_, err = am.CreatePAT(context.Background(), mockAccountID, mockUserID, mockTargetUserId, mockTokenName, mockExpiresIn)
@@ -133,9 +138,11 @@ func TestUser_CreatePAT_ForServiceUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
pat, err := am.CreatePAT(context.Background(), mockAccountID, mockUserID, mockTargetUserId, mockTokenName, mockExpiresIn)
@@ -160,9 +167,11 @@ func TestUser_CreatePAT_WithWrongExpiration(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
_, err = am.CreatePAT(context.Background(), mockAccountID, mockUserID, mockUserID, mockTokenName, mockWrongExpiresIn)
@@ -183,9 +192,11 @@ func TestUser_CreatePAT_WithEmptyName(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
_, err = am.CreatePAT(context.Background(), mockAccountID, mockUserID, mockUserID, mockEmptyTokenName, mockExpiresIn)
@@ -214,9 +225,11 @@ func TestUser_DeletePAT(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
err = am.DeletePAT(context.Background(), mockAccountID, mockUserID, mockUserID, mockTokenID1)
@@ -255,9 +268,11 @@ func TestUser_GetPAT(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
pat, err := am.GetPAT(context.Background(), mockAccountID, mockUserID, mockUserID, mockTokenID1)
@@ -296,9 +311,11 @@ func TestUser_GetAllPATs(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
pats, err := am.GetAllPATs(context.Background(), mockAccountID, mockUserID, mockUserID)
@@ -390,9 +407,11 @@ func TestUser_CreateServiceUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
user, err := am.createServiceUser(context.Background(), mockAccountID, mockUserID, mockRole, mockServiceUserName, false, []string{"group1", "group2"})
@@ -435,9 +454,11 @@ func TestUser_CreateUser_ServiceUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
user, err := am.CreateUser(context.Background(), mockAccountID, mockUserID, &types.UserInfo{
@@ -481,9 +502,11 @@ func TestUser_CreateUser_RegularUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
_, err = am.CreateUser(context.Background(), mockAccountID, mockUserID, &types.UserInfo{
@@ -510,10 +533,12 @@ func TestUser_InviteNewUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
cacheLoading: map[string]chan struct{}{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
cacheLoading: map[string]chan struct{}{},
permissionsManager: permissionsMananagerMock,
}
cs, err := nbcache.NewStore(context.Background(), nbcache.DefaultIDPCacheExpirationMax, nbcache.DefaultIDPCacheCleanupInterval)
@@ -616,9 +641,11 @@ func TestUser_DeleteUser_ServiceUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
err = am.DeleteUser(context.Background(), mockAccountID, mockUserID, mockServiceUserID)
@@ -652,9 +679,11 @@ func TestUser_DeleteUser_SelfDelete(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
err = am.DeleteUser(context.Background(), mockAccountID, mockUserID, mockUserID)
@@ -704,10 +733,12 @@ func TestUser_DeleteUser_regularUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
integratedPeerValidator: MocIntegratedValidator{},
permissionsManager: permissionsMananagerMock,
}
testCases := []struct {
@@ -812,10 +843,12 @@ func TestUser_DeleteUser_RegularUsers(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
integratedPeerValidator: MocIntegratedValidator{},
permissionsManager: permissionsMananagerMock,
}
testCases := []struct {
@@ -921,9 +954,11 @@ func TestDefaultAccountManager_GetUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
claims := nbcontext.UserAuth{
@@ -957,9 +992,11 @@ func TestDefaultAccountManager_ListUsers(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
users, err := am.ListUsers(context.Background(), mockAccountID)
@@ -1044,9 +1081,11 @@ func TestDefaultAccountManager_ListUsers_DashboardPermissions(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
users, err := am.ListUsers(context.Background(), mockAccountID)
@@ -1087,11 +1126,13 @@ func TestDefaultAccountManager_ExternalCache(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
idpManager: &idp.GoogleWorkspaceManager{}, // empty manager
cacheLoading: map[string]chan struct{}{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
idpManager: &idp.GoogleWorkspaceManager{}, // empty manager
cacheLoading: map[string]chan struct{}{},
permissionsManager: permissionsMananagerMock,
}
cacheStore, err := nbcache.NewStore(context.Background(), nbcache.DefaultIDPCacheExpirationMax, nbcache.DefaultIDPCacheCleanupInterval)
@@ -1148,9 +1189,11 @@ func TestUser_GetUsersFromAccount_ForAdmin(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
users, err := am.GetUsersFromAccount(context.Background(), mockAccountID, mockUserID)
@@ -1180,9 +1223,11 @@ func TestUser_GetUsersFromAccount_ForUser(t *testing.T) {
t.Fatalf("Error when saving account: %s", err)
}
permissionsMananagerMock := permissions.NewManagerMock()
am := DefaultAccountManager{
Store: store,
eventStore: &activity.InMemoryEventStore{},
Store: store,
eventStore: &activity.InMemoryEventStore{},
permissionsManager: permissionsMananagerMock,
}
users, err := am.GetUsersFromAccount(context.Background(), mockAccountID, mockServiceUserID)