mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-01 19:19:07 +02:00
Merge branch 'main' into feature/buf-cli
# Conflicts: # management/proto/management.pb.go
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## Issue ticket number and link
|
## Issue ticket number and link
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
<!-- branch-stack -->
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
- [ ] Is it a bug fix
|
- [ ] Is it a bug fix
|
||||||
- [ ] Is a typo/documentation fix
|
- [ ] Is a typo/documentation fix
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ jobs:
|
|||||||
grep -A 10 'relay:' docker-compose.yml | egrep 'NB_AUTH_SECRET=.+$'
|
grep -A 10 'relay:' docker-compose.yml | egrep 'NB_AUTH_SECRET=.+$'
|
||||||
grep -A 7 Relay management.json | grep "rel://$CI_NETBIRD_DOMAIN:33445"
|
grep -A 7 Relay management.json | grep "rel://$CI_NETBIRD_DOMAIN:33445"
|
||||||
grep -A 7 Relay management.json | egrep '"Secret": ".+"'
|
grep -A 7 Relay management.json | egrep '"Secret": ".+"'
|
||||||
|
grep DisablePromptLogin management.json | grep 'true'
|
||||||
|
|
||||||
- name: Install modules
|
- name: Install modules
|
||||||
run: go mod tidy
|
run: go mod tidy
|
||||||
|
|||||||
@@ -57,16 +57,16 @@
|
|||||||
|
|
||||||
### Key features
|
### Key features
|
||||||
|
|
||||||
| Connectivity | Management | Security | Automation | Platforms |
|
| Connectivity | Management | Security | Automation| Platforms |
|
||||||
|------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------|
|
|----|----|----|----|----|
|
||||||
| <ul><li> - \[x] Kernel WireGuard </ul></li> | <ul><li> - \[x] [Admin Web UI](https://github.com/netbirdio/dashboard) </ul></li> | <ul><li> - \[x] [SSO & MFA support](https://docs.netbird.io/how-to/installation#running-net-bird-with-sso-login) </ul></li> | <ul><li> - \[x] [Public API](https://docs.netbird.io/api) </ul></li> | <ul><li> - \[x] Linux </ul></li> |
|
| <ul><li>- \[x] Kernel WireGuard</ul></li> | <ul><li>- \[x] [Admin Web UI](https://github.com/netbirdio/dashboard)</ul></li> | <ul><li>- \[x] [SSO & MFA support](https://docs.netbird.io/how-to/installation#running-net-bird-with-sso-login)</ul></li> | <ul><li>- \[x] [Public API](https://docs.netbird.io/api)</ul></li> | <ul><li>- \[x] Linux</ul></li> |
|
||||||
| <ul><li> - \[x] Peer-to-peer connections </ul></li> | <ul><li> - \[x] Auto peer discovery and configuration </ul></li> | <ul><li> - \[x] [Access control - groups & rules](https://docs.netbird.io/how-to/manage-network-access) </ul></li> | <ul><li> - \[x] [Setup keys for bulk network provisioning](https://docs.netbird.io/how-to/register-machines-using-setup-keys) </ul></li> | <ul><li> - \[x] Mac </ul></li> |
|
| <ul><li>- \[x] Peer-to-peer connections</ul></li> | <ul><li>- \[x] Auto peer discovery and configuration</ui></li> | <ul><li>- \[x] [Access control - groups & rules](https://docs.netbird.io/how-to/manage-network-access)</ui></li> | <ul><li>- \[x] [Setup keys for bulk network provisioning](https://docs.netbird.io/how-to/register-machines-using-setup-keys)</ui></li> | <ul><li>- \[x] Mac</ui></li> |
|
||||||
| <ul><li> - \[x] Connection relay fallback </ul></li> | <ul><li> - \[x] [IdP integrations](https://docs.netbird.io/selfhosted/identity-providers) </ul></li> | <ul><li> - \[x] [Activity logging](https://docs.netbird.io/how-to/monitor-system-and-network-activity) </ul></li> | <ul><li> - \[x] [Self-hosting quickstart script](https://docs.netbird.io/selfhosted/selfhosted-quickstart) </ul></li> | <ul><li> - \[x] Windows </ul></li> |
|
| <ul><li>- \[x] Connection relay fallback</ui></li> | <ul><li>- \[x] [IdP integrations](https://docs.netbird.io/selfhosted/identity-providers)</ui></li> | <ul><li>- \[x] [Activity logging](https://docs.netbird.io/how-to/monitor-system-and-network-activity)</ui></li> | <ul><li>- \[x] [Self-hosting quickstart script](https://docs.netbird.io/selfhosted/selfhosted-quickstart)</ui></li> | <ul><li>- \[x] Windows</ui></li> |
|
||||||
| <ul><li> - \[x] [Routes to external networks](https://docs.netbird.io/how-to/routing-traffic-to-private-networks) </ul></li> | <ul><li> - \[x] [Private DNS](https://docs.netbird.io/how-to/manage-dns-in-your-network) </ul></li> | <ul><li> - \[x] [Device posture checks](https://docs.netbird.io/how-to/manage-posture-checks) </ul></li> | <ul><li> - \[x] IdP groups sync with JWT </ul></li> | <ul><li> - \[x] Android </ul></li> |
|
| <ul><li>- \[x] [Routes to external networks](https://docs.netbird.io/how-to/routing-traffic-to-private-networks)</ui></li> | <ul><li>- \[x] [Private DNS](https://docs.netbird.io/how-to/manage-dns-in-your-network)</ui></li> | <ul><li>- \[x] [Device posture checks](https://docs.netbird.io/how-to/manage-posture-checks)</ui></li> | <ul><li>- \[x] IdP groups sync with JWT</ui></li> | <ul><li>- \[x] Android</ui></li> |
|
||||||
| <ul><li> - \[x] NAT traversal with BPF </ul></li> | <ul><li> - \[x] [Multiuser support](https://docs.netbird.io/how-to/add-users-to-your-network) </ul></li> | <ul><li> - \[x] Peer-to-peer encryption </ul></li> | | <ul><li> - \[x] iOS </ul></li> |
|
| <ul><li>- \[x] NAT traversal with BPF</ui></li> | <ul><li>- \[x] [Multiuser support](https://docs.netbird.io/how-to/add-users-to-your-network)</ui></li> | <ul><li>- \[x] Peer-to-peer encryption</ui></li> || <ul><li>- \[x] iOS</ui></li> |
|
||||||
| | | <ul><li> - \[x] [Quantum-resistance with Rosenpass](https://netbird.io/knowledge-hub/the-first-quantum-resistant-mesh-vpn) </ul></li> | | <ul><li> - \[x] OpenWRT </ul></li> |
|
||| <ul><li>- \[x] [Quantum-resistance with Rosenpass](https://netbird.io/knowledge-hub/the-first-quantum-resistant-mesh-vpn)</ui></li> || <ul><li>- \[x] OpenWRT</ui></li> |
|
||||||
| | | <ui><li> - \[x] [Periodic re-authentication](https://docs.netbird.io/how-to/enforce-periodic-user-authentication)</ul></li> | | <ul><li> - \[x] [Serverless](https://docs.netbird.io/how-to/netbird-on-faas) </ul></li> |
|
||| <ul><li>- \[x] [Periodic re-authentication](https://docs.netbird.io/how-to/enforce-periodic-user-authentication)</ui></li> || <ul><li>- \[x] [Serverless](https://docs.netbird.io/how-to/netbird-on-faas)</ui></li> |
|
||||||
| | | | | <ul><li> - \[x] Docker </ul></li> |
|
||||| <ul><li>- \[x] Docker</ui></li> |
|
||||||
|
|
||||||
### Quickstart with NetBird Cloud
|
### Quickstart with NetBird Cloud
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,12 @@ import (
|
|||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/internal"
|
"github.com/netbirdio/netbird/client/internal"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/debug"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
"github.com/netbirdio/netbird/client/proto"
|
"github.com/netbirdio/netbird/client/proto"
|
||||||
"github.com/netbirdio/netbird/client/server"
|
"github.com/netbirdio/netbird/client/server"
|
||||||
nbstatus "github.com/netbirdio/netbird/client/status"
|
nbstatus "github.com/netbirdio/netbird/client/status"
|
||||||
|
mgmProto "github.com/netbirdio/netbird/management/proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
const errCloseConnection = "Failed to close connection: %v"
|
const errCloseConnection = "Failed to close connection: %v"
|
||||||
@@ -326,3 +329,34 @@ func formatDuration(d time.Duration) string {
|
|||||||
s := d / time.Second
|
s := d / time.Second
|
||||||
return fmt.Sprintf("%02d:%02d:%02d", h, m, s)
|
return fmt.Sprintf("%02d:%02d:%02d", h, m, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateDebugBundle(config *internal.Config, recorder *peer.Status, connectClient *internal.ConnectClient, logFilePath string) {
|
||||||
|
var networkMap *mgmProto.NetworkMap
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if connectClient != nil {
|
||||||
|
networkMap, err = connectClient.GetLatestNetworkMap()
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("Failed to get latest network map: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bundleGenerator := debug.NewBundleGenerator(
|
||||||
|
debug.GeneratorDependencies{
|
||||||
|
InternalConfig: config,
|
||||||
|
StatusRecorder: recorder,
|
||||||
|
NetworkMap: networkMap,
|
||||||
|
LogFile: logFilePath,
|
||||||
|
},
|
||||||
|
debug.BundleConfig{
|
||||||
|
IncludeSystemInfo: true,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
path, err := bundleGenerator.Generate()
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to generate debug bundle: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("Generated debug bundle from SIGUSR1 at: %s", path)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,39 @@
|
|||||||
|
//go:build unix
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
|
)
|
||||||
|
|
||||||
|
func SetupDebugHandler(
|
||||||
|
ctx context.Context,
|
||||||
|
config *internal.Config,
|
||||||
|
recorder *peer.Status,
|
||||||
|
connectClient *internal.ConnectClient,
|
||||||
|
logFilePath string,
|
||||||
|
) {
|
||||||
|
usr1Ch := make(chan os.Signal, 1)
|
||||||
|
|
||||||
|
signal.Notify(usr1Ch, syscall.SIGUSR1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case <-usr1Ch:
|
||||||
|
log.Info("Received SIGUSR1. Triggering debug bundle generation.")
|
||||||
|
go generateDebugBundle(config, recorder, connectClient, logFilePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"golang.org/x/sys/windows"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal"
|
||||||
|
"github.com/netbirdio/netbird/client/internal/peer"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
envListenEvent = "NB_LISTEN_DEBUG_EVENT"
|
||||||
|
debugTriggerEventName = `Global\NetbirdDebugTriggerEvent`
|
||||||
|
|
||||||
|
waitTimeout = 5 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
// SetupDebugHandler sets up a Windows event to listen for a signal to generate a debug bundle.
|
||||||
|
// Example usage with PowerShell:
|
||||||
|
// $evt = [System.Threading.EventWaitHandle]::OpenExisting("Global\NetbirdDebugTriggerEvent")
|
||||||
|
// $evt.Set()
|
||||||
|
// $evt.Close()
|
||||||
|
func SetupDebugHandler(
|
||||||
|
ctx context.Context,
|
||||||
|
config *internal.Config,
|
||||||
|
recorder *peer.Status,
|
||||||
|
connectClient *internal.ConnectClient,
|
||||||
|
logFilePath string,
|
||||||
|
) {
|
||||||
|
env := os.Getenv(envListenEvent)
|
||||||
|
if env == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
listenEvent, err := strconv.ParseBool(env)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to parse %s: %v", envListenEvent, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !listenEvent {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
eventNamePtr, err := windows.UTF16PtrFromString(debugTriggerEventName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to convert event name '%s' to UTF16: %v", debugTriggerEventName, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: restrict access by ACL
|
||||||
|
eventHandle, err := windows.CreateEvent(nil, 1, 0, eventNamePtr)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, windows.ERROR_ALREADY_EXISTS) {
|
||||||
|
log.Warnf("Debug trigger event '%s' already exists. Attempting to open.", debugTriggerEventName)
|
||||||
|
// SYNCHRONIZE is needed for WaitForSingleObject, EVENT_MODIFY_STATE for ResetEvent.
|
||||||
|
eventHandle, err = windows.OpenEvent(windows.SYNCHRONIZE|windows.EVENT_MODIFY_STATE, false, eventNamePtr)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Failed to open existing debug trigger event '%s': %v", debugTriggerEventName, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Infof("Successfully opened existing debug trigger event '%s'.", debugTriggerEventName)
|
||||||
|
} else {
|
||||||
|
log.Errorf("Failed to create debug trigger event '%s': %v", debugTriggerEventName, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if eventHandle == windows.InvalidHandle {
|
||||||
|
log.Errorf("Obtained an invalid handle for debug trigger event '%s'", debugTriggerEventName)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Infof("Debug handler waiting for signal on event: %s", debugTriggerEventName)
|
||||||
|
|
||||||
|
go waitForEvent(ctx, config, recorder, connectClient, logFilePath, eventHandle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForEvent(
|
||||||
|
ctx context.Context,
|
||||||
|
config *internal.Config,
|
||||||
|
recorder *peer.Status,
|
||||||
|
connectClient *internal.ConnectClient,
|
||||||
|
logFilePath string,
|
||||||
|
eventHandle windows.Handle,
|
||||||
|
) {
|
||||||
|
defer func() {
|
||||||
|
if err := windows.CloseHandle(eventHandle); err != nil {
|
||||||
|
log.Errorf("Failed to close debug event handle '%s': %v", debugTriggerEventName, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for {
|
||||||
|
if ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
status, err := windows.WaitForSingleObject(eventHandle, uint32(waitTimeout.Milliseconds()))
|
||||||
|
|
||||||
|
switch status {
|
||||||
|
case windows.WAIT_OBJECT_0:
|
||||||
|
log.Info("Received signal on debug event. Triggering debug bundle generation.")
|
||||||
|
|
||||||
|
// reset the event so it can be triggered again later (manual reset == 1)
|
||||||
|
if err := windows.ResetEvent(eventHandle); err != nil {
|
||||||
|
log.Errorf("Failed to reset debug event '%s': %v", debugTriggerEventName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
go generateDebugBundle(config, recorder, connectClient, logFilePath)
|
||||||
|
case uint32(windows.WAIT_TIMEOUT):
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Errorf("Unexpected status %d from WaitForSingleObject for debug event '%s': %v", status, debugTriggerEventName, err)
|
||||||
|
select {
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -115,6 +115,7 @@ var runCmd = &cobra.Command{
|
|||||||
|
|
||||||
ctx, cancel := context.WithCancel(cmd.Context())
|
ctx, cancel := context.WithCancel(cmd.Context())
|
||||||
SetupCloseHandler(ctx, cancel)
|
SetupCloseHandler(ctx, cancel)
|
||||||
|
SetupDebugHandler(ctx, nil, nil, nil, logFile)
|
||||||
|
|
||||||
s, err := newSVC(newProgram(ctx, cancel), newSVCConfig())
|
s, err := newSVC(newProgram(ctx, cancel), newSVCConfig())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -92,11 +92,11 @@ func startManagement(t *testing.T, config *types.Config, testFile string) (*grpc
|
|||||||
|
|
||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
|
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
|
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||||
|
|
||||||
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, iv, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -219,6 +219,8 @@ func runInForegroundMode(ctx context.Context, cmd *cobra.Command) error {
|
|||||||
r.GetFullStatus()
|
r.GetFullStatus()
|
||||||
|
|
||||||
connectClient := internal.NewConnectClient(ctx, config, r)
|
connectClient := internal.NewConnectClient(ctx, config, r)
|
||||||
|
SetupDebugHandler(ctx, config, r, connectClient, "")
|
||||||
|
|
||||||
return connectClient.Run(nil)
|
return connectClient.Run(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -458,6 +458,6 @@ func newBufferHolder(size int) *bufferHolder {
|
|||||||
|
|
||||||
func getLogger() logging.LeveledLogger {
|
func getLogger() logging.LeveledLogger {
|
||||||
fac := logging.NewDefaultLoggerFactory()
|
fac := logging.NewDefaultLoggerFactory()
|
||||||
fac.Writer = log.StandardLogger().Writer()
|
//fac.Writer = log.StandardLogger().Writer()
|
||||||
return fac.NewLogger("ice")
|
return fac.NewLogger("ice")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,13 +94,17 @@ func (p *PKCEAuthorizationFlow) RequestAuthInfo(ctx context.Context) (AuthFlowIn
|
|||||||
p.codeVerifier = codeVerifier
|
p.codeVerifier = codeVerifier
|
||||||
|
|
||||||
codeChallenge := createCodeChallenge(codeVerifier)
|
codeChallenge := createCodeChallenge(codeVerifier)
|
||||||
authURL := p.oAuthConfig.AuthCodeURL(
|
|
||||||
state,
|
params := []oauth2.AuthCodeOption{
|
||||||
oauth2.SetAuthURLParam("code_challenge_method", "S256"),
|
oauth2.SetAuthURLParam("code_challenge_method", "S256"),
|
||||||
oauth2.SetAuthURLParam("code_challenge", codeChallenge),
|
oauth2.SetAuthURLParam("code_challenge", codeChallenge),
|
||||||
oauth2.SetAuthURLParam("audience", p.providerConfig.Audience),
|
oauth2.SetAuthURLParam("audience", p.providerConfig.Audience),
|
||||||
oauth2.SetAuthURLParam("prompt", "login"),
|
}
|
||||||
)
|
if !p.providerConfig.DisablePromptLogin {
|
||||||
|
params = append(params, oauth2.SetAuthURLParam("prompt", "login"))
|
||||||
|
}
|
||||||
|
|
||||||
|
authURL := p.oAuthConfig.AuthCodeURL(state, params...)
|
||||||
|
|
||||||
return AuthFlowInfo{
|
return AuthFlowInfo{
|
||||||
VerificationURIComplete: authURL,
|
VerificationURIComplete: authURL,
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package auth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPromptLogin(t *testing.T) {
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
prompt bool
|
||||||
|
}{
|
||||||
|
{"PromptLogin", true},
|
||||||
|
{"NoPromptLogin", false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tt {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
config := internal.PKCEAuthProviderConfig{
|
||||||
|
ClientID: "test-client-id",
|
||||||
|
Audience: "test-audience",
|
||||||
|
TokenEndpoint: "https://test-token-endpoint.com/token",
|
||||||
|
Scope: "openid email profile",
|
||||||
|
AuthorizationEndpoint: "https://test-auth-endpoint.com/authorize",
|
||||||
|
RedirectURLs: []string{"http://127.0.0.1:33992/"},
|
||||||
|
UseIDToken: true,
|
||||||
|
DisablePromptLogin: !tc.prompt,
|
||||||
|
}
|
||||||
|
pkce, err := NewPKCEAuthorizationFlow(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create PKCEAuthorizationFlow: %v", err)
|
||||||
|
}
|
||||||
|
authInfo, err := pkce.RequestAuthInfo(context.Background())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to request auth info: %v", err)
|
||||||
|
}
|
||||||
|
pattern := "prompt=login"
|
||||||
|
if tc.prompt {
|
||||||
|
require.Contains(t, authInfo.VerificationURIComplete, pattern)
|
||||||
|
} else {
|
||||||
|
require.NotContains(t, authInfo.VerificationURIComplete, pattern)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -349,6 +349,25 @@ func (c *ConnectClient) Engine() *Engine {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetLatestNetworkMap returns the latest network map from the engine.
|
||||||
|
func (c *ConnectClient) GetLatestNetworkMap() (*mgmProto.NetworkMap, error) {
|
||||||
|
engine := c.Engine()
|
||||||
|
if engine == nil {
|
||||||
|
return nil, errors.New("engine is not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
networkMap, err := engine.GetLatestNetworkMap()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get latest network map: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if networkMap == nil {
|
||||||
|
return nil, errors.New("network map is not available")
|
||||||
|
}
|
||||||
|
|
||||||
|
return networkMap, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Status returns the current client status
|
// Status returns the current client status
|
||||||
func (c *ConnectClient) Status() StatusType {
|
func (c *ConnectClient) Status() StatusType {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +1,8 @@
|
|||||||
//go:build linux && !android
|
//go:build linux && !android
|
||||||
|
|
||||||
package server
|
package debug
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"archive/zip"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -14,36 +13,31 @@ import (
|
|||||||
"github.com/google/nftables"
|
"github.com/google/nftables"
|
||||||
"github.com/google/nftables/expr"
|
"github.com/google/nftables/expr"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/anonymize"
|
|
||||||
"github.com/netbirdio/netbird/client/proto"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// addFirewallRules collects and adds firewall rules to the archive
|
// addFirewallRules collects and adds firewall rules to the archive
|
||||||
func (s *Server) addFirewallRules(req *proto.DebugBundleRequest, anonymizer *anonymize.Anonymizer, archive *zip.Writer) error {
|
func (g *BundleGenerator) addFirewallRules() error {
|
||||||
log.Info("Collecting firewall rules")
|
log.Info("Collecting firewall rules")
|
||||||
// Collect and add iptables rules
|
|
||||||
iptablesRules, err := collectIPTablesRules()
|
iptablesRules, err := collectIPTablesRules()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Failed to collect iptables rules: %v", err)
|
log.Warnf("Failed to collect iptables rules: %v", err)
|
||||||
} else {
|
} else {
|
||||||
if req.GetAnonymize() {
|
if g.anonymize {
|
||||||
iptablesRules = anonymizer.AnonymizeString(iptablesRules)
|
iptablesRules = g.anonymizer.AnonymizeString(iptablesRules)
|
||||||
}
|
}
|
||||||
if err := addFileToZip(archive, strings.NewReader(iptablesRules), "iptables.txt"); err != nil {
|
if err := g.addFileToZip(strings.NewReader(iptablesRules), "iptables.txt"); err != nil {
|
||||||
log.Warnf("Failed to add iptables rules to bundle: %v", err)
|
log.Warnf("Failed to add iptables rules to bundle: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect and add nftables rules
|
|
||||||
nftablesRules, err := collectNFTablesRules()
|
nftablesRules, err := collectNFTablesRules()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Failed to collect nftables rules: %v", err)
|
log.Warnf("Failed to collect nftables rules: %v", err)
|
||||||
} else {
|
} else {
|
||||||
if req.GetAnonymize() {
|
if g.anonymize {
|
||||||
nftablesRules = anonymizer.AnonymizeString(nftablesRules)
|
nftablesRules = g.anonymizer.AnonymizeString(nftablesRules)
|
||||||
}
|
}
|
||||||
if err := addFileToZip(archive, strings.NewReader(nftablesRules), "nftables.txt"); err != nil {
|
if err := g.addFileToZip(strings.NewReader(nftablesRules), "nftables.txt"); err != nil {
|
||||||
log.Warnf("Failed to add nftables rules to bundle: %v", err)
|
log.Warnf("Failed to add nftables rules to bundle: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -65,16 +59,13 @@ func collectIPTablesRules() (string, error) {
|
|||||||
builder.WriteString("\n")
|
builder.WriteString("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then get verbose statistics for each table
|
|
||||||
builder.WriteString("=== iptables -v -n -L output ===\n")
|
builder.WriteString("=== iptables -v -n -L output ===\n")
|
||||||
|
|
||||||
// Get list of tables
|
|
||||||
tables := []string{"filter", "nat", "mangle", "raw", "security"}
|
tables := []string{"filter", "nat", "mangle", "raw", "security"}
|
||||||
|
|
||||||
for _, table := range tables {
|
for _, table := range tables {
|
||||||
builder.WriteString(fmt.Sprintf("*%s\n", table))
|
builder.WriteString(fmt.Sprintf("*%s\n", table))
|
||||||
|
|
||||||
// Get verbose statistics for the entire table
|
|
||||||
stats, err := getTableStatistics(table)
|
stats, err := getTableStatistics(table)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Failed to get statistics for table %s: %v", table, err)
|
log.Warnf("Failed to get statistics for table %s: %v", table, err)
|
||||||
@@ -182,12 +173,10 @@ func formatTables(conn *nftables.Conn, tables []*nftables.Table) string {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format chains
|
|
||||||
for _, chain := range chains {
|
for _, chain := range chains {
|
||||||
formatChain(conn, table, chain, &builder)
|
formatChain(conn, table, chain, &builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format sets
|
|
||||||
if sets, err := conn.GetSets(table); err != nil {
|
if sets, err := conn.GetSets(table); err != nil {
|
||||||
log.Warnf("Failed to get sets for table %s: %v", table.Name, err)
|
log.Warnf("Failed to get sets for table %s: %v", table.Name, err)
|
||||||
} else if len(sets) > 0 {
|
} else if len(sets) > 0 {
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
//go:build ios || android
|
||||||
|
|
||||||
|
package debug
|
||||||
|
|
||||||
|
func (g *BundleGenerator) addRoutes() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
//go:build !linux || android
|
||||||
|
|
||||||
|
package debug
|
||||||
|
|
||||||
|
// collectFirewallRules returns nothing on non-linux systems
|
||||||
|
func (g *BundleGenerator) addFirewallRules() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//go:build !ios && !android
|
||||||
|
|
||||||
|
package debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/netbirdio/netbird/client/internal/routemanager/systemops"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (g *BundleGenerator) addRoutes() error {
|
||||||
|
routes, err := systemops.GetRoutesFromTable()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("get routes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: get routes including nexthop
|
||||||
|
routesContent := formatRoutes(routes, g.anonymize, g.anonymizer)
|
||||||
|
routesReader := strings.NewReader(routesContent)
|
||||||
|
if err := g.addFileToZip(routesReader, "routes.txt"); err != nil {
|
||||||
|
return fmt.Errorf("add routes file to zip: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package server
|
package debug
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@@ -71,6 +71,12 @@ func (d *localResolver) lookupRecords(r *dns.Msg) []dns.RR {
|
|||||||
|
|
||||||
value, found := d.records.Load(key)
|
value, found := d.records.Load(key)
|
||||||
if !found {
|
if !found {
|
||||||
|
// alternatively check if we have a cname
|
||||||
|
if question.Qtype != dns.TypeCNAME {
|
||||||
|
r.Question[0].Qtype = dns.TypeCNAME
|
||||||
|
return d.lookupRecords(r)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -467,6 +467,11 @@ func (s *DefaultServer) applyHostConfig() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prevent reapplying config if we're shutting down
|
||||||
|
if s.ctx.Err() != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
config := s.currentConfig
|
config := s.currentConfig
|
||||||
|
|
||||||
existingDomains := make(map[string]struct{})
|
existingDomains := make(map[string]struct{})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package dnsfwd
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -62,7 +63,6 @@ func (f *DNSForwarder) UpdateDomains(domains []string, resIds map[string]string)
|
|||||||
|
|
||||||
for _, d := range f.domains {
|
for _, d := range f.domains {
|
||||||
f.mux.HandleRemove(d)
|
f.mux.HandleRemove(d)
|
||||||
f.statusRecorder.RemoveResolvedIPLookupEntry(d)
|
|
||||||
}
|
}
|
||||||
f.resId.Clear()
|
f.resId.Clear()
|
||||||
|
|
||||||
@@ -122,8 +122,8 @@ func (f *DNSForwarder) handleDNSQuery(w dns.ResponseWriter, query *dns.Msg) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resId, ok := f.resId.Load(strings.TrimSuffix(domain, "."))
|
resId := f.getResIdForDomain(strings.TrimSuffix(domain, "."))
|
||||||
if ok {
|
if resId != "" {
|
||||||
for _, ip := range ips {
|
for _, ip := range ips {
|
||||||
var ipWithSuffix string
|
var ipWithSuffix string
|
||||||
if ip.Is4() {
|
if ip.Is4() {
|
||||||
@@ -133,7 +133,7 @@ func (f *DNSForwarder) handleDNSQuery(w dns.ResponseWriter, query *dns.Msg) {
|
|||||||
ipWithSuffix = ip.String() + "/128"
|
ipWithSuffix = ip.String() + "/128"
|
||||||
log.Tracef("resolved domain=%s to IPv6=%s", domain, ipWithSuffix)
|
log.Tracef("resolved domain=%s to IPv6=%s", domain, ipWithSuffix)
|
||||||
}
|
}
|
||||||
f.statusRecorder.AddResolvedIPLookupEntry(ipWithSuffix, resId.(string))
|
f.statusRecorder.AddResolvedIPLookupEntry(ipWithSuffix, resId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,6 +204,36 @@ func (f *DNSForwarder) addIPsToResponse(resp *dns.Msg, domain string, ips []neti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *DNSForwarder) getResIdForDomain(domain string) string {
|
||||||
|
var selectedResId string
|
||||||
|
var bestScore int
|
||||||
|
|
||||||
|
f.resId.Range(func(key, value interface{}) bool {
|
||||||
|
var score int
|
||||||
|
pattern := key.(string)
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(pattern, "*."):
|
||||||
|
baseDomain := strings.TrimPrefix(pattern, "*.")
|
||||||
|
if domain == baseDomain || strings.HasSuffix(domain, "."+baseDomain) {
|
||||||
|
score = len(baseDomain)
|
||||||
|
}
|
||||||
|
case domain == pattern:
|
||||||
|
score = math.MaxInt
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if score > bestScore {
|
||||||
|
bestScore = score
|
||||||
|
selectedResId = value.(string)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return selectedResId
|
||||||
|
}
|
||||||
|
|
||||||
// filterDomains returns a list of normalized domains
|
// filterDomains returns a list of normalized domains
|
||||||
func filterDomains(domains []string) []string {
|
func filterDomains(domains []string) []string {
|
||||||
newDomains := make([]string, 0, len(domains))
|
newDomains := make([]string, 0, len(domains))
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package dnsfwd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetResIdForDomain(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
storedMappings map[string]string // key: domain pattern, value: resId
|
||||||
|
queryDomain string
|
||||||
|
expectedResId string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Empty map returns empty string",
|
||||||
|
storedMappings: map[string]string{},
|
||||||
|
queryDomain: "example.com",
|
||||||
|
expectedResId: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Exact match returns stored resId",
|
||||||
|
storedMappings: map[string]string{"example.com": "res1"},
|
||||||
|
queryDomain: "example.com",
|
||||||
|
expectedResId: "res1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wildcard pattern matches base domain",
|
||||||
|
storedMappings: map[string]string{"*.example.com": "res2"},
|
||||||
|
queryDomain: "example.com",
|
||||||
|
expectedResId: "res2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wildcard pattern matches subdomain",
|
||||||
|
storedMappings: map[string]string{"*.example.com": "res3"},
|
||||||
|
queryDomain: "foo.example.com",
|
||||||
|
expectedResId: "res3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wildcard pattern does not match different domain",
|
||||||
|
storedMappings: map[string]string{"*.example.com": "res4"},
|
||||||
|
queryDomain: "foo.notexample.com",
|
||||||
|
expectedResId: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Non-wildcard pattern does not match subdomain",
|
||||||
|
storedMappings: map[string]string{"example.com": "res5"},
|
||||||
|
queryDomain: "foo.example.com",
|
||||||
|
expectedResId: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Exact match over overlapping wildcard",
|
||||||
|
storedMappings: map[string]string{
|
||||||
|
"*.example.com": "resWildcard",
|
||||||
|
"foo.example.com": "resExact",
|
||||||
|
},
|
||||||
|
queryDomain: "foo.example.com",
|
||||||
|
expectedResId: "resExact",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Overlapping wildcards: Select more specific wildcard",
|
||||||
|
storedMappings: map[string]string{
|
||||||
|
"*.example.com": "resA",
|
||||||
|
"*.sub.example.com": "resB",
|
||||||
|
},
|
||||||
|
queryDomain: "bar.sub.example.com",
|
||||||
|
expectedResId: "resB",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Wildcard multi-level subdomain match",
|
||||||
|
storedMappings: map[string]string{
|
||||||
|
"*.example.com": "resMulti",
|
||||||
|
},
|
||||||
|
queryDomain: "a.b.example.com",
|
||||||
|
expectedResId: "resMulti",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
fwd := &DNSForwarder{
|
||||||
|
resId: sync.Map{},
|
||||||
|
}
|
||||||
|
|
||||||
|
for domainPattern, resId := range tc.storedMappings {
|
||||||
|
fwd.resId.Store(domainPattern, resId)
|
||||||
|
}
|
||||||
|
|
||||||
|
got := fwd.getResIdForDomain(tc.queryDomain)
|
||||||
|
if got != tc.expectedResId {
|
||||||
|
t.Errorf("For query domain %q, expected resId %q, but got %q", tc.queryDomain, tc.expectedResId, got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
-27
@@ -1231,36 +1231,19 @@ func (e *Engine) createPeerConn(pubKey string, allowedIPs []netip.Prefix) (*peer
|
|||||||
PreSharedKey: e.config.PreSharedKey,
|
PreSharedKey: e.config.PreSharedKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.config.RosenpassEnabled && !e.config.RosenpassPermissive {
|
|
||||||
lk := []byte(e.config.WgPrivateKey.PublicKey().String())
|
|
||||||
rk := []byte(wgConfig.RemoteKey)
|
|
||||||
var keyInput []byte
|
|
||||||
if string(lk) > string(rk) {
|
|
||||||
//nolint:gocritic
|
|
||||||
keyInput = append(lk[:16], rk[:16]...)
|
|
||||||
} else {
|
|
||||||
//nolint:gocritic
|
|
||||||
keyInput = append(rk[:16], lk[:16]...)
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := wgtypes.NewKey(keyInput)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
wgConfig.PreSharedKey = &key
|
|
||||||
}
|
|
||||||
|
|
||||||
// randomize connection timeout
|
// randomize connection timeout
|
||||||
timeout := time.Duration(rand.Intn(PeerConnectionTimeoutMax-PeerConnectionTimeoutMin)+PeerConnectionTimeoutMin) * time.Millisecond
|
timeout := time.Duration(rand.Intn(PeerConnectionTimeoutMax-PeerConnectionTimeoutMin)+PeerConnectionTimeoutMin) * time.Millisecond
|
||||||
config := peer.ConnConfig{
|
config := peer.ConnConfig{
|
||||||
Key: pubKey,
|
Key: pubKey,
|
||||||
LocalKey: e.config.WgPrivateKey.PublicKey().String(),
|
LocalKey: e.config.WgPrivateKey.PublicKey().String(),
|
||||||
Timeout: timeout,
|
Timeout: timeout,
|
||||||
WgConfig: wgConfig,
|
WgConfig: wgConfig,
|
||||||
LocalWgPort: e.config.WgPort,
|
LocalWgPort: e.config.WgPort,
|
||||||
RosenpassPubKey: e.getRosenpassPubKey(),
|
RosenpassConfig: peer.RosenpassConfig{
|
||||||
RosenpassAddr: e.getRosenpassAddr(),
|
PubKey: e.getRosenpassPubKey(),
|
||||||
|
Addr: e.getRosenpassAddr(),
|
||||||
|
PermissiveMode: e.config.RosenpassPermissive,
|
||||||
|
},
|
||||||
ICEConfig: icemaker.Config{
|
ICEConfig: icemaker.Config{
|
||||||
StunTurn: &e.stunTurn,
|
StunTurn: &e.stunTurn,
|
||||||
InterfaceBlackList: e.config.IFaceBlackList,
|
InterfaceBlackList: e.config.IFaceBlackList,
|
||||||
|
|||||||
@@ -1439,8 +1439,6 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
|
|||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
@@ -1449,7 +1447,9 @@ func startManagement(t *testing.T, dataDir, testFile string) (*grpc.Server, stri
|
|||||||
Return(&types.Settings{}, nil).
|
Return(&types.Settings{}, nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
|
|
||||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
permissionsManager := permissions.NewManager(store)
|
||||||
|
|
||||||
|
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, "", err
|
return nil, "", err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,6 +60,15 @@ type WgConfig struct {
|
|||||||
PreSharedKey *wgtypes.Key
|
PreSharedKey *wgtypes.Key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RosenpassConfig struct {
|
||||||
|
// RosenpassPubKey is this peer's Rosenpass public key
|
||||||
|
PubKey []byte
|
||||||
|
// RosenpassPubKey is this peer's RosenpassAddr server address (IP:port)
|
||||||
|
Addr string
|
||||||
|
|
||||||
|
PermissiveMode bool
|
||||||
|
}
|
||||||
|
|
||||||
// ConnConfig is a peer Connection configuration
|
// ConnConfig is a peer Connection configuration
|
||||||
type ConnConfig struct {
|
type ConnConfig struct {
|
||||||
// Key is a public key of a remote peer
|
// Key is a public key of a remote peer
|
||||||
@@ -73,10 +82,7 @@ type ConnConfig struct {
|
|||||||
|
|
||||||
LocalWgPort int
|
LocalWgPort int
|
||||||
|
|
||||||
// RosenpassPubKey is this peer's Rosenpass public key
|
RosenpassConfig RosenpassConfig
|
||||||
RosenpassPubKey []byte
|
|
||||||
// RosenpassPubKey is this peer's RosenpassAddr server address (IP:port)
|
|
||||||
RosenpassAddr string
|
|
||||||
|
|
||||||
// ICEConfig ICE protocol configuration
|
// ICEConfig ICE protocol configuration
|
||||||
ICEConfig icemaker.Config
|
ICEConfig icemaker.Config
|
||||||
@@ -109,6 +115,8 @@ type Conn struct {
|
|||||||
connIDICE nbnet.ConnectionID
|
connIDICE nbnet.ConnectionID
|
||||||
beforeAddPeerHooks []nbnet.AddHookFunc
|
beforeAddPeerHooks []nbnet.AddHookFunc
|
||||||
afterRemovePeerHooks []nbnet.RemoveHookFunc
|
afterRemovePeerHooks []nbnet.RemoveHookFunc
|
||||||
|
// used to store the remote Rosenpass key for Relayed connection in case of connection update from ice
|
||||||
|
rosenpassRemoteKey []byte
|
||||||
|
|
||||||
wgProxyICE wgproxy.Proxy
|
wgProxyICE wgproxy.Proxy
|
||||||
wgProxyRelay wgproxy.Proxy
|
wgProxyRelay wgproxy.Proxy
|
||||||
@@ -375,7 +383,7 @@ func (conn *Conn) onICEConnectionIsReady(priority ConnPriority, iceConnInfo ICEC
|
|||||||
wgProxy.Work()
|
wgProxy.Work()
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = conn.configureWGEndpoint(ep); err != nil {
|
if err = conn.configureWGEndpoint(ep, iceConnInfo.RosenpassPubKey); err != nil {
|
||||||
conn.handleConfigurationFailure(err, wgProxy)
|
conn.handleConfigurationFailure(err, wgProxy)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -408,7 +416,7 @@ func (conn *Conn) onICEStateDisconnected() {
|
|||||||
conn.dumpState.SwitchToRelay()
|
conn.dumpState.SwitchToRelay()
|
||||||
conn.wgProxyRelay.Work()
|
conn.wgProxyRelay.Work()
|
||||||
|
|
||||||
if err := conn.configureWGEndpoint(conn.wgProxyRelay.EndpointAddr()); err != nil {
|
if err := conn.configureWGEndpoint(conn.wgProxyRelay.EndpointAddr(), conn.rosenpassRemoteKey); err != nil {
|
||||||
conn.log.Errorf("failed to switch to relay conn: %v", err)
|
conn.log.Errorf("failed to switch to relay conn: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,7 +486,7 @@ func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wgProxy.Work()
|
wgProxy.Work()
|
||||||
if err := conn.configureWGEndpoint(wgProxy.EndpointAddr()); err != nil {
|
if err := conn.configureWGEndpoint(wgProxy.EndpointAddr(), rci.rosenpassPubKey); err != nil {
|
||||||
if err := wgProxy.CloseConn(); err != nil {
|
if err := wgProxy.CloseConn(); err != nil {
|
||||||
conn.log.Warnf("Failed to close relay connection: %v", err)
|
conn.log.Warnf("Failed to close relay connection: %v", err)
|
||||||
}
|
}
|
||||||
@@ -493,6 +501,7 @@ func (conn *Conn) onRelayConnectionIsReady(rci RelayConnInfo) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
wgConfigWorkaround()
|
wgConfigWorkaround()
|
||||||
|
conn.rosenpassRemoteKey = rci.rosenpassPubKey
|
||||||
conn.currentConnPriority = connPriorityRelay
|
conn.currentConnPriority = connPriorityRelay
|
||||||
conn.statusRelay.Set(StatusConnected)
|
conn.statusRelay.Set(StatusConnected)
|
||||||
conn.setRelayedProxy(wgProxy)
|
conn.setRelayedProxy(wgProxy)
|
||||||
@@ -556,13 +565,14 @@ func (conn *Conn) listenGuardEvent(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conn *Conn) configureWGEndpoint(addr *net.UDPAddr) error {
|
func (conn *Conn) configureWGEndpoint(addr *net.UDPAddr, remoteRPKey []byte) error {
|
||||||
|
presharedKey := conn.presharedKey(remoteRPKey)
|
||||||
return conn.config.WgConfig.WgInterface.UpdatePeer(
|
return conn.config.WgConfig.WgInterface.UpdatePeer(
|
||||||
conn.config.WgConfig.RemoteKey,
|
conn.config.WgConfig.RemoteKey,
|
||||||
conn.config.WgConfig.AllowedIps,
|
conn.config.WgConfig.AllowedIps,
|
||||||
defaultWgKeepAlive,
|
defaultWgKeepAlive,
|
||||||
addr,
|
addr,
|
||||||
conn.config.WgConfig.PreSharedKey,
|
presharedKey,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -783,6 +793,44 @@ func (conn *Conn) AllowedIP() netip.Addr {
|
|||||||
return conn.config.WgConfig.AllowedIps[0].Addr()
|
return conn.config.WgConfig.AllowedIps[0].Addr()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (conn *Conn) presharedKey(remoteRosenpassKey []byte) *wgtypes.Key {
|
||||||
|
if conn.config.RosenpassConfig.PubKey == nil {
|
||||||
|
return conn.config.WgConfig.PreSharedKey
|
||||||
|
}
|
||||||
|
|
||||||
|
if remoteRosenpassKey == nil && conn.config.RosenpassConfig.PermissiveMode {
|
||||||
|
return conn.config.WgConfig.PreSharedKey
|
||||||
|
}
|
||||||
|
|
||||||
|
determKey, err := conn.rosenpassDetermKey()
|
||||||
|
if err != nil {
|
||||||
|
conn.log.Errorf("failed to generate Rosenpass initial key: %v", err)
|
||||||
|
return conn.config.WgConfig.PreSharedKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return determKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo: move this logic into Rosenpass package
|
||||||
|
func (conn *Conn) rosenpassDetermKey() (*wgtypes.Key, error) {
|
||||||
|
lk := []byte(conn.config.LocalKey)
|
||||||
|
rk := []byte(conn.config.Key) // remote key
|
||||||
|
var keyInput []byte
|
||||||
|
if string(lk) > string(rk) {
|
||||||
|
//nolint:gocritic
|
||||||
|
keyInput = append(lk[:16], rk[:16]...)
|
||||||
|
} else {
|
||||||
|
//nolint:gocritic
|
||||||
|
keyInput = append(rk[:16], lk[:16]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := wgtypes.NewKey(keyInput)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &key, nil
|
||||||
|
}
|
||||||
|
|
||||||
func isController(config ConnConfig) bool {
|
func isController(config ConnConfig) bool {
|
||||||
return config.LocalKey > config.Key
|
return config.LocalKey > config.Key
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package peer
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -161,3 +162,145 @@ func TestConn_Status(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConn_presharedKey(t *testing.T) {
|
||||||
|
conn1 := Conn{
|
||||||
|
config: ConnConfig{
|
||||||
|
Key: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
||||||
|
LocalKey: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
||||||
|
RosenpassConfig: RosenpassConfig{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
conn2 := Conn{
|
||||||
|
config: ConnConfig{
|
||||||
|
Key: "RRHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
||||||
|
LocalKey: "LLHf3Ma6z6mdLbriAJbqhX7+nM/B71lgw2+91q3LfhU=",
|
||||||
|
RosenpassConfig: RosenpassConfig{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
conn1Permissive bool
|
||||||
|
conn1RosenpassEnabled bool
|
||||||
|
conn2Permissive bool
|
||||||
|
conn2RosenpassEnabled bool
|
||||||
|
conn1ExpectedInitialKey bool
|
||||||
|
conn2ExpectedInitialKey bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
conn1Permissive: false,
|
||||||
|
conn1RosenpassEnabled: false,
|
||||||
|
conn2Permissive: false,
|
||||||
|
conn2RosenpassEnabled: false,
|
||||||
|
conn1ExpectedInitialKey: false,
|
||||||
|
conn2ExpectedInitialKey: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: false,
|
||||||
|
conn1RosenpassEnabled: true,
|
||||||
|
conn2Permissive: false,
|
||||||
|
conn2RosenpassEnabled: true,
|
||||||
|
conn1ExpectedInitialKey: true,
|
||||||
|
conn2ExpectedInitialKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: false,
|
||||||
|
conn1RosenpassEnabled: true,
|
||||||
|
conn2Permissive: false,
|
||||||
|
conn2RosenpassEnabled: false,
|
||||||
|
conn1ExpectedInitialKey: true,
|
||||||
|
conn2ExpectedInitialKey: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: false,
|
||||||
|
conn1RosenpassEnabled: false,
|
||||||
|
conn2Permissive: false,
|
||||||
|
conn2RosenpassEnabled: true,
|
||||||
|
conn1ExpectedInitialKey: false,
|
||||||
|
conn2ExpectedInitialKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: true,
|
||||||
|
conn1RosenpassEnabled: true,
|
||||||
|
conn2Permissive: false,
|
||||||
|
conn2RosenpassEnabled: false,
|
||||||
|
conn1ExpectedInitialKey: false,
|
||||||
|
conn2ExpectedInitialKey: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: false,
|
||||||
|
conn1RosenpassEnabled: false,
|
||||||
|
conn2Permissive: true,
|
||||||
|
conn2RosenpassEnabled: true,
|
||||||
|
conn1ExpectedInitialKey: false,
|
||||||
|
conn2ExpectedInitialKey: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: true,
|
||||||
|
conn1RosenpassEnabled: true,
|
||||||
|
conn2Permissive: true,
|
||||||
|
conn2RosenpassEnabled: true,
|
||||||
|
conn1ExpectedInitialKey: true,
|
||||||
|
conn2ExpectedInitialKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: false,
|
||||||
|
conn1RosenpassEnabled: false,
|
||||||
|
conn2Permissive: false,
|
||||||
|
conn2RosenpassEnabled: true,
|
||||||
|
conn1ExpectedInitialKey: false,
|
||||||
|
conn2ExpectedInitialKey: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
conn1Permissive: false,
|
||||||
|
conn1RosenpassEnabled: true,
|
||||||
|
conn2Permissive: true,
|
||||||
|
conn2RosenpassEnabled: true,
|
||||||
|
conn1ExpectedInitialKey: true,
|
||||||
|
conn2ExpectedInitialKey: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
conn1.config.RosenpassConfig.PermissiveMode = true
|
||||||
|
for i, test := range tests {
|
||||||
|
tcase := i + 1
|
||||||
|
t.Run(fmt.Sprintf("Rosenpass test case %d", tcase), func(t *testing.T) {
|
||||||
|
conn1.config.RosenpassConfig = RosenpassConfig{}
|
||||||
|
conn2.config.RosenpassConfig = RosenpassConfig{}
|
||||||
|
|
||||||
|
if test.conn1RosenpassEnabled {
|
||||||
|
conn1.config.RosenpassConfig.PubKey = []byte("dummykey")
|
||||||
|
}
|
||||||
|
conn1.config.RosenpassConfig.PermissiveMode = test.conn1Permissive
|
||||||
|
|
||||||
|
if test.conn2RosenpassEnabled {
|
||||||
|
conn2.config.RosenpassConfig.PubKey = []byte("dummykey")
|
||||||
|
}
|
||||||
|
conn2.config.RosenpassConfig.PermissiveMode = test.conn2Permissive
|
||||||
|
|
||||||
|
conn1PresharedKey := conn1.presharedKey(conn2.config.RosenpassConfig.PubKey)
|
||||||
|
conn2PresharedKey := conn2.presharedKey(conn1.config.RosenpassConfig.PubKey)
|
||||||
|
|
||||||
|
if test.conn1ExpectedInitialKey {
|
||||||
|
if conn1PresharedKey == nil {
|
||||||
|
t.Errorf("Case %d: Expected conn1 to have a non-nil key, but got nil", tcase)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if conn1PresharedKey != nil {
|
||||||
|
t.Errorf("Case %d: Expected conn1 to have a nil key, but got %v", tcase, conn1PresharedKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert conn2's key expectation
|
||||||
|
if test.conn2ExpectedInitialKey {
|
||||||
|
if conn2PresharedKey == nil {
|
||||||
|
t.Errorf("Case %d: Expected conn2 to have a non-nil key, but got nil", tcase)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if conn2PresharedKey != nil {
|
||||||
|
t.Errorf("Case %d: Expected conn2 to have a nil key, but got %v", tcase, conn2PresharedKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -154,8 +154,8 @@ func (h *Handshaker) sendOffer() error {
|
|||||||
IceCredentials: IceCredentials{iceUFrag, icePwd},
|
IceCredentials: IceCredentials{iceUFrag, icePwd},
|
||||||
WgListenPort: h.config.LocalWgPort,
|
WgListenPort: h.config.LocalWgPort,
|
||||||
Version: version.NetbirdVersion(),
|
Version: version.NetbirdVersion(),
|
||||||
RosenpassPubKey: h.config.RosenpassPubKey,
|
RosenpassPubKey: h.config.RosenpassConfig.PubKey,
|
||||||
RosenpassAddr: h.config.RosenpassAddr,
|
RosenpassAddr: h.config.RosenpassConfig.Addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
addr, err := h.relay.RelayInstanceAddress()
|
addr, err := h.relay.RelayInstanceAddress()
|
||||||
@@ -174,8 +174,8 @@ func (h *Handshaker) sendAnswer() error {
|
|||||||
IceCredentials: IceCredentials{uFrag, pwd},
|
IceCredentials: IceCredentials{uFrag, pwd},
|
||||||
WgListenPort: h.config.LocalWgPort,
|
WgListenPort: h.config.LocalWgPort,
|
||||||
Version: version.NetbirdVersion(),
|
Version: version.NetbirdVersion(),
|
||||||
RosenpassPubKey: h.config.RosenpassPubKey,
|
RosenpassPubKey: h.config.RosenpassConfig.PubKey,
|
||||||
RosenpassAddr: h.config.RosenpassAddr,
|
RosenpassAddr: h.config.RosenpassConfig.Addr,
|
||||||
}
|
}
|
||||||
addr, err := h.relay.RelayInstanceAddress()
|
addr, err := h.relay.RelayInstanceAddress()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ func NewAgent(iFaceDiscover stdnet.ExternalIFaceDiscover, config Config, candida
|
|||||||
}
|
}
|
||||||
|
|
||||||
fac := logging.NewDefaultLoggerFactory()
|
fac := logging.NewDefaultLoggerFactory()
|
||||||
fac.Writer = log.StandardLogger().Writer()
|
|
||||||
|
//fac.Writer = log.StandardLogger().Writer()
|
||||||
|
|
||||||
agentConfig := &ice.AgentConfig{
|
agentConfig := &ice.AgentConfig{
|
||||||
MulticastDNSMode: ice.MulticastDNSModeDisabled,
|
MulticastDNSMode: ice.MulticastDNSModeDisabled,
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ type PKCEAuthProviderConfig struct {
|
|||||||
UseIDToken bool
|
UseIDToken bool
|
||||||
// ClientCertPair is used for mTLS authentication to the IDP
|
// ClientCertPair is used for mTLS authentication to the IDP
|
||||||
ClientCertPair *tls.Certificate
|
ClientCertPair *tls.Certificate
|
||||||
|
// DisablePromptLogin makes the PKCE flow to not prompt the user for login
|
||||||
|
DisablePromptLogin bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPKCEAuthorizationFlowInfo initialize a PKCEAuthorizationFlow instance and return with it
|
// GetPKCEAuthorizationFlowInfo initialize a PKCEAuthorizationFlow instance and return with it
|
||||||
@@ -97,6 +99,7 @@ func GetPKCEAuthorizationFlowInfo(ctx context.Context, privateKey string, mgmURL
|
|||||||
RedirectURLs: protoPKCEAuthorizationFlow.GetProviderConfig().GetRedirectURLs(),
|
RedirectURLs: protoPKCEAuthorizationFlow.GetProviderConfig().GetRedirectURLs(),
|
||||||
UseIDToken: protoPKCEAuthorizationFlow.GetProviderConfig().GetUseIDToken(),
|
UseIDToken: protoPKCEAuthorizationFlow.GetProviderConfig().GetUseIDToken(),
|
||||||
ClientCertPair: clientCert,
|
ClientCertPair: clientCert,
|
||||||
|
DisablePromptLogin: protoPKCEAuthorizationFlow.GetProviderConfig().GetDisablePromptLogin(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,20 +10,27 @@ import (
|
|||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/errors"
|
"github.com/netbirdio/netbird/client/errors"
|
||||||
route "github.com/netbirdio/netbird/route"
|
"github.com/netbirdio/netbird/route"
|
||||||
)
|
)
|
||||||
|
|
||||||
type RouteSelector struct {
|
type RouteSelector struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
selectedRoutes map[route.NetID]struct{}
|
selectedRoutes map[route.NetID]struct{}
|
||||||
selectAll bool
|
selectAll bool
|
||||||
|
|
||||||
|
// Indicates if new routes should be automatically selected
|
||||||
|
includeNewRoutes bool
|
||||||
|
|
||||||
|
// All known routes at the time of deselection
|
||||||
|
knownRoutes []route.NetID
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRouteSelector() *RouteSelector {
|
func NewRouteSelector() *RouteSelector {
|
||||||
return &RouteSelector{
|
return &RouteSelector{
|
||||||
selectedRoutes: map[route.NetID]struct{}{},
|
selectedRoutes: map[route.NetID]struct{}{},
|
||||||
// default selects all routes
|
selectAll: true,
|
||||||
selectAll: true,
|
includeNewRoutes: false,
|
||||||
|
knownRoutes: []route.NetID{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +53,7 @@ func (rs *RouteSelector) SelectRoutes(routes []route.NetID, appendRoute bool, al
|
|||||||
rs.selectedRoutes[route] = struct{}{}
|
rs.selectedRoutes[route] = struct{}{}
|
||||||
}
|
}
|
||||||
rs.selectAll = false
|
rs.selectAll = false
|
||||||
|
rs.includeNewRoutes = false
|
||||||
|
|
||||||
return errors.FormatErrorOrNil(err)
|
return errors.FormatErrorOrNil(err)
|
||||||
}
|
}
|
||||||
@@ -57,16 +65,22 @@ func (rs *RouteSelector) SelectAllRoutes() {
|
|||||||
|
|
||||||
rs.selectAll = true
|
rs.selectAll = true
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
rs.selectedRoutes = map[route.NetID]struct{}{}
|
||||||
|
rs.includeNewRoutes = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeselectRoutes removes specific routes from the selection.
|
// DeselectRoutes removes specific routes from the selection.
|
||||||
// If the selector is in "select all" mode, it will transition to "select specific" mode.
|
// If the selector is in "select all" mode, it will transition to "select specific" mode
|
||||||
|
// but will keep new routes selected.
|
||||||
func (rs *RouteSelector) DeselectRoutes(routes []route.NetID, allRoutes []route.NetID) error {
|
func (rs *RouteSelector) DeselectRoutes(routes []route.NetID, allRoutes []route.NetID) error {
|
||||||
rs.mu.Lock()
|
rs.mu.Lock()
|
||||||
defer rs.mu.Unlock()
|
defer rs.mu.Unlock()
|
||||||
|
|
||||||
if rs.selectAll {
|
if rs.selectAll {
|
||||||
rs.selectAll = false
|
rs.selectAll = false
|
||||||
|
rs.includeNewRoutes = true
|
||||||
|
rs.knownRoutes = make([]route.NetID, len(allRoutes))
|
||||||
|
copy(rs.knownRoutes, allRoutes)
|
||||||
|
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
rs.selectedRoutes = map[route.NetID]struct{}{}
|
||||||
for _, route := range allRoutes {
|
for _, route := range allRoutes {
|
||||||
rs.selectedRoutes[route] = struct{}{}
|
rs.selectedRoutes[route] = struct{}{}
|
||||||
@@ -92,6 +106,7 @@ func (rs *RouteSelector) DeselectAllRoutes() {
|
|||||||
defer rs.mu.Unlock()
|
defer rs.mu.Unlock()
|
||||||
|
|
||||||
rs.selectAll = false
|
rs.selectAll = false
|
||||||
|
rs.includeNewRoutes = false
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
rs.selectedRoutes = map[route.NetID]struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,8 +118,20 @@ func (rs *RouteSelector) IsSelected(routeID route.NetID) bool {
|
|||||||
if rs.selectAll {
|
if rs.selectAll {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the route exists in selectedRoutes
|
||||||
_, selected := rs.selectedRoutes[routeID]
|
_, selected := rs.selectedRoutes[routeID]
|
||||||
return selected
|
if selected {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// If includeNewRoutes is true and this is a new route (not in knownRoutes),
|
||||||
|
// then it should be selected
|
||||||
|
if rs.includeNewRoutes && !slices.Contains(rs.knownRoutes, routeID) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilterSelected removes unselected routes from the provided map.
|
// FilterSelected removes unselected routes from the provided map.
|
||||||
@@ -118,7 +145,11 @@ func (rs *RouteSelector) FilterSelected(routes route.HAMap) route.HAMap {
|
|||||||
|
|
||||||
filtered := route.HAMap{}
|
filtered := route.HAMap{}
|
||||||
for id, rt := range routes {
|
for id, rt := range routes {
|
||||||
if rs.IsSelected(id.NetID()) {
|
netID := id.NetID()
|
||||||
|
_, selected := rs.selectedRoutes[netID]
|
||||||
|
|
||||||
|
// Include if directly selected or if it's a new route and includeNewRoutes is true
|
||||||
|
if selected || (rs.includeNewRoutes && !slices.Contains(rs.knownRoutes, netID)) {
|
||||||
filtered[id] = rt
|
filtered[id] = rt
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,11 +162,15 @@ func (rs *RouteSelector) MarshalJSON() ([]byte, error) {
|
|||||||
defer rs.mu.RUnlock()
|
defer rs.mu.RUnlock()
|
||||||
|
|
||||||
return json.Marshal(struct {
|
return json.Marshal(struct {
|
||||||
SelectedRoutes map[route.NetID]struct{} `json:"selected_routes"`
|
SelectedRoutes map[route.NetID]struct{} `json:"selected_routes"`
|
||||||
SelectAll bool `json:"select_all"`
|
SelectAll bool `json:"select_all"`
|
||||||
|
IncludeNewRoutes bool `json:"include_new_routes"`
|
||||||
|
KnownRoutes []route.NetID `json:"known_routes"`
|
||||||
}{
|
}{
|
||||||
SelectAll: rs.selectAll,
|
SelectAll: rs.selectAll,
|
||||||
SelectedRoutes: rs.selectedRoutes,
|
SelectedRoutes: rs.selectedRoutes,
|
||||||
|
IncludeNewRoutes: rs.includeNewRoutes,
|
||||||
|
KnownRoutes: rs.knownRoutes,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,12 +184,16 @@ func (rs *RouteSelector) UnmarshalJSON(data []byte) error {
|
|||||||
if len(data) == 0 || string(data) == "null" {
|
if len(data) == 0 || string(data) == "null" {
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
rs.selectedRoutes = map[route.NetID]struct{}{}
|
||||||
rs.selectAll = true
|
rs.selectAll = true
|
||||||
|
rs.includeNewRoutes = false
|
||||||
|
rs.knownRoutes = []route.NetID{}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var temp struct {
|
var temp struct {
|
||||||
SelectedRoutes map[route.NetID]struct{} `json:"selected_routes"`
|
SelectedRoutes map[route.NetID]struct{} `json:"selected_routes"`
|
||||||
SelectAll bool `json:"select_all"`
|
SelectAll bool `json:"select_all"`
|
||||||
|
IncludeNewRoutes bool `json:"include_new_routes"`
|
||||||
|
KnownRoutes []route.NetID `json:"known_routes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := json.Unmarshal(data, &temp); err != nil {
|
if err := json.Unmarshal(data, &temp); err != nil {
|
||||||
@@ -163,10 +202,15 @@ func (rs *RouteSelector) UnmarshalJSON(data []byte) error {
|
|||||||
|
|
||||||
rs.selectedRoutes = temp.SelectedRoutes
|
rs.selectedRoutes = temp.SelectedRoutes
|
||||||
rs.selectAll = temp.SelectAll
|
rs.selectAll = temp.SelectAll
|
||||||
|
rs.includeNewRoutes = temp.IncludeNewRoutes
|
||||||
|
rs.knownRoutes = temp.KnownRoutes
|
||||||
|
|
||||||
if rs.selectedRoutes == nil {
|
if rs.selectedRoutes == nil {
|
||||||
rs.selectedRoutes = map[route.NetID]struct{}{}
|
rs.selectedRoutes = map[route.NetID]struct{}{}
|
||||||
}
|
}
|
||||||
|
if rs.knownRoutes == nil {
|
||||||
|
rs.knownRoutes = []route.NetID{}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ func TestRouteSelector_NewRoutesBehavior(t *testing.T) {
|
|||||||
return rs.DeselectRoutes([]route.NetID{"route1"}, initialRoutes)
|
return rs.DeselectRoutes([]route.NetID{"route1"}, initialRoutes)
|
||||||
},
|
},
|
||||||
// After deselecting specific routes, new routes should remain unselected
|
// After deselecting specific routes, new routes should remain unselected
|
||||||
wantNewSelected: []route.NetID{"route2", "route3"},
|
wantNewSelected: []route.NetID{"route2", "route3", "route4", "route5"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "New routes after selecting with append",
|
name: "New routes after selecting with append",
|
||||||
@@ -358,3 +358,73 @@ func TestRouteSelector_NewRoutesBehavior(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRouteSelector_MixedSelectionDeselection(t *testing.T) {
|
||||||
|
allRoutes := []route.NetID{"route1", "route2", "route3"}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
routesToSelect []route.NetID
|
||||||
|
selectAppend bool
|
||||||
|
routesToDeselect []route.NetID
|
||||||
|
selectFirst bool
|
||||||
|
wantSelectedFinal []route.NetID
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "1. Select A, then Deselect B",
|
||||||
|
routesToSelect: []route.NetID{"route1"},
|
||||||
|
selectAppend: false,
|
||||||
|
routesToDeselect: []route.NetID{"route2"},
|
||||||
|
selectFirst: true,
|
||||||
|
wantSelectedFinal: []route.NetID{"route1"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "2. Select A, then Deselect A",
|
||||||
|
routesToSelect: []route.NetID{"route1"},
|
||||||
|
selectAppend: false,
|
||||||
|
routesToDeselect: []route.NetID{"route1"},
|
||||||
|
selectFirst: true,
|
||||||
|
wantSelectedFinal: []route.NetID{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "3. Deselect A (from all), then Select B",
|
||||||
|
routesToSelect: []route.NetID{"route2"},
|
||||||
|
selectAppend: false,
|
||||||
|
routesToDeselect: []route.NetID{"route1"},
|
||||||
|
selectFirst: false,
|
||||||
|
wantSelectedFinal: []route.NetID{"route2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "4. Deselect A (from all), then Select A",
|
||||||
|
routesToSelect: []route.NetID{"route1"},
|
||||||
|
selectAppend: false,
|
||||||
|
routesToDeselect: []route.NetID{"route1"},
|
||||||
|
selectFirst: false,
|
||||||
|
wantSelectedFinal: []route.NetID{"route1"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
rs := routeselector.NewRouteSelector()
|
||||||
|
|
||||||
|
var err1, err2 error
|
||||||
|
|
||||||
|
if tt.selectFirst {
|
||||||
|
err1 = rs.SelectRoutes(tt.routesToSelect, tt.selectAppend, allRoutes)
|
||||||
|
require.NoError(t, err1)
|
||||||
|
err2 = rs.DeselectRoutes(tt.routesToDeselect, allRoutes)
|
||||||
|
require.NoError(t, err2)
|
||||||
|
} else {
|
||||||
|
err1 = rs.DeselectRoutes(tt.routesToDeselect, allRoutes)
|
||||||
|
require.NoError(t, err1)
|
||||||
|
err2 = rs.SelectRoutes(tt.routesToSelect, tt.selectAppend, allRoutes)
|
||||||
|
require.NoError(t, err2)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range allRoutes {
|
||||||
|
assert.Equal(t, slices.Contains(tt.wantSelectedFinal, r), rs.IsSelected(r), "Route %s final state mismatch", r)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+24
-963
File diff suppressed because it is too large
Load Diff
@@ -1,15 +0,0 @@
|
|||||||
//go:build !linux || android
|
|
||||||
|
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"archive/zip"
|
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/client/anonymize"
|
|
||||||
"github.com/netbirdio/netbird/client/proto"
|
|
||||||
)
|
|
||||||
|
|
||||||
// collectFirewallRules returns nothing on non-linux systems
|
|
||||||
func (s *Server) addFirewallRules(req *proto.DebugBundleRequest, anonymizer *anonymize.Anonymizer, archive *zip.Writer) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -8,10 +8,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/netbirdio/management-integrations/integrations"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.opentelemetry.io/otel"
|
"go.opentelemetry.io/otel"
|
||||||
|
|
||||||
|
"github.com/netbirdio/management-integrations/integrations"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -200,10 +201,10 @@ func startManagement(t *testing.T, signalAddr string, counter *int) (*grpc.Serve
|
|||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
|
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||||
|
|
||||||
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
accountManager, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+66
-62
@@ -569,7 +569,7 @@ var file_flow_flow_proto_rawDesc = []byte{
|
|||||||
0x0a, 0x0f, 0x66, 0x6c, 0x6f, 0x77, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
0x0a, 0x0f, 0x66, 0x6c, 0x6f, 0x77, 0x2f, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x70, 0x72, 0x6f, 0x74,
|
||||||
0x6f, 0x12, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
|
0x6f, 0x12, 0x04, 0x66, 0x6c, 0x6f, 0x77, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
|
||||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61,
|
||||||
0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb2, 0x01, 0x0a, 0x09, 0x46, 0x6c, 0x6f,
|
0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd4, 0x01, 0x0a, 0x09, 0x46, 0x6c, 0x6f,
|
||||||
0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f,
|
0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f,
|
||||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49,
|
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49,
|
||||||
0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02,
|
0x64, 0x12, 0x38, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x02,
|
||||||
@@ -580,67 +580,71 @@ var file_flow_flow_proto_rawDesc = []byte{
|
|||||||
0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x66, 0x6c,
|
0x09, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x4b, 0x65, 0x79, 0x12, 0x31, 0x0a, 0x0b, 0x66, 0x6c,
|
||||||
0x6f, 0x77, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
0x6f, 0x77, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||||
0x10, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
0x10, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64,
|
||||||
0x73, 0x52, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x22, 0x29, 0x0a,
|
0x73, 0x52, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x20, 0x0a,
|
||||||
0x0c, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x12, 0x19, 0x0a,
|
0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01,
|
||||||
0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
|
0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22,
|
||||||
0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x9c, 0x04, 0x0a, 0x0a, 0x46, 0x6c, 0x6f,
|
0x4b, 0x0a, 0x0c, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x12,
|
||||||
0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66, 0x6c, 0x6f, 0x77, 0x5f,
|
0x19, 0x0a, 0x08, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x6c, 0x6f, 0x77, 0x49, 0x64,
|
0x0c, 0x52, 0x07, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x69, 0x73,
|
||||||
0x12, 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a,
|
0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||||
0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65,
|
0x0b, 0x69, 0x73, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x9c, 0x04, 0x0a,
|
||||||
0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
|
0x0a, 0x46, 0x6c, 0x6f, 0x77, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x66,
|
||||||
0x0c, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a, 0x09, 0x64, 0x69, 0x72,
|
0x6c, 0x6f, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x66, 0x6c,
|
||||||
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x66,
|
0x6f, 0x77, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||||
0x6c, 0x6f, 0x77, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x64,
|
0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04,
|
||||||
0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74,
|
0x74, 0x79, 0x70, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18,
|
||||||
0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74,
|
0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x2d, 0x0a,
|
||||||
0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69,
|
0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e,
|
||||||
0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49,
|
0x32, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f,
|
||||||
0x70, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x70, 0x18, 0x07, 0x20, 0x01,
|
0x6e, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08,
|
||||||
0x28, 0x0c, 0x52, 0x06, 0x64, 0x65, 0x73, 0x74, 0x49, 0x70, 0x12, 0x2d, 0x0a, 0x09, 0x70, 0x6f,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08,
|
||||||
0x72, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e,
|
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x6f, 0x75, 0x72,
|
||||||
0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52,
|
0x63, 0x65, 0x5f, 0x69, 0x70, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x73, 0x6f, 0x75,
|
||||||
0x08, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a, 0x09, 0x69, 0x63, 0x6d,
|
0x72, 0x63, 0x65, 0x49, 0x70, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x69, 0x70,
|
||||||
0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x66,
|
0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x64, 0x65, 0x73, 0x74, 0x49, 0x70, 0x12, 0x2d,
|
||||||
0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x48, 0x00, 0x52, 0x08,
|
0x0a, 0x09, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x08, 0x20, 0x01, 0x28,
|
||||||
0x69, 0x63, 0x6d, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x78, 0x5f, 0x70,
|
0x0b, 0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66,
|
||||||
0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x72, 0x78,
|
0x6f, 0x48, 0x00, 0x52, 0x08, 0x70, 0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2d, 0x0a,
|
||||||
0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74, 0x78, 0x5f, 0x70, 0x61,
|
0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b,
|
||||||
0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x78, 0x50,
|
0x32, 0x0e, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f,
|
||||||
0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x78, 0x5f, 0x62, 0x79, 0x74,
|
0x48, 0x00, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a,
|
||||||
0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x78, 0x42, 0x79, 0x74, 0x65,
|
0x72, 0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04,
|
||||||
0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0d, 0x20,
|
0x52, 0x09, 0x72, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x74,
|
||||||
0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x12,
|
0x78, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x04, 0x52,
|
||||||
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
|
0x09, 0x74, 0x78, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x78,
|
||||||
0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x72, 0x78,
|
||||||
0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x64, 0x65,
|
0x42, 0x79, 0x74, 0x65, 0x73, 0x12, 0x19, 0x0a, 0x08, 0x74, 0x78, 0x5f, 0x62, 0x79, 0x74, 0x65,
|
||||||
0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0f,
|
0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x78, 0x42, 0x79, 0x74, 0x65, 0x73,
|
||||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
|
0x12, 0x2c, 0x0a, 0x12, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75,
|
||||||
0x63, 0x65, 0x49, 0x64, 0x42, 0x11, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69,
|
0x72, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x73, 0x6f,
|
||||||
0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x48, 0x0a, 0x08, 0x50, 0x6f, 0x72, 0x74, 0x49,
|
0x75, 0x72, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x12, 0x28,
|
||||||
0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x70, 0x6f,
|
0x0a, 0x10, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
|
||||||
0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
|
0x69, 0x64, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0e, 0x64, 0x65, 0x73, 0x74, 0x52, 0x65,
|
||||||
0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x73, 0x74, 0x5f, 0x70, 0x6f, 0x72,
|
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x64, 0x42, 0x11, 0x0a, 0x0f, 0x63, 0x6f, 0x6e, 0x6e,
|
||||||
0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x73, 0x74, 0x50, 0x6f, 0x72,
|
0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x22, 0x48, 0x0a, 0x08, 0x50,
|
||||||
0x74, 0x22, 0x44, 0x0a, 0x08, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a,
|
0x6f, 0x72, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||||
0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d,
|
0x65, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x6f,
|
||||||
0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63,
|
0x75, 0x72, 0x63, 0x65, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x65, 0x73, 0x74,
|
||||||
0x6d, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69,
|
0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x64, 0x65, 0x73,
|
||||||
0x63, 0x6d, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x2a, 0x45, 0x0a, 0x04, 0x54, 0x79, 0x70, 0x65, 0x12,
|
0x74, 0x50, 0x6f, 0x72, 0x74, 0x22, 0x44, 0x0a, 0x08, 0x49, 0x43, 0x4d, 0x50, 0x49, 0x6e, 0x66,
|
||||||
0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10,
|
0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01,
|
||||||
0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10,
|
0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b,
|
||||||
0x01, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e, 0x44, 0x10, 0x02, 0x12,
|
0x0a, 0x09, 0x69, 0x63, 0x6d, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||||
0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50, 0x10, 0x03, 0x2a, 0x3b,
|
0x0d, 0x52, 0x08, 0x69, 0x63, 0x6d, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x2a, 0x45, 0x0a, 0x04, 0x54,
|
||||||
0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x15, 0x0a, 0x11, 0x44,
|
0x79, 0x70, 0x65, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x4b, 0x4e,
|
||||||
0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e,
|
0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x54,
|
||||||
0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12,
|
0x41, 0x52, 0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x45, 0x4e,
|
||||||
0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x32, 0x42, 0x0a, 0x0b, 0x46,
|
0x44, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x52, 0x4f, 0x50,
|
||||||
0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x45, 0x76,
|
0x10, 0x03, 0x2a, 0x3b, 0x0a, 0x09, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12,
|
||||||
0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f, 0x77,
|
0x15, 0x0a, 0x11, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x4b,
|
||||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e, 0x46, 0x6c, 0x6f,
|
0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53,
|
||||||
0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42,
|
0x53, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x45, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x02, 0x32,
|
||||||
0x0c, 0x5a, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70,
|
0x42, 0x0a, 0x0b, 0x46, 0x6c, 0x6f, 0x77, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x33,
|
||||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x0f, 0x2e, 0x66, 0x6c, 0x6f, 0x77, 0x2e,
|
||||||
|
0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x1a, 0x12, 0x2e, 0x66, 0x6c, 0x6f, 0x77,
|
||||||
|
0x2e, 0x46, 0x6c, 0x6f, 0x77, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x6b, 0x22, 0x00, 0x28,
|
||||||
|
0x01, 0x30, 0x01, 0x42, 0x0c, 0x5a, 0x0a, 0x66, 0x6c, 0x6f, 0x77, 0x2f, 0x70, 0x72, 0x6f, 0x74,
|
||||||
|
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ NETBIRD_TOKEN_SOURCE=${NETBIRD_TOKEN_SOURCE:-accessToken}
|
|||||||
# PKCE authorization flow
|
# PKCE authorization flow
|
||||||
NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS=${NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS:-"53000"}
|
NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS=${NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS:-"53000"}
|
||||||
NETBIRD_AUTH_PKCE_USE_ID_TOKEN=${NETBIRD_AUTH_PKCE_USE_ID_TOKEN:-false}
|
NETBIRD_AUTH_PKCE_USE_ID_TOKEN=${NETBIRD_AUTH_PKCE_USE_ID_TOKEN:-false}
|
||||||
|
NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN=${NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN:-false}
|
||||||
NETBIRD_AUTH_PKCE_AUDIENCE=$NETBIRD_AUTH_AUDIENCE
|
NETBIRD_AUTH_PKCE_AUDIENCE=$NETBIRD_AUTH_AUDIENCE
|
||||||
|
|
||||||
# Dashboard
|
# Dashboard
|
||||||
@@ -120,6 +121,7 @@ export NETBIRD_AUTH_DEVICE_AUTH_SCOPE
|
|||||||
export NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN
|
export NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN
|
||||||
export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT
|
export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT
|
||||||
export NETBIRD_AUTH_PKCE_USE_ID_TOKEN
|
export NETBIRD_AUTH_PKCE_USE_ID_TOKEN
|
||||||
|
export NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN
|
||||||
export NETBIRD_AUTH_PKCE_AUDIENCE
|
export NETBIRD_AUTH_PKCE_AUDIENCE
|
||||||
export NETBIRD_DASH_AUTH_USE_AUDIENCE
|
export NETBIRD_DASH_AUTH_USE_AUDIENCE
|
||||||
export NETBIRD_DASH_AUTH_AUDIENCE
|
export NETBIRD_DASH_AUTH_AUDIENCE
|
||||||
|
|||||||
@@ -94,7 +94,8 @@
|
|||||||
"TokenEndpoint": "$NETBIRD_AUTH_TOKEN_ENDPOINT",
|
"TokenEndpoint": "$NETBIRD_AUTH_TOKEN_ENDPOINT",
|
||||||
"Scope": "$NETBIRD_AUTH_SUPPORTED_SCOPES",
|
"Scope": "$NETBIRD_AUTH_SUPPORTED_SCOPES",
|
||||||
"RedirectURLs": [$NETBIRD_AUTH_PKCE_REDIRECT_URLS],
|
"RedirectURLs": [$NETBIRD_AUTH_PKCE_REDIRECT_URLS],
|
||||||
"UseIDToken": $NETBIRD_AUTH_PKCE_USE_ID_TOKEN
|
"UseIDToken": $NETBIRD_AUTH_PKCE_USE_ID_TOKEN,
|
||||||
|
"DisablePromptLogin": $NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,3 +27,4 @@ NETBIRD_STORE_CONFIG_ENGINE=$CI_NETBIRD_STORE_CONFIG_ENGINE
|
|||||||
NETBIRD_MGMT_IDP_SIGNKEY_REFRESH=$CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH
|
NETBIRD_MGMT_IDP_SIGNKEY_REFRESH=$CI_NETBIRD_MGMT_IDP_SIGNKEY_REFRESH
|
||||||
NETBIRD_TURN_EXTERNAL_IP=1.2.3.4
|
NETBIRD_TURN_EXTERNAL_IP=1.2.3.4
|
||||||
NETBIRD_RELAY_PORT=33445
|
NETBIRD_RELAY_PORT=33445
|
||||||
|
NETBIRD_AUTH_PKCE_DISABLE_PROMPT_LOGIN=true
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
|
|||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
@@ -88,6 +87,18 @@ func startManagement(t *testing.T) (*grpc.Server, net.Listener) {
|
|||||||
).
|
).
|
||||||
Return(&types.Settings{}, nil).
|
Return(&types.Settings{}, nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
|
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||||
|
permissionsManagerMock.
|
||||||
|
EXPECT().
|
||||||
|
ValidateUserPermissions(
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
gomock.Any(),
|
||||||
|
).
|
||||||
|
Return(true, nil).
|
||||||
|
AnyTimes()
|
||||||
|
|
||||||
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
accountManager, err := mgmt.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted", eventStore, nil, false, ia, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -80,3 +80,16 @@ func (a *UsersAPI) ResendInvitation(ctx context.Context, userID string) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Current gets the current user info
|
||||||
|
// See more: https://docs.netbird.io/api/resources/users#retrieve-current-user
|
||||||
|
func (a *UsersAPI) Current(ctx context.Context) (*api.User, error) {
|
||||||
|
resp, err := a.c.newRequest(ctx, "GET", "/api/users/current", nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
ret, err := parseResponse[api.User](resp)
|
||||||
|
return &ret, err
|
||||||
|
}
|
||||||
|
|||||||
@@ -196,8 +196,42 @@ func TestUsers_ResendInvitation_Err(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUsers_Current_200(t *testing.T) {
|
||||||
|
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||||
|
mux.HandleFunc("/api/users/current", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
retBytes, _ := json.Marshal(testUser)
|
||||||
|
_, err := w.Write(retBytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
ret, err := c.Users.Current(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, testUser, *ret)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUsers_Current_Err(t *testing.T) {
|
||||||
|
withMockClient(func(c *rest.Client, mux *http.ServeMux) {
|
||||||
|
mux.HandleFunc("/api/users/current", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
retBytes, _ := json.Marshal(util.ErrorResponse{Message: "No", Code: 400})
|
||||||
|
w.WriteHeader(400)
|
||||||
|
_, err := w.Write(retBytes)
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
ret, err := c.Users.Current(context.Background())
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Equal(t, "No", err.Error())
|
||||||
|
assert.Empty(t, ret)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestUsers_Integration(t *testing.T) {
|
func TestUsers_Integration(t *testing.T) {
|
||||||
withBlackBoxServer(t, func(c *rest.Client) {
|
withBlackBoxServer(t, func(c *rest.Client) {
|
||||||
|
// rest client PAT is owner's
|
||||||
|
current, err := c.Users.Current(context.Background())
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "a23efe53-63fb-11ec-90d6-0242ac120003", current.Id)
|
||||||
|
assert.Equal(t, "owner", current.Role)
|
||||||
|
|
||||||
user, err := c.Users.Create(context.Background(), api.UserCreateRequest{
|
user, err := c.Users.Create(context.Background(), api.UserCreateRequest{
|
||||||
AutoGroups: []string{},
|
AutoGroups: []string{},
|
||||||
Email: ptr("test@example.com"),
|
Email: ptr("test@example.com"),
|
||||||
|
|||||||
@@ -2140,6 +2140,8 @@ type ProviderConfig struct {
|
|||||||
AuthorizationEndpoint string `protobuf:"bytes,9,opt,name=AuthorizationEndpoint,proto3" json:"AuthorizationEndpoint,omitempty"`
|
AuthorizationEndpoint string `protobuf:"bytes,9,opt,name=AuthorizationEndpoint,proto3" json:"AuthorizationEndpoint,omitempty"`
|
||||||
// RedirectURLs handles authorization code from IDP manager
|
// RedirectURLs handles authorization code from IDP manager
|
||||||
RedirectURLs []string `protobuf:"bytes,10,rep,name=RedirectURLs,proto3" json:"RedirectURLs,omitempty"`
|
RedirectURLs []string `protobuf:"bytes,10,rep,name=RedirectURLs,proto3" json:"RedirectURLs,omitempty"`
|
||||||
|
// DisablePromptLogin makes the PKCE flow to not prompt the user for login
|
||||||
|
DisablePromptLogin bool `protobuf:"varint,11,opt,name=DisablePromptLogin,proto3" json:"DisablePromptLogin,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *ProviderConfig) Reset() {
|
func (x *ProviderConfig) Reset() {
|
||||||
@@ -2242,6 +2244,13 @@ func (x *ProviderConfig) GetRedirectURLs() []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (x *ProviderConfig) GetDisablePromptLogin() bool {
|
||||||
|
if x != nil {
|
||||||
|
return x.DisablePromptLogin
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// Route represents a route.Route object
|
// Route represents a route.Route object
|
||||||
type Route struct {
|
type Route struct {
|
||||||
state protoimpl.MessageState
|
state protoimpl.MessageState
|
||||||
@@ -3499,7 +3508,7 @@ var file_management_management_proto_rawDesc = []byte{
|
|||||||
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
|
||||||
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e,
|
0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e,
|
||||||
0x66, 0x69, 0x67, 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e,
|
0x66, 0x69, 0x67, 0x52, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x43, 0x6f, 0x6e,
|
||||||
0x66, 0x69, 0x67, 0x22, 0xea, 0x02, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
0x66, 0x69, 0x67, 0x22, 0x9a, 0x03, 0x0a, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72,
|
||||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1a, 0x0a, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||||
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74,
|
||||||
0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72,
|
0x49, 0x44, 0x12, 0x22, 0x0a, 0x0c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x53, 0x65, 0x63, 0x72,
|
||||||
@@ -3522,6 +3531,9 @@ var file_management_management_proto_rawDesc = []byte{
|
|||||||
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c,
|
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c,
|
||||||
0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x52, 0x4c, 0x73, 0x18, 0x0a, 0x20, 0x03,
|
0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x52, 0x4c, 0x73, 0x18, 0x0a, 0x20, 0x03,
|
||||||
0x28, 0x09, 0x52, 0x0c, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x52, 0x4c, 0x73,
|
0x28, 0x09, 0x52, 0x0c, 0x52, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x55, 0x52, 0x4c, 0x73,
|
||||||
|
0x12, 0x2e, 0x0a, 0x12, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6d, 0x70,
|
||||||
|
0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x44, 0x69,
|
||||||
|
0x73, 0x61, 0x62, 0x6c, 0x65, 0x50, 0x72, 0x6f, 0x6d, 0x70, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
|
||||||
0x22, 0xed, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44,
|
0x22, 0xed, 0x01, 0x0a, 0x05, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44,
|
||||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x4e, 0x65,
|
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x18, 0x0a, 0x07, 0x4e, 0x65,
|
||||||
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4e, 0x65, 0x74,
|
0x74, 0x77, 0x6f, 0x72, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4e, 0x65, 0x74,
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
cacheStore "github.com/eko/gocache/lib/v4/store"
|
cacheStore "github.com/eko/gocache/lib/v4/store"
|
||||||
@@ -30,6 +33,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
"github.com/netbirdio/netbird/management/server/integrations/port_forwarding"
|
||||||
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
nbpeer "github.com/netbirdio/netbird/management/server/peer"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"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/posture"
|
"github.com/netbirdio/netbird/management/server/posture"
|
||||||
"github.com/netbirdio/netbird/management/server/settings"
|
"github.com/netbirdio/netbird/management/server/settings"
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
@@ -92,6 +97,9 @@ type DefaultAccountManager struct {
|
|||||||
metrics telemetry.AppMetrics
|
metrics telemetry.AppMetrics
|
||||||
|
|
||||||
permissionsManager permissions.Manager
|
permissionsManager permissions.Manager
|
||||||
|
|
||||||
|
accountUpdateLocks sync.Map
|
||||||
|
updateAccountPeersBufferInterval atomic.Int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// getJWTGroupsChanges calculates the changes needed to sync a user's JWT groups.
|
// getJWTGroupsChanges calculates the changes needed to sync a user's JWT groups.
|
||||||
@@ -186,6 +194,23 @@ func BuildManager(
|
|||||||
settingsManager: settingsManager,
|
settingsManager: settingsManager,
|
||||||
permissionsManager: permissionsManager,
|
permissionsManager: permissionsManager,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var initialInterval int64
|
||||||
|
intervalStr := os.Getenv("PEER_UPDATE_INTERVAL_MS")
|
||||||
|
interval, err := strconv.Atoi(intervalStr)
|
||||||
|
if err != nil {
|
||||||
|
initialInterval = 1
|
||||||
|
} else {
|
||||||
|
initialInterval = int64(interval) * 10
|
||||||
|
go func() {
|
||||||
|
time.Sleep(30 * time.Second)
|
||||||
|
am.updateAccountPeersBufferInterval.Store(int64(time.Duration(interval) * time.Millisecond))
|
||||||
|
log.WithContext(ctx).Infof("set peer update buffer interval to %dms", interval)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
am.updateAccountPeersBufferInterval.Store(initialInterval)
|
||||||
|
log.WithContext(ctx).Infof("set peer update buffer interval to %dms", initialInterval)
|
||||||
|
|
||||||
accountsCounter, err := store.GetAccountsCounter(ctx)
|
accountsCounter, err := store.GetAccountsCounter(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithContext(ctx).Error(err)
|
log.WithContext(ctx).Error(err)
|
||||||
@@ -258,7 +283,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Settings, permissions.Write)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Settings, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
|
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
|
||||||
}
|
}
|
||||||
@@ -508,7 +533,7 @@ func (am *DefaultAccountManager) DeleteAccount(ctx context.Context, accountID, u
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Accounts, permissions.Write)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Accounts, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to validate user permissions: %w", err)
|
return fmt.Errorf("failed to validate user permissions: %w", err)
|
||||||
}
|
}
|
||||||
@@ -1021,13 +1046,12 @@ func (am *DefaultAccountManager) GetAccount(ctx context.Context, accountID strin
|
|||||||
|
|
||||||
// GetAccountByID returns an account associated with this account ID.
|
// GetAccountByID returns an account associated with this account ID.
|
||||||
func (am *DefaultAccountManager) GetAccountByID(ctx context.Context, accountID string, userID string) (*types.Account, error) {
|
func (am *DefaultAccountManager) GetAccountByID(ctx context.Context, accountID string, userID string) (*types.Account, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Accounts, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccount(ctx, accountID)
|
return am.Store.GetAccount(ctx, accountID)
|
||||||
@@ -1223,7 +1247,7 @@ func (am *DefaultAccountManager) SyncUserJWTGroups(ctx context.Context, userAuth
|
|||||||
|
|
||||||
if removedGroupAffectsPeers || newGroupsAffectsPeers {
|
if removedGroupAffectsPeers || newGroupsAffectsPeers {
|
||||||
log.WithContext(ctx).Tracef("user %s: JWT group membership changed, updating account peers", userAuth.UserId)
|
log.WithContext(ctx).Tracef("user %s: JWT group membership changed, updating account peers", userAuth.UserId)
|
||||||
am.UpdateAccountPeers(ctx, userAuth.AccountId)
|
am.BufferUpdateAccountPeers(ctx, userAuth.AccountId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1462,7 +1486,7 @@ func (am *DefaultAccountManager) GetDNSDomain() string {
|
|||||||
|
|
||||||
func (am *DefaultAccountManager) onPeersInvalidated(ctx context.Context, accountID string) {
|
func (am *DefaultAccountManager) onPeersInvalidated(ctx context.Context, accountID string) {
|
||||||
log.WithContext(ctx).Debugf("validated peers has been invalidated for account %s", accountID)
|
log.WithContext(ctx).Debugf("validated peers has been invalidated for account %s", accountID)
|
||||||
am.UpdateAccountPeers(ctx, accountID)
|
am.BufferUpdateAccountPeers(ctx, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *DefaultAccountManager) FindExistingPostureCheck(accountID string, checks *posture.ChecksDefinition) (*posture.Checks, error) {
|
func (am *DefaultAccountManager) FindExistingPostureCheck(accountID string, checks *posture.ChecksDefinition) (*posture.Checks, error) {
|
||||||
@@ -1515,19 +1539,13 @@ func (am *DefaultAccountManager) getFreeDNSLabel(ctx context.Context, s store.St
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (am *DefaultAccountManager) GetAccountSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) {
|
func (am *DefaultAccountManager) GetAccountSettings(ctx context.Context, accountID string, userID string) (*types.Settings, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Settings, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.HasAdminPower() && !user.IsServiceUser {
|
|
||||||
return nil, status.Errorf(status.PermissionDenied, "the user has no permission to access account data")
|
|
||||||
}
|
|
||||||
|
|
||||||
return am.Store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
|
return am.Store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -59,15 +59,15 @@ type Manager interface {
|
|||||||
GetGroup(ctx context.Context, accountId, groupID, userID string) (*types.Group, error)
|
GetGroup(ctx context.Context, accountId, groupID, userID string) (*types.Group, error)
|
||||||
GetAllGroups(ctx context.Context, accountID, userID string) ([]*types.Group, error)
|
GetAllGroups(ctx context.Context, accountID, userID string) ([]*types.Group, error)
|
||||||
GetGroupByName(ctx context.Context, groupName, accountID string) (*types.Group, error)
|
GetGroupByName(ctx context.Context, groupName, accountID string) (*types.Group, error)
|
||||||
SaveGroup(ctx context.Context, accountID, userID string, group *types.Group) error
|
SaveGroup(ctx context.Context, accountID, userID string, group *types.Group, create bool) error
|
||||||
SaveGroups(ctx context.Context, accountID, userID string, newGroups []*types.Group) error
|
SaveGroups(ctx context.Context, accountID, userID string, newGroups []*types.Group, create bool) error
|
||||||
DeleteGroup(ctx context.Context, accountId, userId, groupID string) error
|
DeleteGroup(ctx context.Context, accountId, userId, groupID string) error
|
||||||
DeleteGroups(ctx context.Context, accountId, userId string, groupIDs []string) error
|
DeleteGroups(ctx context.Context, accountId, userId string, groupIDs []string) error
|
||||||
GroupAddPeer(ctx context.Context, accountId, groupID, peerID string) error
|
GroupAddPeer(ctx context.Context, accountId, groupID, peerID string) error
|
||||||
GroupDeletePeer(ctx context.Context, accountId, groupID, peerID string) error
|
GroupDeletePeer(ctx context.Context, accountId, groupID, peerID string) error
|
||||||
GetPeerGroups(ctx context.Context, accountID, peerID string) ([]*types.Group, error)
|
GetPeerGroups(ctx context.Context, accountID, peerID string) ([]*types.Group, error)
|
||||||
GetPolicy(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error)
|
GetPolicy(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error)
|
||||||
SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy) (*types.Policy, error)
|
SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy, create bool) (*types.Policy, error)
|
||||||
DeletePolicy(ctx context.Context, accountID, policyID, userID string) error
|
DeletePolicy(ctx context.Context, accountID, policyID, userID string) error
|
||||||
ListPolicies(ctx context.Context, accountID, userID string) ([]*types.Policy, error)
|
ListPolicies(ctx context.Context, accountID, userID string) ([]*types.Policy, error)
|
||||||
GetRoute(ctx context.Context, accountID string, routeID route.ID, userID string) (*route.Route, error)
|
GetRoute(ctx context.Context, accountID string, routeID route.ID, userID string) (*route.Route, error)
|
||||||
@@ -93,7 +93,7 @@ type Manager interface {
|
|||||||
HasConnectedChannel(peerID string) bool
|
HasConnectedChannel(peerID string) bool
|
||||||
GetExternalCacheManager() ExternalCacheManager
|
GetExternalCacheManager() ExternalCacheManager
|
||||||
GetPostureChecks(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error)
|
GetPostureChecks(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error)
|
||||||
SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error)
|
SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks, create bool) (*posture.Checks, error)
|
||||||
DeletePostureChecks(ctx context.Context, accountID, postureChecksID, userID string) error
|
DeletePostureChecks(ctx context.Context, accountID, postureChecksID, userID string) error
|
||||||
ListPostureChecks(ctx context.Context, accountID, userID string) ([]*posture.Checks, error)
|
ListPostureChecks(ctx context.Context, accountID, userID string) ([]*posture.Checks, error)
|
||||||
GetIdpManager() idp.Manager
|
GetIdpManager() idp.Manager
|
||||||
@@ -114,4 +114,5 @@ type Manager interface {
|
|||||||
CreateAccountByPrivateDomain(ctx context.Context, initiatorId, domain string) (*types.Account, error)
|
CreateAccountByPrivateDomain(ctx context.Context, initiatorId, domain string) (*types.Account, error)
|
||||||
UpdateToPrimaryAccount(ctx context.Context, accountId string) (*types.Account, error)
|
UpdateToPrimaryAccount(ctx context.Context, accountId string) (*types.Account, error)
|
||||||
GetOwnerInfo(ctx context.Context, accountId string) (*types.UserInfo, error)
|
GetOwnerInfo(ctx context.Context, accountId string) (*types.UserInfo, error)
|
||||||
|
GetCurrentUserInfo(ctx context.Context, accountID, userID string) (*types.UserInfo, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1115,7 +1115,7 @@ func TestAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
|||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
}
|
}
|
||||||
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group); err != nil {
|
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group, true); err != nil {
|
||||||
t.Errorf("save group: %v", err)
|
t.Errorf("save group: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1131,7 +1131,7 @@ func TestAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
@@ -1150,7 +1150,7 @@ func TestAccountManager_NetworkUpdates_SaveGroup(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
group.Peers = []string{peer1.ID, peer2.ID, peer3.ID}
|
group.Peers = []string{peer1.ID, peer2.ID, peer3.ID}
|
||||||
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group); err != nil {
|
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group, true); err != nil {
|
||||||
t.Errorf("save group: %v", err)
|
t.Errorf("save group: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1192,7 +1192,7 @@ func TestAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
|||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
}
|
}
|
||||||
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group); err != nil {
|
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group, true); err != nil {
|
||||||
t.Errorf("save group: %v", err)
|
t.Errorf("save group: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1223,7 +1223,7 @@ func TestAccountManager_NetworkUpdates_SavePolicy(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("delete default rule: %v", err)
|
t.Errorf("delete default rule: %v", err)
|
||||||
return
|
return
|
||||||
@@ -1240,7 +1240,7 @@ func TestAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
|||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer3.ID},
|
||||||
}
|
}
|
||||||
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group); err != nil {
|
if err := manager.SaveGroup(context.Background(), account.Id, userID, &group, true); err != nil {
|
||||||
t.Errorf("save group: %v", err)
|
t.Errorf("save group: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -1256,7 +1256,7 @@ func TestAccountManager_NetworkUpdates_DeletePeer(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("save policy: %v", err)
|
t.Errorf("save policy: %v", err)
|
||||||
return
|
return
|
||||||
@@ -1295,7 +1295,7 @@ func TestAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
|
|||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
})
|
}, true)
|
||||||
|
|
||||||
require.NoError(t, err, "failed to save group")
|
require.NoError(t, err, "failed to save group")
|
||||||
|
|
||||||
@@ -1315,7 +1315,7 @@ func TestAccountManager_NetworkUpdates_DeleteGroup(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("save policy: %v", err)
|
t.Errorf("save policy: %v", err)
|
||||||
return
|
return
|
||||||
@@ -2794,13 +2794,13 @@ func TestAccount_UserGroupsRemoveFromPeers(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//type TB interface {
|
// type TB interface {
|
||||||
// Cleanup(func())
|
// Cleanup(func())
|
||||||
// Helper()
|
// Helper()
|
||||||
// TempDir() string
|
// TempDir() string
|
||||||
// Errorf(format string, args ...interface{})
|
// Errorf(format string, args ...interface{})
|
||||||
// Fatalf(format string, args ...interface{})
|
// Fatalf(format string, args ...interface{})
|
||||||
//}
|
// }
|
||||||
|
|
||||||
func createManager(t testing.TB) (*DefaultAccountManager, error) {
|
func createManager(t testing.TB) (*DefaultAccountManager, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@@ -2816,8 +2816,6 @@ func createManager(t testing.TB) (*DefaultAccountManager, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
|
|
||||||
@@ -2831,7 +2829,9 @@ func createManager(t testing.TB) (*DefaultAccountManager, error) {
|
|||||||
Return(false, nil).
|
Return(false, nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
|
|
||||||
manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
permissionsManager := permissions.NewManager(store)
|
||||||
|
|
||||||
|
manager, err := BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-18
@@ -10,6 +10,8 @@ import (
|
|||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/proto"
|
"github.com/netbirdio/netbird/management/proto"
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
@@ -62,17 +64,12 @@ func (c *DNSConfigCache) SetNameServerGroup(key string, value *proto.NameServerG
|
|||||||
|
|
||||||
// GetDNSSettings validates a user role and returns the DNS settings for the provided account ID
|
// GetDNSSettings validates a user role and returns the DNS settings for the provided account ID
|
||||||
func (am *DefaultAccountManager) GetDNSSettings(ctx context.Context, accountID string, userID string) (*types.DNSSettings, error) {
|
func (am *DefaultAccountManager) GetDNSSettings(ctx context.Context, accountID string, userID string) (*types.DNSSettings, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Dns, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccountDNSSettings(ctx, store.LockingStrengthShare, accountID)
|
return am.Store.GetAccountDNSSettings(ctx, store.LockingStrengthShare, accountID)
|
||||||
@@ -84,17 +81,12 @@ func (am *DefaultAccountManager) SaveDNSSettings(ctx context.Context, accountID
|
|||||||
return status.Errorf(status.InvalidArgument, "the dns settings provided are nil")
|
return status.Errorf(status.InvalidArgument, "the dns settings provided are nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Dns, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.HasAdminPower() {
|
|
||||||
return status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateAccountPeers bool
|
var updateAccountPeers bool
|
||||||
|
|||||||
@@ -211,14 +211,13 @@ func createDNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
|||||||
|
|
||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
|
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
|
permissionsManager := permissions.NewManager(store)
|
||||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.test", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createDNSStore(t *testing.T) (store.Store, error) {
|
func createDNSStore(t *testing.T) (store.Store, error) {
|
||||||
@@ -505,7 +504,7 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
|
|||||||
Name: "GroupB",
|
Name: "GroupB",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
@@ -565,7 +564,7 @@ func TestDNSAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|||||||
+14
-17
@@ -9,6 +9,8 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
@@ -21,17 +23,12 @@ func isEnabled() bool {
|
|||||||
|
|
||||||
// GetEvents returns a list of activity events of an account
|
// GetEvents returns a list of activity events of an account
|
||||||
func (am *DefaultAccountManager) GetEvents(ctx context.Context, accountID, userID string) ([]*activity.Event, error) {
|
func (am *DefaultAccountManager) GetEvents(ctx context.Context, accountID, userID string) ([]*activity.Event, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Events, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !(user.HasAdminPower() || user.IsServiceUser) {
|
|
||||||
return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view events")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
events, err := am.eventStore.Get(ctx, accountID, 0, 10000, true)
|
events, err := am.eventStore.Get(ctx, accountID, 0, 10000, true)
|
||||||
@@ -56,7 +53,7 @@ func (am *DefaultAccountManager) GetEvents(ctx context.Context, accountID, userI
|
|||||||
filtered = append(filtered, event)
|
filtered = append(filtered, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = am.fillEventsWithUserInfo(ctx, events, accountID, user)
|
err = am.fillEventsWithUserInfo(ctx, events, accountID, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -89,8 +86,8 @@ type eventUserInfo struct {
|
|||||||
accountId string
|
accountId string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *DefaultAccountManager) fillEventsWithUserInfo(ctx context.Context, events []*activity.Event, accountId string, user *types.User) error {
|
func (am *DefaultAccountManager) fillEventsWithUserInfo(ctx context.Context, events []*activity.Event, accountId string, userId string) error {
|
||||||
eventUserInfo, err := am.getEventsUserInfo(ctx, events, accountId, user)
|
eventUserInfo, err := am.getEventsUserInfo(ctx, events, accountId, userId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -105,14 +102,14 @@ func (am *DefaultAccountManager) fillEventsWithUserInfo(ctx context.Context, eve
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *DefaultAccountManager) getEventsUserInfo(ctx context.Context, events []*activity.Event, accountId string, user *types.User) (map[string]eventUserInfo, error) {
|
func (am *DefaultAccountManager) getEventsUserInfo(ctx context.Context, events []*activity.Event, accountId string, userId string) (map[string]eventUserInfo, error) {
|
||||||
accountUsers, err := am.Store.GetAccountUsers(ctx, store.LockingStrengthShare, accountId)
|
accountUsers, err := am.Store.GetAccountUsers(ctx, store.LockingStrengthShare, accountId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// @note check whether using a external initiator user here is an issue
|
// @note check whether using a external initiator user here is an issue
|
||||||
userInfos, err := am.BuildUserInfosForAccount(ctx, accountId, user.Id, accountUsers)
|
userInfos, err := am.BuildUserInfosForAccount(ctx, accountId, userId, accountUsers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -146,10 +143,10 @@ func (am *DefaultAccountManager) getEventsUserInfo(ctx context.Context, events [
|
|||||||
return eventUserInfos, nil
|
return eventUserInfos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.getEventsExternalUserInfo(ctx, externalUserIds, eventUserInfos, user)
|
return am.getEventsExternalUserInfo(ctx, externalUserIds, eventUserInfos, userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *DefaultAccountManager) getEventsExternalUserInfo(ctx context.Context, externalUserIds []string, eventUserInfos map[string]eventUserInfo, user *types.User) (map[string]eventUserInfo, error) {
|
func (am *DefaultAccountManager) getEventsExternalUserInfo(ctx context.Context, externalUserIds []string, eventUserInfos map[string]eventUserInfo, userId string) (map[string]eventUserInfo, error) {
|
||||||
externalAccountId := ""
|
externalAccountId := ""
|
||||||
fetched := make(map[string]struct{})
|
fetched := make(map[string]struct{})
|
||||||
externalUsers := []*types.User{}
|
externalUsers := []*types.User{}
|
||||||
@@ -182,7 +179,7 @@ func (am *DefaultAccountManager) getEventsExternalUserInfo(ctx context.Context,
|
|||||||
return eventUserInfos, nil
|
return eventUserInfos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
externalUserInfos, err := am.BuildUserInfosForAccount(ctx, externalAccountId, user.Id, externalUsers)
|
externalUserInfos, err := am.BuildUserInfosForAccount(ctx, externalAccountId, userId, externalUsers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-28
@@ -12,6 +12,8 @@ import (
|
|||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
|
routerTypes "github.com/netbirdio/netbird/management/server/networks/routers/types"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
@@ -30,17 +32,13 @@ func (e *GroupLinkError) Error() string {
|
|||||||
|
|
||||||
// CheckGroupPermissions validates if a user has the necessary permissions to view groups
|
// CheckGroupPermissions validates if a user has the necessary permissions to view groups
|
||||||
func (am *DefaultAccountManager) CheckGroupPermissions(ctx context.Context, accountID, userID string) error {
|
func (am *DefaultAccountManager) CheckGroupPermissions(ctx context.Context, accountID, userID string) error {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Groups, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
if !allowed {
|
||||||
return err
|
return status.NewPermissionDeniedError()
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -68,27 +66,26 @@ func (am *DefaultAccountManager) GetGroupByName(ctx context.Context, groupName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveGroup object of the peers
|
// SaveGroup object of the peers
|
||||||
func (am *DefaultAccountManager) SaveGroup(ctx context.Context, accountID, userID string, newGroup *types.Group) error {
|
func (am *DefaultAccountManager) SaveGroup(ctx context.Context, accountID, userID string, newGroup *types.Group, create bool) error {
|
||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
return am.SaveGroups(ctx, accountID, userID, []*types.Group{newGroup})
|
return am.SaveGroups(ctx, accountID, userID, []*types.Group{newGroup}, create)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveGroups adds new groups to the account.
|
// SaveGroups adds new groups to the account.
|
||||||
// Note: This function does not acquire the global lock.
|
// Note: This function does not acquire the global lock.
|
||||||
// It is the caller's responsibility to ensure proper locking is in place before invoking this method.
|
// It is the caller's responsibility to ensure proper locking is in place before invoking this method.
|
||||||
func (am *DefaultAccountManager) SaveGroups(ctx context.Context, accountID, userID string, groups []*types.Group) error {
|
func (am *DefaultAccountManager) SaveGroups(ctx context.Context, accountID, userID string, groups []*types.Group, create bool) error {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
operation := operations.Create
|
||||||
|
if !create {
|
||||||
|
operation = operations.Update
|
||||||
|
}
|
||||||
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Groups, operation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var eventsToStore []func()
|
var eventsToStore []func()
|
||||||
@@ -210,17 +207,12 @@ func (am *DefaultAccountManager) DeleteGroup(ctx context.Context, accountID, use
|
|||||||
// If an error occurs while deleting a group, the function skips it and continues deleting other groups.
|
// If an error occurs while deleting a group, the function skips it and continues deleting other groups.
|
||||||
// Errors are collected and returned at the end.
|
// Errors are collected and returned at the end.
|
||||||
func (am *DefaultAccountManager) DeleteGroups(ctx context.Context, accountID, userID string, groupIDs []string) error {
|
func (am *DefaultAccountManager) DeleteGroups(ctx context.Context, accountID, userID string, groupIDs []string) error {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Groups, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var allErrors error
|
var allErrors error
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func TestDefaultAccountManager_CreateGroup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, group := range account.Groups {
|
for _, group := range account.Groups {
|
||||||
group.Issued = types.GroupIssuedIntegration
|
group.Issued = types.GroupIssuedIntegration
|
||||||
err = am.SaveGroup(context.Background(), account.Id, groupAdminUserID, group)
|
err = am.SaveGroup(context.Background(), account.Id, groupAdminUserID, group, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("should allow to create %s groups", types.GroupIssuedIntegration)
|
t.Errorf("should allow to create %s groups", types.GroupIssuedIntegration)
|
||||||
}
|
}
|
||||||
@@ -48,7 +48,7 @@ func TestDefaultAccountManager_CreateGroup(t *testing.T) {
|
|||||||
|
|
||||||
for _, group := range account.Groups {
|
for _, group := range account.Groups {
|
||||||
group.Issued = types.GroupIssuedJWT
|
group.Issued = types.GroupIssuedJWT
|
||||||
err = am.SaveGroup(context.Background(), account.Id, groupAdminUserID, group)
|
err = am.SaveGroup(context.Background(), account.Id, groupAdminUserID, group, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("should allow to create %s groups", types.GroupIssuedJWT)
|
t.Errorf("should allow to create %s groups", types.GroupIssuedJWT)
|
||||||
}
|
}
|
||||||
@@ -56,7 +56,7 @@ func TestDefaultAccountManager_CreateGroup(t *testing.T) {
|
|||||||
for _, group := range account.Groups {
|
for _, group := range account.Groups {
|
||||||
group.Issued = types.GroupIssuedAPI
|
group.Issued = types.GroupIssuedAPI
|
||||||
group.ID = ""
|
group.ID = ""
|
||||||
err = am.SaveGroup(context.Background(), account.Id, groupAdminUserID, group)
|
err = am.SaveGroup(context.Background(), account.Id, groupAdminUserID, group, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("should not create api group with the same name, %s", group.Name)
|
t.Errorf("should not create api group with the same name, %s", group.Name)
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ func TestDefaultAccountManager_DeleteGroups(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = manager.SaveGroups(context.Background(), account.Id, groupAdminUserID, groups)
|
err = manager.SaveGroups(context.Background(), account.Id, groupAdminUserID, groups, true)
|
||||||
assert.NoError(t, err, "Failed to save test groups")
|
assert.NoError(t, err, "Failed to save test groups")
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
@@ -382,13 +382,13 @@ func initTestGroupAccount(am *DefaultAccountManager) (*DefaultAccountManager, *t
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForRoute)
|
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForRoute, true)
|
||||||
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForRoute2)
|
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForRoute2, true)
|
||||||
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForNameServerGroups)
|
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForNameServerGroups, true)
|
||||||
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForPolicies)
|
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForPolicies, true)
|
||||||
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForSetupKeys)
|
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForSetupKeys, true)
|
||||||
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForUsers)
|
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForUsers, true)
|
||||||
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForIntegration)
|
_ = am.SaveGroup(context.Background(), accountID, groupAdminUserID, groupForIntegration, true)
|
||||||
|
|
||||||
acc, err := am.Store.GetAccount(context.Background(), account.Id)
|
acc, err := am.Store.GetAccount(context.Background(), account.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -426,7 +426,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
Name: "GroupE",
|
Name: "GroupE",
|
||||||
Peers: []string{peer2.ID},
|
Peers: []string{peer2.ID},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
@@ -446,7 +446,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupB",
|
ID: "groupB",
|
||||||
Name: "GroupB",
|
Name: "GroupB",
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -524,7 +524,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Saving a group linked to policy should update account peers and send peer update
|
// Saving a group linked to policy should update account peers and send peer update
|
||||||
@@ -539,7 +539,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -608,7 +608,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupC",
|
ID: "groupC",
|
||||||
Name: "GroupC",
|
Name: "GroupC",
|
||||||
Peers: []string{peer1.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer3.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -649,7 +649,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -676,7 +676,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupD",
|
ID: "groupD",
|
||||||
Name: "GroupD",
|
Name: "GroupD",
|
||||||
Peers: []string{peer1.ID},
|
Peers: []string{peer1.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -723,7 +723,7 @@ func TestGroupAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupE",
|
ID: "groupE",
|
||||||
Name: "GroupE",
|
Name: "GroupE",
|
||||||
Peers: []string{peer2.ID, peer3.ID},
|
Peers: []string{peer2.ID, peer3.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/http/api"
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"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/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
)
|
)
|
||||||
@@ -39,7 +41,7 @@ func NewManager(store store.Store, permissionsManager permissions.Manager, accou
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllGroups(ctx context.Context, accountID, userID string) ([]*types.Group, error) {
|
func (m *managerImpl) GetAllGroups(ctx context.Context, accountID, userID string) ([]*types.Group, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Groups, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Groups, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -70,7 +72,7 @@ func (m *managerImpl) GetAllGroupsMap(ctx context.Context, accountID, userID str
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) AddResourceToGroup(ctx context.Context, accountID, userID, groupID string, resource *types.Resource) error {
|
func (m *managerImpl) AddResourceToGroup(ctx context.Context, accountID, userID, groupID string, resource *types.Resource) error {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Groups, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Groups, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -828,6 +828,7 @@ func (s *GRPCServer) GetPKCEAuthorizationFlow(ctx context.Context, req *proto.En
|
|||||||
Scope: s.config.PKCEAuthorizationFlow.ProviderConfig.Scope,
|
Scope: s.config.PKCEAuthorizationFlow.ProviderConfig.Scope,
|
||||||
RedirectURLs: s.config.PKCEAuthorizationFlow.ProviderConfig.RedirectURLs,
|
RedirectURLs: s.config.PKCEAuthorizationFlow.ProviderConfig.RedirectURLs,
|
||||||
UseIDToken: s.config.PKCEAuthorizationFlow.ProviderConfig.UseIDToken,
|
UseIDToken: s.config.PKCEAuthorizationFlow.ProviderConfig.UseIDToken,
|
||||||
|
DisablePromptLogin: s.config.PKCEAuthorizationFlow.ProviderConfig.DisablePromptLogin,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2397,6 +2397,29 @@ paths:
|
|||||||
"$ref": "#/components/responses/forbidden"
|
"$ref": "#/components/responses/forbidden"
|
||||||
'500':
|
'500':
|
||||||
"$ref": "#/components/responses/internal_error"
|
"$ref": "#/components/responses/internal_error"
|
||||||
|
/api/users/current:
|
||||||
|
get:
|
||||||
|
summary: Retrieve current user
|
||||||
|
description: Get information about the current user
|
||||||
|
tags: [ Users ]
|
||||||
|
security:
|
||||||
|
- BearerAuth: [ ]
|
||||||
|
- TokenAuth: [ ]
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: A User object
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
'400':
|
||||||
|
"$ref": "#/components/responses/bad_request"
|
||||||
|
'401':
|
||||||
|
"$ref": "#/components/responses/requires_authentication"
|
||||||
|
'403':
|
||||||
|
"$ref": "#/components/responses/forbidden"
|
||||||
|
'500':
|
||||||
|
"$ref": "#/components/responses/internal_error"
|
||||||
/api/peers:
|
/api/peers:
|
||||||
get:
|
get:
|
||||||
summary: List all Peers
|
summary: List all Peers
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ type Account struct {
|
|||||||
|
|
||||||
// AccountExtraSettings defines model for AccountExtraSettings.
|
// AccountExtraSettings defines model for AccountExtraSettings.
|
||||||
type AccountExtraSettings struct {
|
type AccountExtraSettings struct {
|
||||||
// NetworkTrafficLogsEnabled Enables or disables network traffic logs. If enabled, all network traffic logs from peers will be stored.
|
// NetworkTrafficLogsEnabled Enables or disables network traffic logging. If enabled, all network traffic events from peers will be stored.
|
||||||
NetworkTrafficLogsEnabled bool `json:"network_traffic_logs_enabled"`
|
NetworkTrafficLogsEnabled bool `json:"network_traffic_logs_enabled"`
|
||||||
|
|
||||||
// NetworkTrafficPacketCounterEnabled Enables or disables network traffic packet counter. If enabled, network packets and their size will be counted and reported. (This can have an slight impact on performance)
|
// NetworkTrafficPacketCounterEnabled Enables or disables network traffic packet counter. If enabled, network packets and their size will be counted and reported. (This can have an slight impact on performance)
|
||||||
|
|||||||
@@ -66,15 +66,13 @@ func NewAPIHandler(
|
|||||||
|
|
||||||
corsMiddleware := cors.AllowAll()
|
corsMiddleware := cors.AllowAll()
|
||||||
|
|
||||||
acMiddleware := middleware.NewAccessControl(accountManager.GetUserFromUserAuth)
|
|
||||||
|
|
||||||
rootRouter := mux.NewRouter()
|
rootRouter := mux.NewRouter()
|
||||||
metricsMiddleware := appMetrics.HTTPMiddleware()
|
metricsMiddleware := appMetrics.HTTPMiddleware()
|
||||||
|
|
||||||
prefix := apiPrefix
|
prefix := apiPrefix
|
||||||
router := rootRouter.PathPrefix(prefix).Subrouter()
|
router := rootRouter.PathPrefix(prefix).Subrouter()
|
||||||
|
|
||||||
router.Use(metricsMiddleware.Handler, corsMiddleware.Handler, authMiddleware.Handler, acMiddleware.Handler)
|
router.Use(metricsMiddleware.Handler, corsMiddleware.Handler, authMiddleware.Handler)
|
||||||
|
|
||||||
if _, err := integrations.RegisterHandlers(ctx, prefix, router, accountManager, integratedValidator, appMetrics.GetMeter(), permissionsManager, peersManager, proxyController, settingsManager); err != nil {
|
if _, err := integrations.RegisterHandlers(ctx, prefix, router, accountManager, integratedValidator, appMetrics.GetMeter(), permissionsManager, peersManager, proxyController, settingsManager); err != nil {
|
||||||
return nil, fmt.Errorf("register integrations endpoints: %w", err)
|
return nil, fmt.Errorf("register integrations endpoints: %w", err)
|
||||||
@@ -85,6 +83,8 @@ func NewAPIHandler(
|
|||||||
users.AddEndpoints(accountManager, router)
|
users.AddEndpoints(accountManager, router)
|
||||||
setup_keys.AddEndpoints(accountManager, router)
|
setup_keys.AddEndpoints(accountManager, router)
|
||||||
policies.AddEndpoints(accountManager, LocationManager, router)
|
policies.AddEndpoints(accountManager, LocationManager, router)
|
||||||
|
policies.AddPostureCheckEndpoints(accountManager, LocationManager, router)
|
||||||
|
policies.AddLocationsEndpoints(accountManager, LocationManager, permissionsManager, router)
|
||||||
groups.AddEndpoints(accountManager, router)
|
groups.AddEndpoints(accountManager, router)
|
||||||
routes.AddEndpoints(accountManager, router)
|
routes.AddEndpoints(accountManager, router)
|
||||||
dns.AddEndpoints(accountManager, router)
|
dns.AddEndpoints(accountManager, router)
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ func (h *handler) updateGroup(w http.ResponseWriter, r *http.Request) {
|
|||||||
IntegrationReference: existingGroup.IntegrationReference,
|
IntegrationReference: existingGroup.IntegrationReference,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.accountManager.SaveGroup(r.Context(), accountID, userID, &group); err != nil {
|
if err := h.accountManager.SaveGroup(r.Context(), accountID, userID, &group, false); err != nil {
|
||||||
log.WithContext(r.Context()).Errorf("failed updating group %s under account %s %v", groupID, accountID, err)
|
log.WithContext(r.Context()).Errorf("failed updating group %s under account %s %v", groupID, accountID, err)
|
||||||
util.WriteError(r.Context(), err, w)
|
util.WriteError(r.Context(), err, w)
|
||||||
return
|
return
|
||||||
@@ -203,7 +203,7 @@ func (h *handler) createGroup(w http.ResponseWriter, r *http.Request) {
|
|||||||
Issued: types.GroupIssuedAPI,
|
Issued: types.GroupIssuedAPI,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = h.accountManager.SaveGroup(r.Context(), accountID, userID, &group)
|
err = h.accountManager.SaveGroup(r.Context(), accountID, userID, &group, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(r.Context(), err, w)
|
util.WriteError(r.Context(), err, w)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ var TestPeers = map[string]*nbpeer.Peer{
|
|||||||
func initGroupTestData(initGroups ...*types.Group) *handler {
|
func initGroupTestData(initGroups ...*types.Group) *handler {
|
||||||
return &handler{
|
return &handler{
|
||||||
accountManager: &mock_server.MockAccountManager{
|
accountManager: &mock_server.MockAccountManager{
|
||||||
SaveGroupFunc: func(_ context.Context, accountID, userID string, group *types.Group) error {
|
SaveGroupFunc: func(_ context.Context, accountID, userID string, group *types.Group, create bool) error {
|
||||||
if !strings.HasPrefix(group.ID, "id-") {
|
if !strings.HasPrefix(group.ID, "id-") {
|
||||||
group.ID = "id-was-set"
|
group.ID = "id-was-set"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/account"
|
"github.com/netbirdio/netbird/management/server/account"
|
||||||
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
||||||
"github.com/netbirdio/netbird/management/server/groups"
|
"github.com/netbirdio/netbird/management/server/groups"
|
||||||
"github.com/netbirdio/netbird/management/server/http/api"
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
@@ -244,7 +245,7 @@ func (h *Handler) GetAccessiblePeers(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := h.accountManager.GetAccountByID(r.Context(), accountID, userID)
|
account, err := h.accountManager.GetAccountByID(r.Context(), accountID, activity.SystemInitiator)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(r.Context(), err, w)
|
util.WriteError(r.Context(), err, w)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
@@ -17,6 +18,9 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/geolocation"
|
"github.com/netbirdio/netbird/management/server/geolocation"
|
||||||
"github.com/netbirdio/netbird/management/server/http/api"
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
"github.com/netbirdio/netbird/management/server/mock_server"
|
"github.com/netbirdio/netbird/management/server/mock_server"
|
||||||
|
"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/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
"github.com/netbirdio/netbird/util"
|
"github.com/netbirdio/netbird/util"
|
||||||
)
|
)
|
||||||
@@ -41,6 +45,14 @@ func initGeolocationTestData(t *testing.T) *geolocationsHandler {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
t.Cleanup(func() { _ = geo.Stop() })
|
t.Cleanup(func() { _ = geo.Stop() })
|
||||||
|
|
||||||
|
ctrl := gomock.NewController(t)
|
||||||
|
permissionsManagerMock := permissions.NewMockManager(ctrl)
|
||||||
|
permissionsManagerMock.
|
||||||
|
EXPECT().
|
||||||
|
ValidateUserPermissions(gomock.Any(), gomock.Any(), gomock.Any(), modules.Policies, operations.Read).
|
||||||
|
Return(true, nil).
|
||||||
|
AnyTimes()
|
||||||
|
|
||||||
return &geolocationsHandler{
|
return &geolocationsHandler{
|
||||||
accountManager: &mock_server.MockAccountManager{
|
accountManager: &mock_server.MockAccountManager{
|
||||||
GetUserByIDFunc: func(ctx context.Context, id string) (*types.User, error) {
|
GetUserByIDFunc: func(ctx context.Context, id string) (*types.User, error) {
|
||||||
@@ -48,6 +60,7 @@ func initGeolocationTestData(t *testing.T) *geolocationsHandler {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
geolocationManager: geo,
|
geolocationManager: geo,
|
||||||
|
permissionsManager: permissionsManagerMock,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/geolocation"
|
"github.com/netbirdio/netbird/management/server/geolocation"
|
||||||
"github.com/netbirdio/netbird/management/server/http/api"
|
"github.com/netbirdio/netbird/management/server/http/api"
|
||||||
"github.com/netbirdio/netbird/management/server/http/util"
|
"github.com/netbirdio/netbird/management/server/http/util"
|
||||||
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -22,19 +25,21 @@ var (
|
|||||||
type geolocationsHandler struct {
|
type geolocationsHandler struct {
|
||||||
accountManager account.Manager
|
accountManager account.Manager
|
||||||
geolocationManager geolocation.Geolocation
|
geolocationManager geolocation.Geolocation
|
||||||
|
permissionsManager permissions.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
func addLocationsEndpoint(accountManager account.Manager, locationManager geolocation.Geolocation, router *mux.Router) {
|
func AddLocationsEndpoints(accountManager account.Manager, locationManager geolocation.Geolocation, permissionsManager permissions.Manager, router *mux.Router) {
|
||||||
locationHandler := newGeolocationsHandlerHandler(accountManager, locationManager)
|
locationHandler := newGeolocationsHandlerHandler(accountManager, locationManager, permissionsManager)
|
||||||
router.HandleFunc("/locations/countries", locationHandler.getAllCountries).Methods("GET", "OPTIONS")
|
router.HandleFunc("/locations/countries", locationHandler.getAllCountries).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/locations/countries/{country}/cities", locationHandler.getCitiesByCountry).Methods("GET", "OPTIONS")
|
router.HandleFunc("/locations/countries/{country}/cities", locationHandler.getCitiesByCountry).Methods("GET", "OPTIONS")
|
||||||
}
|
}
|
||||||
|
|
||||||
// newGeolocationsHandlerHandler creates a new Geolocations handler
|
// newGeolocationsHandlerHandler creates a new Geolocations handler
|
||||||
func newGeolocationsHandlerHandler(accountManager account.Manager, geolocationManager geolocation.Geolocation) *geolocationsHandler {
|
func newGeolocationsHandlerHandler(accountManager account.Manager, geolocationManager geolocation.Geolocation, permissionsManager permissions.Manager) *geolocationsHandler {
|
||||||
return &geolocationsHandler{
|
return &geolocationsHandler{
|
||||||
accountManager: accountManager,
|
accountManager: accountManager,
|
||||||
geolocationManager: geolocationManager,
|
geolocationManager: geolocationManager,
|
||||||
|
permissionsManager: permissionsManager,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,20 +103,22 @@ func (l *geolocationsHandler) getCitiesByCountry(w http.ResponseWriter, r *http.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *geolocationsHandler) authenticateUser(r *http.Request) error {
|
func (l *geolocationsHandler) authenticateUser(r *http.Request) error {
|
||||||
userAuth, err := nbcontext.GetUserAuthFromContext(r.Context())
|
ctx := r.Context()
|
||||||
|
|
||||||
|
userAuth, err := nbcontext.GetUserAuthFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, userID := userAuth.AccountId, userAuth.UserId
|
accountID, userID := userAuth.AccountId, userAuth.UserId
|
||||||
|
|
||||||
user, err := l.accountManager.GetUserByID(r.Context(), userID)
|
allowed, err := l.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.HasAdminPower() {
|
if !allowed {
|
||||||
return status.Errorf(status.PermissionDenied, "user is not allowed to perform this action")
|
return status.NewPermissionDeniedError()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ func AddEndpoints(accountManager account.Manager, locationManager geolocation.Ge
|
|||||||
router.HandleFunc("/policies/{policyId}", policiesHandler.updatePolicy).Methods("PUT", "OPTIONS")
|
router.HandleFunc("/policies/{policyId}", policiesHandler.updatePolicy).Methods("PUT", "OPTIONS")
|
||||||
router.HandleFunc("/policies/{policyId}", policiesHandler.getPolicy).Methods("GET", "OPTIONS")
|
router.HandleFunc("/policies/{policyId}", policiesHandler.getPolicy).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/policies/{policyId}", policiesHandler.deletePolicy).Methods("DELETE", "OPTIONS")
|
router.HandleFunc("/policies/{policyId}", policiesHandler.deletePolicy).Methods("DELETE", "OPTIONS")
|
||||||
addPostureCheckEndpoint(accountManager, locationManager, router)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newHandler creates a new policies handler
|
// newHandler creates a new policies handler
|
||||||
@@ -96,7 +95,7 @@ func (h *handler) updatePolicy(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
h.savePolicy(w, r, accountID, userID, policyID)
|
h.savePolicy(w, r, accountID, userID, policyID, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createPolicy handles policy creation request
|
// createPolicy handles policy creation request
|
||||||
@@ -109,11 +108,11 @@ func (h *handler) createPolicy(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
accountID, userID := userAuth.AccountId, userAuth.UserId
|
accountID, userID := userAuth.AccountId, userAuth.UserId
|
||||||
|
|
||||||
h.savePolicy(w, r, accountID, userID, "")
|
h.savePolicy(w, r, accountID, userID, "", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// savePolicy handles policy creation and update
|
// savePolicy handles policy creation and update
|
||||||
func (h *handler) savePolicy(w http.ResponseWriter, r *http.Request, accountID string, userID string, policyID string) {
|
func (h *handler) savePolicy(w http.ResponseWriter, r *http.Request, accountID string, userID string, policyID string, create bool) {
|
||||||
var req api.PutApiPoliciesPolicyIdJSONRequestBody
|
var req api.PutApiPoliciesPolicyIdJSONRequestBody
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
|
util.WriteErrorResponse("couldn't parse JSON request", http.StatusBadRequest, w)
|
||||||
@@ -280,7 +279,7 @@ func (h *handler) savePolicy(w http.ResponseWriter, r *http.Request, accountID s
|
|||||||
policy.SourcePostureChecks = *req.SourcePostureChecks
|
policy.SourcePostureChecks = *req.SourcePostureChecks
|
||||||
}
|
}
|
||||||
|
|
||||||
policy, err := h.accountManager.SavePolicy(r.Context(), accountID, userID, policy)
|
policy, err := h.accountManager.SavePolicy(r.Context(), accountID, userID, policy, create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(r.Context(), err, w)
|
util.WriteError(r.Context(), err, w)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func initPoliciesTestData(policies ...*types.Policy) *handler {
|
|||||||
}
|
}
|
||||||
return policy, nil
|
return policy, nil
|
||||||
},
|
},
|
||||||
SavePolicyFunc: func(_ context.Context, _, _ string, policy *types.Policy) (*types.Policy, error) {
|
SavePolicyFunc: func(_ context.Context, _, _ string, policy *types.Policy, create bool) (*types.Policy, error) {
|
||||||
if !strings.HasPrefix(policy.ID, "id-") {
|
if !strings.HasPrefix(policy.ID, "id-") {
|
||||||
policy.ID = "id-was-set"
|
policy.ID = "id-was-set"
|
||||||
policy.Rules[0].ID = "id-was-set"
|
policy.Rules[0].ID = "id-was-set"
|
||||||
|
|||||||
@@ -21,14 +21,13 @@ type postureChecksHandler struct {
|
|||||||
geolocationManager geolocation.Geolocation
|
geolocationManager geolocation.Geolocation
|
||||||
}
|
}
|
||||||
|
|
||||||
func addPostureCheckEndpoint(accountManager account.Manager, locationManager geolocation.Geolocation, router *mux.Router) {
|
func AddPostureCheckEndpoints(accountManager account.Manager, locationManager geolocation.Geolocation, router *mux.Router) {
|
||||||
postureCheckHandler := newPostureChecksHandler(accountManager, locationManager)
|
postureCheckHandler := newPostureChecksHandler(accountManager, locationManager)
|
||||||
router.HandleFunc("/posture-checks", postureCheckHandler.getAllPostureChecks).Methods("GET", "OPTIONS")
|
router.HandleFunc("/posture-checks", postureCheckHandler.getAllPostureChecks).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/posture-checks", postureCheckHandler.createPostureCheck).Methods("POST", "OPTIONS")
|
router.HandleFunc("/posture-checks", postureCheckHandler.createPostureCheck).Methods("POST", "OPTIONS")
|
||||||
router.HandleFunc("/posture-checks/{postureCheckId}", postureCheckHandler.updatePostureCheck).Methods("PUT", "OPTIONS")
|
router.HandleFunc("/posture-checks/{postureCheckId}", postureCheckHandler.updatePostureCheck).Methods("PUT", "OPTIONS")
|
||||||
router.HandleFunc("/posture-checks/{postureCheckId}", postureCheckHandler.getPostureCheck).Methods("GET", "OPTIONS")
|
router.HandleFunc("/posture-checks/{postureCheckId}", postureCheckHandler.getPostureCheck).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/posture-checks/{postureCheckId}", postureCheckHandler.deletePostureCheck).Methods("DELETE", "OPTIONS")
|
router.HandleFunc("/posture-checks/{postureCheckId}", postureCheckHandler.deletePostureCheck).Methods("DELETE", "OPTIONS")
|
||||||
addLocationsEndpoint(accountManager, locationManager, router)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newPostureChecksHandler creates a new PostureChecks handler
|
// newPostureChecksHandler creates a new PostureChecks handler
|
||||||
@@ -85,7 +84,7 @@ func (p *postureChecksHandler) updatePostureCheck(w http.ResponseWriter, r *http
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
p.savePostureChecks(w, r, accountID, userID, postureChecksID)
|
p.savePostureChecks(w, r, accountID, userID, postureChecksID, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createPostureCheck handles posture check creation request
|
// createPostureCheck handles posture check creation request
|
||||||
@@ -98,7 +97,7 @@ func (p *postureChecksHandler) createPostureCheck(w http.ResponseWriter, r *http
|
|||||||
|
|
||||||
accountID, userID := userAuth.AccountId, userAuth.UserId
|
accountID, userID := userAuth.AccountId, userAuth.UserId
|
||||||
|
|
||||||
p.savePostureChecks(w, r, accountID, userID, "")
|
p.savePostureChecks(w, r, accountID, userID, "", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPostureCheck handles a posture check Get request identified by ID
|
// getPostureCheck handles a posture check Get request identified by ID
|
||||||
@@ -151,7 +150,7 @@ func (p *postureChecksHandler) deletePostureCheck(w http.ResponseWriter, r *http
|
|||||||
}
|
}
|
||||||
|
|
||||||
// savePostureChecks handles posture checks create and update
|
// savePostureChecks handles posture checks create and update
|
||||||
func (p *postureChecksHandler) savePostureChecks(w http.ResponseWriter, r *http.Request, accountID, userID, postureChecksID string) {
|
func (p *postureChecksHandler) savePostureChecks(w http.ResponseWriter, r *http.Request, accountID, userID, postureChecksID string, create bool) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
req api.PostureCheckUpdate
|
req api.PostureCheckUpdate
|
||||||
@@ -176,7 +175,7 @@ func (p *postureChecksHandler) savePostureChecks(w http.ResponseWriter, r *http.
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
postureChecks, err = p.accountManager.SavePostureChecks(r.Context(), accountID, userID, postureChecks)
|
postureChecks, err = p.accountManager.SavePostureChecks(r.Context(), accountID, userID, postureChecks, create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
util.WriteError(r.Context(), err, w)
|
util.WriteError(r.Context(), err, w)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ func initPostureChecksTestData(postureChecks ...*posture.Checks) *postureChecksH
|
|||||||
}
|
}
|
||||||
return p, nil
|
return p, nil
|
||||||
},
|
},
|
||||||
SavePostureChecksFunc: func(_ context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error) {
|
SavePostureChecksFunc: func(_ context.Context, accountID, userID string, postureChecks *posture.Checks, create bool) (*posture.Checks, error) {
|
||||||
postureChecks.ID = "postureCheck"
|
postureChecks.ID = "postureCheck"
|
||||||
testPostureChecks[postureChecks.ID] = postureChecks
|
testPostureChecks[postureChecks.ID] = postureChecks
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ type handler struct {
|
|||||||
func AddEndpoints(accountManager account.Manager, router *mux.Router) {
|
func AddEndpoints(accountManager account.Manager, router *mux.Router) {
|
||||||
userHandler := newHandler(accountManager)
|
userHandler := newHandler(accountManager)
|
||||||
router.HandleFunc("/users", userHandler.getAllUsers).Methods("GET", "OPTIONS")
|
router.HandleFunc("/users", userHandler.getAllUsers).Methods("GET", "OPTIONS")
|
||||||
|
router.HandleFunc("/users/current", userHandler.getCurrentUser).Methods("GET", "OPTIONS")
|
||||||
router.HandleFunc("/users/{userId}", userHandler.updateUser).Methods("PUT", "OPTIONS")
|
router.HandleFunc("/users/{userId}", userHandler.updateUser).Methods("PUT", "OPTIONS")
|
||||||
router.HandleFunc("/users/{userId}", userHandler.deleteUser).Methods("DELETE", "OPTIONS")
|
router.HandleFunc("/users/{userId}", userHandler.deleteUser).Methods("DELETE", "OPTIONS")
|
||||||
router.HandleFunc("/users", userHandler.createUser).Methods("POST", "OPTIONS")
|
router.HandleFunc("/users", userHandler.createUser).Methods("POST", "OPTIONS")
|
||||||
@@ -259,6 +260,29 @@ func (h *handler) inviteUser(w http.ResponseWriter, r *http.Request) {
|
|||||||
util.WriteJSONObject(r.Context(), w, util.EmptyObject{})
|
util.WriteJSONObject(r.Context(), w, util.EmptyObject{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *handler) getCurrentUser(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != http.MethodGet {
|
||||||
|
util.WriteErrorResponse("wrong HTTP method", http.StatusMethodNotAllowed, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx := r.Context()
|
||||||
|
userAuth, err := nbcontext.GetUserAuthFromContext(ctx)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
accountID, userID := userAuth.AccountId, userAuth.UserId
|
||||||
|
|
||||||
|
user, err := h.accountManager.GetCurrentUserInfo(ctx, accountID, userID)
|
||||||
|
if err != nil {
|
||||||
|
util.WriteError(r.Context(), err, w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
util.WriteJSONObject(r.Context(), w, toUserResponse(user, userID))
|
||||||
|
}
|
||||||
|
|
||||||
func toUserResponse(user *types.UserInfo, currenUserID string) *api.User {
|
func toUserResponse(user *types.UserInfo, currenUserID string) *api.User {
|
||||||
autoGroups := user.AutoGroups
|
autoGroups := user.AutoGroups
|
||||||
if autoGroups == nil {
|
if autoGroups == nil {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -123,6 +124,64 @@ func initUsersTestData() *handler {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
GetCurrentUserInfoFunc: func(ctx context.Context, accountID, userID string) (*types.UserInfo, error) {
|
||||||
|
switch userID {
|
||||||
|
case "not-found":
|
||||||
|
return nil, status.NewUserNotFoundError("not-found")
|
||||||
|
case "not-of-account":
|
||||||
|
return nil, status.NewUserNotPartOfAccountError()
|
||||||
|
case "blocked-user":
|
||||||
|
return nil, status.NewUserBlockedError()
|
||||||
|
case "service-user":
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
case "owner":
|
||||||
|
return &types.UserInfo{
|
||||||
|
ID: "owner",
|
||||||
|
Name: "",
|
||||||
|
Role: "owner",
|
||||||
|
Status: "active",
|
||||||
|
IsServiceUser: false,
|
||||||
|
IsBlocked: false,
|
||||||
|
NonDeletable: false,
|
||||||
|
Issued: "api",
|
||||||
|
Permissions: types.UserPermissions{
|
||||||
|
DashboardView: "full",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
case "regular-user":
|
||||||
|
return &types.UserInfo{
|
||||||
|
ID: "regular-user",
|
||||||
|
Name: "",
|
||||||
|
Role: "user",
|
||||||
|
Status: "active",
|
||||||
|
IsServiceUser: false,
|
||||||
|
IsBlocked: false,
|
||||||
|
NonDeletable: false,
|
||||||
|
Issued: "api",
|
||||||
|
Permissions: types.UserPermissions{
|
||||||
|
DashboardView: "limited",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
|
||||||
|
case "admin-user":
|
||||||
|
return &types.UserInfo{
|
||||||
|
ID: "admin-user",
|
||||||
|
Name: "",
|
||||||
|
Role: "admin",
|
||||||
|
Status: "active",
|
||||||
|
IsServiceUser: false,
|
||||||
|
IsBlocked: false,
|
||||||
|
NonDeletable: false,
|
||||||
|
LastLogin: time.Time{},
|
||||||
|
Issued: "api",
|
||||||
|
Permissions: types.UserPermissions{
|
||||||
|
DashboardView: "full",
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("user id %s not handled", userID)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -481,3 +540,73 @@ func TestDeleteUser(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCurrentUser(t *testing.T) {
|
||||||
|
tt := []struct {
|
||||||
|
name string
|
||||||
|
expectedStatus int
|
||||||
|
requestAuth nbcontext.UserAuth
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "without auth",
|
||||||
|
expectedStatus: http.StatusInternalServerError,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "user not found",
|
||||||
|
requestAuth: nbcontext.UserAuth{UserId: "not-found"},
|
||||||
|
expectedStatus: http.StatusNotFound,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not of account",
|
||||||
|
requestAuth: nbcontext.UserAuth{UserId: "not-of-account"},
|
||||||
|
expectedStatus: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "blocked user",
|
||||||
|
requestAuth: nbcontext.UserAuth{UserId: "blocked-user"},
|
||||||
|
expectedStatus: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "service user",
|
||||||
|
requestAuth: nbcontext.UserAuth{UserId: "service-user"},
|
||||||
|
expectedStatus: http.StatusForbidden,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "owner",
|
||||||
|
requestAuth: nbcontext.UserAuth{UserId: "owner"},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "regular user",
|
||||||
|
requestAuth: nbcontext.UserAuth{UserId: "regular-user"},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "admin user",
|
||||||
|
requestAuth: nbcontext.UserAuth{UserId: "admin-user"},
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
userHandler := initUsersTestData()
|
||||||
|
for _, tc := range tt {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
req := httptest.NewRequest(http.MethodGet, "/api/users/current", nil)
|
||||||
|
if tc.requestAuth.UserId != "" {
|
||||||
|
req = nbcontext.SetUserAuthInRequest(req, tc.requestAuth)
|
||||||
|
}
|
||||||
|
|
||||||
|
rr := httptest.NewRecorder()
|
||||||
|
|
||||||
|
userHandler.getCurrentUser(rr, req)
|
||||||
|
|
||||||
|
res := rr.Result()
|
||||||
|
defer res.Body.Close()
|
||||||
|
|
||||||
|
if status := rr.Code; status != tc.expectedStatus {
|
||||||
|
t.Fatalf("handler returned wrong status code: got %v want %v",
|
||||||
|
status, tc.expectedStatus)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,77 +0,0 @@
|
|||||||
package middleware
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"net/http"
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
|
|
||||||
nbcontext "github.com/netbirdio/netbird/management/server/context"
|
|
||||||
"github.com/netbirdio/netbird/management/server/http/middleware/bypass"
|
|
||||||
"github.com/netbirdio/netbird/management/server/http/util"
|
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// GetUser function defines a function to fetch user from Account by jwtclaims.AuthorizationClaims
|
|
||||||
type GetUser func(ctx context.Context, userAuth nbcontext.UserAuth) (*types.User, error)
|
|
||||||
|
|
||||||
// AccessControl middleware to restrict to make POST/PUT/DELETE requests by admin only
|
|
||||||
type AccessControl struct {
|
|
||||||
getUser GetUser
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAccessControl instance constructor
|
|
||||||
func NewAccessControl(getUser GetUser) *AccessControl {
|
|
||||||
return &AccessControl{
|
|
||||||
getUser: getUser,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokenPathRegexp = regexp.MustCompile(`^.*/api/users/.*/tokens.*$`)
|
|
||||||
|
|
||||||
// Handler method of the middleware which forbids all modify requests for non admin users
|
|
||||||
func (a *AccessControl) Handler(h http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
if bypass.ShouldBypass(r.URL.Path, h, w, r) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
userAuth, err := nbcontext.GetUserAuthFromRequest(r)
|
|
||||||
if err != nil {
|
|
||||||
log.WithContext(r.Context()).Errorf("failed to get user auth from request: %s", err)
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.Unauthorized, "invalid user auth"), w)
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := a.getUser(r.Context(), userAuth)
|
|
||||||
if err != nil {
|
|
||||||
log.WithContext(r.Context()).Errorf("failed to get user: %s", err)
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.Unauthorized, "invalid user auth"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsBlocked() {
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.PermissionDenied, "the user has no access to the API or is blocked"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.HasAdminPower() {
|
|
||||||
switch r.Method {
|
|
||||||
case http.MethodDelete, http.MethodPost, http.MethodPatch, http.MethodPut:
|
|
||||||
|
|
||||||
if tokenPathRegexp.MatchString(r.URL.Path) {
|
|
||||||
log.WithContext(r.Context()).Debugf("valid Path")
|
|
||||||
h.ServeHTTP(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
util.WriteError(r.Context(), status.Errorf(status.PermissionDenied, "only users with admin power can perform this operation"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h.ServeHTTP(w, r)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -15,7 +15,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
||||||
|
|
||||||
@@ -123,9 +122,9 @@ func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *serve
|
|||||||
validatorMock := server.MocIntegratedValidator{}
|
validatorMock := server.MocIntegratedValidator{}
|
||||||
proxyController := integrations.NewController(store)
|
proxyController := integrations.NewController(store)
|
||||||
userManager := users.NewManager(store)
|
userManager := users.NewManager(store)
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
settingsManager := settings.NewManager(store, userManager, integrations.NewManager(&activity.InMemoryEventStore{}), permissionsManagerMock)
|
settingsManager := settings.NewManager(store, userManager, integrations.NewManager(&activity.InMemoryEventStore{}), permissionsManager)
|
||||||
am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager, permissionsManagerMock)
|
am, err := server.BuildManager(context.Background(), store, peersUpdateManager, nil, "", "", &activity.InMemoryEventStore{}, geoMock, false, validatorMock, metrics, proxyController, settingsManager, permissionsManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create manager: %v", err)
|
t.Fatalf("Failed to create manager: %v", err)
|
||||||
}
|
}
|
||||||
@@ -143,9 +142,9 @@ func BuildApiBlackBoxWithDBState(t TB, sqlFile string, expectedPeerUpdate *serve
|
|||||||
resourcesManagerMock := resources.NewManagerMock()
|
resourcesManagerMock := resources.NewManagerMock()
|
||||||
routersManagerMock := routers.NewManagerMock()
|
routersManagerMock := routers.NewManagerMock()
|
||||||
groupsManagerMock := groups.NewManagerMock()
|
groupsManagerMock := groups.NewManagerMock()
|
||||||
peersManager := peers.NewManager(store, permissionsManagerMock)
|
peersManager := peers.NewManager(store, permissionsManager)
|
||||||
|
|
||||||
apiHandler, err := nbhttp.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManagerMock, peersManager, settingsManager)
|
apiHandler, err := nbhttp.NewAPIHandler(context.Background(), am, networksManagerMock, resourcesManagerMock, routersManagerMock, groupsManagerMock, geoMock, authManagerMock, metrics, validatorMock, proxyController, permissionsManager, peersManager, settingsManager)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create API handler: %v", err)
|
t.Fatalf("Failed to create API handler: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -432,8 +432,6 @@ func startManagementForTest(t *testing.T, testFile string, config *types.Config)
|
|||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
@@ -443,8 +441,10 @@ func startManagementForTest(t *testing.T, testFile string, config *types.Config)
|
|||||||
AnyTimes().
|
AnyTimes().
|
||||||
Return(&types.Settings{}, nil)
|
Return(&types.Settings{}, nil)
|
||||||
|
|
||||||
|
permissionsManager := permissions.NewManager(store)
|
||||||
|
|
||||||
accountManager, err := BuildManager(ctx, store, peersUpdateManager, nil, "", "netbird.selfhosted",
|
accountManager, err := BuildManager(ctx, store, peersUpdateManager, nil, "", "netbird.selfhosted",
|
||||||
eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cleanup()
|
cleanup()
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ func startServer(
|
|||||||
Return(&types.Settings{}, nil).
|
Return(&types.Settings{}, nil).
|
||||||
AnyTimes()
|
AnyTimes()
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(str)
|
||||||
accountManager, err := server.BuildManager(
|
accountManager, err := server.BuildManager(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
str,
|
str,
|
||||||
@@ -210,7 +210,7 @@ func startServer(
|
|||||||
metrics,
|
metrics,
|
||||||
port_forwarding.NewControllerMock(),
|
port_forwarding.NewControllerMock(),
|
||||||
settingsMockManager,
|
settingsMockManager,
|
||||||
permissionsManagerMock,
|
permissionsManager,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed creating an account manager: %v", err)
|
t.Fatalf("failed creating an account manager: %v", err)
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ type MockAccountManager struct {
|
|||||||
GetGroupFunc func(ctx context.Context, accountID, groupID, userID string) (*types.Group, error)
|
GetGroupFunc func(ctx context.Context, accountID, groupID, userID string) (*types.Group, error)
|
||||||
GetAllGroupsFunc func(ctx context.Context, accountID, userID string) ([]*types.Group, error)
|
GetAllGroupsFunc func(ctx context.Context, accountID, userID string) ([]*types.Group, error)
|
||||||
GetGroupByNameFunc func(ctx context.Context, accountID, groupName string) (*types.Group, error)
|
GetGroupByNameFunc func(ctx context.Context, accountID, groupName string) (*types.Group, error)
|
||||||
SaveGroupFunc func(ctx context.Context, accountID, userID string, group *types.Group) error
|
SaveGroupFunc func(ctx context.Context, accountID, userID string, group *types.Group, create bool) error
|
||||||
SaveGroupsFunc func(ctx context.Context, accountID, userID string, groups []*types.Group) error
|
SaveGroupsFunc func(ctx context.Context, accountID, userID string, groups []*types.Group, create bool) error
|
||||||
DeleteGroupFunc func(ctx context.Context, accountID, userId, groupID string) error
|
DeleteGroupFunc func(ctx context.Context, accountID, userId, groupID string) error
|
||||||
DeleteGroupsFunc func(ctx context.Context, accountId, userId string, groupIDs []string) error
|
DeleteGroupsFunc func(ctx context.Context, accountId, userId string, groupIDs []string) error
|
||||||
GroupAddPeerFunc func(ctx context.Context, accountID, groupID, peerID string) error
|
GroupAddPeerFunc func(ctx context.Context, accountID, groupID, peerID string) error
|
||||||
@@ -53,7 +53,7 @@ type MockAccountManager struct {
|
|||||||
GetPeerGroupsFunc func(ctx context.Context, accountID, peerID string) ([]*types.Group, error)
|
GetPeerGroupsFunc func(ctx context.Context, accountID, peerID string) ([]*types.Group, error)
|
||||||
DeleteRuleFunc func(ctx context.Context, accountID, ruleID, userID string) error
|
DeleteRuleFunc func(ctx context.Context, accountID, ruleID, userID string) error
|
||||||
GetPolicyFunc func(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error)
|
GetPolicyFunc func(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error)
|
||||||
SavePolicyFunc func(ctx context.Context, accountID, userID string, policy *types.Policy) (*types.Policy, error)
|
SavePolicyFunc func(ctx context.Context, accountID, userID string, policy *types.Policy, create bool) (*types.Policy, error)
|
||||||
DeletePolicyFunc func(ctx context.Context, accountID, policyID, userID string) error
|
DeletePolicyFunc func(ctx context.Context, accountID, policyID, userID string) error
|
||||||
ListPoliciesFunc func(ctx context.Context, accountID, userID string) ([]*types.Policy, error)
|
ListPoliciesFunc func(ctx context.Context, accountID, userID string) ([]*types.Policy, error)
|
||||||
GetUsersFromAccountFunc func(ctx context.Context, accountID, userID string) (map[string]*types.UserInfo, error)
|
GetUsersFromAccountFunc func(ctx context.Context, accountID, userID string) (map[string]*types.UserInfo, error)
|
||||||
@@ -97,7 +97,7 @@ type MockAccountManager struct {
|
|||||||
HasConnectedChannelFunc func(peerID string) bool
|
HasConnectedChannelFunc func(peerID string) bool
|
||||||
GetExternalCacheManagerFunc func() account.ExternalCacheManager
|
GetExternalCacheManagerFunc func() account.ExternalCacheManager
|
||||||
GetPostureChecksFunc func(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error)
|
GetPostureChecksFunc func(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error)
|
||||||
SavePostureChecksFunc func(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error)
|
SavePostureChecksFunc func(ctx context.Context, accountID, userID string, postureChecks *posture.Checks, create bool) (*posture.Checks, error)
|
||||||
DeletePostureChecksFunc func(ctx context.Context, accountID, postureChecksID, userID string) error
|
DeletePostureChecksFunc func(ctx context.Context, accountID, postureChecksID, userID string) error
|
||||||
ListPostureChecksFunc func(ctx context.Context, accountID, userID string) ([]*posture.Checks, error)
|
ListPostureChecksFunc func(ctx context.Context, accountID, userID string) ([]*posture.Checks, error)
|
||||||
GetIdpManagerFunc func() idp.Manager
|
GetIdpManagerFunc func() idp.Manager
|
||||||
@@ -115,6 +115,7 @@ type MockAccountManager struct {
|
|||||||
CreateAccountByPrivateDomainFunc func(ctx context.Context, initiatorId, domain string) (*types.Account, error)
|
CreateAccountByPrivateDomainFunc func(ctx context.Context, initiatorId, domain string) (*types.Account, error)
|
||||||
UpdateToPrimaryAccountFunc func(ctx context.Context, accountId string) (*types.Account, error)
|
UpdateToPrimaryAccountFunc func(ctx context.Context, accountId string) (*types.Account, error)
|
||||||
GetOwnerInfoFunc func(ctx context.Context, accountID string) (*types.UserInfo, error)
|
GetOwnerInfoFunc func(ctx context.Context, accountID string) (*types.UserInfo, error)
|
||||||
|
GetCurrentUserInfoFunc func(ctx context.Context, accountID, userID string) (*types.UserInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (am *MockAccountManager) UpdateAccountPeers(ctx context.Context, accountID string) {
|
func (am *MockAccountManager) UpdateAccountPeers(ctx context.Context, accountID string) {
|
||||||
@@ -322,17 +323,17 @@ func (am *MockAccountManager) GetGroupByName(ctx context.Context, accountID, gro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SaveGroup mock implementation of SaveGroup from server.AccountManager interface
|
// SaveGroup mock implementation of SaveGroup from server.AccountManager interface
|
||||||
func (am *MockAccountManager) SaveGroup(ctx context.Context, accountID, userID string, group *types.Group) error {
|
func (am *MockAccountManager) SaveGroup(ctx context.Context, accountID, userID string, group *types.Group, create bool) error {
|
||||||
if am.SaveGroupFunc != nil {
|
if am.SaveGroupFunc != nil {
|
||||||
return am.SaveGroupFunc(ctx, accountID, userID, group)
|
return am.SaveGroupFunc(ctx, accountID, userID, group, create)
|
||||||
}
|
}
|
||||||
return status.Errorf(codes.Unimplemented, "method SaveGroup is not implemented")
|
return status.Errorf(codes.Unimplemented, "method SaveGroup is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// SaveGroups mock implementation of SaveGroups from server.AccountManager interface
|
// SaveGroups mock implementation of SaveGroups from server.AccountManager interface
|
||||||
func (am *MockAccountManager) SaveGroups(ctx context.Context, accountID, userID string, groups []*types.Group) error {
|
func (am *MockAccountManager) SaveGroups(ctx context.Context, accountID, userID string, groups []*types.Group, create bool) error {
|
||||||
if am.SaveGroupsFunc != nil {
|
if am.SaveGroupsFunc != nil {
|
||||||
return am.SaveGroupsFunc(ctx, accountID, userID, groups)
|
return am.SaveGroupsFunc(ctx, accountID, userID, groups, create)
|
||||||
}
|
}
|
||||||
return status.Errorf(codes.Unimplemented, "method SaveGroups is not implemented")
|
return status.Errorf(codes.Unimplemented, "method SaveGroups is not implemented")
|
||||||
}
|
}
|
||||||
@@ -386,9 +387,9 @@ func (am *MockAccountManager) GetPolicy(ctx context.Context, accountID, policyID
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SavePolicy mock implementation of SavePolicy from server.AccountManager interface
|
// SavePolicy mock implementation of SavePolicy from server.AccountManager interface
|
||||||
func (am *MockAccountManager) SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy) (*types.Policy, error) {
|
func (am *MockAccountManager) SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy, create bool) (*types.Policy, error) {
|
||||||
if am.SavePolicyFunc != nil {
|
if am.SavePolicyFunc != nil {
|
||||||
return am.SavePolicyFunc(ctx, accountID, userID, policy)
|
return am.SavePolicyFunc(ctx, accountID, userID, policy, create)
|
||||||
}
|
}
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method SavePolicy is not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method SavePolicy is not implemented")
|
||||||
}
|
}
|
||||||
@@ -722,9 +723,9 @@ func (am *MockAccountManager) GetPostureChecks(ctx context.Context, accountID, p
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SavePostureChecks mocks SavePostureChecks of the AccountManager interface
|
// SavePostureChecks mocks SavePostureChecks of the AccountManager interface
|
||||||
func (am *MockAccountManager) SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error) {
|
func (am *MockAccountManager) SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks, create bool) (*posture.Checks, error) {
|
||||||
if am.SavePostureChecksFunc != nil {
|
if am.SavePostureChecksFunc != nil {
|
||||||
return am.SavePostureChecksFunc(ctx, accountID, userID, postureChecks)
|
return am.SavePostureChecksFunc(ctx, accountID, userID, postureChecks, create)
|
||||||
}
|
}
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method SavePostureChecks is not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method SavePostureChecks is not implemented")
|
||||||
}
|
}
|
||||||
@@ -871,3 +872,10 @@ func (am *MockAccountManager) GetOwnerInfo(ctx context.Context, accountId string
|
|||||||
}
|
}
|
||||||
return nil, status.Errorf(codes.Unimplemented, "method GetOwnerInfo is not implemented")
|
return nil, status.Errorf(codes.Unimplemented, "method GetOwnerInfo is not implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (am *MockAccountManager) GetCurrentUserInfo(ctx context.Context, accountID, userID string) (*types.UserInfo, error) {
|
||||||
|
if am.GetCurrentUserInfoFunc != nil {
|
||||||
|
return am.GetCurrentUserInfoFunc(ctx, accountID, userID)
|
||||||
|
}
|
||||||
|
return nil, status.Errorf(codes.Unimplemented, "method GetCurrentUserInfo is not implemented")
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ import (
|
|||||||
|
|
||||||
nbdns "github.com/netbirdio/netbird/dns"
|
nbdns "github.com/netbirdio/netbird/dns"
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
@@ -20,17 +22,12 @@ const domainPattern = `^(?i)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$`
|
|||||||
|
|
||||||
// GetNameServerGroup gets a nameserver group object from account and nameserver group IDs
|
// GetNameServerGroup gets a nameserver group object from account and nameserver group IDs
|
||||||
func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) {
|
func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Nameservers, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetNameServerGroupByID(ctx, store.LockingStrengthShare, accountID, nsGroupID)
|
return am.Store.GetNameServerGroupByID(ctx, store.LockingStrengthShare, accountID, nsGroupID)
|
||||||
@@ -41,13 +38,12 @@ func (am *DefaultAccountManager) CreateNameServerGroup(ctx context.Context, acco
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Nameservers, operations.Create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newNSGroup := &nbdns.NameServerGroup{
|
newNSGroup := &nbdns.NameServerGroup{
|
||||||
@@ -103,13 +99,12 @@ func (am *DefaultAccountManager) SaveNameServerGroup(ctx context.Context, accoun
|
|||||||
return status.Errorf(status.InvalidArgument, "nameserver group provided is nil")
|
return status.Errorf(status.InvalidArgument, "nameserver group provided is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Nameservers, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateAccountPeers bool
|
var updateAccountPeers bool
|
||||||
@@ -154,13 +149,12 @@ func (am *DefaultAccountManager) DeleteNameServerGroup(ctx context.Context, acco
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Nameservers, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var nsGroup *nbdns.NameServerGroup
|
var nsGroup *nbdns.NameServerGroup
|
||||||
@@ -198,17 +192,12 @@ func (am *DefaultAccountManager) DeleteNameServerGroup(ctx context.Context, acco
|
|||||||
|
|
||||||
// ListNameServerGroups returns a list of nameserver groups from account
|
// ListNameServerGroups returns a list of nameserver groups from account
|
||||||
func (am *DefaultAccountManager) ListNameServerGroups(ctx context.Context, accountID string, userID string) ([]*nbdns.NameServerGroup, error) {
|
func (am *DefaultAccountManager) ListNameServerGroups(ctx context.Context, accountID string, userID string) ([]*nbdns.NameServerGroup, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Nameservers, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccountNameServerGroups(ctx, store.LockingStrengthShare, accountID)
|
return am.Store.GetAccountNameServerGroups(ctx, store.LockingStrengthShare, accountID)
|
||||||
|
|||||||
@@ -775,12 +775,11 @@ func createNSManager(t *testing.T) (*DefaultAccountManager, error) {
|
|||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
|
permissionsManager := permissions.NewManager(store)
|
||||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNSStore(t *testing.T) (store.Store, error) {
|
func createNSStore(t *testing.T) (store.Store, error) {
|
||||||
@@ -966,7 +965,7 @@ func TestNameServerAccountPeersUpdate(t *testing.T) {
|
|||||||
Name: "GroupB",
|
Name: "GroupB",
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/networks/routers"
|
"github.com/netbirdio/netbird/management/server/networks/routers"
|
||||||
"github.com/netbirdio/netbird/management/server/networks/types"
|
"github.com/netbirdio/netbird/management/server/networks/types"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
)
|
)
|
||||||
@@ -46,7 +48,7 @@ func NewManager(store store.Store, permissionsManager permissions.Manager, resou
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllNetworks(ctx context.Context, accountID, userID string) ([]*types.Network, error) {
|
func (m *managerImpl) GetAllNetworks(ctx context.Context, accountID, userID string) ([]*types.Network, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -58,7 +60,7 @@ func (m *managerImpl) GetAllNetworks(ctx context.Context, accountID, userID stri
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) CreateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) {
|
func (m *managerImpl) CreateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, network.AccountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, network.AccountID, userID, modules.Networks, operations.Create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -82,7 +84,7 @@ func (m *managerImpl) CreateNetwork(ctx context.Context, userID string, network
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetNetwork(ctx context.Context, accountID, userID, networkID string) (*types.Network, error) {
|
func (m *managerImpl) GetNetwork(ctx context.Context, accountID, userID, networkID string) (*types.Network, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -94,7 +96,7 @@ func (m *managerImpl) GetNetwork(ctx context.Context, accountID, userID, network
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) UpdateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) {
|
func (m *managerImpl) UpdateNetwork(ctx context.Context, userID string, network *types.Network) (*types.Network, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, network.AccountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, network.AccountID, userID, modules.Networks, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -116,7 +118,7 @@ func (m *managerImpl) UpdateNetwork(ctx context.Context, userID string, network
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) DeleteNetwork(ctx context.Context, accountID, userID, networkID string) error {
|
func (m *managerImpl) DeleteNetwork(ctx context.Context, accountID, userID, networkID string) error {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.NewPermissionValidationError(err)
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import (
|
|||||||
func Test_GetAllNetworksReturnsNetworks(t *testing.T) {
|
func Test_GetAllNetworksReturnsNetworks(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -26,7 +26,7 @@ func Test_GetAllNetworksReturnsNetworks(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -41,7 +41,7 @@ func Test_GetAllNetworksReturnsNetworks(t *testing.T) {
|
|||||||
func Test_GetAllNetworksReturnsPermissionDenied(t *testing.T) {
|
func Test_GetAllNetworksReturnsPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -49,7 +49,7 @@ func Test_GetAllNetworksReturnsPermissionDenied(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -63,7 +63,7 @@ func Test_GetAllNetworksReturnsPermissionDenied(t *testing.T) {
|
|||||||
func Test_GetNetworkReturnsNetwork(t *testing.T) {
|
func Test_GetNetworkReturnsNetwork(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
||||||
@@ -72,7 +72,7 @@ func Test_GetNetworkReturnsNetwork(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -86,7 +86,7 @@ func Test_GetNetworkReturnsNetwork(t *testing.T) {
|
|||||||
func Test_GetNetworkReturnsPermissionDenied(t *testing.T) {
|
func Test_GetNetworkReturnsPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
||||||
@@ -95,7 +95,7 @@ func Test_GetNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -108,7 +108,7 @@ func Test_GetNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateNetworkSuccessfully(t *testing.T) {
|
func Test_CreateNetworkSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
network := &types.Network{
|
network := &types.Network{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
Name: "new-network",
|
Name: "new-network",
|
||||||
@@ -120,7 +120,7 @@ func Test_CreateNetworkSuccessfully(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -133,7 +133,7 @@ func Test_CreateNetworkSuccessfully(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateNetworkFailsWithPermissionDenied(t *testing.T) {
|
func Test_CreateNetworkFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
network := &types.Network{
|
network := &types.Network{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
Name: "new-network",
|
Name: "new-network",
|
||||||
@@ -145,7 +145,7 @@ func Test_CreateNetworkFailsWithPermissionDenied(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -159,7 +159,7 @@ func Test_CreateNetworkFailsWithPermissionDenied(t *testing.T) {
|
|||||||
func Test_DeleteNetworkSuccessfully(t *testing.T) {
|
func Test_DeleteNetworkSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
||||||
@@ -168,7 +168,7 @@ func Test_DeleteNetworkSuccessfully(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -181,7 +181,7 @@ func Test_DeleteNetworkSuccessfully(t *testing.T) {
|
|||||||
func Test_DeleteNetworkFailsWithPermissionDenied(t *testing.T) {
|
func Test_DeleteNetworkFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../testdata/networks.sql", t.TempDir())
|
||||||
@@ -190,7 +190,7 @@ func Test_DeleteNetworkFailsWithPermissionDenied(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -202,7 +202,7 @@ func Test_DeleteNetworkFailsWithPermissionDenied(t *testing.T) {
|
|||||||
|
|
||||||
func Test_UpdateNetworkSuccessfully(t *testing.T) {
|
func Test_UpdateNetworkSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
network := &types.Network{
|
network := &types.Network{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
ID: "testNetworkId",
|
ID: "testNetworkId",
|
||||||
@@ -215,7 +215,7 @@ func Test_UpdateNetworkSuccessfully(t *testing.T) {
|
|||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
@@ -228,7 +228,7 @@ func Test_UpdateNetworkSuccessfully(t *testing.T) {
|
|||||||
|
|
||||||
func Test_UpdateNetworkFailsWithPermissionDenied(t *testing.T) {
|
func Test_UpdateNetworkFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
network := &types.Network{
|
network := &types.Network{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
ID: "testNetworkId",
|
ID: "testNetworkId",
|
||||||
@@ -242,7 +242,7 @@ func Test_UpdateNetworkFailsWithPermissionDenied(t *testing.T) {
|
|||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
|
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
routerManager := routers.NewManagerMock()
|
routerManager := routers.NewManagerMock()
|
||||||
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
resourcesManager := resources.NewManager(s, permissionsManager, groupsManager, &am)
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/groups"
|
"github.com/netbirdio/netbird/management/server/groups"
|
||||||
"github.com/netbirdio/netbird/management/server/networks/resources/types"
|
"github.com/netbirdio/netbird/management/server/networks/resources/types"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
nbtypes "github.com/netbirdio/netbird/management/server/types"
|
nbtypes "github.com/netbirdio/netbird/management/server/types"
|
||||||
@@ -47,7 +49,7 @@ func NewManager(store store.Store, permissionsManager permissions.Manager, group
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllResourcesInNetwork(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkResource, error) {
|
func (m *managerImpl) GetAllResourcesInNetwork(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkResource, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -59,7 +61,7 @@ func (m *managerImpl) GetAllResourcesInNetwork(ctx context.Context, accountID, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllResourcesInAccount(ctx context.Context, accountID, userID string) ([]*types.NetworkResource, error) {
|
func (m *managerImpl) GetAllResourcesInAccount(ctx context.Context, accountID, userID string) ([]*types.NetworkResource, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -71,7 +73,7 @@ func (m *managerImpl) GetAllResourcesInAccount(ctx context.Context, accountID, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllResourceIDsInAccount(ctx context.Context, accountID, userID string) (map[string][]string, error) {
|
func (m *managerImpl) GetAllResourceIDsInAccount(ctx context.Context, accountID, userID string) (map[string][]string, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -93,7 +95,7 @@ func (m *managerImpl) GetAllResourceIDsInAccount(ctx context.Context, accountID,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) CreateResource(ctx context.Context, userID string, resource *types.NetworkResource) (*types.NetworkResource, error) {
|
func (m *managerImpl) CreateResource(ctx context.Context, userID string, resource *types.NetworkResource) (*types.NetworkResource, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, resource.AccountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, resource.AccountID, userID, modules.Networks, operations.Create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -164,7 +166,7 @@ func (m *managerImpl) CreateResource(ctx context.Context, userID string, resourc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetResource(ctx context.Context, accountID, userID, networkID, resourceID string) (*types.NetworkResource, error) {
|
func (m *managerImpl) GetResource(ctx context.Context, accountID, userID, networkID, resourceID string) (*types.NetworkResource, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -185,7 +187,7 @@ func (m *managerImpl) GetResource(ctx context.Context, accountID, userID, networ
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) UpdateResource(ctx context.Context, userID string, resource *types.NetworkResource) (*types.NetworkResource, error) {
|
func (m *managerImpl) UpdateResource(ctx context.Context, userID string, resource *types.NetworkResource) (*types.NetworkResource, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, resource.AccountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, resource.AccountID, userID, modules.Networks, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -305,7 +307,7 @@ func (m *managerImpl) updateResourceGroups(ctx context.Context, transaction stor
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) DeleteResource(ctx context.Context, accountID, userID, networkID, resourceID string) error {
|
func (m *managerImpl) DeleteResource(ctx context.Context, accountID, userID, networkID, resourceID string) error {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.NewPermissionValidationError(err)
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import (
|
|||||||
func Test_GetAllResourcesInNetworkReturnsResources(t *testing.T) {
|
func Test_GetAllResourcesInNetworkReturnsResources(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
||||||
@@ -25,7 +25,7 @@ func Test_GetAllResourcesInNetworkReturnsResources(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -38,7 +38,7 @@ func Test_GetAllResourcesInNetworkReturnsResources(t *testing.T) {
|
|||||||
func Test_GetAllResourcesInNetworkReturnsPermissionDenied(t *testing.T) {
|
func Test_GetAllResourcesInNetworkReturnsPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
||||||
@@ -46,7 +46,7 @@ func Test_GetAllResourcesInNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -59,14 +59,14 @@ func Test_GetAllResourcesInNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
func Test_GetAllResourcesInAccountReturnsResources(t *testing.T) {
|
func Test_GetAllResourcesInAccountReturnsResources(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
|
|
||||||
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -79,14 +79,14 @@ func Test_GetAllResourcesInAccountReturnsResources(t *testing.T) {
|
|||||||
func Test_GetAllResourcesInAccountReturnsPermissionDenied(t *testing.T) {
|
func Test_GetAllResourcesInAccountReturnsPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
|
|
||||||
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
store, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -100,7 +100,7 @@ func Test_GetAllResourcesInAccountReturnsPermissionDenied(t *testing.T) {
|
|||||||
func Test_GetResourceInNetworkReturnsResources(t *testing.T) {
|
func Test_GetResourceInNetworkReturnsResources(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testResourceId"
|
resourceID := "testResourceId"
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ func Test_GetResourceInNetworkReturnsResources(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -122,7 +122,7 @@ func Test_GetResourceInNetworkReturnsResources(t *testing.T) {
|
|||||||
func Test_GetResourceInNetworkReturnsPermissionDenied(t *testing.T) {
|
func Test_GetResourceInNetworkReturnsPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testResourceId"
|
resourceID := "testResourceId"
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ func Test_GetResourceInNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -144,7 +144,7 @@ func Test_GetResourceInNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateResourceSuccessfully(t *testing.T) {
|
func Test_CreateResourceSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
NetworkID: "testNetworkId",
|
NetworkID: "testNetworkId",
|
||||||
@@ -158,7 +158,7 @@ func Test_CreateResourceSuccessfully(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -170,7 +170,7 @@ func Test_CreateResourceSuccessfully(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateResourceFailsWithPermissionDenied(t *testing.T) {
|
func Test_CreateResourceFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
NetworkID: "testNetworkId",
|
NetworkID: "testNetworkId",
|
||||||
@@ -184,7 +184,7 @@ func Test_CreateResourceFailsWithPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -197,7 +197,7 @@ func Test_CreateResourceFailsWithPermissionDenied(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateResourceFailsWithInvalidAddress(t *testing.T) {
|
func Test_CreateResourceFailsWithInvalidAddress(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
NetworkID: "testNetworkId",
|
NetworkID: "testNetworkId",
|
||||||
@@ -211,7 +211,7 @@ func Test_CreateResourceFailsWithInvalidAddress(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -223,7 +223,7 @@ func Test_CreateResourceFailsWithInvalidAddress(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateResourceFailsWithUsedName(t *testing.T) {
|
func Test_CreateResourceFailsWithUsedName(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
AccountID: "testAccountId",
|
AccountID: "testAccountId",
|
||||||
NetworkID: "testNetworkId",
|
NetworkID: "testNetworkId",
|
||||||
@@ -237,7 +237,7 @@ func Test_CreateResourceFailsWithUsedName(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -250,7 +250,7 @@ func Test_CreateResourceFailsWithUsedName(t *testing.T) {
|
|||||||
func Test_UpdateResourceSuccessfully(t *testing.T) {
|
func Test_UpdateResourceSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testResourceId"
|
resourceID := "testResourceId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
@@ -267,7 +267,7 @@ func Test_UpdateResourceSuccessfully(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -283,7 +283,7 @@ func Test_UpdateResourceSuccessfully(t *testing.T) {
|
|||||||
func Test_UpdateResourceFailsWithResourceNotFound(t *testing.T) {
|
func Test_UpdateResourceFailsWithResourceNotFound(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "otherResourceId"
|
resourceID := "otherResourceId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
@@ -299,7 +299,7 @@ func Test_UpdateResourceFailsWithResourceNotFound(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -312,7 +312,7 @@ func Test_UpdateResourceFailsWithResourceNotFound(t *testing.T) {
|
|||||||
func Test_UpdateResourceFailsWithNameInUse(t *testing.T) {
|
func Test_UpdateResourceFailsWithNameInUse(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testResourceId"
|
resourceID := "testResourceId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
@@ -329,7 +329,7 @@ func Test_UpdateResourceFailsWithNameInUse(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -342,7 +342,7 @@ func Test_UpdateResourceFailsWithNameInUse(t *testing.T) {
|
|||||||
func Test_UpdateResourceFailsWithPermissionDenied(t *testing.T) {
|
func Test_UpdateResourceFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testResourceId"
|
resourceID := "testResourceId"
|
||||||
resource := &types.NetworkResource{
|
resource := &types.NetworkResource{
|
||||||
@@ -358,7 +358,7 @@ func Test_UpdateResourceFailsWithPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -371,7 +371,7 @@ func Test_UpdateResourceFailsWithPermissionDenied(t *testing.T) {
|
|||||||
func Test_DeleteResourceSuccessfully(t *testing.T) {
|
func Test_DeleteResourceSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testResourceId"
|
resourceID := "testResourceId"
|
||||||
|
|
||||||
@@ -380,7 +380,7 @@ func Test_DeleteResourceSuccessfully(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
@@ -392,7 +392,7 @@ func Test_DeleteResourceSuccessfully(t *testing.T) {
|
|||||||
func Test_DeleteResourceFailsWithPermissionDenied(t *testing.T) {
|
func Test_DeleteResourceFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testResourceId"
|
resourceID := "testResourceId"
|
||||||
|
|
||||||
@@ -401,7 +401,7 @@ func Test_DeleteResourceFailsWithPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(store)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
groupsManager := groups.NewManagerMock()
|
groupsManager := groups.NewManagerMock()
|
||||||
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
manager := NewManager(store, permissionsManager, groupsManager, &am)
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/networks/routers/types"
|
"github.com/netbirdio/netbird/management/server/networks/routers/types"
|
||||||
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
|
networkTypes "github.com/netbirdio/netbird/management/server/networks/types"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
)
|
)
|
||||||
@@ -44,7 +46,7 @@ func NewManager(store store.Store, permissionsManager permissions.Manager, accou
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllRoutersInNetwork(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkRouter, error) {
|
func (m *managerImpl) GetAllRoutersInNetwork(ctx context.Context, accountID, userID, networkID string) ([]*types.NetworkRouter, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ func (m *managerImpl) GetAllRoutersInNetwork(ctx context.Context, accountID, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllRoutersInAccount(ctx context.Context, accountID, userID string) (map[string][]*types.NetworkRouter, error) {
|
func (m *managerImpl) GetAllRoutersInAccount(ctx context.Context, accountID, userID string) (map[string][]*types.NetworkRouter, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -78,7 +80,7 @@ func (m *managerImpl) GetAllRoutersInAccount(ctx context.Context, accountID, use
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) CreateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) {
|
func (m *managerImpl) CreateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, modules.Networks, operations.Create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -126,7 +128,7 @@ func (m *managerImpl) CreateRouter(ctx context.Context, userID string, router *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetRouter(ctx context.Context, accountID, userID, networkID, routerID string) (*types.NetworkRouter, error) {
|
func (m *managerImpl) GetRouter(ctx context.Context, accountID, userID, networkID, routerID string) (*types.NetworkRouter, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -147,7 +149,7 @@ func (m *managerImpl) GetRouter(ctx context.Context, accountID, userID, networkI
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) UpdateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) {
|
func (m *managerImpl) UpdateRouter(ctx context.Context, userID string, router *types.NetworkRouter) (*types.NetworkRouter, error) {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, router.AccountID, userID, modules.Networks, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
@@ -193,7 +195,7 @@ func (m *managerImpl) UpdateRouter(ctx context.Context, userID string, router *t
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) DeleteRouter(ctx context.Context, accountID, userID, networkID, routerID string) error {
|
func (m *managerImpl) DeleteRouter(ctx context.Context, accountID, userID, networkID, routerID string) error {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Networks, permissions.Write)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Networks, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status.NewPermissionValidationError(err)
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import (
|
|||||||
func Test_GetAllRoutersInNetworkReturnsRouters(t *testing.T) {
|
func Test_GetAllRoutersInNetworkReturnsRouters(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
||||||
@@ -24,7 +24,7 @@ func Test_GetAllRoutersInNetworkReturnsRouters(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ func Test_GetAllRoutersInNetworkReturnsRouters(t *testing.T) {
|
|||||||
func Test_GetAllRoutersInNetworkReturnsPermissionDenied(t *testing.T) {
|
func Test_GetAllRoutersInNetworkReturnsPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
|
|
||||||
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
s, cleanUp, err := store.NewTestStoreFromSQL(context.Background(), "../../testdata/networks.sql", t.TempDir())
|
||||||
@@ -45,7 +45,7 @@ func Test_GetAllRoutersInNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ func Test_GetAllRoutersInNetworkReturnsPermissionDenied(t *testing.T) {
|
|||||||
func Test_GetRouterReturnsRouter(t *testing.T) {
|
func Test_GetRouterReturnsRouter(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testRouterId"
|
resourceID := "testRouterId"
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ func Test_GetRouterReturnsRouter(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ func Test_GetRouterReturnsRouter(t *testing.T) {
|
|||||||
func Test_GetRouterReturnsPermissionDenied(t *testing.T) {
|
func Test_GetRouterReturnsPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
resourceID := "testRouterId"
|
resourceID := "testRouterId"
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ func Test_GetRouterReturnsPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ func Test_GetRouterReturnsPermissionDenied(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateRouterSuccessfully(t *testing.T) {
|
func Test_CreateRouterSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 9999, true)
|
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 9999, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -111,7 +111,7 @@ func Test_CreateRouterSuccessfully(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ func Test_CreateRouterSuccessfully(t *testing.T) {
|
|||||||
|
|
||||||
func Test_CreateRouterFailsWithPermissionDenied(t *testing.T) {
|
func Test_CreateRouterFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 9999, true)
|
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 9999, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -137,7 +137,7 @@ func Test_CreateRouterFailsWithPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ func Test_CreateRouterFailsWithPermissionDenied(t *testing.T) {
|
|||||||
func Test_DeleteRouterSuccessfully(t *testing.T) {
|
func Test_DeleteRouterSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
routerID := "testRouterId"
|
routerID := "testRouterId"
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ func Test_DeleteRouterSuccessfully(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ func Test_DeleteRouterSuccessfully(t *testing.T) {
|
|||||||
func Test_DeleteRouterFailsWithPermissionDenied(t *testing.T) {
|
func Test_DeleteRouterFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
accountID := "testAccountId"
|
accountID := "testAccountId"
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
networkID := "testNetworkId"
|
networkID := "testNetworkId"
|
||||||
routerID := "testRouterId"
|
routerID := "testRouterId"
|
||||||
|
|
||||||
@@ -179,7 +179,7 @@ func Test_DeleteRouterFailsWithPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ func Test_DeleteRouterFailsWithPermissionDenied(t *testing.T) {
|
|||||||
|
|
||||||
func Test_UpdateRouterSuccessfully(t *testing.T) {
|
func Test_UpdateRouterSuccessfully(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "allowedUser"
|
userID := "testAdminId"
|
||||||
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 1, true)
|
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 1, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -201,7 +201,7 @@ func Test_UpdateRouterSuccessfully(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ func Test_UpdateRouterSuccessfully(t *testing.T) {
|
|||||||
|
|
||||||
func Test_UpdateRouterFailsWithPermissionDenied(t *testing.T) {
|
func Test_UpdateRouterFailsWithPermissionDenied(t *testing.T) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
userID := "invalidUser"
|
userID := "testUserId"
|
||||||
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 1, true)
|
router, err := types.NewNetworkRouter("testAccountId", "testNetworkId", "testPeerId", []string{}, false, 1, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -223,7 +223,7 @@ func Test_UpdateRouterFailsWithPermissionDenied(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
t.Cleanup(cleanUp)
|
t.Cleanup(cleanUp)
|
||||||
permissionsManager := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am := mock_server.MockAccountManager{}
|
am := mock_server.MockAccountManager{}
|
||||||
manager := NewManager(s, permissionsManager, &am)
|
manager := NewManager(s, permissionsManager, &am)
|
||||||
|
|
||||||
|
|||||||
+73
-56
@@ -17,6 +17,8 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/management/domain"
|
"github.com/netbirdio/netbird/management/domain"
|
||||||
"github.com/netbirdio/netbird/management/server/geolocation"
|
"github.com/netbirdio/netbird/management/server/geolocation"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/idp"
|
"github.com/netbirdio/netbird/management/server/idp"
|
||||||
"github.com/netbirdio/netbird/management/server/posture"
|
"github.com/netbirdio/netbird/management/server/posture"
|
||||||
@@ -37,17 +39,9 @@ func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Read)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() && settings.RegularUsersViewBlocked {
|
|
||||||
return []*nbpeer.Peer{}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
accountPeers, err := am.Store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, nameFilter, ipFilter)
|
accountPeers, err := am.Store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, nameFilter, ipFilter)
|
||||||
@@ -67,10 +61,23 @@ func (am *DefaultAccountManager) GetPeers(ctx context.Context, accountID, userID
|
|||||||
peersMap[peer.ID] = peer
|
peersMap[peer.ID] = peer
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.IsAdminOrServiceUser() {
|
if allowed {
|
||||||
return peers, nil
|
return peers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get account settings: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if settings.RegularUsersViewBlocked {
|
||||||
|
return []*nbpeer.Peer{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return am.getUserAccessiblePeers(ctx, accountID, peersMap, peers)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (am *DefaultAccountManager) getUserAccessiblePeers(ctx context.Context, accountID string, peersMap map[string]*nbpeer.Peer, peers []*nbpeer.Peer) ([]*nbpeer.Peer, error) {
|
||||||
account, err := am.requestBuffer.GetAccountWithBackpressure(ctx, accountID)
|
account, err := am.requestBuffer.GetAccountWithBackpressure(ctx, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -135,7 +142,7 @@ func (am *DefaultAccountManager) MarkPeerConnected(ctx context.Context, peerPubK
|
|||||||
if expired {
|
if expired {
|
||||||
// we need to update other peers because when peer login expires all other peers are notified to disconnect from
|
// we need to update other peers because when peer login expires all other peers are notified to disconnect from
|
||||||
// the expired one. Here we notify them that connection is now allowed again.
|
// the expired one. Here we notify them that connection is now allowed again.
|
||||||
am.UpdateAccountPeers(ctx, accountID)
|
am.BufferUpdateAccountPeers(ctx, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -183,13 +190,12 @@ func (am *DefaultAccountManager) UpdatePeer(ctx context.Context, accountID, user
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var peer *nbpeer.Peer
|
var peer *nbpeer.Peer
|
||||||
@@ -315,15 +321,12 @@ func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peer
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
if userID != activity.SystemInitiator {
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Delete)
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
if err != nil {
|
||||||
if err != nil {
|
return status.NewPermissionValidationError(err)
|
||||||
return err
|
}
|
||||||
}
|
if !allowed {
|
||||||
|
return status.NewPermissionDeniedError()
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
peerAccountID, err := am.Store.GetAccountIDByPeerID(ctx, store.LockingStrengthShare, peerID)
|
peerAccountID, err := am.Store.GetAccountIDByPeerID(ctx, store.LockingStrengthShare, peerID)
|
||||||
@@ -383,7 +386,7 @@ func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peer
|
|||||||
}
|
}
|
||||||
|
|
||||||
if updateAccountPeers {
|
if updateAccountPeers {
|
||||||
am.UpdateAccountPeers(ctx, accountID)
|
am.BufferUpdateAccountPeers(ctx, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -653,7 +656,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
|
|||||||
unlock = nil
|
unlock = nil
|
||||||
|
|
||||||
if updateAccountPeers {
|
if updateAccountPeers {
|
||||||
am.UpdateAccountPeers(ctx, accountID)
|
am.BufferUpdateAccountPeers(ctx, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.getValidatedPeerWithMap(ctx, false, accountID, newPeer)
|
return am.getValidatedPeerWithMap(ctx, false, accountID, newPeer)
|
||||||
@@ -748,7 +751,7 @@ func (am *DefaultAccountManager) SyncPeer(ctx context.Context, sync types.PeerSy
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isStatusChanged || sync.UpdateAccountPeers || (updated && len(postureChecks) > 0) {
|
if isStatusChanged || sync.UpdateAccountPeers || (updated && len(postureChecks) > 0) {
|
||||||
am.UpdateAccountPeers(ctx, accountID)
|
am.BufferUpdateAccountPeers(ctx, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.getValidatedPeerWithMap(ctx, peerNotValid, accountID, peer)
|
return am.getValidatedPeerWithMap(ctx, peerNotValid, accountID, peer)
|
||||||
@@ -893,7 +896,7 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login types.Peer
|
|||||||
unlockPeer = nil
|
unlockPeer = nil
|
||||||
|
|
||||||
if updateRemotePeers || isStatusChanged || (isPeerUpdated && len(postureChecks) > 0) {
|
if updateRemotePeers || isStatusChanged || (isPeerUpdated && len(postureChecks) > 0) {
|
||||||
am.UpdateAccountPeers(ctx, accountID)
|
am.BufferUpdateAccountPeers(ctx, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.getValidatedPeerWithMap(ctx, isRequiresApproval, accountID, peer)
|
return am.getValidatedPeerWithMap(ctx, isRequiresApproval, accountID, peer)
|
||||||
@@ -1094,41 +1097,33 @@ func peerLoginExpired(ctx context.Context, peer *nbpeer.Peer, settings *types.Se
|
|||||||
|
|
||||||
// GetPeer for a given accountID, peerID and userID error if not found.
|
// GetPeer for a given accountID, peerID and userID error if not found.
|
||||||
func (am *DefaultAccountManager) GetPeer(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error) {
|
func (am *DefaultAccountManager) GetPeer(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
settings, err := am.Store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() && settings.RegularUsersViewBlocked {
|
|
||||||
return nil, status.Errorf(status.Internal, "user %s has no access to his own peer %s under account %s", userID, peerID, accountID)
|
|
||||||
}
|
|
||||||
|
|
||||||
peer, err := am.Store.GetPeerByID(ctx, store.LockingStrengthShare, accountID, peerID)
|
peer, err := am.Store.GetPeerByID(ctx, store.LockingStrengthShare, accountID, peerID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Read)
|
||||||
|
if err != nil {
|
||||||
|
return nil, status.NewPermissionValidationError(err)
|
||||||
|
}
|
||||||
|
if allowed {
|
||||||
|
return peer, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// if admin or user owns this peer, return peer
|
// if admin or user owns this peer, return peer
|
||||||
if user.IsAdminOrServiceUser() || peer.UserID == userID {
|
if user.IsAdminOrServiceUser() || peer.UserID == userID {
|
||||||
return peer, nil
|
return peer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// it is also possible that user doesn't own the peer but some of his peers have access to it,
|
return am.checkIfUserOwnsPeer(ctx, accountID, userID, peer)
|
||||||
// this is a valid case, show the peer as well.
|
}
|
||||||
userPeers, err := am.Store.GetUserPeers(ctx, store.LockingStrengthShare, accountID, userID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func (am *DefaultAccountManager) checkIfUserOwnsPeer(ctx context.Context, accountID, userID string, peer *nbpeer.Peer) (*nbpeer.Peer, error) {
|
||||||
account, err := am.requestBuffer.GetAccountWithBackpressure(ctx, accountID)
|
account, err := am.requestBuffer.GetAccountWithBackpressure(ctx, accountID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -1139,16 +1134,23 @@ func (am *DefaultAccountManager) GetPeer(ctx context.Context, accountID, peerID,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// it is also possible that user doesn't own the peer but some of his peers have access to it,
|
||||||
|
// this is a valid case, show the peer as well.
|
||||||
|
userPeers, err := am.Store.GetUserPeers(ctx, store.LockingStrengthShare, accountID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
for _, p := range userPeers {
|
for _, p := range userPeers {
|
||||||
aclPeers, _ := account.GetPeerConnectionResources(ctx, p.ID, approvedPeersMap)
|
aclPeers, _ := account.GetPeerConnectionResources(ctx, p.ID, approvedPeersMap)
|
||||||
for _, aclPeer := range aclPeers {
|
for _, aclPeer := range aclPeers {
|
||||||
if aclPeer.ID == peerID {
|
if aclPeer.ID == peer.ID {
|
||||||
return peer, nil
|
return peer, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, status.Errorf(status.Internal, "user %s has no access to peer %s under account %s", userID, peerID, accountID)
|
return nil, status.Errorf(status.Internal, "user %s has no access to peer %s under account %s", userID, peer.ID, accountID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateAccountPeers updates all peers that belong to an account.
|
// UpdateAccountPeers updates all peers that belong to an account.
|
||||||
@@ -1226,6 +1228,21 @@ func (am *DefaultAccountManager) UpdateAccountPeers(ctx context.Context, account
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (am *DefaultAccountManager) BufferUpdateAccountPeers(ctx context.Context, accountID string) {
|
||||||
|
mu, _ := am.accountUpdateLocks.LoadOrStore(accountID, &sync.Mutex{})
|
||||||
|
lock := mu.(*sync.Mutex)
|
||||||
|
|
||||||
|
if !lock.TryLock() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
time.Sleep(time.Duration(am.updateAccountPeersBufferInterval.Load()))
|
||||||
|
lock.Unlock()
|
||||||
|
am.UpdateAccountPeers(ctx, accountID)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
// UpdateAccountPeer updates a single peer that belongs to an account.
|
// UpdateAccountPeer updates a single peer that belongs to an account.
|
||||||
// Should be called when changes need to be synced to a specific peer only.
|
// Should be called when changes need to be synced to a specific peer only.
|
||||||
func (am *DefaultAccountManager) UpdateAccountPeer(ctx context.Context, accountId string, peerId string) {
|
func (am *DefaultAccountManager) UpdateAccountPeer(ctx context.Context, accountId string, peerId string) {
|
||||||
|
|||||||
@@ -303,12 +303,12 @@ func TestAccountManager_GetNetworkMapWithPolicy(t *testing.T) {
|
|||||||
group1.Peers = append(group1.Peers, peer1.ID)
|
group1.Peers = append(group1.Peers, peer1.ID)
|
||||||
group2.Peers = append(group2.Peers, peer2.ID)
|
group2.Peers = append(group2.Peers, peer2.ID)
|
||||||
|
|
||||||
err = manager.SaveGroup(context.Background(), account.Id, userID, &group1)
|
err = manager.SaveGroup(context.Background(), account.Id, userID, &group1, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expecting group1 to be added, got failure %v", err)
|
t.Errorf("expecting group1 to be added, got failure %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = manager.SaveGroup(context.Background(), account.Id, userID, &group2)
|
err = manager.SaveGroup(context.Background(), account.Id, userID, &group2, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expecting group2 to be added, got failure %v", err)
|
t.Errorf("expecting group2 to be added, got failure %v", err)
|
||||||
return
|
return
|
||||||
@@ -327,7 +327,7 @@ func TestAccountManager_GetNetworkMapWithPolicy(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy)
|
policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expecting rule to be added, got failure %v", err)
|
t.Errorf("expecting rule to be added, got failure %v", err)
|
||||||
return
|
return
|
||||||
@@ -375,7 +375,7 @@ func TestAccountManager_GetNetworkMapWithPolicy(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
policy.Enabled = false
|
policy.Enabled = false
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy)
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("expecting rule to be added, got failure %v", err)
|
t.Errorf("expecting rule to be added, got failure %v", err)
|
||||||
return
|
return
|
||||||
@@ -1264,9 +1264,9 @@ func Test_RegisterPeerByUser(t *testing.T) {
|
|||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
|
permissionsManager := permissions.NewManager(s)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
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)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
@@ -1333,9 +1333,9 @@ func Test_RegisterPeerBySetupKey(t *testing.T) {
|
|||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
|
permissionsManager := permissions.NewManager(s)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
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)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
@@ -1406,8 +1406,9 @@ func Test_RegisterPeerRollbackOnFailure(t *testing.T) {
|
|||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
settingsMockManager := settings.NewMockManager(ctrl)
|
settingsMockManager := settings.NewMockManager(ctrl)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
permissionsManager := permissions.NewManager(s)
|
||||||
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
|
||||||
|
am, err := BuildManager(context.Background(), s, NewPeersUpdateManager(nil), nil, "", "netbird.cloud", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
existingAccountID := "bf1c8084-ba50-4ce7-9439-34653001fc3b"
|
||||||
@@ -1477,7 +1478,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
|
|||||||
Name: "GroupC",
|
Name: "GroupC",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// create a user with auto groups
|
// create a user with auto groups
|
||||||
@@ -1653,7 +1654,7 @@ func TestPeerAccountPeersUpdate(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/peer"
|
"github.com/netbirdio/netbird/management/server/peer"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
)
|
)
|
||||||
@@ -31,7 +33,7 @@ func NewManager(store store.Store, permissionsManager permissions.Manager) Manag
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetPeer(ctx context.Context, accountID, userID, peerID string) (*peer.Peer, error) {
|
func (m *managerImpl) GetPeer(ctx context.Context, accountID, userID, peerID string) (*peer.Peer, error) {
|
||||||
allowed, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Peers, permissions.Read)
|
allowed, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
|
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
|
||||||
}
|
}
|
||||||
@@ -44,13 +46,13 @@ func (m *managerImpl) GetPeer(ctx context.Context, accountID, userID, peerID str
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) GetAllPeers(ctx context.Context, accountID, userID string) ([]*peer.Peer, error) {
|
func (m *managerImpl) GetAllPeers(ctx context.Context, accountID, userID string) ([]*peer.Peer, error) {
|
||||||
allowed, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Peers, permissions.Read)
|
allowed, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Peers, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
|
return nil, fmt.Errorf("failed to validate user permissions: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !allowed {
|
if !allowed {
|
||||||
return nil, status.NewPermissionDeniedError()
|
return m.store.GetUserPeers(ctx, store.LockingStrengthShare, accountID, userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
return m.store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "")
|
return m.store.GetAccountPeers(ctx, store.LockingStrengthShare, accountID, "", "")
|
||||||
|
|||||||
@@ -1,34 +1,24 @@
|
|||||||
package permissions
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
"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"
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"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 {
|
type Manager interface {
|
||||||
ValidateUserPermissions(ctx context.Context, accountID, userID string, module Module, operation Operation) (bool, error)
|
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
|
ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,16 +26,23 @@ type managerImpl struct {
|
|||||||
store store.Store
|
store store.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
type managerMock struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewManager(store store.Store) Manager {
|
func NewManager(store store.Store) Manager {
|
||||||
return &managerImpl{
|
return &managerImpl{
|
||||||
store: store,
|
store: store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) ValidateUserPermissions(ctx context.Context, accountID, userID string, module Module, operation Operation) (bool, error) {
|
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.store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
user, err := m.store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
@@ -55,49 +52,42 @@ func (m *managerImpl) ValidateUserPermissions(ctx context.Context, accountID, us
|
|||||||
return false, status.NewUserNotFoundError(userID)
|
return false, status.NewUserNotFoundError(userID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.IsBlocked() {
|
||||||
|
return false, status.NewUserBlockedError()
|
||||||
|
}
|
||||||
|
|
||||||
if err := m.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
if err := m.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch module {
|
if operation == operations.Read && user.IsServiceUser {
|
||||||
case Accounts:
|
return true, nil // this should be replaced by proper granular access role
|
||||||
if operation == Write && user.Role != types.UserRoleOwner {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch user.Role {
|
role, ok := roles.RolesMap[user.Role]
|
||||||
case types.UserRoleAdmin, types.UserRoleOwner:
|
if !ok {
|
||||||
return true, nil
|
return false, status.NewUserRoleNotFoundError(string(user.Role))
|
||||||
case types.UserRoleUser:
|
|
||||||
return m.validateRegularUserPermissions(ctx, accountID, module, operation)
|
|
||||||
case types.UserRoleBillingAdmin:
|
|
||||||
return false, nil
|
|
||||||
default:
|
|
||||||
return false, errors.New("invalid role")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return m.ValidateRoleModuleAccess(ctx, accountID, role, module, operation), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *managerImpl) validateRegularUserPermissions(ctx context.Context, accountID string, module Module, operation Operation) (bool, error) {
|
func (m *managerImpl) ValidateRoleModuleAccess(
|
||||||
settings, err := m.store.GetAccountSettings(ctx, store.LockingStrengthShare, accountID)
|
ctx context.Context,
|
||||||
if err != nil {
|
accountID string,
|
||||||
return false, fmt.Errorf("failed to get settings: %w", err)
|
role roles.RolePermissions,
|
||||||
}
|
module modules.Module,
|
||||||
if settings.RegularUsersViewBlocked {
|
operation operations.Operation,
|
||||||
return false, nil
|
) 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
|
||||||
}
|
}
|
||||||
|
|
||||||
if operation == Write {
|
return role.AutoAllowNew[operation]
|
||||||
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 {
|
func (m *managerImpl) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error {
|
||||||
@@ -106,24 +96,3 @@ func (m *managerImpl) ValidateAccountAccess(ctx context.Context, accountID strin
|
|||||||
}
|
}
|
||||||
return nil
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
// Code generated by MockGen. DO NOT EDIT.
|
||||||
|
// Source: ./manager.go
|
||||||
|
|
||||||
|
// Package permissions is a generated GoMock package.
|
||||||
|
package permissions
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
reflect "reflect"
|
||||||
|
|
||||||
|
gomock "github.com/golang/mock/gomock"
|
||||||
|
modules "github.com/netbirdio/netbird/management/server/permissions/modules"
|
||||||
|
operations "github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
|
roles "github.com/netbirdio/netbird/management/server/permissions/roles"
|
||||||
|
types "github.com/netbirdio/netbird/management/server/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MockManager is a mock of Manager interface.
|
||||||
|
type MockManager struct {
|
||||||
|
ctrl *gomock.Controller
|
||||||
|
recorder *MockManagerMockRecorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// MockManagerMockRecorder is the mock recorder for MockManager.
|
||||||
|
type MockManagerMockRecorder struct {
|
||||||
|
mock *MockManager
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMockManager creates a new mock instance.
|
||||||
|
func NewMockManager(ctrl *gomock.Controller) *MockManager {
|
||||||
|
mock := &MockManager{ctrl: ctrl}
|
||||||
|
mock.recorder = &MockManagerMockRecorder{mock}
|
||||||
|
return mock
|
||||||
|
}
|
||||||
|
|
||||||
|
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||||
|
func (m *MockManager) EXPECT() *MockManagerMockRecorder {
|
||||||
|
return m.recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAccountAccess mocks base method.
|
||||||
|
func (m *MockManager) ValidateAccountAccess(ctx context.Context, accountID string, user *types.User, allowOwnerAndAdmin bool) error {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ValidateAccountAccess", ctx, accountID, user, allowOwnerAndAdmin)
|
||||||
|
ret0, _ := ret[0].(error)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateAccountAccess indicates an expected call of ValidateAccountAccess.
|
||||||
|
func (mr *MockManagerMockRecorder) ValidateAccountAccess(ctx, accountID, user, allowOwnerAndAdmin interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAccountAccess", reflect.TypeOf((*MockManager)(nil).ValidateAccountAccess), ctx, accountID, user, allowOwnerAndAdmin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateRoleModuleAccess mocks base method.
|
||||||
|
func (m *MockManager) ValidateRoleModuleAccess(ctx context.Context, accountID string, role roles.RolePermissions, module modules.Module, operation operations.Operation) bool {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ValidateRoleModuleAccess", ctx, accountID, role, module, operation)
|
||||||
|
ret0, _ := ret[0].(bool)
|
||||||
|
return ret0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateRoleModuleAccess indicates an expected call of ValidateRoleModuleAccess.
|
||||||
|
func (mr *MockManagerMockRecorder) ValidateRoleModuleAccess(ctx, accountID, role, module, operation interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRoleModuleAccess", reflect.TypeOf((*MockManager)(nil).ValidateRoleModuleAccess), ctx, accountID, role, module, operation)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUserPermissions mocks base method.
|
||||||
|
func (m *MockManager) ValidateUserPermissions(ctx context.Context, accountID, userID string, module modules.Module, operation operations.Operation) (bool, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "ValidateUserPermissions", ctx, accountID, userID, module, operation)
|
||||||
|
ret0, _ := ret[0].(bool)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// ValidateUserPermissions indicates an expected call of ValidateUserPermissions.
|
||||||
|
func (mr *MockManagerMockRecorder) ValidateUserPermissions(ctx, accountID, userID, module, operation interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateUserPermissions", reflect.TypeOf((*MockManager)(nil).ValidateUserPermissions), ctx, accountID, userID, module, operation)
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package modules
|
||||||
|
|
||||||
|
type Module string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Networks Module = "networks"
|
||||||
|
Peers Module = "peers"
|
||||||
|
Groups Module = "groups"
|
||||||
|
Settings Module = "settings"
|
||||||
|
Accounts Module = "accounts"
|
||||||
|
Dns Module = "dns"
|
||||||
|
Nameservers Module = "nameservers"
|
||||||
|
Events Module = "events"
|
||||||
|
Policies Module = "policies"
|
||||||
|
Routes Module = "routes"
|
||||||
|
Users Module = "users"
|
||||||
|
SetupKeys Module = "setup_keys"
|
||||||
|
Pats Module = "pats"
|
||||||
|
)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package operations
|
||||||
|
|
||||||
|
type Operation string
|
||||||
|
|
||||||
|
const (
|
||||||
|
Create Operation = "create"
|
||||||
|
Read Operation = "read"
|
||||||
|
Update Operation = "update"
|
||||||
|
Delete Operation = "delete"
|
||||||
|
)
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Admin = RolePermissions{
|
||||||
|
Role: types.UserRoleAdmin,
|
||||||
|
AutoAllowNew: map[operations.Operation]bool{
|
||||||
|
operations.Read: true,
|
||||||
|
operations.Create: true,
|
||||||
|
operations.Update: true,
|
||||||
|
operations.Delete: true,
|
||||||
|
},
|
||||||
|
Permissions: Permissions{
|
||||||
|
modules.Accounts: {
|
||||||
|
operations.Read: true,
|
||||||
|
operations.Create: false,
|
||||||
|
operations.Update: false,
|
||||||
|
operations.Delete: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Owner = RolePermissions{
|
||||||
|
Role: types.UserRoleOwner,
|
||||||
|
AutoAllowNew: map[operations.Operation]bool{
|
||||||
|
operations.Read: true,
|
||||||
|
operations.Create: true,
|
||||||
|
operations.Update: true,
|
||||||
|
operations.Delete: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/modules"
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RolePermissions struct {
|
||||||
|
Role types.UserRole
|
||||||
|
Permissions Permissions
|
||||||
|
AutoAllowNew map[operations.Operation]bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Permissions map[modules.Module]map[operations.Operation]bool
|
||||||
|
|
||||||
|
var RolesMap = map[types.UserRole]RolePermissions{
|
||||||
|
types.UserRoleOwner: Owner,
|
||||||
|
types.UserRoleAdmin: Admin,
|
||||||
|
types.UserRoleUser: User,
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package roles
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/netbirdio/netbird/management/server/permissions/operations"
|
||||||
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
var User = RolePermissions{
|
||||||
|
Role: types.UserRoleUser,
|
||||||
|
AutoAllowNew: map[operations.Operation]bool{
|
||||||
|
operations.Read: false,
|
||||||
|
operations.Create: false,
|
||||||
|
operations.Update: false,
|
||||||
|
operations.Delete: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
+23
-37
@@ -7,6 +7,8 @@ import (
|
|||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/proto"
|
"github.com/netbirdio/netbird/management/proto"
|
||||||
|
"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/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
|
||||||
@@ -17,38 +19,32 @@ import (
|
|||||||
|
|
||||||
// GetPolicy from the store
|
// GetPolicy from the store
|
||||||
func (am *DefaultAccountManager) GetPolicy(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error) {
|
func (am *DefaultAccountManager) GetPolicy(ctx context.Context, accountID, policyID, userID string) (*types.Policy, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetPolicyByID(ctx, store.LockingStrengthShare, accountID, policyID)
|
return am.Store.GetPolicyByID(ctx, store.LockingStrengthShare, accountID, policyID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SavePolicy in the store
|
// SavePolicy in the store
|
||||||
func (am *DefaultAccountManager) SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy) (*types.Policy, error) {
|
func (am *DefaultAccountManager) SavePolicy(ctx context.Context, accountID, userID string, policy *types.Policy, create bool) (*types.Policy, error) {
|
||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
operation := operations.Create
|
||||||
|
if !create {
|
||||||
|
operation = operations.Update
|
||||||
|
}
|
||||||
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var isUpdate = policy.ID != ""
|
var isUpdate = policy.ID != ""
|
||||||
@@ -95,17 +91,12 @@ func (am *DefaultAccountManager) DeletePolicy(ctx context.Context, accountID, po
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var policy *types.Policy
|
var policy *types.Policy
|
||||||
@@ -143,17 +134,12 @@ func (am *DefaultAccountManager) DeletePolicy(ctx context.Context, accountID, po
|
|||||||
|
|
||||||
// ListPolicies from the store.
|
// ListPolicies from the store.
|
||||||
func (am *DefaultAccountManager) ListPolicies(ctx context.Context, accountID, userID string) ([]*types.Policy, error) {
|
func (am *DefaultAccountManager) ListPolicies(ctx context.Context, accountID, userID string) ([]*types.Policy, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccountPolicies(ctx, store.LockingStrengthShare, accountID)
|
return am.Store.GetAccountPolicies(ctx, store.LockingStrengthShare, accountID)
|
||||||
|
|||||||
@@ -883,7 +883,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
Name: "GroupD",
|
Name: "GroupD",
|
||||||
Peers: []string{peer1.ID, peer2.ID},
|
Peers: []string{peer1.ID, peer2.ID},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
@@ -915,7 +915,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -947,7 +947,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -979,7 +979,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -1010,7 +1010,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
Action: types.PolicyTrafficActionAccept,
|
Action: types.PolicyTrafficActionAccept,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -1030,7 +1030,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
policyWithSourceAndDestinationPeers.Enabled = false
|
policyWithSourceAndDestinationPeers.Enabled = false
|
||||||
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers)
|
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -1051,7 +1051,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
|
|
||||||
policyWithSourceAndDestinationPeers.Description = "updated description"
|
policyWithSourceAndDestinationPeers.Description = "updated description"
|
||||||
policyWithSourceAndDestinationPeers.Rules[0].Destinations = []string{"groupA"}
|
policyWithSourceAndDestinationPeers.Rules[0].Destinations = []string{"groupA"}
|
||||||
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers)
|
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -1071,7 +1071,7 @@ func TestPolicyAccountPeersUpdate(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
policyWithSourceAndDestinationPeers.Enabled = true
|
policyWithSourceAndDestinationPeers.Enabled = true
|
||||||
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers)
|
policyWithSourceAndDestinationPeers, err = manager.SavePolicy(context.Background(), account.Id, userID, policyWithSourceAndDestinationPeers, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"golang.org/x/exp/maps"
|
"golang.org/x/exp/maps"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"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/posture"
|
"github.com/netbirdio/netbird/management/server/posture"
|
||||||
"github.com/netbirdio/netbird/management/server/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
@@ -17,38 +19,32 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (am *DefaultAccountManager) GetPostureChecks(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error) {
|
func (am *DefaultAccountManager) GetPostureChecks(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.HasAdminPower() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetPostureChecksByID(ctx, store.LockingStrengthShare, accountID, postureChecksID)
|
return am.Store.GetPostureChecksByID(ctx, store.LockingStrengthShare, accountID, postureChecksID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SavePostureChecks saves a posture check.
|
// SavePostureChecks saves a posture check.
|
||||||
func (am *DefaultAccountManager) SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) (*posture.Checks, error) {
|
func (am *DefaultAccountManager) SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks, create bool) (*posture.Checks, error) {
|
||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
operation := operations.Create
|
||||||
|
if !create {
|
||||||
|
operation = operations.Update
|
||||||
|
}
|
||||||
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.HasAdminPower() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var updateAccountPeers bool
|
var updateAccountPeers bool
|
||||||
@@ -94,17 +90,12 @@ func (am *DefaultAccountManager) DeletePostureChecks(ctx context.Context, accoun
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Routes, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.HasAdminPower() {
|
|
||||||
return status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var postureChecks *posture.Checks
|
var postureChecks *posture.Checks
|
||||||
@@ -136,17 +127,12 @@ func (am *DefaultAccountManager) DeletePostureChecks(ctx context.Context, accoun
|
|||||||
|
|
||||||
// ListPostureChecks returns a list of posture checks.
|
// ListPostureChecks returns a list of posture checks.
|
||||||
func (am *DefaultAccountManager) ListPostureChecks(ctx context.Context, accountID, userID string) ([]*posture.Checks, error) {
|
func (am *DefaultAccountManager) ListPostureChecks(ctx context.Context, accountID, userID string) ([]*posture.Checks, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Policies, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.HasAdminPower() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccountPostureChecks(ctx, store.LockingStrengthShare, accountID)
|
return am.Store.GetAccountPostureChecks(ctx, store.LockingStrengthShare, accountID)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func TestDefaultAccountManager_PostureCheck(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("Generic posture check flow", func(t *testing.T) {
|
t.Run("Generic posture check flow", func(t *testing.T) {
|
||||||
// regular users can not create checks
|
// regular users can not create checks
|
||||||
_, err = am.SavePostureChecks(context.Background(), account.Id, regularUserID, &posture.Checks{})
|
_, err = am.SavePostureChecks(context.Background(), account.Id, regularUserID, &posture.Checks{}, true)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
// regular users cannot list check
|
// regular users cannot list check
|
||||||
@@ -48,7 +48,7 @@ func TestDefaultAccountManager_PostureCheck(t *testing.T) {
|
|||||||
MinVersion: "0.26.0",
|
MinVersion: "0.26.0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// admin users can list check
|
// admin users can list check
|
||||||
@@ -68,7 +68,7 @@ func TestDefaultAccountManager_PostureCheck(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
|
|
||||||
// admins can update posture checks
|
// admins can update posture checks
|
||||||
@@ -77,7 +77,7 @@ func TestDefaultAccountManager_PostureCheck(t *testing.T) {
|
|||||||
MinVersion: "0.27.0",
|
MinVersion: "0.27.0",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = am.SavePostureChecks(context.Background(), account.Id, adminUserID, postureCheck)
|
_, err = am.SavePostureChecks(context.Background(), account.Id, adminUserID, postureCheck, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// users should not be able to delete posture checks
|
// users should not be able to delete posture checks
|
||||||
@@ -137,7 +137,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
Name: "GroupC",
|
Name: "GroupC",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
@@ -156,7 +156,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
postureCheckA, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckA)
|
postureCheckA, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckA, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
postureCheckB := &posture.Checks{
|
postureCheckB := &posture.Checks{
|
||||||
@@ -177,7 +177,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB)
|
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -200,7 +200,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
MinVersion: "0.29.0",
|
MinVersion: "0.29.0",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB)
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -232,7 +232,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy)
|
policy, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -261,7 +261,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
close(done)
|
close(done)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB)
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -280,7 +280,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
policy.SourcePostureChecks = []string{}
|
policy.SourcePostureChecks = []string{}
|
||||||
_, err := manager.SavePolicy(context.Background(), account.Id, userID, policy)
|
_, err := manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -308,7 +308,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB)
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Updating linked posture check to policy with no peers should not trigger account peers update and not send peer update
|
// Updating linked posture check to policy with no peers should not trigger account peers update and not send peer update
|
||||||
@@ -325,7 +325,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SourcePostureChecks: []string{postureCheckB.ID},
|
SourcePostureChecks: []string{postureCheckB.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
@@ -339,7 +339,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
MinVersion: "0.29.0",
|
MinVersion: "0.29.0",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB)
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -369,7 +369,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SourcePostureChecks: []string{postureCheckB.ID},
|
SourcePostureChecks: []string{postureCheckB.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
@@ -383,7 +383,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
MinVersion: "0.29.0",
|
MinVersion: "0.29.0",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB)
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -408,7 +408,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
SourcePostureChecks: []string{postureCheckB.ID},
|
SourcePostureChecks: []string{postureCheckB.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
done := make(chan struct{})
|
done := make(chan struct{})
|
||||||
@@ -426,7 +426,7 @@ func TestPostureCheckAccountPeersUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB)
|
_, err = manager.SavePostureChecks(context.Background(), account.Id, userID, postureCheckB, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -465,7 +465,7 @@ func TestArePostureCheckChangesAffectPeers(t *testing.T) {
|
|||||||
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.33.1"},
|
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.33.1"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
postureCheckA, err = manager.SavePostureChecks(context.Background(), account.Id, adminUserID, postureCheckA)
|
postureCheckA, err = manager.SavePostureChecks(context.Background(), account.Id, adminUserID, postureCheckA, true)
|
||||||
require.NoError(t, err, "failed to save postureCheckA")
|
require.NoError(t, err, "failed to save postureCheckA")
|
||||||
|
|
||||||
postureCheckB := &posture.Checks{
|
postureCheckB := &posture.Checks{
|
||||||
@@ -475,7 +475,7 @@ func TestArePostureCheckChangesAffectPeers(t *testing.T) {
|
|||||||
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.33.1"},
|
NBVersionCheck: &posture.NBVersionCheck{MinVersion: "0.33.1"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, adminUserID, postureCheckB)
|
postureCheckB, err = manager.SavePostureChecks(context.Background(), account.Id, adminUserID, postureCheckB, true)
|
||||||
require.NoError(t, err, "failed to save postureCheckB")
|
require.NoError(t, err, "failed to save postureCheckB")
|
||||||
|
|
||||||
policy := &types.Policy{
|
policy := &types.Policy{
|
||||||
@@ -490,7 +490,7 @@ func TestArePostureCheckChangesAffectPeers(t *testing.T) {
|
|||||||
SourcePostureChecks: []string{postureCheckA.ID},
|
SourcePostureChecks: []string{postureCheckA.ID},
|
||||||
}
|
}
|
||||||
|
|
||||||
policy, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy)
|
policy, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy, true)
|
||||||
require.NoError(t, err, "failed to save policy")
|
require.NoError(t, err, "failed to save policy")
|
||||||
|
|
||||||
t.Run("posture check exists and is linked to policy with peers", func(t *testing.T) {
|
t.Run("posture check exists and is linked to policy with peers", func(t *testing.T) {
|
||||||
@@ -514,7 +514,7 @@ func TestArePostureCheckChangesAffectPeers(t *testing.T) {
|
|||||||
t.Run("posture check is linked to policy with no peers in source groups", func(t *testing.T) {
|
t.Run("posture check is linked to policy with no peers in source groups", func(t *testing.T) {
|
||||||
policy.Rules[0].Sources = []string{"groupB"}
|
policy.Rules[0].Sources = []string{"groupB"}
|
||||||
policy.Rules[0].Destinations = []string{"groupA"}
|
policy.Rules[0].Destinations = []string{"groupA"}
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy)
|
_, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy, true)
|
||||||
require.NoError(t, err, "failed to update policy")
|
require.NoError(t, err, "failed to update policy")
|
||||||
|
|
||||||
result, err := arePostureCheckChangesAffectPeers(context.Background(), manager.Store, account.Id, postureCheckA.ID)
|
result, err := arePostureCheckChangesAffectPeers(context.Background(), manager.Store, account.Id, postureCheckA.ID)
|
||||||
@@ -525,7 +525,7 @@ func TestArePostureCheckChangesAffectPeers(t *testing.T) {
|
|||||||
t.Run("posture check is linked to policy with no peers in destination groups", func(t *testing.T) {
|
t.Run("posture check is linked to policy with no peers in destination groups", func(t *testing.T) {
|
||||||
policy.Rules[0].Sources = []string{"groupA"}
|
policy.Rules[0].Sources = []string{"groupA"}
|
||||||
policy.Rules[0].Destinations = []string{"groupB"}
|
policy.Rules[0].Destinations = []string{"groupB"}
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy)
|
_, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy, true)
|
||||||
require.NoError(t, err, "failed to update policy")
|
require.NoError(t, err, "failed to update policy")
|
||||||
|
|
||||||
result, err := arePostureCheckChangesAffectPeers(context.Background(), manager.Store, account.Id, postureCheckA.ID)
|
result, err := arePostureCheckChangesAffectPeers(context.Background(), manager.Store, account.Id, postureCheckA.ID)
|
||||||
@@ -546,7 +546,7 @@ func TestArePostureCheckChangesAffectPeers(t *testing.T) {
|
|||||||
t.Run("posture check is linked to policy with non-existent group", func(t *testing.T) {
|
t.Run("posture check is linked to policy with non-existent group", func(t *testing.T) {
|
||||||
policy.Rules[0].Sources = []string{"nonExistentGroup"}
|
policy.Rules[0].Sources = []string{"nonExistentGroup"}
|
||||||
policy.Rules[0].Destinations = []string{"nonExistentGroup"}
|
policy.Rules[0].Destinations = []string{"nonExistentGroup"}
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy)
|
_, err = manager.SavePolicy(context.Background(), account.Id, adminUserID, policy, true)
|
||||||
require.NoError(t, err, "failed to update policy")
|
require.NoError(t, err, "failed to update policy")
|
||||||
|
|
||||||
result, err := arePostureCheckChangesAffectPeers(context.Background(), manager.Store, account.Id, postureCheckA.ID)
|
result, err := arePostureCheckChangesAffectPeers(context.Background(), manager.Store, account.Id, postureCheckA.ID)
|
||||||
|
|||||||
+22
-33
@@ -8,6 +8,8 @@ import (
|
|||||||
|
|
||||||
"github.com/rs/xid"
|
"github.com/rs/xid"
|
||||||
|
|
||||||
|
"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/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
|
|
||||||
@@ -20,17 +22,12 @@ import (
|
|||||||
|
|
||||||
// GetRoute gets a route object from account and route IDs
|
// GetRoute gets a route object from account and route IDs
|
||||||
func (am *DefaultAccountManager) GetRoute(ctx context.Context, accountID string, routeID route.ID, userID string) (*route.Route, error) {
|
func (am *DefaultAccountManager) GetRoute(ctx context.Context, accountID string, routeID route.ID, userID string) (*route.Route, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Routes, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.IsAdminOrServiceUser() {
|
|
||||||
return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view Network Routes")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetRouteByID(ctx, store.LockingStrengthShare, string(routeID), accountID)
|
return am.Store.GetRouteByID(ctx, store.LockingStrengthShare, string(routeID), accountID)
|
||||||
@@ -123,13 +120,12 @@ func (am *DefaultAccountManager) CreateRoute(ctx context.Context, accountID stri
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Routes, operations.Create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err = am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := am.Store.GetAccount(ctx, accountID)
|
account, err := am.Store.GetAccount(ctx, accountID)
|
||||||
@@ -242,13 +238,12 @@ func (am *DefaultAccountManager) SaveRoute(ctx context.Context, accountID, userI
|
|||||||
return status.Errorf(status.InvalidArgument, "identifier should be between 1 and %d", route.MaxNetIDChar)
|
return status.Errorf(status.InvalidArgument, "identifier should be between 1 and %d", route.MaxNetIDChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Routes, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err = am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := am.Store.GetAccount(ctx, accountID)
|
account, err := am.Store.GetAccount(ctx, accountID)
|
||||||
@@ -318,13 +313,12 @@ func (am *DefaultAccountManager) DeleteRoute(ctx context.Context, accountID stri
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Routes, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err = am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
account, err := am.Store.GetAccount(ctx, accountID)
|
account, err := am.Store.GetAccount(ctx, accountID)
|
||||||
@@ -354,17 +348,12 @@ func (am *DefaultAccountManager) DeleteRoute(ctx context.Context, accountID stri
|
|||||||
|
|
||||||
// ListRoutes returns a list of routes from account
|
// ListRoutes returns a list of routes from account
|
||||||
func (am *DefaultAccountManager) ListRoutes(ctx context.Context, accountID, userID string) ([]*route.Route, error) {
|
func (am *DefaultAccountManager) ListRoutes(ctx context.Context, accountID, userID string) ([]*route.Route, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Routes, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !user.IsAdminOrServiceUser() {
|
|
||||||
return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view Network Routes")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccountRoutes(ctx, store.LockingStrengthShare, accountID)
|
return am.Store.GetAccountRoutes(ctx, store.LockingStrengthShare, accountID)
|
||||||
|
|||||||
@@ -1215,7 +1215,7 @@ func TestGetNetworkMap_RouteSync(t *testing.T) {
|
|||||||
Name: "peer1 group",
|
Name: "peer1 group",
|
||||||
Peers: []string{peer1ID},
|
Peers: []string{peer1ID},
|
||||||
}
|
}
|
||||||
err = am.SaveGroup(context.Background(), account.Id, userID, newGroup)
|
err = am.SaveGroup(context.Background(), account.Id, userID, newGroup, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
rules, err := am.ListPolicies(context.Background(), account.Id, "testingUser")
|
rules, err := am.ListPolicies(context.Background(), account.Id, "testingUser")
|
||||||
@@ -1227,7 +1227,7 @@ func TestGetNetworkMap_RouteSync(t *testing.T) {
|
|||||||
newPolicy.Rules[0].Sources = []string{newGroup.ID}
|
newPolicy.Rules[0].Sources = []string{newGroup.ID}
|
||||||
newPolicy.Rules[0].Destinations = []string{newGroup.ID}
|
newPolicy.Rules[0].Destinations = []string{newGroup.ID}
|
||||||
|
|
||||||
_, err = am.SavePolicy(context.Background(), account.Id, userID, newPolicy)
|
_, err = am.SavePolicy(context.Background(), account.Id, userID, newPolicy, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = am.DeletePolicy(context.Background(), account.Id, defaultRule.ID, userID)
|
err = am.DeletePolicy(context.Background(), account.Id, defaultRule.ID, userID)
|
||||||
@@ -1260,7 +1260,6 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
|
|||||||
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
metrics, err := telemetry.NewDefaultAppMetrics(context.Background())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
permissionsManagerMock := permissions.NewManagerMock()
|
|
||||||
ctrl := gomock.NewController(t)
|
ctrl := gomock.NewController(t)
|
||||||
t.Cleanup(ctrl.Finish)
|
t.Cleanup(ctrl.Finish)
|
||||||
|
|
||||||
@@ -1283,7 +1282,9 @@ func createRouterManager(t *testing.T) (*DefaultAccountManager, error) {
|
|||||||
AnyTimes().
|
AnyTimes().
|
||||||
Return(&types.ExtraSettings{}, nil)
|
Return(&types.ExtraSettings{}, nil)
|
||||||
|
|
||||||
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManagerMock)
|
permissionsManager := permissions.NewManager(store)
|
||||||
|
|
||||||
|
return BuildManager(context.Background(), store, NewPeersUpdateManager(nil), nil, "", "netbird.selfhosted", eventStore, nil, false, MocIntegratedValidator{}, metrics, port_forwarding.NewControllerMock(), settingsMockManager, permissionsManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
func createRouterStore(t *testing.T) (store.Store, error) {
|
func createRouterStore(t *testing.T) (store.Store, error) {
|
||||||
@@ -1504,7 +1505,7 @@ func initTestRouteAccount(t *testing.T, am *DefaultAccountManager) (*types.Accou
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, group := range newGroup {
|
for _, group := range newGroup {
|
||||||
err = am.SaveGroup(context.Background(), accountID, userID, group)
|
err = am.SaveGroup(context.Background(), accountID, userID, group, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1958,7 +1959,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
|
|||||||
Name: "GroupC",
|
Name: "GroupC",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1ID)
|
||||||
@@ -2142,7 +2143,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupB",
|
ID: "groupB",
|
||||||
Name: "GroupB",
|
Name: "GroupB",
|
||||||
Peers: []string{peer1ID},
|
Peers: []string{peer1ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@@ -2182,7 +2183,7 @@ func TestRouteAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupC",
|
ID: "groupC",
|
||||||
Name: "GroupC",
|
Name: "GroupC",
|
||||||
Peers: []string{peer1ID},
|
Peers: []string{peer1ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import (
|
|||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"github.com/netbirdio/netbird/management/server/activity"
|
||||||
"github.com/netbirdio/netbird/management/server/integrations/extra_settings"
|
"github.com/netbirdio/netbird/management/server/integrations/extra_settings"
|
||||||
"github.com/netbirdio/netbird/management/server/permissions"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
@@ -44,7 +46,7 @@ func (m *managerImpl) GetExtraSettingsManager() extra_settings.Manager {
|
|||||||
|
|
||||||
func (m *managerImpl) GetSettings(ctx context.Context, accountID, userID string) (*types.Settings, error) {
|
func (m *managerImpl) GetSettings(ctx context.Context, accountID, userID string) (*types.Settings, error) {
|
||||||
if userID != activity.SystemInitiator {
|
if userID != activity.SystemInitiator {
|
||||||
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, permissions.Settings, permissions.Read)
|
ok, err := m.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.Settings, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.NewPermissionValidationError(err)
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/netbirdio/netbird/management/server/activity"
|
"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/status"
|
"github.com/netbirdio/netbird/management/server/status"
|
||||||
"github.com/netbirdio/netbird/management/server/store"
|
"github.com/netbirdio/netbird/management/server/store"
|
||||||
"github.com/netbirdio/netbird/management/server/types"
|
"github.com/netbirdio/netbird/management/server/types"
|
||||||
@@ -56,17 +58,12 @@ func (am *DefaultAccountManager) CreateSetupKey(ctx context.Context, accountID s
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.SetupKeys, operations.Create)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var setupKey *types.SetupKey
|
var setupKey *types.SetupKey
|
||||||
@@ -113,17 +110,12 @@ func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID str
|
|||||||
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
|
||||||
defer unlock()
|
defer unlock()
|
||||||
|
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.SetupKeys, operations.Update)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldKey *types.SetupKey
|
var oldKey *types.SetupKey
|
||||||
@@ -175,17 +167,12 @@ func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID str
|
|||||||
|
|
||||||
// ListSetupKeys returns a list of all setup keys of the account
|
// ListSetupKeys returns a list of all setup keys of the account
|
||||||
func (am *DefaultAccountManager) ListSetupKeys(ctx context.Context, accountID, userID string) ([]*types.SetupKey, error) {
|
func (am *DefaultAccountManager) ListSetupKeys(ctx context.Context, accountID, userID string) ([]*types.SetupKey, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.SetupKeys, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return am.Store.GetAccountSetupKeys(ctx, store.LockingStrengthShare, accountID)
|
return am.Store.GetAccountSetupKeys(ctx, store.LockingStrengthShare, accountID)
|
||||||
@@ -193,17 +180,12 @@ func (am *DefaultAccountManager) ListSetupKeys(ctx context.Context, accountID, u
|
|||||||
|
|
||||||
// GetSetupKey looks up a SetupKey by KeyID, returns NotFound error if not found.
|
// GetSetupKey looks up a SetupKey by KeyID, returns NotFound error if not found.
|
||||||
func (am *DefaultAccountManager) GetSetupKey(ctx context.Context, accountID, userID, keyID string) (*types.SetupKey, error) {
|
func (am *DefaultAccountManager) GetSetupKey(ctx context.Context, accountID, userID, keyID string) (*types.SetupKey, error) {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.SetupKeys, operations.Read)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return nil, status.NewPermissionDeniedError()
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return nil, status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setupKey, err := am.Store.GetSetupKeyByID(ctx, store.LockingStrengthShare, accountID, keyID)
|
setupKey, err := am.Store.GetSetupKeyByID(ctx, store.LockingStrengthShare, accountID, keyID)
|
||||||
@@ -221,17 +203,12 @@ func (am *DefaultAccountManager) GetSetupKey(ctx context.Context, accountID, use
|
|||||||
|
|
||||||
// DeleteSetupKey removes the setup key from the account
|
// DeleteSetupKey removes the setup key from the account
|
||||||
func (am *DefaultAccountManager) DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error {
|
func (am *DefaultAccountManager) DeleteSetupKey(ctx context.Context, accountID, userID, keyID string) error {
|
||||||
user, err := am.Store.GetUserByUserID(ctx, store.LockingStrengthShare, userID)
|
allowed, err := am.permissionsManager.ValidateUserPermissions(ctx, accountID, userID, modules.SetupKeys, operations.Delete)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return status.NewPermissionValidationError(err)
|
||||||
}
|
}
|
||||||
|
if !allowed {
|
||||||
if err := am.permissionsManager.ValidateAccountAccess(ctx, accountID, user, false); err != nil {
|
return status.NewPermissionDeniedError()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if user.IsRegularUser() {
|
|
||||||
return status.NewAdminPermissionError()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var deletedSetupKey *types.SetupKey
|
var deletedSetupKey *types.SetupKey
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func TestDefaultAccountManager_SaveSetupKey(t *testing.T) {
|
|||||||
Name: "group_name_2",
|
Name: "group_name_2",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
},
|
},
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -109,7 +109,7 @@ func TestDefaultAccountManager_CreateSetupKey(t *testing.T) {
|
|||||||
ID: "group_1",
|
ID: "group_1",
|
||||||
Name: "group_name_1",
|
Name: "group_name_1",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -118,7 +118,7 @@ func TestDefaultAccountManager_CreateSetupKey(t *testing.T) {
|
|||||||
ID: "group_2",
|
ID: "group_2",
|
||||||
Name: "group_name_2",
|
Name: "group_name_2",
|
||||||
Peers: []string{},
|
Peers: []string{},
|
||||||
})
|
}, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
@@ -403,7 +403,7 @@ func TestSetupKeyAccountPeersUpdate(t *testing.T) {
|
|||||||
ID: "groupA",
|
ID: "groupA",
|
||||||
Name: "GroupA",
|
Name: "GroupA",
|
||||||
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
Peers: []string{peer1.ID, peer2.ID, peer3.ID},
|
||||||
})
|
}, true)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
policy := &types.Policy{
|
policy := &types.Policy{
|
||||||
@@ -418,7 +418,7 @@ func TestSetupKeyAccountPeersUpdate(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy)
|
_, err = manager.SavePolicy(context.Background(), account.Id, userID, policy, true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
updMsg := manager.peersUpdateManager.CreateChannel(context.Background(), peer1.ID)
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user