diff --git a/management/server/account.go b/management/server/account.go index 79bde81ea..e1a739229 100644 --- a/management/server/account.go +++ b/management/server/account.go @@ -102,11 +102,11 @@ type AccountManager interface { SaveRoute(accountID, userID string, route *route.Route) error DeleteRoute(accountID, routeID, userID string) error ListRoutes(accountID, userID string) ([]*route.Route, error) - GetNameServerGroup(accountID, nsGroupID string) (*nbdns.NameServerGroup, error) + GetNameServerGroup(accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) CreateNameServerGroup(accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string, searchDomainsEnabled bool) (*nbdns.NameServerGroup, error) SaveNameServerGroup(accountID, userID string, nsGroupToSave *nbdns.NameServerGroup) error DeleteNameServerGroup(accountID, nsGroupID, userID string) error - ListNameServerGroups(accountID string) ([]*nbdns.NameServerGroup, error) + ListNameServerGroups(accountID string, userID string) ([]*nbdns.NameServerGroup, error) GetDNSDomain() string StoreEvent(initiatorID, targetID, accountID string, activityID activity.Activity, meta map[string]any) GetEvents(accountID, userID string) ([]*activity.Event, error) diff --git a/management/server/account_test.go b/management/server/account_test.go index 5e204984e..a944871dd 100644 --- a/management/server/account_test.go +++ b/management/server/account_test.go @@ -934,7 +934,7 @@ func TestAccountManager_AddPeer(t *testing.T) { return } - userID := "account_creator" + userID := "testingUser" account, err := createAccount(manager, "test_account", userID, "netbird.cloud") if err != nil { t.Fatal(err) diff --git a/management/server/dns.go b/management/server/dns.go index 820a5431f..f6e3531ec 100644 --- a/management/server/dns.go +++ b/management/server/dns.go @@ -48,7 +48,7 @@ func (am *DefaultAccountManager) GetDNSSettings(accountID string, userID string) return nil, err } - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { return nil, status.Errorf(status.PermissionDenied, "only users with admin power are allowed to view DNS settings") } dnsSettings := account.DNSSettings.Copy() diff --git a/management/server/event.go b/management/server/event.go index 450d1c00d..58ee9547f 100644 --- a/management/server/event.go +++ b/management/server/event.go @@ -7,10 +7,28 @@ import ( log "github.com/sirupsen/logrus" "github.com/netbirdio/netbird/management/server/activity" + "github.com/netbirdio/netbird/management/server/status" ) // GetEvents returns a list of activity events of an account func (am *DefaultAccountManager) GetEvents(accountID, userID string) ([]*activity.Event, error) { + unlock := am.Store.AcquireAccountLock(accountID) + defer unlock() + + account, err := am.Store.GetAccount(accountID) + if err != nil { + return nil, err + } + + user, err := account.FindUser(userID) + if err != nil { + 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(accountID, 0, 10000, true) if err != nil { return nil, err diff --git a/management/server/http/accounts_handler.go b/management/server/http/accounts_handler.go index bab00219b..71088cfaf 100644 --- a/management/server/http/accounts_handler.go +++ b/management/server/http/accounts_handler.go @@ -41,7 +41,7 @@ func (h *AccountsHandler) GetAllAccounts(w http.ResponseWriter, r *http.Request) return } - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { util.WriteError(status.Errorf(status.PermissionDenied, "the user has no permission to access account data"), w) return } diff --git a/management/server/http/nameservers_handler.go b/management/server/http/nameservers_handler.go index 871bf639a..8d9f0d717 100644 --- a/management/server/http/nameservers_handler.go +++ b/management/server/http/nameservers_handler.go @@ -36,14 +36,14 @@ func NewNameserversHandler(accountManager server.AccountManager, authCfg AuthCfg // GetAllNameservers returns the list of nameserver groups for the account func (h *NameserversHandler) GetAllNameservers(w http.ResponseWriter, r *http.Request) { claims := h.claimsExtractor.FromRequestContext(r) - account, _, err := h.accountManager.GetAccountFromToken(claims) + account, user, err := h.accountManager.GetAccountFromToken(claims) if err != nil { log.Error(err) http.Redirect(w, r, "/", http.StatusInternalServerError) return } - nsGroups, err := h.accountManager.ListNameServerGroups(account.Id) + nsGroups, err := h.accountManager.ListNameServerGroups(account.Id, user.Id) if err != nil { util.WriteError(err, w) return @@ -168,7 +168,7 @@ func (h *NameserversHandler) DeleteNameserverGroup(w http.ResponseWriter, r *htt // GetNameserverGroup handles a nameserver group Get request identified by ID func (h *NameserversHandler) GetNameserverGroup(w http.ResponseWriter, r *http.Request) { claims := h.claimsExtractor.FromRequestContext(r) - account, _, err := h.accountManager.GetAccountFromToken(claims) + account, user, err := h.accountManager.GetAccountFromToken(claims) if err != nil { log.Error(err) http.Redirect(w, r, "/", http.StatusInternalServerError) @@ -181,7 +181,7 @@ func (h *NameserversHandler) GetNameserverGroup(w http.ResponseWriter, r *http.R return } - nsGroup, err := h.accountManager.GetNameServerGroup(account.Id, nsGroupID) + nsGroup, err := h.accountManager.GetNameServerGroup(account.Id, user.Id, nsGroupID) if err != nil { util.WriteError(err, w) return diff --git a/management/server/http/nameservers_handler_test.go b/management/server/http/nameservers_handler_test.go index b00ff606f..e1fabb198 100644 --- a/management/server/http/nameservers_handler_test.go +++ b/management/server/http/nameservers_handler_test.go @@ -61,7 +61,7 @@ var baseExistingNSGroup = &nbdns.NameServerGroup{ func initNameserversTestData() *NameserversHandler { return &NameserversHandler{ accountManager: &mock_server.MockAccountManager{ - GetNameServerGroupFunc: func(accountID, nsGroupID string) (*nbdns.NameServerGroup, error) { + GetNameServerGroupFunc: func(accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) { if nsGroupID == existingNSGroupID { return baseExistingNSGroup.Copy(), nil } diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go index f337ef1cf..c8e49457b 100644 --- a/management/server/mock_server/account_mock.go +++ b/management/server/mock_server/account_mock.go @@ -63,11 +63,11 @@ type MockAccountManager struct { DeletePATFunc func(accountID string, initiatorUserID string, targetUserId string, tokenID string) error GetPATFunc func(accountID string, initiatorUserID string, targetUserId string, tokenID string) (*server.PersonalAccessToken, error) GetAllPATsFunc func(accountID string, initiatorUserID string, targetUserId string) ([]*server.PersonalAccessToken, error) - GetNameServerGroupFunc func(accountID, nsGroupID string) (*nbdns.NameServerGroup, error) + GetNameServerGroupFunc func(accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) CreateNameServerGroupFunc func(accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string, searchDomainsEnabled bool) (*nbdns.NameServerGroup, error) SaveNameServerGroupFunc func(accountID, userID string, nsGroupToSave *nbdns.NameServerGroup) error DeleteNameServerGroupFunc func(accountID, nsGroupID, userID string) error - ListNameServerGroupsFunc func(accountID string) ([]*nbdns.NameServerGroup, error) + ListNameServerGroupsFunc func(accountID string, userID string) ([]*nbdns.NameServerGroup, error) CreateUserFunc func(accountID, userID string, key *server.UserInfo) (*server.UserInfo, error) GetAccountFromTokenFunc func(claims jwtclaims.AuthorizationClaims) (*server.Account, *server.User, error) CheckUserAccessByJWTGroupsFunc func(claims jwtclaims.AuthorizationClaims) error @@ -496,9 +496,9 @@ func (am *MockAccountManager) InviteUser(accountID string, initiatorUserID strin } // GetNameServerGroup mocks GetNameServerGroup of the AccountManager interface -func (am *MockAccountManager) GetNameServerGroup(accountID, nsGroupID string) (*nbdns.NameServerGroup, error) { +func (am *MockAccountManager) GetNameServerGroup(accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) { if am.GetNameServerGroupFunc != nil { - return am.GetNameServerGroupFunc(accountID, nsGroupID) + return am.GetNameServerGroupFunc(accountID, userID, nsGroupID) } return nil, nil } @@ -528,9 +528,9 @@ func (am *MockAccountManager) DeleteNameServerGroup(accountID, nsGroupID, userID } // ListNameServerGroups mocks ListNameServerGroups of the AccountManager interface -func (am *MockAccountManager) ListNameServerGroups(accountID string) ([]*nbdns.NameServerGroup, error) { +func (am *MockAccountManager) ListNameServerGroups(accountID string, userID string) ([]*nbdns.NameServerGroup, error) { if am.ListNameServerGroupsFunc != nil { - return am.ListNameServerGroupsFunc(accountID) + return am.ListNameServerGroupsFunc(accountID, userID) } return nil, nil } diff --git a/management/server/nameserver.go b/management/server/nameserver.go index 1b8d59e29..ee1453ea4 100644 --- a/management/server/nameserver.go +++ b/management/server/nameserver.go @@ -16,7 +16,7 @@ import ( 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 -func (am *DefaultAccountManager) GetNameServerGroup(accountID, nsGroupID string) (*nbdns.NameServerGroup, error) { +func (am *DefaultAccountManager) GetNameServerGroup(accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) { unlock := am.Store.AcquireAccountLock(accountID) defer unlock() @@ -26,6 +26,15 @@ func (am *DefaultAccountManager) GetNameServerGroup(accountID, nsGroupID string) return nil, err } + user, err := account.FindUser(userID) + if err != nil { + return nil, err + } + + if !(user.HasAdminPower() || user.IsServiceUser) { + return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view nameserver groups") + } + nsGroup, found := account.NameServerGroups[nsGroupID] if found { return nsGroup.Copy(), nil @@ -147,7 +156,7 @@ func (am *DefaultAccountManager) DeleteNameServerGroup(accountID, nsGroupID, use } // ListNameServerGroups returns a list of nameserver groups from account -func (am *DefaultAccountManager) ListNameServerGroups(accountID string) ([]*nbdns.NameServerGroup, error) { +func (am *DefaultAccountManager) ListNameServerGroups(accountID string, userID string) ([]*nbdns.NameServerGroup, error) { unlock := am.Store.AcquireAccountLock(accountID) defer unlock() @@ -157,6 +166,15 @@ func (am *DefaultAccountManager) ListNameServerGroups(accountID string) ([]*nbdn return nil, err } + user, err := account.FindUser(userID) + if err != nil { + return nil, err + } + + if !(user.HasAdminPower() || user.IsServiceUser) { + return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view name server groups") + } + nsGroups := make([]*nbdns.NameServerGroup, 0, len(account.NameServerGroups)) for _, item := range account.NameServerGroups { nsGroups = append(nsGroups, item.Copy()) diff --git a/management/server/nameserver_test.go b/management/server/nameserver_test.go index 791dc5677..ba9826f31 100644 --- a/management/server/nameserver_test.go +++ b/management/server/nameserver_test.go @@ -20,6 +20,7 @@ const ( nsGroupPeer2Key = "/yF0+vCfv+mRR5k0dca0TrGdO/oiNeAI58gToZm5NyI=" validDomain = "example.com" invalidDomain = "dnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdnsdns.com" + testUserID = "testingUser" ) func TestCreateNameServerGroup(t *testing.T) { @@ -726,7 +727,7 @@ func TestGetNameServerGroup(t *testing.T) { t.Error("failed to init testing account") } - foundGroup, err := am.GetNameServerGroup(account.Id, existingNSGroupID) + foundGroup, err := am.GetNameServerGroup(account.Id, testUserID, existingNSGroupID) if err != nil { t.Error("getting existing nameserver group failed with error: ", err) } @@ -735,7 +736,7 @@ func TestGetNameServerGroup(t *testing.T) { t.Error("got a nil group while getting nameserver group with ID") } - _, err = am.GetNameServerGroup(account.Id, "not existing") + _, err = am.GetNameServerGroup(account.Id, testUserID, "not existing") if err == nil { t.Error("getting not existing nameserver group should return error, got nil") } @@ -813,7 +814,7 @@ func initTestNSAccount(t *testing.T, am *DefaultAccountManager) (*Account, error } accountID := "testingAcc" - userID := "testingUser" + userID := testUserID domain := "example.com" account := newAccountWithId(accountID, userID, domain) diff --git a/management/server/peer.go b/management/server/peer.go index 33975cdda..2b3bfe167 100644 --- a/management/server/peer.go +++ b/management/server/peer.go @@ -54,7 +54,7 @@ func (am *DefaultAccountManager) GetPeers(accountID, userID string) ([]*nbpeer.P peers := make([]*nbpeer.Peer, 0) peersMap := make(map[string]*nbpeer.Peer) for _, peer := range account.Peers { - if !user.HasAdminPower() && user.Id != peer.UserID { + if !(user.HasAdminPower() || user.IsServiceUser) && user.Id != peer.UserID { // only display peers that belong to the current user if the current user is not an admin continue } @@ -723,7 +723,7 @@ func (am *DefaultAccountManager) GetPeer(accountID, peerID, userID string) (*nbp } // if admin or user owns this peer, return peer - if user.HasAdminPower() || peer.UserID == userID { + if user.HasAdminPower() || user.IsServiceUser || peer.UserID == userID { return peer, nil } diff --git a/management/server/policy.go b/management/server/policy.go index d7e27a1b5..ff8b1dd92 100644 --- a/management/server/policy.go +++ b/management/server/policy.go @@ -323,7 +323,7 @@ func (am *DefaultAccountManager) GetPolicy(accountID, policyID, userID string) ( return nil, err } - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { return nil, status.Errorf(status.PermissionDenied, "only users with admin power are allowed to view policies") } @@ -406,7 +406,7 @@ func (am *DefaultAccountManager) ListPolicies(accountID, userID string) ([]*Poli return nil, err } - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view policies") } diff --git a/management/server/route.go b/management/server/route.go index 5f7976fe4..4de552a2d 100644 --- a/management/server/route.go +++ b/management/server/route.go @@ -27,7 +27,7 @@ func (am *DefaultAccountManager) GetRoute(accountID, routeID, userID string) (*r return nil, err } - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view Network Routes") } @@ -296,7 +296,7 @@ func (am *DefaultAccountManager) ListRoutes(accountID, userID string) ([]*route. return nil, err } - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { return nil, status.Errorf(status.PermissionDenied, "only users with admin power can view Network Routes") } diff --git a/management/server/setupkey.go b/management/server/setupkey.go index b557b07c8..972665527 100644 --- a/management/server/setupkey.go +++ b/management/server/setupkey.go @@ -342,7 +342,7 @@ func (am *DefaultAccountManager) ListSetupKeys(accountID, userID string) ([]*Set keys := make([]*SetupKey, 0, len(account.SetupKeys)) for _, key := range account.SetupKeys { var k *SetupKey - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { k = key.HiddenCopy(999) } else { k = key.Copy() @@ -384,7 +384,7 @@ func (am *DefaultAccountManager) GetSetupKey(accountID, userID, keyID string) (* foundKey.UpdatedAt = foundKey.CreatedAt } - if !user.HasAdminPower() { + if !(user.HasAdminPower() || user.IsServiceUser) { foundKey = foundKey.HiddenCopy(999) } diff --git a/management/server/setupkey_test.go b/management/server/setupkey_test.go index b104a6959..c22df2094 100644 --- a/management/server/setupkey_test.go +++ b/management/server/setupkey_test.go @@ -18,7 +18,7 @@ func TestDefaultAccountManager_SaveSetupKey(t *testing.T) { t.Fatal(err) } - userID := "test_user" + userID := "testingUser" account, err := manager.GetOrCreateAccountByUser(userID, "") if err != nil { t.Fatal(err) @@ -76,7 +76,7 @@ func TestDefaultAccountManager_CreateSetupKey(t *testing.T) { t.Fatal(err) } - userID := "test_user" + userID := "testingUser" account, err := manager.GetOrCreateAccountByUser(userID, "") if err != nil { t.Fatal(err) diff --git a/management/server/user.go b/management/server/user.go index d48299b1e..b2e273d9a 100644 --- a/management/server/user.go +++ b/management/server/user.go @@ -991,7 +991,7 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID, userID string) ( // in case of self-hosted, or IDP doesn't return anything, we will return the locally stored userInfo if len(queriedUsers) == 0 { for _, accountUser := range account.Users { - if !user.HasAdminPower() && user.Id != accountUser.Id { + if !(user.HasAdminPower() || user.IsServiceUser || user.Id == accountUser.Id) { // if user is not an admin then show only current user and do not show other users continue } @@ -1005,7 +1005,7 @@ func (am *DefaultAccountManager) GetUsersFromAccount(accountID, userID string) ( } for _, localUser := range account.Users { - if !user.HasAdminPower() && user.Id != localUser.Id { + if !(user.HasAdminPower() || user.IsServiceUser) && user.Id != localUser.Id { // if user is not an admin then show only current user and do not show other users continue } diff --git a/management/server/user_test.go b/management/server/user_test.go index d445ade62..8de2267b3 100644 --- a/management/server/user_test.go +++ b/management/server/user_test.go @@ -822,8 +822,8 @@ func TestUser_GetUsersFromAccount_ForUser(t *testing.T) { t.Fatalf("Error when getting users from account: %s", err) } - assert.Equal(t, 1, len(users)) - assert.Equal(t, mockServiceUserID, users[0].ID) + // Service users should see all users + assert.Equal(t, 2, len(users)) } func TestDefaultAccountManager_SaveUser(t *testing.T) {