Files
netbird/management/server/permissions/manager.go

130 lines
3.2 KiB
Go

package permissions
import (
"context"
"errors"
"fmt"
"github.com/netbirdio/netbird/management/server/status"
"github.com/netbirdio/netbird/management/server/store"
"github.com/netbirdio/netbird/management/server/types"
)
type Module string
const (
Networks Module = "networks"
Peers Module = "peers"
Groups Module = "groups"
Settings Module = "settings"
Accounts Module = "accounts"
)
type Operation string
const (
Read Operation = "read"
Write Operation = "write"
)
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, allowOwnerAndAdmin bool) error
}
type managerImpl struct {
store store.Store
}
type managerMock struct {
}
func NewManager(store store.Store) Manager {
return &managerImpl{
store: store,
}
}
func (m *managerImpl) ValidateUserPermissions(ctx context.Context, accountID, userID string, module Module, operation Operation) (bool, error) {
user, err := m.store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
if err != nil {
return false, err
}
if user == nil {
return false, status.NewUserNotFoundError(userID)
}
if err := m.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
return false, err
}
switch module {
case Accounts:
if operation == Write && user.Role != types.UserRoleOwner {
return false, nil
}
return true, nil
default:
}
switch user.Role {
case types.UserRoleAdmin, types.UserRoleOwner:
return true, nil
case types.UserRoleUser:
return m.validateRegularUserPermissions(ctx, accountID, module, operation)
case types.UserRoleBillingAdmin:
return false, nil
default:
return false, errors.New("invalid role")
}
}
func (m *managerImpl) validateRegularUserPermissions(ctx context.Context, accountID string, module Module, operation Operation) (bool, error) {
settings, err := m.store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
if err != nil {
return false, fmt.Errorf("failed to get settings: %w", err)
}
if settings.RegularUsersViewBlocked {
return false, nil
}
if operation == Write {
return false, nil
}
if module == Peers {
return true, nil
}
return false, nil
}
func (m *managerImpl) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error {
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
}
return nil
}
func NewManagerMock() Manager {
return &managerMock{}
}
func (m *managerMock) ValidateUserPermissions(ctx context.Context, accountID, userID string, module Module, operation Operation) (bool, error) {
switch userID {
case "a23efe53-63fb-11ec-90d6-0242ac120003", "allowedUser", "testingUser", "account_creator", "serviceUserID", "test_user":
return true, nil
default:
return false, nil
}
}
func (m *managerMock) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error {
// @note managers explicitly checked this, so should the mock
if user.AccountID != accountID {
return status.NewUserNotPartOfAccountError()
}
return nil
}