mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-16 07:16:38 +00:00
[management] add target user account validation (#5741)
This commit is contained in:
2
.github/workflows/golangci-lint.yml
vendored
2
.github/workflows/golangci-lint.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
|||||||
- name: codespell
|
- name: codespell
|
||||||
uses: codespell-project/actions-codespell@v2
|
uses: codespell-project/actions-codespell@v2
|
||||||
with:
|
with:
|
||||||
ignore_words_list: erro,clienta,hastable,iif,groupd,testin,groupe,cros,ans,deriver,te
|
ignore_words_list: erro,clienta,hastable,iif,groupd,testin,groupe,cros,ans,deriver,te,userA
|
||||||
skip: go.mod,go.sum,**/proxy/web/**
|
skip: go.mod,go.sum,**/proxy/web/**
|
||||||
golangci:
|
golangci:
|
||||||
strategy:
|
strategy:
|
||||||
|
|||||||
@@ -417,6 +417,10 @@ func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if targetUser.AccountID != accountID {
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
// @note this is essential to prevent non admin users with Pats create permission frpm creating one for a service user
|
// @note this is essential to prevent non admin users with Pats create permission frpm creating one for a service user
|
||||||
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
||||||
return nil, status.NewAdminPermissionError()
|
return nil, status.NewAdminPermissionError()
|
||||||
@@ -457,6 +461,10 @@ func (am *DefaultAccountManager) DeletePAT(ctx context.Context, accountID string
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if targetUser.AccountID != accountID {
|
||||||
|
return status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
||||||
return status.NewAdminPermissionError()
|
return status.NewAdminPermissionError()
|
||||||
}
|
}
|
||||||
@@ -496,6 +504,10 @@ func (am *DefaultAccountManager) GetPAT(ctx context.Context, accountID string, i
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if targetUser.AccountID != accountID {
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
||||||
return nil, status.NewAdminPermissionError()
|
return nil, status.NewAdminPermissionError()
|
||||||
}
|
}
|
||||||
@@ -523,6 +535,10 @@ func (am *DefaultAccountManager) GetAllPATs(ctx context.Context, accountID strin
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if targetUser.AccountID != accountID {
|
||||||
|
return nil, status.NewPermissionDeniedError()
|
||||||
|
}
|
||||||
|
|
||||||
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
if initiatorUserID != targetUserID && !(initiatorUser.HasAdminPower() && targetUser.IsServiceUser) {
|
||||||
return nil, status.NewAdminPermissionError()
|
return nil, status.NewAdminPermissionError()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -336,6 +336,104 @@ func TestUser_GetAllPATs(t *testing.T) {
|
|||||||
assert.Equal(t, 2, len(pats))
|
assert.Equal(t, 2, len(pats))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestUser_PAT_CrossAccountProtection(t *testing.T) {
|
||||||
|
const (
|
||||||
|
accountAID = "accountA"
|
||||||
|
accountBID = "accountB"
|
||||||
|
userAID = "userA"
|
||||||
|
adminBID = "adminB"
|
||||||
|
serviceUserBID = "serviceUserB"
|
||||||
|
regularUserBID = "regularUserB"
|
||||||
|
tokenBID = "tokenB1"
|
||||||
|
hashedTokenB = "SoMeHaShEdToKeNB"
|
||||||
|
)
|
||||||
|
|
||||||
|
setupStore := func(t *testing.T) (*DefaultAccountManager, func()) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
s, cleanup, err := store.NewTestStoreFromSQL(context.Background(), "", t.TempDir())
|
||||||
|
require.NoError(t, err, "creating store")
|
||||||
|
|
||||||
|
accountA := newAccountWithId(context.Background(), accountAID, userAID, "", "", "", false)
|
||||||
|
require.NoError(t, s.SaveAccount(context.Background(), accountA))
|
||||||
|
|
||||||
|
accountB := newAccountWithId(context.Background(), accountBID, adminBID, "", "", "", false)
|
||||||
|
accountB.Users[serviceUserBID] = &types.User{
|
||||||
|
Id: serviceUserBID,
|
||||||
|
AccountID: accountBID,
|
||||||
|
IsServiceUser: true,
|
||||||
|
ServiceUserName: "svcB",
|
||||||
|
Role: types.UserRoleAdmin,
|
||||||
|
PATs: map[string]*types.PersonalAccessToken{
|
||||||
|
tokenBID: {
|
||||||
|
ID: tokenBID,
|
||||||
|
HashedToken: hashedTokenB,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
accountB.Users[regularUserBID] = &types.User{
|
||||||
|
Id: regularUserBID,
|
||||||
|
AccountID: accountBID,
|
||||||
|
Role: types.UserRoleUser,
|
||||||
|
}
|
||||||
|
require.NoError(t, s.SaveAccount(context.Background(), accountB))
|
||||||
|
|
||||||
|
pm := permissions.NewManager(s)
|
||||||
|
am := &DefaultAccountManager{
|
||||||
|
Store: s,
|
||||||
|
eventStore: &activity.InMemoryEventStore{},
|
||||||
|
permissionsManager: pm,
|
||||||
|
}
|
||||||
|
return am, cleanup
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("CreatePAT for user in different account is denied", func(t *testing.T) {
|
||||||
|
am, cleanup := setupStore(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
_, err := am.CreatePAT(context.Background(), accountAID, userAID, serviceUserBID, "xss-token", 7)
|
||||||
|
require.Error(t, err, "cross-account CreatePAT must fail")
|
||||||
|
|
||||||
|
_, err = am.CreatePAT(context.Background(), accountAID, userAID, regularUserBID, "xss-token", 7)
|
||||||
|
require.Error(t, err, "cross-account CreatePAT for regular user must fail")
|
||||||
|
|
||||||
|
_, err = am.CreatePAT(context.Background(), accountBID, adminBID, serviceUserBID, "legit-token", 7)
|
||||||
|
require.NoError(t, err, "same-account CreatePAT should succeed")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("DeletePAT for user in different account is denied", func(t *testing.T) {
|
||||||
|
am, cleanup := setupStore(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
err := am.DeletePAT(context.Background(), accountAID, userAID, serviceUserBID, tokenBID)
|
||||||
|
require.Error(t, err, "cross-account DeletePAT must fail")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("GetPAT for user in different account is denied", func(t *testing.T) {
|
||||||
|
am, cleanup := setupStore(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
_, err := am.GetPAT(context.Background(), accountAID, userAID, serviceUserBID, tokenBID)
|
||||||
|
require.Error(t, err, "cross-account GetPAT must fail")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("GetAllPATs for user in different account is denied", func(t *testing.T) {
|
||||||
|
am, cleanup := setupStore(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
_, err := am.GetAllPATs(context.Background(), accountAID, userAID, serviceUserBID)
|
||||||
|
require.Error(t, err, "cross-account GetAllPATs must fail")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("CreatePAT with forged accountID targeting foreign user is denied", func(t *testing.T) {
|
||||||
|
am, cleanup := setupStore(t)
|
||||||
|
t.Cleanup(cleanup)
|
||||||
|
|
||||||
|
_, err := am.CreatePAT(context.Background(), accountAID, userAID, adminBID, "forged", 7)
|
||||||
|
require.Error(t, err, "forged accountID CreatePAT must fail")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestUser_Copy(t *testing.T) {
|
func TestUser_Copy(t *testing.T) {
|
||||||
// this is an imaginary case which will never be in DB this way
|
// this is an imaginary case which will never be in DB this way
|
||||||
user := types.User{
|
user := types.User{
|
||||||
|
|||||||
Reference in New Issue
Block a user