Add team access checks (#2862)

This commit is contained in:
Miguel de la Cruz 2022-04-25 17:39:40 +02:00 committed by GitHub
parent bc3c081bf4
commit cda064a83a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 116 additions and 9 deletions

View file

@ -194,8 +194,11 @@ func (pa *PluginAdapter) getUserIDsForTeam(teamID string) []string {
userIDs := []string{}
for userID := range userMap {
if pa.auth.DoesUserHaveTeamAccess(userID, teamID) {
userIDs = append(userIDs, userID)
}
}
return userIDs
}
@ -223,7 +226,7 @@ func (pa *PluginAdapter) getUserIDsForTeamAndBoard(teamID, boardID string, ensur
userIDs := []string{}
for _, member := range members {
for userID := range userMap {
if userID == member.UserID {
if userID == member.UserID && pa.auth.DoesUserHaveTeamAccess(userID, teamID) {
userIDs = append(userIDs, userID)
}
}
@ -396,13 +399,6 @@ func (pa *PluginAdapter) BroadcastConfigChange(pluginConfig model.ClientConfig)
pa.sendMessageToAll(utils.StructToMap(pluginConfig))
}
// sendTeamMessageSkipCluster sends a message to all the users
// with a websocket client subscribed to a given team.
func (pa *PluginAdapter) sendTeamMessageSkipCluster(event, teamID string, payload map[string]interface{}) {
userIDs := pa.getUserIDsForTeam(teamID)
pa.sendUserMessageSkipCluster(event, payload, userIDs...)
}
// sendUserMessageSkipCluster sends the message to specific users.
func (pa *PluginAdapter) sendUserMessageSkipCluster(event string, payload map[string]interface{}, userIDs ...string) {
for _, userID := range userIDs {
@ -410,6 +406,13 @@ func (pa *PluginAdapter) sendUserMessageSkipCluster(event string, payload map[st
}
}
// sendTeamMessageSkipCluster sends a message to all the users
// with a websocket client subscribed to a given team.
func (pa *PluginAdapter) sendTeamMessageSkipCluster(event, teamID string, payload map[string]interface{}) {
userIDs := pa.getUserIDsForTeam(teamID)
pa.sendUserMessageSkipCluster(event, payload, userIDs...)
}
// sendTeamMessage sends and propagates a message that is aimed
// for all the users that are subscribed to a given team.
func (pa *PluginAdapter) sendTeamMessage(event, teamID string, payload map[string]interface{}, ensureUserIDs ...string) {

View file

@ -228,11 +228,25 @@ func TestGetUserIDsForTeam(t *testing.T) {
wg.Wait()
t.Run("should find that only user1 is connected to team 1", func(t *testing.T) {
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID1).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeam(teamID1)
require.ElementsMatch(t, []string{userID1}, userIDs)
})
t.Run("should find that both users are connected to team 2", func(t *testing.T) {
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID2, teamID2).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeam(teamID2)
require.ElementsMatch(t, []string{userID1, userID2}, userIDs)
})
@ -240,11 +254,21 @@ func TestGetUserIDsForTeam(t *testing.T) {
t.Run("should ignore user1 if webConn 2 inactive when getting team 2 user ids", func(t *testing.T) {
th.pa.OnWebSocketDisconnect(webConnID2, userID1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID2, teamID2).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeam(teamID2)
require.ElementsMatch(t, []string{userID2}, userIDs)
})
t.Run("should still find user 1 in team 1 after the webConn 2 disconnection", func(t *testing.T) {
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID1).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeam(teamID1)
require.ElementsMatch(t, []string{userID1}, userIDs)
})
@ -252,9 +276,34 @@ func TestGetUserIDsForTeam(t *testing.T) {
t.Run("should find again both users if the webConn 2 comes back", func(t *testing.T) {
th.pa.OnWebSocketConnect(webConnID2, userID1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID2, teamID2).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeam(teamID2)
require.ElementsMatch(t, []string{userID1, userID2}, userIDs)
})
t.Run("should only find user 1 if user 2 has an active connection but is not a team member anymore", func(t *testing.T) {
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
// userID2 does not have team access
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID2, teamID2).
Return(false).
Times(1)
userIDs := th.pa.getUserIDsForTeam(teamID2)
require.ElementsMatch(t, []string{userID1}, userIDs)
})
}
func TestGetUserIDsForTeamAndBoard(t *testing.T) {
@ -305,6 +354,11 @@ func TestGetUserIDsForTeamAndBoard(t *testing.T) {
Return(mockedMembers, nil).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID1).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeamAndBoard(teamID1, boardID1)
require.ElementsMatch(t, []string{userID1}, userIDs)
})
@ -316,6 +370,15 @@ func TestGetUserIDsForTeamAndBoard(t *testing.T) {
Return(mockedMembers, nil).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID2, teamID2).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeamAndBoard(teamID2, boardID2)
require.ElementsMatch(t, []string{userID1, userID2}, userIDs)
})
@ -327,6 +390,11 @@ func TestGetUserIDsForTeamAndBoard(t *testing.T) {
Return(mockedMembers, nil).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeamAndBoard(teamID2, boardID2)
require.ElementsMatch(t, []string{userID1}, userIDs)
})
@ -341,6 +409,11 @@ func TestGetUserIDsForTeamAndBoard(t *testing.T) {
Return(mockedMembers, nil).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeamAndBoard(teamID2, boardID2)
require.ElementsMatch(t, []string{userID1}, userIDs)
})
@ -353,9 +426,40 @@ func TestGetUserIDsForTeamAndBoard(t *testing.T) {
Return(mockedMembers, nil).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID2, teamID2).
Return(true).
Times(1)
userIDs := th.pa.getUserIDsForTeamAndBoard(teamID2, boardID2, userID3)
require.ElementsMatch(t, []string{userID1, userID2, userID3}, userIDs)
})
t.Run("should not include a user that, although present, has no team access anymore", func(t *testing.T) {
mockedMembers := []*model.BoardMember{{UserID: userID1}, {UserID: userID2}}
th.store.EXPECT().
GetMembersForBoard(boardID2).
Return(mockedMembers, nil).
Times(1)
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID1, teamID2).
Return(true).
Times(1)
// userID2 has no team access
th.auth.EXPECT().
DoesUserHaveTeamAccess(userID2, teamID2).
Return(false).
Times(1)
userIDs := th.pa.getUserIDsForTeamAndBoard(teamID2, boardID2)
require.ElementsMatch(t, []string{userID1}, userIDs)
})
}
func TestParallelSubscriptionsOnMultipleConnections(t *testing.T) {