Files
2025-05-27 09:22:01 +02:00

108 lines
3.0 KiB
Go

package permissions
//go:generate go run github.com/golang/mock/mockgen -package permissions -destination=manager_mock.go -source=./manager.go -build_flags=-mod=mod
import (
"context"
"github.com/netbirdio/netbird/management/server/status"
"management/internal/modules/users/types"
"management/internal/shared/activity"
"management/internal/shared/db"
"management/internal/shared/permissions/modules"
"management/internal/shared/permissions/operations"
"management/internal/shared/permissions/roles"
"management/pkg/logging"
)
var log = logging.LoggerForThisPackage()
type Manager interface {
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
Init(userManager userManager)
}
type userManager interface {
GetUserByID(ctx context.Context, tx db.Transaction, strength db.LockingStrength, id string) (*types.User, error)
}
type managerImpl struct {
userManager userManager
}
func NewManager() Manager {
return &managerImpl{}
}
func (m *managerImpl) Init(userManager userManager) {
m.userManager = userManager
}
func (m *managerImpl) ValidateUserPermissions(
ctx context.Context,
accountID string,
userID string,
module modules.Module,
operation operations.Operation,
) (bool, error) {
if userID == activity.SystemInitiator {
return true, nil
}
user, err := m.userManager.GetUserByID(ctx, nil, db.LockingStrengthShare, userID)
if err != nil {
return false, err
}
if user == nil {
return false, status.NewUserNotFoundError(userID)
}
if user.IsBlocked() {
return false, status.NewUserBlockedError()
}
if err := m.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
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))
}
return m.ValidateRoleModuleAccess(ctx, accountID, role, module, operation), nil
}
func (m *managerImpl) ValidateRoleModuleAccess(
ctx context.Context,
accountID string,
role roles.RolePermissions,
module modules.Module,
operation operations.Operation,
) bool {
if permissions, ok := role.Permissions[module]; ok {
if allowed, exists := permissions[operation]; exists {
return allowed
}
log.WithContext(ctx).Tracef("operation %s not found on module %s for role %s", operation, module, role.Role)
return false
}
return role.AutoAllowNew[operation]
}
func (m *managerImpl) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error {
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
}
return nil
}