mirror of
https://github.com/netbirdio/netbird.git
synced 2026-04-25 19:56:46 +00:00
update account isolation
This commit is contained in:
@@ -233,6 +233,71 @@ func Test_Accounts_Update(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Accounts_Update_CrossAccountAttack(t *testing.T) {
|
||||
t.Run("Other user attempts to update testAccount via URL", func(t *testing.T) {
|
||||
apiHandler, _, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/accounts.sql", nil, false)
|
||||
|
||||
body, err := json.Marshal(&api.AccountRequest{
|
||||
Settings: api.AccountSettings{
|
||||
PeerLoginExpirationEnabled: false,
|
||||
PeerLoginExpiration: 86400,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to marshal request body: %v", err)
|
||||
}
|
||||
|
||||
// OtherUserId belongs to otherAccountId, but we target testAccountId in URL
|
||||
req := testing_tools.BuildRequest(t, body, http.MethodPut, "/api/accounts/"+testing_tools.TestAccountId, testing_tools.OtherUserId)
|
||||
recorder := httptest.NewRecorder()
|
||||
apiHandler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.NotEqual(t, http.StatusOK, recorder.Code, "cross-account update must be rejected")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Accounts_Delete(t *testing.T) {
|
||||
users := []struct {
|
||||
name string
|
||||
userId string
|
||||
expectResponse bool
|
||||
}{
|
||||
{"Regular user", testing_tools.TestUserId, false},
|
||||
{"Admin user", testing_tools.TestAdminId, false},
|
||||
{"Owner user", testing_tools.TestOwnerId, true},
|
||||
{"Regular service user", testing_tools.TestServiceUserId, false},
|
||||
{"Admin service user", testing_tools.TestServiceAdminId, false},
|
||||
{"Blocked user", testing_tools.BlockedUserId, false},
|
||||
{"Other user", testing_tools.OtherUserId, false},
|
||||
{"Invalid token", testing_tools.InvalidToken, false},
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
t.Run(user.name+" - Delete account", func(t *testing.T) {
|
||||
apiHandler, _, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/accounts.sql", nil, false)
|
||||
|
||||
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, "/api/accounts/"+testing_tools.TestAccountId, user.userId)
|
||||
recorder := httptest.NewRecorder()
|
||||
apiHandler.ServeHTTP(recorder, req)
|
||||
|
||||
testing_tools.ReadResponse(t, recorder, http.StatusOK, user.expectResponse)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Accounts_Delete_CrossAccountAttack(t *testing.T) {
|
||||
t.Run("Other user attempts to delete testAccount via URL", func(t *testing.T) {
|
||||
apiHandler, _, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/accounts.sql", nil, false)
|
||||
|
||||
// OtherUserId belongs to otherAccountId, but we target testAccountId in URL
|
||||
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, "/api/accounts/"+testing_tools.TestAccountId, testing_tools.OtherUserId)
|
||||
recorder := httptest.NewRecorder()
|
||||
apiHandler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.NotEqual(t, http.StatusOK, recorder.Code, "cross-account delete must be rejected")
|
||||
})
|
||||
}
|
||||
|
||||
func stringPointer(s string) *string {
|
||||
return &s
|
||||
}
|
||||
|
||||
@@ -637,6 +637,38 @@ func Test_PATs_Create(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func Test_Users_Update_CrossAccountAttack(t *testing.T) {
|
||||
t.Run("Admin attempts to update user from other account", func(t *testing.T) {
|
||||
apiHandler, _, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, false)
|
||||
|
||||
body, _ := json.Marshal(&api.UserRequest{
|
||||
Role: "user",
|
||||
AutoGroups: []string{},
|
||||
IsBlocked: true,
|
||||
})
|
||||
|
||||
// TestAdminId belongs to testAccountId, but targets otherUserId which belongs to otherAccountId
|
||||
req := testing_tools.BuildRequest(t, body, http.MethodPut, "/api/users/otherUserId", testing_tools.TestAdminId)
|
||||
recorder := httptest.NewRecorder()
|
||||
apiHandler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.NotEqual(t, http.StatusOK, recorder.Code, "cross-account user update must be rejected")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Users_Delete_CrossAccountAttack(t *testing.T) {
|
||||
t.Run("Admin attempts to delete service user from other account", func(t *testing.T) {
|
||||
apiHandler, _, _ := channel.BuildApiBlackBoxWithDBState(t, "../testdata/users_integration.sql", nil, false)
|
||||
|
||||
// TestAdminId belongs to testAccountId, but targets otherServiceUserId which belongs to otherAccountId
|
||||
req := testing_tools.BuildRequest(t, []byte{}, http.MethodDelete, "/api/users/otherServiceUserId", testing_tools.TestAdminId)
|
||||
recorder := httptest.NewRecorder()
|
||||
apiHandler.ServeHTTP(recorder, req)
|
||||
|
||||
assert.NotEqual(t, http.StatusOK, recorder.Code, "cross-account user delete must be rejected")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_PATs_Delete(t *testing.T) {
|
||||
users := []struct {
|
||||
name string
|
||||
|
||||
@@ -16,6 +16,7 @@ INSERT INTO users VALUES('testServiceAdminId','testAccountId','admin',1,0,'testS
|
||||
INSERT INTO users VALUES('blockedUserId','testAccountId','admin',0,0,'','[]',1,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||
INSERT INTO users VALUES('otherUserId','otherAccountId','admin',0,0,'','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||
INSERT INTO users VALUES('deletableServiceUserId','testAccountId','user',1,0,'deletableServiceUser','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||
INSERT INTO users VALUES('otherServiceUserId','otherAccountId','user',1,0,'otherServiceUser','[]',0,NULL,'2024-10-02 16:01:38.000000000+00:00','api',0,'');
|
||||
INSERT INTO "groups" VALUES('testGroupId','testAccountId','testGroupName','api','["testPeerId"]',0,'');
|
||||
INSERT INTO "groups" VALUES('newGroupId','testAccountId','newGroupName','api','[]',0,'');
|
||||
INSERT INTO setup_keys VALUES('testKeyId','testAccountId','testKey','testK****','existingKey','one-off','2021-08-19 20:46:20.000000000+00:00','2321-09-18 20:46:20.000000000+00:00','2021-08-19 20:46:20.000000000+00:00',0,0,NULL,'["testGroupId"]',1,0);
|
||||
|
||||
@@ -106,6 +106,10 @@ func ReadResponse(t *testing.T, recorder *httptest.ResponseRecorder, expectedSta
|
||||
}
|
||||
|
||||
if !expectResponse {
|
||||
if recorder.Code == http.StatusOK || recorder.Code == http.StatusCreated {
|
||||
t.Fatalf("expected unauthorized/error status code but got %d, content: %s",
|
||||
recorder.Code, string(content))
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user