Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
32730af
use api wrapper for permissions management
pascal-fischer Feb 23, 2026
b0ce004
Merge branch 'refs/heads/main' into refactor/permissions-manager
pascal-fischer Mar 6, 2026
da4a0eb
Merge branch 'main' into refactor/permissions-manager
pascal-fischer Mar 6, 2026
d85ee0b
remove old permissions management
pascal-fischer Mar 6, 2026
3741eb4
Merge remote-tracking branch 'origin/main' into refactor/permissions-…
pascal-fischer Mar 17, 2026
3013c98
Merge branch 'main' into refactor/permissions-manager
pascal-fischer Mar 27, 2026
beee14b
fix merge conflicts
pascal-fischer Mar 27, 2026
f5c8a6f
update integrations
pascal-fischer Mar 27, 2026
20e6dff
Merge branch 'main' into refactor/permissions-manager
pascal-fischer Apr 7, 2026
31d901c
update role permissions for admins
pascal-fischer Apr 8, 2026
e46ea89
Merge branch 'main' into refactor/permissions-manager
pascal-fischer Apr 16, 2026
9e385eb
add optional auth error handlers
pascal-fischer Apr 16, 2026
9406de9
add exception handler and add exception for users
pascal-fischer Apr 16, 2026
8530f9b
Merge branch 'main' into refactor/permissions-manager
pascal-fischer Apr 16, 2026
dd9539a
fix gomod
pascal-fischer Apr 16, 2026
5be80e9
fix mock
pascal-fischer Apr 16, 2026
ce522ea
fix mock
pascal-fischer Apr 16, 2026
53e47da
fix tests
pascal-fischer Apr 16, 2026
16d6cc1
update management integrations
pascal-fischer Apr 16, 2026
fb6447e
fix engine test
pascal-fischer Apr 16, 2026
4835909
fix client test
pascal-fischer Apr 17, 2026
dbe5333
fix client server test
pascal-fischer Apr 17, 2026
d139a4f
fix client cmd test
pascal-fischer Apr 17, 2026
a572d88
fix user handler test
pascal-fischer Apr 17, 2026
e006373
update tests
pascal-fischer Apr 17, 2026
8a41117
fix version test
pascal-fischer Apr 17, 2026
a53c38a
add sql test files
pascal-fischer Apr 17, 2026
b65a8bc
update sql test data files and auth wrappers
pascal-fischer Apr 20, 2026
bed8d89
account for peers permission on the groups endpoint
pascal-fischer Apr 20, 2026
0b04c0d
leave todo comments
pascal-fischer Apr 20, 2026
4703070
update account isolation
pascal-fischer Apr 20, 2026
a4b55af
add additional integration tests
pascal-fischer Apr 20, 2026
d774e9a
Merge branch 'main' into refactor/permissions-manager
pascal-fischer Apr 23, 2026
4051af4
fix error response
pascal-fischer Apr 23, 2026
381858a
add accountID to test data
pascal-fischer Apr 23, 2026
312bcf6
remove service user exception
pascal-fischer Apr 24, 2026
9b10d74
copy zones and records for testing
pascal-fischer Apr 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions client/cmd/testutil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (

"github.com/netbirdio/management-integrations/integrations"

"github.com/netbirdio/netbird/management/internals/modules/permissions"

nbcache "github.com/netbirdio/netbird/management/server/cache"

"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
Expand All @@ -29,7 +31,6 @@ import (
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/groups"
"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"
Expand Down Expand Up @@ -97,7 +98,7 @@ func startManagement(t *testing.T, config *config.Config, testFile string) (*grp
t.Cleanup(ctrl.Finish)

permissionsManagerMock := permissions.NewMockManager(ctrl)
peersmanager := peers.NewManager(store, permissionsManagerMock)
peersmanager := peers.NewManager(store)
settingsManagerMock := settings.NewMockManager(ctrl)

jobManager := job.NewJobManager(nil, store, peersmanager)
Expand Down
4 changes: 2 additions & 2 deletions client/internal/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"google.golang.org/grpc/keepalive"

"github.com/netbirdio/netbird/client/internal/stdnet"
"github.com/netbirdio/netbird/management/internals/modules/permissions"
"github.com/netbirdio/netbird/management/server/job"

"github.com/netbirdio/management-integrations/integrations"
Expand Down Expand Up @@ -57,7 +58,6 @@ import (
"github.com/netbirdio/netbird/management/server/activity"
nbcache "github.com/netbirdio/netbird/management/server/cache"
"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"
Expand Down Expand Up @@ -1632,7 +1632,7 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
}

permissionsManager := permissions.NewManager(store)
peersManager := peers.NewManager(store, permissionsManager)
peersManager := peers.NewManager(store)
jobManager := job.NewJobManager(nil, store, peersManager)

cacheStore, err := nbcache.NewStore(context.Background(), 100*time.Millisecond, 300*time.Millisecond, 100)
Expand Down
5 changes: 3 additions & 2 deletions client/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import (

"github.com/netbirdio/management-integrations/integrations"

"github.com/netbirdio/netbird/management/internals/modules/permissions"

"github.com/netbirdio/netbird/management/internals/controllers/network_map/controller"
"github.com/netbirdio/netbird/management/internals/controllers/network_map/update_channel"
"github.com/netbirdio/netbird/management/internals/modules/peers"
Expand All @@ -38,7 +40,6 @@ import (
"github.com/netbirdio/netbird/management/server/activity"
nbcache "github.com/netbirdio/netbird/management/server/cache"
"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"
Expand Down Expand Up @@ -305,7 +306,7 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve
t.Cleanup(ctrl.Finish)

permissionsManagerMock := permissions.NewMockManager(ctrl)
peersManager := peers.NewManager(store, permissionsManagerMock)
peersManager := peers.NewManager(store)
settingsManagerMock := settings.NewMockManager(ctrl)

jobManager := job.NewJobManager(nil, store, peersManager)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ require (
github.com/mdlayher/socket v0.5.1
github.com/miekg/dns v1.1.59
github.com/mitchellh/hashstructure/v2 v2.0.2
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416163311-004852ffaf34
github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45
github.com/oapi-codegen/runtime v1.1.2
github.com/okta/okta-sdk-golang/v2 v2.18.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,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/v4 v4.0.0-20250908184934-6202be846b51 h1:Ov4qdafATOgGMB1wbSuh+0aAHcwz9hdvB6VZjh1mVMI=
github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51/go.mod h1:ZSIbPdBn5hePO8CpF1PekH2SfpTxg1PDhEwtbqZS7R8=
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42 h1:F3zS5fT9xzD1OFLfcdAE+3FfyiwjGukF1hvj0jErgs8=
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42/go.mod h1:n47r67ZSPgwSmT/Z1o48JjZQW9YJ6m/6Bd/uAXkL3Pg=
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416163311-004852ffaf34 h1:g74mB64wnjCagzE1spKgPfTI/ont1SdSL3uX5bOecgM=
github.com/netbirdio/management-integrations/integrations v0.0.0-20260416163311-004852ffaf34/go.mod h1:lCOq5d1i19AQjEEW2d7aNK0Nn0KC0MKyfMz/PLwVBFg=
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-20250805121659-6b4ac470ca45 h1:ujgviVYmx243Ksy7NdSwrdGPSRNE3pb8kEDSpH0QuAQ=
Expand Down
27 changes: 2 additions & 25 deletions management/internals/modules/peers/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ import (
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/integrations/integrated_validator"
"github.com/netbirdio/netbird/management/server/peer"
"github.com/netbirdio/netbird/management/server/permissions"
"github.com/netbirdio/netbird/management/server/permissions/modules"
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/shared/management/status"
)
Expand All @@ -38,17 +35,15 @@ type Manager interface {

type managerImpl struct {
store store.Store
permissionsManager permissions.Manager
integratedPeerValidator integrated_validator.IntegratedValidator
accountManager account.Manager

networkMapController network_map.Controller
}

func NewManager(store store.Store, permissionsManager permissions.Manager) Manager {
func NewManager(store store.Store) Manager {
return &managerImpl{
store: store,
permissionsManager: permissionsManager,
store: store,
}
}

Expand All @@ -65,28 +60,10 @@ func (m *managerImpl) SetAccountManager(accountManager account.Manager) {
}

func (m *managerImpl) GetPeer(ctx context.Context, accountID, userID, peerID string) (*peer.Peer, error) {
allowed, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Read)
if err != nil {
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
}

if !allowed {
return nil, status.NewPermissionDeniedError()
}

return m.store.GetPeerByID(ctx, store.LockingStrengthNone, accountID, peerID)
}

func (m *managerImpl) GetAllPeers(ctx context.Context, accountID, userID string) ([]*peer.Peer, error) {
allowed, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Read)
if err != nil {
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
}

if !allowed {
return m.store.GetUserPeers(ctx, store.LockingStrengthNone, accountID, userID)
}

return m.store.GetAccountPeers(ctx, store.LockingStrengthNone, accountID, "", "")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,29 @@ package permissions

import (
"context"
"net/http"

log "github.com/sirupsen/logrus"

"github.com/netbirdio/netbird/management/internals/modules/permissions/modules"
"github.com/netbirdio/netbird/management/internals/modules/permissions/operations"
"github.com/netbirdio/netbird/management/internals/modules/permissions/roles"
"github.com/netbirdio/netbird/management/server/account"
"github.com/netbirdio/netbird/management/server/activity"
"github.com/netbirdio/netbird/management/server/permissions/modules"
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/server/permissions/roles"
nbcontext "github.com/netbirdio/netbird/management/server/context"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/types"
"github.com/netbirdio/netbird/shared/auth"
"github.com/netbirdio/netbird/shared/management/http/util"
"github.com/netbirdio/netbird/shared/management/status"
)

// AuthErrorHandler is called when an auth error occurs during permission validation.
// If it returns true, the error is considered handled and the default error response is skipped.
type AuthErrorHandler func(w http.ResponseWriter, r *http.Request, userAuth *auth.UserAuth, err error) bool

type Manager interface {
WithPermission(module modules.Module, operation operations.Operation, handlerFunc func(w http.ResponseWriter, r *http.Request, auth *auth.UserAuth), authErrHandler ...AuthErrorHandler) http.HandlerFunc
ValidateUserPermissions(ctx context.Context, accountID, userID string, module modules.Module, operation operations.Operation) (bool, error)
ValidateRoleModuleAccess(ctx context.Context, accountID string, role roles.RolePermissions, module modules.Module, operation operations.Operation) bool
ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error
Expand All @@ -36,6 +45,51 @@ func NewManager(store store.Store) Manager {
}
}

// WithPermission wraps an HTTP handler with permission checking logic.
// An optional AuthErrorHandler can be provided to intercept auth errors before the default response is written.
func (m *managerImpl) WithPermission(
module modules.Module,
operation operations.Operation,
handlerFunc func(w http.ResponseWriter, r *http.Request, auth *auth.UserAuth),
authErrHandler ...AuthErrorHandler,
) http.HandlerFunc {
var onAuthErr AuthErrorHandler
if len(authErrHandler) > 0 {
onAuthErr = authErrHandler[0]
}

return func(w http.ResponseWriter, r *http.Request) {
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
if err != nil {
log.WithContext(r.Context()).Errorf("failed to get user auth from context: %v", err)
util.WriteError(r.Context(), err, w)
return
}

allowed, err := m.ValidateUserPermissions(r.Context(), userAuth.AccountId, userAuth.UserId, module, operation)
if err != nil {
if onAuthErr != nil && onAuthErr(w, r, &userAuth, err) {
return
}
log.WithContext(r.Context()).Errorf("failed to validate permissions for user %s on account %s: %v", userAuth.UserId, userAuth.AccountId, err)
util.WriteError(r.Context(), status.NewPermissionValidationError(err), w)
return
}

if !allowed {
permErr := status.NewPermissionDeniedError()
if onAuthErr != nil && onAuthErr(w, r, &userAuth, permErr) {
return
}
log.WithContext(r.Context()).Tracef("user %s on account %s is not allowed to %s in %s", userAuth.UserId, userAuth.AccountId, operation, module)
util.WriteError(r.Context(), permErr, w)
return
}

handlerFunc(w, r, &userAuth)
}
}

func (m *managerImpl) ValidateUserPermissions(
ctx context.Context,
accountID string,
Expand Down Expand Up @@ -68,10 +122,6 @@ func (m *managerImpl) ValidateUserPermissions(
return false, err
}

if operation == operations.Read && user.IsServiceUser {
return true, nil // this should be replaced by proper granular access role
}

role, ok := roles.RolesMap[user.Role]
if !ok {
return false, status.NewUserRoleNotFoundError(string(user.Role))
Expand Down Expand Up @@ -127,3 +177,17 @@ func (m *managerImpl) GetPermissionsByRole(ctx context.Context, role types.UserR
func (m *managerImpl) SetAccountManager(accountManager account.Manager) {
// no-op
}

// WrapHandler wraps a handler that expects UserAuth with context extraction.
// Unlike WithPermission, it does not perform any permission checks.
func WrapHandler(h func(w http.ResponseWriter, r *http.Request, userAuth *auth.UserAuth)) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
if err != nil {
log.WithContext(r.Context()).Errorf("failed to get user auth from context: %v", err)
util.WriteError(r.Context(), err, w)
return
}
h(w, r, &userAuth)
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package roles

import (
"github.com/netbirdio/netbird/management/server/permissions/modules"
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/internals/modules/permissions/modules"
"github.com/netbirdio/netbird/management/internals/modules/permissions/operations"
"github.com/netbirdio/netbird/management/server/types"
)

Expand All @@ -18,7 +18,7 @@ var Admin = RolePermissions{
modules.Accounts: {
operations.Read: true,
operations.Create: false,
operations.Update: false,
operations.Update: true,
operations.Delete: false,
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package roles

import (
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/internals/modules/permissions/operations"
"github.com/netbirdio/netbird/management/server/types"
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package roles

import (
"github.com/netbirdio/netbird/management/server/permissions/modules"
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/internals/modules/permissions/modules"
"github.com/netbirdio/netbird/management/internals/modules/permissions/operations"
"github.com/netbirdio/netbird/management/server/types"
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package roles

import (
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/internals/modules/permissions/operations"
"github.com/netbirdio/netbird/management/server/types"
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package roles

import (
"github.com/netbirdio/netbird/management/server/permissions/modules"
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/internals/modules/permissions/modules"
"github.com/netbirdio/netbird/management/internals/modules/permissions/operations"
"github.com/netbirdio/netbird/management/server/types"
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package roles

import (
"github.com/netbirdio/netbird/management/server/permissions/operations"
"github.com/netbirdio/netbird/management/internals/modules/permissions/operations"
"github.com/netbirdio/netbird/management/server/types"
)

Expand Down
Loading
Loading