mirror of
https://github.com/hanzoai/team.git
synced 2026-09-30 01:57:35 +00:00
* MM-68547: Tighten authorization on group syncable link and patch endpoints
Adds an additional permission check on the group syncable link and patch
endpoints. Callers must hold the role-management permission for the
target team or channel (or the sysconsole groups-management permission).
Made-with: Cursor
* Linting
* MM-68547: Extend group syncable scheme_admin authorization checks
Gate any explicit scheme_admin value (in either direction) on link and
patch. Populate SchemeAdmin in the singular getGroupSyncable so that
patches that do not touch scheme_admin no longer overwrite the persisted
value. Restrict PermittedSyncableAdmins to active syncables. Start the
link upsert from the existing active row to preserve fields the caller
did not, or could not, set.
Made-with: Cursor
* MM-68547: Add store-layer regression coverage for SchemeAdmin handling
Extend testGetGroupSyncable to round-trip SchemeAdmin: true through
UpdateGroupSyncable and re-fetch, locking in that getGroupSyncable
populates the field from the persisted row.
Strengthen groupTestPermittedSyncableAdmins{Team,Channel} to assert
that DeleteGroupSyncable preserves SchemeAdmin in the persisted row
and that PermittedSyncableAdmins still excludes the row, making the
coupling between the two store changes explicit.
Made-with: Cursor
* MM-68547: Fix group details role-change dedup on remove
The roleChangeKey helper was reading team_id/channel_id from the items
in itemsToRemove, but onRemoveTeamOrChannel pushes those items with a
generic id field. The deletion of the staged role change in
handleRemovedTeamsAndChannels therefore never matched the key produced
by onChangeRoles, and a stale patchGroupSyncable was dispatched after
the unlink.
Accept either id or team_id/channel_id when computing the key. Also
extend the e2e assertion to verify the channel removal took effect
(delete_at != 0) alongside the existing scheme_admin check.
Made-with: Cursor
* MM-68547: Mirror delete_at assertion on the removed-team e2e test
The team variant of "does not update the role of a removed X" was left
asserting only on scheme_admin. Add the matching delete_at != 0 check
already present in the channel variant so both tests verify the same
user-visible contract.
Made-with: Cursor
* Skip SyncSyncableRoles if no scheme_admin
(cherry picked from commit 6afe64ff9f)
Co-authored-by: Maria A Nunez <[email protected]>
3738 lines
131 KiB
Go
3738 lines
131 KiB
Go
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
package api4
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/mattermost/mattermost/server/public/model"
|
|
)
|
|
|
|
func TestGetGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, response, err := th.Client.GetGroup(context.Background(), g.Id, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroup(context.Background(), g.Id, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
group, _, err := th.SystemAdminClient.GetGroup(context.Background(), g.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, g.DisplayName, group.DisplayName)
|
|
assert.Equal(t, g.Name, group.Name)
|
|
assert.Equal(t, g.Source, group.Source)
|
|
assert.Equal(t, g.Description, group.Description)
|
|
assert.Equal(t, g.RemoteId, group.RemoteId)
|
|
assert.Equal(t, g.CreateAt, group.CreateAt)
|
|
assert.Equal(t, g.UpdateAt, group.UpdateAt)
|
|
assert.Equal(t, g.DeleteAt, group.DeleteAt)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroup(context.Background(), model.NewId(), "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroup(context.Background(), "12345", "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.GetGroup(context.Background(), group.Id, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestCreateGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
id := model.NewId()
|
|
g := &model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + id,
|
|
AllowReference: true,
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional, "ldap"))
|
|
|
|
_, resp, err := th.SystemAdminClient.CreateGroup(context.Background(), nil)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
|
|
group, _, err := th.SystemAdminClient.CreateGroup(context.Background(), g)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, g.DisplayName, group.DisplayName)
|
|
assert.Equal(t, g.Name, group.Name)
|
|
assert.Equal(t, g.Source, group.Source)
|
|
assert.Equal(t, g.Description, group.Description)
|
|
assert.Equal(t, g.RemoteId, group.RemoteId)
|
|
|
|
gbroken := &model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: "rrrr",
|
|
Description: "description_" + id,
|
|
}
|
|
|
|
_, response, err := th.SystemAdminClient.CreateGroup(context.Background(), gbroken)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
validGroup := &model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: model.NewPointer("name" + model.NewId()),
|
|
Source: model.GroupSourceCustom,
|
|
AllowReference: true,
|
|
}
|
|
|
|
th.RemovePermissionFromRole(t, model.PermissionCreateCustomGroup.Id, model.SystemAdminRoleId)
|
|
th.RemovePermissionFromRole(t, model.PermissionCreateCustomGroup.Id, model.SystemUserRoleId)
|
|
defer th.AddPermissionToRole(t, model.PermissionCreateCustomGroup.Id, model.SystemUserRoleId)
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), validGroup)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
th.AddPermissionToRole(t, model.PermissionCreateCustomGroup.Id, model.SystemAdminRoleId)
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), validGroup)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
usernameGroup := &model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: &th.BasicUser.Username,
|
|
Source: model.GroupSourceCustom,
|
|
AllowReference: true,
|
|
}
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), usernameGroup)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
unReferenceableCustomGroup := &model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: model.NewPointer("name" + model.NewId()),
|
|
Source: model.GroupSourceCustom,
|
|
AllowReference: false,
|
|
}
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), unReferenceableCustomGroup)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
unReferenceableCustomGroup.AllowReference = true
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), unReferenceableCustomGroup)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
customGroupWithRemoteID := &model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: model.NewPointer("name" + model.NewId()),
|
|
Source: model.GroupSourceCustom,
|
|
AllowReference: true,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
}
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), customGroupWithRemoteID)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
reservedNameGroup := &model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: model.NewPointer("here"),
|
|
Source: model.GroupSourceCustom,
|
|
AllowReference: true,
|
|
}
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), reservedNameGroup)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.CreateGroup(context.Background(), g)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestDeleteGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
_, response, err := th.Client.DeleteGroup(context.Background(), g.Id)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
th.AddPermissionToRole(t, model.PermissionDeleteCustomGroup.Id, model.SystemUserRoleId)
|
|
_, response, err = th.Client.DeleteGroup(context.Background(), g.Id)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, response, err = th.Client.DeleteGroup(context.Background(), g.Id)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, response, err = th.Client.DeleteGroup(context.Background(), "wertyuijhbgvfcde")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
validGroup, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: model.NewPointer("name" + model.NewId()),
|
|
Source: model.GroupSourceCustom,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, response, err = th.Client.DeleteGroup(context.Background(), validGroup.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
}
|
|
|
|
func TestUndeleteGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
validGroup, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: model.NewPointer("name" + model.NewId()),
|
|
Source: model.GroupSourceCustom,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, response, err := th.Client.DeleteGroup(context.Background(), validGroup.Id)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
th.RemovePermissionFromRole(t, model.PermissionRestoreCustomGroup.Id, model.SystemUserRoleId)
|
|
// shouldn't allow restoring unless user has required permission
|
|
_, response, err = th.Client.RestoreGroup(context.Background(), validGroup.Id, "")
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
th.AddPermissionToRole(t, model.PermissionRestoreCustomGroup.Id, model.SystemUserRoleId)
|
|
_, response, err = th.Client.RestoreGroup(context.Background(), validGroup.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
_, response, err = th.Client.RestoreGroup(context.Background(), validGroup.Id, "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
}
|
|
|
|
func TestPatchGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
g2, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + model.NewId(),
|
|
Name: model.NewPointer("name" + model.NewId()),
|
|
Source: model.GroupSourceCustom,
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
updateFmt := "%s_updated"
|
|
|
|
newName := fmt.Sprintf(updateFmt, *g.Name)
|
|
newDisplayName := fmt.Sprintf(updateFmt, g.DisplayName)
|
|
newDescription := fmt.Sprintf(updateFmt, g.Description)
|
|
|
|
gp := &model.GroupPatch{
|
|
Name: &newName,
|
|
DisplayName: &newDisplayName,
|
|
Description: &newDescription,
|
|
}
|
|
|
|
_, response, err := th.Client.PatchGroup(context.Background(), g.Id, gp)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroup(context.Background(), g.Id, gp)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional, "ldap"))
|
|
|
|
group2, response, err := th.SystemAdminClient.PatchGroup(context.Background(), g.Id, gp)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
group, _, err := th.SystemAdminClient.GetGroup(context.Background(), g.Id, "")
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, *gp.DisplayName, group.DisplayName)
|
|
assert.Equal(t, *gp.DisplayName, group2.DisplayName)
|
|
assert.Equal(t, *gp.Name, *group.Name)
|
|
assert.Equal(t, *gp.Name, *group2.Name)
|
|
assert.Equal(t, *gp.Description, group.Description)
|
|
assert.Equal(t, *gp.Description, group2.Description)
|
|
|
|
assert.Equal(t, group2.UpdateAt, group.UpdateAt)
|
|
|
|
assert.Equal(t, g.Source, group.Source)
|
|
assert.Equal(t, g.Source, group2.Source)
|
|
assert.Equal(t, g.RemoteId, group.RemoteId)
|
|
assert.Equal(t, g.RemoteId, group2.RemoteId)
|
|
assert.Equal(t, g.CreateAt, group.CreateAt)
|
|
assert.Equal(t, g.CreateAt, group2.CreateAt)
|
|
assert.Equal(t, g.DeleteAt, group.DeleteAt)
|
|
assert.Equal(t, g.DeleteAt, group2.DeleteAt)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroup(context.Background(), model.NewId(), gp)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroup(context.Background(), g2.Id, &model.GroupPatch{
|
|
Name: model.NewPointer(model.NewId()),
|
|
DisplayName: model.NewPointer("foo"),
|
|
AllowReference: model.NewPointer(false),
|
|
})
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
// ensure that omitting the AllowReference field from the patch doesn't patch it to false
|
|
patchedG2, response, err := th.SystemAdminClient.PatchGroup(context.Background(), g2.Id, &model.GroupPatch{
|
|
Name: model.NewPointer(model.NewId()),
|
|
DisplayName: model.NewPointer("foo"),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
require.Equal(t, true, patchedG2.AllowReference)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroup(context.Background(), g2.Id, &model.GroupPatch{
|
|
Name: model.NewPointer("here"),
|
|
})
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.PatchGroup(context.Background(), group.Id, gp)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestLinkGroupTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
id = model.NewId()
|
|
gRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
t.Run("Error if no license is installed", func(t *testing.T) {
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
|
|
groupSyncable, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
t.Run("Normal users are not allowed to link", func(t *testing.T) {
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
|
|
th.UpdateUserToTeamAdmin(t, th.BasicUser, th.BasicTeam)
|
|
response, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
_, response, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
var groupSyncable *model.GroupSyncable
|
|
t.Run("Team admins are not allowed to link", func(t *testing.T) {
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
|
|
t.Run("Team admins are allowed to link if AllowReference is enabled", func(t *testing.T) {
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
t.Cleanup(func() {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), gRef.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
})
|
|
})
|
|
|
|
t.Run("System admins are allowed to link", func(t *testing.T) {
|
|
groupSyncable, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
})
|
|
|
|
t.Run("System manager without invite_user are allowed to link", func(t *testing.T) {
|
|
_, _, err = th.SystemManagerClient.Login(context.Background(), th.SystemManagerUser.Email, th.SystemManagerUser.Password)
|
|
require.NoError(t, err)
|
|
groupSyncable, response, err = th.SystemManagerClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
})
|
|
|
|
t.Run("Custom groups can't be linked", func(t *testing.T) {
|
|
gid := model.NewId()
|
|
gCustom, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + gid,
|
|
Name: model.NewPointer("name" + gid),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + gid,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), gCustom.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
}
|
|
|
|
func TestLinkGroupChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
id = model.NewId()
|
|
gRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
t.Run("Error if no license is installed", func(t *testing.T) {
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
|
|
groupSyncable, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
t.Run("Normal users are not allowed to link", func(t *testing.T) {
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
|
|
th.MakeUserChannelAdmin(t, th.BasicUser, th.BasicChannel)
|
|
response, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
_, response, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
var groupSyncable *model.GroupSyncable
|
|
t.Run("Channel admins are not allowed to link", func(t *testing.T) {
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
|
|
t.Run("Channel admins are not allowed to link if AllowReference is enabled, but not team syncable exists", func(t *testing.T) {
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
|
|
groupSyncable, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
t.Run("Channel admins are allowed to link if AllowReference is enabled and a team syncable exists", func(t *testing.T) {
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
t.Cleanup(func() {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), gRef.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
})
|
|
})
|
|
|
|
t.Run("System admins are allowed to link", func(t *testing.T) {
|
|
groupSyncable, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
})
|
|
|
|
t.Run("System manager without invite_user are allowed to link", func(t *testing.T) {
|
|
_, _, err = th.SystemManagerClient.Login(context.Background(), th.SystemManagerUser.Email, th.SystemManagerUser.Password)
|
|
require.NoError(t, err)
|
|
groupSyncable, response, err = th.SystemManagerClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
})
|
|
|
|
t.Run("Custom groups can't be linked", func(t *testing.T) {
|
|
gid := model.NewId()
|
|
g2, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + gid,
|
|
Name: model.NewPointer("name" + gid),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + gid,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), g2.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
})
|
|
}
|
|
|
|
func TestUnlinkGroupTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
id = model.NewId()
|
|
gRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
groupSyncable, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
groupSyncable, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
t.Run("Error if no license is installed", func(t *testing.T) {
|
|
th.App.Srv().SetLicense(nil)
|
|
t.Cleanup(func() { th.App.Srv().SetLicense(model.NewTestLicense("ldap")) })
|
|
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
response, err = th.SystemAdminClient.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
})
|
|
|
|
t.Run("Normal users are not allowed to unlink", func(t *testing.T) {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
assert.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
})
|
|
|
|
time.Sleep(4 * time.Second) // A hack to let "go c.App.SyncRolesAndMembership" finish before moving on.
|
|
th.UpdateUserToTeamAdmin(t, th.BasicUser, th.BasicTeam)
|
|
response, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
_, response, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
t.Run("Team admins are not allowed to link", func(t *testing.T) {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
})
|
|
|
|
t.Run("Team admins are allowed to unlink if AllowReference is enabled", func(t *testing.T) {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), gRef.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
t.Cleanup(func() {
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
})
|
|
})
|
|
|
|
t.Run("System admins are allowed to unlink", func(t *testing.T) {
|
|
response, err = th.SystemAdminClient.UnlinkGroupSyncable(context.Background(), gRef.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
})
|
|
|
|
t.Run("System manager without invite_user are allowed to link", func(t *testing.T) {
|
|
_, _, err = th.SystemManagerClient.Login(context.Background(), th.SystemManagerUser.Email, th.SystemManagerUser.Password)
|
|
require.NoError(t, err)
|
|
response, err = th.SystemManagerClient.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
})
|
|
|
|
t.Run("Custom groups can't get unlinked", func(t *testing.T) {
|
|
gid := model.NewId()
|
|
g2, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + gid,
|
|
Name: model.NewPointer("name" + gid),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + gid,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g2.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
}
|
|
|
|
func TestUnlinkGroupChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
id = model.NewId()
|
|
gRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
groupSyncable, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
groupSyncable, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
t.Run("Error if no license is installed", func(t *testing.T) {
|
|
th.App.Srv().SetLicense(nil)
|
|
t.Cleanup(func() { th.App.Srv().SetLicense(model.NewTestLicense("ldap")) })
|
|
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
response, err = th.SystemAdminClient.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
})
|
|
|
|
t.Run("Normal users are not allowed to unlink", func(t *testing.T) {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
assert.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
})
|
|
|
|
th.MakeUserChannelAdmin(t, th.BasicUser, th.BasicChannel)
|
|
|
|
response, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
_, response, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
t.Run("Team admins are not allowed to link", func(t *testing.T) {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
})
|
|
|
|
t.Run("Team admins are allowed to unlink if AllowReference is enabled", func(t *testing.T) {
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), gRef.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
t.Cleanup(func() {
|
|
groupSyncable, response, err = th.Client.LinkGroupSyncable(context.Background(), gRef.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
})
|
|
})
|
|
|
|
t.Run("System admins are allowed to unlink", func(t *testing.T) {
|
|
response, err = th.SystemAdminClient.UnlinkGroupSyncable(context.Background(), gRef.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
})
|
|
|
|
t.Run("System manager without invite_user are allowed to link", func(t *testing.T) {
|
|
_, _, err = th.SystemManagerClient.Login(context.Background(), th.SystemManagerUser.Email, th.SystemManagerUser.Password)
|
|
require.NoError(t, err)
|
|
response, err = th.SystemManagerClient.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
})
|
|
|
|
t.Run("Custom groups can't get unlinked", func(t *testing.T) {
|
|
gid := model.NewId()
|
|
g2, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + gid,
|
|
Name: model.NewPointer("name" + gid),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + gid,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
response, err = th.Client.UnlinkGroupSyncable(context.Background(), g2.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
|
|
t.Run("Unlinking a group in a group constrained channel causes group members to be removed", func(t *testing.T) {
|
|
// Create a test group
|
|
group := th.CreateGroup(t)
|
|
|
|
// Create a channel and set it as group-constrained
|
|
channel := th.CreatePrivateChannel(t)
|
|
|
|
// Create a group user
|
|
groupUser := th.CreateUser(t)
|
|
th.LinkUserToTeam(t, groupUser, th.BasicTeam)
|
|
|
|
// Create a group member
|
|
_, appErr := th.App.UpsertGroupMember(group.Id, groupUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
// Associate the group with the channel
|
|
autoAdd := true
|
|
schemeAdmin := true
|
|
_, r, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), group.Id, channel.Id, model.GroupSyncableTypeChannel, &model.GroupSyncablePatch{AutoAdd: &autoAdd, SchemeAdmin: &schemeAdmin})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, r)
|
|
|
|
// Wait for the user to be added to the channel by polling until you see them
|
|
// or until we hit the timeout
|
|
timeout := time.After(5 * time.Second)
|
|
ticker := time.NewTicker(100 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
|
|
var cm *model.ChannelMember
|
|
userFound := false
|
|
for !userFound {
|
|
select {
|
|
case <-timeout:
|
|
require.Fail(t, "Timed out waiting for user to be added to the channel")
|
|
return
|
|
case <-ticker.C:
|
|
// Check if the user is now a member
|
|
cm, _, err = th.SystemAdminClient.GetChannelMember(context.Background(), channel.Id, groupUser.Id, "")
|
|
if err == nil && cm.UserId == groupUser.Id {
|
|
// User has been added, we can continue the test
|
|
userFound = true
|
|
}
|
|
}
|
|
}
|
|
|
|
patch := &model.ChannelPatch{}
|
|
patch.GroupConstrained = model.NewPointer(true)
|
|
_, r, err = th.SystemAdminClient.PatchChannel(context.Background(), channel.Id, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, r)
|
|
|
|
// Unlink the group
|
|
r, err = th.SystemAdminClient.UnlinkGroupSyncable(context.Background(), group.Id, channel.Id, model.GroupSyncableTypeChannel)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, r)
|
|
|
|
// Wait for the user to be removed from the channel by polling until they're gone
|
|
// or until we hit the timeout
|
|
timeout = time.After(3 * time.Second)
|
|
ticker = time.NewTicker(100 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
|
|
userRemoved := false
|
|
for !userRemoved {
|
|
select {
|
|
case <-timeout:
|
|
require.Fail(t, "Timed out waiting for user to be removed from channel")
|
|
return
|
|
case <-ticker.C:
|
|
// Check if the user is still a member
|
|
_, r, err = th.SystemAdminClient.GetChannelMember(context.Background(), channel.Id, groupUser.Id, "")
|
|
if err != nil && r.StatusCode == http.StatusNotFound {
|
|
// User has been removed, we can continue the test
|
|
userRemoved = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Verify the user is no longer a member of the channel
|
|
_, r, err = th.SystemAdminClient.GetChannelMember(context.Background(), channel.Id, groupUser.Id, "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, r)
|
|
})
|
|
|
|
t.Run("Unlinking a group in a non group constrained channel does not remove group members from the channel", func(t *testing.T) {
|
|
// Create a test group
|
|
group := th.CreateGroup(t)
|
|
|
|
// Create a channel and set it as group-constrained
|
|
channel := th.CreatePrivateChannel(t)
|
|
|
|
// Create a group user
|
|
groupUser := th.CreateUser(t)
|
|
th.LinkUserToTeam(t, groupUser, th.BasicTeam)
|
|
|
|
// Create a group member
|
|
_, appErr := th.App.UpsertGroupMember(group.Id, groupUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
// Associate the group with the channel
|
|
autoAdd := true
|
|
schemeAdmin := true
|
|
_, r, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), group.Id, channel.Id, model.GroupSyncableTypeChannel, &model.GroupSyncablePatch{AutoAdd: &autoAdd, SchemeAdmin: &schemeAdmin})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, r)
|
|
|
|
// Wait for the user to be added to the channel by polling until you see them
|
|
// or until we hit the timeout
|
|
timeout := time.After(5 * time.Second)
|
|
ticker := time.NewTicker(100 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
|
|
var cm *model.ChannelMember
|
|
userFound := false
|
|
for !userFound {
|
|
select {
|
|
case <-timeout:
|
|
require.Fail(t, "Timed out waiting for user to be added to the channel")
|
|
return
|
|
case <-ticker.C:
|
|
// Check if the user is now a member
|
|
cm, _, err = th.SystemAdminClient.GetChannelMember(context.Background(), channel.Id, groupUser.Id, "")
|
|
if err == nil && cm.UserId == groupUser.Id {
|
|
// User has been added, we can continue the test
|
|
userFound = true
|
|
}
|
|
}
|
|
}
|
|
|
|
// Unlink the group
|
|
r, err = th.SystemAdminClient.UnlinkGroupSyncable(context.Background(), group.Id, channel.Id, model.GroupSyncableTypeChannel)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, r)
|
|
|
|
// Wait for a reasonable amount of time to ensure the user is not removed because the channel is not group constrained
|
|
timeout = time.After(2 * time.Second)
|
|
ticker = time.NewTicker(100 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
|
|
userStillPresent := true
|
|
for userStillPresent {
|
|
select {
|
|
case <-timeout:
|
|
// If we reach the timeout, the user is still present, which is what we want
|
|
// Verify the user is still a member of the channel
|
|
cm, r, err = th.SystemAdminClient.GetChannelMember(context.Background(), channel.Id, groupUser.Id, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, r)
|
|
require.Equal(t, groupUser.Id, cm.UserId)
|
|
return
|
|
case <-ticker.C:
|
|
// Check if the user is still a member
|
|
_, r, err = th.SystemAdminClient.GetChannelMember(context.Background(), channel.Id, groupUser.Id, "")
|
|
if err != nil && r.StatusCode == http.StatusNotFound {
|
|
// User has been removed, which is not what we want
|
|
require.Fail(t, "User was incorrectly removed from the channel")
|
|
userStillPresent = false
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetGroupTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, response, err := th.Client.GetGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
_, response, _ = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
assert.Equal(t, http.StatusCreated, response.StatusCode)
|
|
|
|
groupSyncable, response, err := th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
assert.Equal(t, g.Id, groupSyncable.GroupId)
|
|
assert.Equal(t, th.BasicTeam.Id, groupSyncable.SyncableId)
|
|
assert.Equal(t, *patch.AutoAdd, groupSyncable.AutoAdd)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), model.NewId(), th.BasicTeam.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, model.NewId(), model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), "asdfasdfe3", th.BasicTeam.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, "asdfasdfe3", model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestGetGroupChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, response, err := th.Client.GetGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
_, response, _ = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
assert.Equal(t, http.StatusCreated, response.StatusCode)
|
|
|
|
groupSyncable, response, err := th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
assert.NotNil(t, groupSyncable)
|
|
|
|
assert.Equal(t, g.Id, groupSyncable.GroupId)
|
|
assert.Equal(t, th.BasicChannel.Id, groupSyncable.SyncableId)
|
|
assert.Equal(t, *patch.AutoAdd, groupSyncable.AutoAdd)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), model.NewId(), th.BasicChannel.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, model.NewId(), model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), "asdfasdfe3", th.BasicChannel.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, "asdfasdfe3", model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestGetGroupTeams(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
for range 10 {
|
|
team := th.CreateTeam(t)
|
|
_, response, _ := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, team.Id, model.GroupSyncableTypeTeam, patch)
|
|
assert.Equal(t, http.StatusCreated, response.StatusCode)
|
|
}
|
|
|
|
th.App.Srv().SetLicense(nil)
|
|
|
|
_, response, err := th.Client.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
_, response, _ = th.Client.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeTeam, "")
|
|
assert.Equal(t, http.StatusForbidden, response.StatusCode)
|
|
|
|
groupSyncables, response, err := th.SystemAdminClient.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeTeam, "")
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
assert.Len(t, groupSyncables, 10)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeTeam, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestGetGroupChannels(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
for range 10 {
|
|
channel := th.CreatePublicChannel(t)
|
|
_, response, _ := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, channel.Id, model.GroupSyncableTypeChannel, patch)
|
|
assert.Equal(t, http.StatusCreated, response.StatusCode)
|
|
}
|
|
|
|
th.App.Srv().SetLicense(nil)
|
|
|
|
_, response, err := th.Client.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
_, response, _ = th.Client.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeChannel, "")
|
|
assert.Equal(t, http.StatusForbidden, response.StatusCode)
|
|
|
|
groupSyncables, response, _ := th.SystemAdminClient.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeChannel, "")
|
|
CheckOKStatus(t, response)
|
|
|
|
assert.Len(t, groupSyncables, 10)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.GetGroupSyncables(context.Background(), g.Id, model.GroupSyncableTypeChannel, "")
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestPatchGroupTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
groupSyncable, response, _ := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
assert.Equal(t, http.StatusCreated, response.StatusCode)
|
|
assert.NotNil(t, groupSyncable)
|
|
assert.True(t, groupSyncable.AutoAdd)
|
|
|
|
_, response, _ = th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
assert.Equal(t, http.StatusForbidden, response.StatusCode)
|
|
|
|
th.App.Srv().SetLicense(nil)
|
|
|
|
_, response, err := th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
patch.AutoAdd = model.NewPointer(false)
|
|
groupSyncable, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
assert.False(t, groupSyncable.AutoAdd)
|
|
|
|
assert.Equal(t, g.Id, groupSyncable.GroupId)
|
|
assert.Equal(t, th.BasicTeam.Id, groupSyncable.SyncableId)
|
|
assert.Equal(t, model.GroupSyncableTypeTeam, groupSyncable.Type)
|
|
|
|
patch.AutoAdd = model.NewPointer(true)
|
|
_, response, _ = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
CheckOKStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), model.NewId(), th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, model.NewId(), model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), "abc", th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, "abc", model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestPatchGroupChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
groupSyncable, response, _ := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
assert.Equal(t, http.StatusCreated, response.StatusCode)
|
|
assert.NotNil(t, groupSyncable)
|
|
assert.True(t, groupSyncable.AutoAdd)
|
|
|
|
role, appErr := th.App.GetRoleByName(th.Context, "channel_user")
|
|
require.Nil(t, appErr)
|
|
originalPermissions := role.Permissions
|
|
_, appErr = th.App.PatchRole(role, &model.RolePatch{Permissions: &[]string{}})
|
|
require.Nil(t, appErr)
|
|
|
|
_, response, _ = th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
assert.Equal(t, http.StatusForbidden, response.StatusCode)
|
|
|
|
_, appErr = th.App.PatchRole(role, &model.RolePatch{Permissions: &originalPermissions})
|
|
require.Nil(t, appErr)
|
|
|
|
th.App.Srv().SetLicense(nil)
|
|
|
|
_, response, err := th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
patch.AutoAdd = model.NewPointer(false)
|
|
groupSyncable, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
assert.False(t, groupSyncable.AutoAdd)
|
|
|
|
assert.Equal(t, g.Id, groupSyncable.GroupId)
|
|
assert.Equal(t, th.BasicChannel.Id, groupSyncable.SyncableId)
|
|
assert.Equal(t, th.BasicChannel.TeamId, groupSyncable.TeamID)
|
|
assert.Equal(t, model.GroupSyncableTypeChannel, groupSyncable.Type)
|
|
|
|
patch.AutoAdd = model.NewPointer(true)
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), model.NewId(), th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, model.NewId(), model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckNotFoundStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), "abc", th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, "abc", model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, err = th.SystemAdminClient.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, response, err = th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, response)
|
|
}
|
|
|
|
func TestGetGroupsByChannel(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
// Create a group with AllowReference=false
|
|
id2 := model.NewId()
|
|
groupNoRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id2,
|
|
Name: model.NewPointer("name" + id2),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id2,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: false,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
// Create a group with AllowReference=true
|
|
id3 := model.NewId()
|
|
groupWithRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id3,
|
|
Name: model.NewPointer("name" + id3),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id3,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
groupSyncable, appErr := th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicChannel.Id,
|
|
Type: model.GroupSyncableTypeChannel,
|
|
GroupId: group.Id,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, appErr = th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicChannel.Id,
|
|
Type: model.GroupSyncableTypeChannel,
|
|
GroupId: groupNoRef.Id,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, appErr = th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicChannel.Id,
|
|
Type: model.GroupSyncableTypeChannel,
|
|
GroupId: groupWithRef.Id,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
opts := model.GroupSearchOpts{
|
|
PageOpts: &model.PageOpts{
|
|
Page: 0,
|
|
PerPage: 60,
|
|
},
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, _, response, err := client.GetGroupsByChannel(context.Background(), "asdfasdf", opts)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(nil)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, _, response, err := client.GetGroupsByChannel(context.Background(), th.BasicChannel.Id, opts)
|
|
require.Error(t, err)
|
|
if client == th.SystemAdminClient {
|
|
CheckNotImplementedStatus(t, response)
|
|
} else {
|
|
CheckForbiddenStatus(t, response)
|
|
}
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
privateChannel := th.CreateChannelWithClient(t, th.SystemAdminClient, model.ChannelTypePrivate)
|
|
|
|
_, _, response, err := th.Client.GetGroupsByChannel(context.Background(), privateChannel.Id, opts)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
var groups []*model.GroupWithSchemeAdmin
|
|
groups, _, _, err = client.GetGroupsByChannel(context.Background(), th.BasicChannel.Id, opts)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, groups, 3)
|
|
|
|
// Admin should see all groups
|
|
foundNoRef := false
|
|
foundWithRef := false
|
|
for _, g := range groups {
|
|
if g.Group.Id == groupNoRef.Id {
|
|
foundNoRef = true
|
|
}
|
|
if g.Group.Id == groupWithRef.Id {
|
|
foundWithRef = true
|
|
}
|
|
}
|
|
assert.True(t, foundNoRef, "Admin should see groups with AllowReference=false")
|
|
assert.True(t, foundWithRef, "Admin should see groups with AllowReference=true")
|
|
})
|
|
|
|
// set syncable to true
|
|
groupSyncable.SchemeAdmin = true
|
|
_, appErr = th.App.UpdateGroupSyncable(groupSyncable)
|
|
require.Nil(t, appErr)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
groups, _, _, err := client.GetGroupsByChannel(context.Background(), th.BasicChannel.Id, opts)
|
|
assert.NoError(t, err)
|
|
assert.Len(t, groups, 3)
|
|
|
|
// Verify SchemeAdmin field is updated for the first group
|
|
for _, g := range groups {
|
|
if g.Group.Id == group.Id {
|
|
require.NotNil(t, g.SchemeAdmin)
|
|
require.True(t, *g.SchemeAdmin)
|
|
}
|
|
}
|
|
|
|
groups, _, _, err = client.GetGroupsByChannel(context.Background(), model.NewId(), opts)
|
|
CheckErrorID(t, err, "app.channel.get.existing.app_error")
|
|
assert.Empty(t, groups)
|
|
})
|
|
}
|
|
|
|
func TestGetGroupsAssociatedToChannelsByTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
// Create a group with AllowReference=false
|
|
id2 := model.NewId()
|
|
groupNoRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id2,
|
|
Name: model.NewPointer("name" + id2),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id2,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: false,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
// Create a group with AllowReference=true
|
|
id3 := model.NewId()
|
|
groupWithRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id3,
|
|
Name: model.NewPointer("name" + id3),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id3,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
groupSyncable, appErr := th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicChannel.Id,
|
|
Type: model.GroupSyncableTypeChannel,
|
|
GroupId: group.Id,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, appErr = th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicChannel.Id,
|
|
Type: model.GroupSyncableTypeChannel,
|
|
GroupId: groupNoRef.Id,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, appErr = th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicChannel.Id,
|
|
Type: model.GroupSyncableTypeChannel,
|
|
GroupId: groupWithRef.Id,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
opts := model.GroupSearchOpts{
|
|
PageOpts: &model.PageOpts{
|
|
Page: 0,
|
|
PerPage: 60,
|
|
},
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
_, response, err := th.SystemAdminClient.GetGroupsAssociatedToChannelsByTeam(context.Background(), "asdfasdf", opts)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(nil)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupsAssociatedToChannelsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
groups, _, err := th.SystemAdminClient.GetGroupsAssociatedToChannelsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
assert.NoError(t, err)
|
|
|
|
// Admin should see all groups
|
|
assert.Len(t, groups[th.BasicChannel.Id], 3)
|
|
|
|
foundNoRef := false
|
|
foundWithRef := false
|
|
for _, g := range groups[th.BasicChannel.Id] {
|
|
if g.Group.Id == groupNoRef.Id {
|
|
foundNoRef = true
|
|
}
|
|
if g.Group.Id == groupWithRef.Id {
|
|
foundWithRef = true
|
|
}
|
|
}
|
|
assert.True(t, foundNoRef, "Admin should see groups with AllowReference=false")
|
|
assert.True(t, foundWithRef, "Admin should see groups with AllowReference=true")
|
|
|
|
// set syncable to true
|
|
groupSyncable.SchemeAdmin = true
|
|
_, appErr = th.App.UpdateGroupSyncable(groupSyncable)
|
|
require.Nil(t, appErr)
|
|
|
|
// Test with regular user and FilterAllowReference
|
|
t.Run("regular user with FilterAllowReference", func(t *testing.T) {
|
|
optsWithFilter := opts
|
|
optsWithFilter.FilterAllowReference = true
|
|
|
|
groups, _, err = th.Client.GetGroupsAssociatedToChannelsByTeam(context.Background(), th.BasicTeam.Id, optsWithFilter)
|
|
assert.NoError(t, err)
|
|
|
|
// Regular user should only see groups with AllowReference=true
|
|
for _, groupList := range groups {
|
|
for _, g := range groupList {
|
|
if g.Group.Id == groupWithRef.Id {
|
|
assert.True(t, g.Group.AllowReference)
|
|
}
|
|
assert.NotEqual(t, g.Group.Id, groupNoRef.Id, "Non-admin user should not see groups with AllowReference=false")
|
|
}
|
|
}
|
|
})
|
|
|
|
groups, _, err = th.SystemAdminClient.GetGroupsAssociatedToChannelsByTeam(context.Background(), model.NewId(), opts)
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, groups)
|
|
|
|
t.Run("should get the groups ok when belonging to the team", func(t *testing.T) {
|
|
var resp *model.Response
|
|
groups, resp, err = th.Client.GetGroupsAssociatedToChannelsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.NotEmpty(t, groups)
|
|
})
|
|
|
|
t.Run("should return forbidden when the user doesn't have the right permissions", func(t *testing.T) {
|
|
require.Nil(t, th.App.RemoveUserFromTeam(th.Context, th.BasicTeam.Id, th.BasicUser.Id, th.SystemAdminUser.Id))
|
|
defer func() {
|
|
_, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, th.BasicUser.Id, th.SystemAdminUser.Id)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
var resp *model.Response
|
|
groups, resp, err = th.Client.GetGroupsAssociatedToChannelsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, resp)
|
|
require.Empty(t, groups)
|
|
})
|
|
}
|
|
|
|
func TestGetGroupsByTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group, err := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn1_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
id2 := model.NewId()
|
|
groupNoRef, err := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn2_" + id2,
|
|
Name: model.NewPointer("name" + id2),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id2,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: false,
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
id3 := model.NewId()
|
|
groupWithRef, err := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn3_" + id3,
|
|
Name: model.NewPointer("name" + id3),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id3,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
groupSyncable, err := th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicTeam.Id,
|
|
Type: model.GroupSyncableTypeTeam,
|
|
GroupId: group.Id,
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
_, err = th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicTeam.Id,
|
|
Type: model.GroupSyncableTypeTeam,
|
|
GroupId: groupNoRef.Id,
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
_, err = th.App.UpsertGroupSyncable(&model.GroupSyncable{
|
|
AutoAdd: true,
|
|
SyncableId: th.BasicTeam.Id,
|
|
Type: model.GroupSyncableTypeTeam,
|
|
GroupId: groupWithRef.Id,
|
|
})
|
|
assert.Nil(t, err)
|
|
|
|
opts := model.GroupSearchOpts{
|
|
PageOpts: &model.PageOpts{
|
|
Page: 0,
|
|
PerPage: 60,
|
|
},
|
|
}
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, _, response, err := client.GetGroupsByTeam(context.Background(), "asdfasdf", opts)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
|
|
appErr := th.App.Srv().RemoveLicense()
|
|
require.Nil(t, appErr)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
_, _, response, err := client.GetGroupsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
require.Error(t, err)
|
|
if client == th.SystemAdminClient {
|
|
CheckNotImplementedStatus(t, response)
|
|
} else {
|
|
CheckForbiddenStatus(t, response)
|
|
}
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
groups, _, _, err := client.GetGroupsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
assert.NoError(t, err)
|
|
existingGroups := []*model.GroupWithSchemeAdmin{
|
|
{
|
|
Group: *group,
|
|
SchemeAdmin: model.NewPointer(false),
|
|
},
|
|
{
|
|
Group: *groupNoRef,
|
|
SchemeAdmin: model.NewPointer(false),
|
|
},
|
|
{
|
|
Group: *groupWithRef,
|
|
SchemeAdmin: model.NewPointer(false),
|
|
},
|
|
}
|
|
assert.ElementsMatch(t, existingGroups, groups)
|
|
require.NotNil(t, groups[0].SchemeAdmin)
|
|
require.False(t, *groups[0].SchemeAdmin)
|
|
})
|
|
|
|
// set syncable to true
|
|
groupSyncable.SchemeAdmin = true
|
|
_, err = th.App.UpdateGroupSyncable(groupSyncable)
|
|
require.Nil(t, err)
|
|
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
groups, _, _, err := client.GetGroupsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
assert.NoError(t, err)
|
|
existingGroups := []*model.GroupWithSchemeAdmin{
|
|
{
|
|
Group: *group,
|
|
SchemeAdmin: model.NewPointer(true),
|
|
},
|
|
{
|
|
Group: *groupNoRef,
|
|
SchemeAdmin: model.NewPointer(false),
|
|
},
|
|
{
|
|
Group: *groupWithRef,
|
|
SchemeAdmin: model.NewPointer(false),
|
|
},
|
|
}
|
|
|
|
assert.ElementsMatch(t, existingGroups, groups)
|
|
|
|
groups, _, _, err = client.GetGroupsByTeam(context.Background(), model.NewId(), opts)
|
|
assert.NoError(t, err)
|
|
assert.Empty(t, groups)
|
|
})
|
|
|
|
t.Run("groups should be fetched only by users with the right permissions", func(t *testing.T) {
|
|
th.TestForSystemAdminAndLocal(t, func(t *testing.T, client *model.Client4) {
|
|
groups, _, _, err := client.GetGroupsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
require.NoError(t, err)
|
|
require.Len(t, groups, 3)
|
|
// Admin should see all groups
|
|
foundNoRef := false
|
|
foundWithRef := false
|
|
for _, g := range groups {
|
|
if g.Group.Id == groupNoRef.Id {
|
|
foundNoRef = true
|
|
}
|
|
if g.Group.Id == groupWithRef.Id {
|
|
foundWithRef = true
|
|
}
|
|
}
|
|
assert.True(t, foundNoRef, "Admin should see groups with AllowReference=false")
|
|
assert.True(t, foundWithRef, "Admin should see groups with AllowReference=true")
|
|
}, "groups can be fetched by system admins even if they're not part of a team")
|
|
|
|
t.Run("user can fetch groups if it's part of the team", func(t *testing.T) {
|
|
optsWithFilter := opts
|
|
|
|
groups, _, _, err := th.Client.GetGroupsByTeam(context.Background(), th.BasicTeam.Id, optsWithFilter)
|
|
require.NoError(t, err)
|
|
|
|
for _, g := range groups {
|
|
if g.Group.Id == groupWithRef.Id {
|
|
assert.True(t, g.Group.AllowReference)
|
|
}
|
|
assert.NotEqual(t, g.Group.Id, groupNoRef.Id, "Non-admin user should not see groups with AllowReference=false")
|
|
}
|
|
})
|
|
|
|
t.Run("user can't fetch groups if it's not part of the team", func(t *testing.T) {
|
|
require.Nil(t, th.App.RemoveUserFromTeam(th.Context, th.BasicTeam.Id, th.BasicUser.Id, th.SystemAdminUser.Id))
|
|
defer func() {
|
|
_, _, appErr := th.App.AddUserToTeam(th.Context, th.BasicTeam.Id, th.BasicUser.Id, th.SystemAdminUser.Id)
|
|
require.Nil(t, appErr)
|
|
}()
|
|
|
|
groups, _, response, err := th.Client.GetGroupsByTeam(context.Background(), th.BasicTeam.Id, opts)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
require.Empty(t, groups)
|
|
})
|
|
})
|
|
}
|
|
|
|
func TestGetGroups(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
// make sure "createdDate" for next group is after one created in InitBasic()
|
|
time.Sleep(2 * time.Millisecond)
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
start := group.UpdateAt - 1
|
|
|
|
id2 := model.NewId()
|
|
group2, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id2,
|
|
Name: model.NewPointer("name" + id2),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + id2,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
// Create a group with AllowReference=false
|
|
id3 := model.NewId()
|
|
groupNoRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id3,
|
|
Name: model.NewPointer("name" + id3),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id3,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: false,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
// Create a group with AllowReference=true
|
|
id4 := model.NewId()
|
|
groupWithRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id4,
|
|
Name: model.NewPointer("name" + id4),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id4,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
baseOpts := model.GroupSearchOpts{
|
|
Source: model.GroupSourceLdap,
|
|
}
|
|
|
|
t.Run("without license", func(t *testing.T) {
|
|
opts := baseOpts
|
|
th.App.Srv().SetLicense(nil)
|
|
groups, response, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
assert.Nil(t, groups)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
t.Run("basic search for all groups", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.Source = ""
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, []*model.Group{group, th.Group, groupNoRef, groupWithRef, group2}, groups)
|
|
assert.Nil(t, groups[0].MemberCount)
|
|
})
|
|
|
|
t.Run("test FilterAllowReference for non-admin user", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.FilterAllowReference = true
|
|
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
|
|
groups, _, err := th.Client.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
|
|
for _, g := range groups {
|
|
if g.Id == groupWithRef.Id {
|
|
assert.True(t, g.AllowReference)
|
|
}
|
|
assert.NotEqual(t, g.Id, groupNoRef.Id, "Non-admin user should not see groups with AllowReference=false")
|
|
}
|
|
|
|
_, _, err = th.SystemAdminClient.Login(context.Background(), th.SystemAdminUser.Email, th.SystemAdminUser.Password)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("test FilterAllowReference for admin user", func(t *testing.T) {
|
|
opts := baseOpts
|
|
|
|
groups, _, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
|
|
foundNoRef := false
|
|
foundWithRef := false
|
|
for _, g := range groups {
|
|
if g.Id == groupNoRef.Id {
|
|
foundNoRef = true
|
|
}
|
|
if g.Id == groupWithRef.Id {
|
|
foundWithRef = true
|
|
}
|
|
}
|
|
assert.True(t, foundNoRef, "Admin should see groups with AllowReference=false")
|
|
assert.True(t, foundWithRef, "Admin should see groups with AllowReference=true")
|
|
})
|
|
|
|
t.Run("include member count", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.IncludeMemberCount = true
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.NotNil(t, groups[0].MemberCount)
|
|
})
|
|
|
|
t.Run("search with Q parameter", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.Q = "-fOo"
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, groups, 3)
|
|
})
|
|
|
|
t.Run("test FilterAllowReference for non-admin user", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.FilterAllowReference = true
|
|
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
|
|
groups, _, err := th.Client.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
|
|
for _, g := range groups {
|
|
if g.Id == groupWithRef.Id {
|
|
assert.True(t, g.AllowReference)
|
|
}
|
|
assert.NotEqual(t, g.Id, groupNoRef.Id, "Non-admin user should not see groups with AllowReference=false")
|
|
}
|
|
|
|
_, _, err = th.SystemAdminClient.Login(context.Background(), th.SystemAdminUser.Email, th.SystemAdminUser.Password)
|
|
require.NoError(t, err)
|
|
})
|
|
|
|
t.Run("test FilterAllowReference for admin user", func(t *testing.T) {
|
|
opts := baseOpts
|
|
|
|
groups, _, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
|
|
foundNoRef := false
|
|
foundWithRef := false
|
|
for _, g := range groups {
|
|
if g.Id == groupNoRef.Id {
|
|
foundNoRef = true
|
|
}
|
|
if g.Id == groupWithRef.Id {
|
|
foundWithRef = true
|
|
}
|
|
}
|
|
assert.True(t, foundNoRef, "Admin should see groups with AllowReference=false")
|
|
assert.True(t, foundWithRef, "Admin should see groups with AllowReference=true")
|
|
})
|
|
|
|
t.Run("not associated to channel", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.NotAssociatedToChannel = th.BasicChannel.Id
|
|
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, []*model.Group{group, th.Group, groupNoRef, groupWithRef}, groups)
|
|
})
|
|
|
|
t.Run("not associated to team", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.NotAssociatedToTeam = th.BasicTeam.Id
|
|
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, []*model.Group{group, th.Group, groupNoRef, groupWithRef}, groups)
|
|
})
|
|
|
|
t.Run("since parameter", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.Since = start
|
|
groups, resp, err := th.Client.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, groups, 1)
|
|
assert.Equal(t, groups[0].Id, groupWithRef.Id)
|
|
|
|
opts.Since = model.GetMillis()
|
|
groups, resp, err = th.Client.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Empty(t, groups)
|
|
})
|
|
|
|
t.Run("archived groups", func(t *testing.T) {
|
|
opts := baseOpts
|
|
_, appErr = th.App.DeleteGroup(group.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
// Test include_archived parameter
|
|
opts.IncludeArchived = true
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, groups, 4)
|
|
|
|
// Test returning only archived groups
|
|
opts.FilterArchived = true
|
|
groups, _, err = th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, groups, 1)
|
|
assert.Equal(t, groups[0].Id, group.Id)
|
|
})
|
|
|
|
t.Run("group source filtering", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.Source = model.GroupSourceCustom
|
|
groups, resp, err := th.Client.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, groups, 1)
|
|
assert.Equal(t, groups[0].Id, group2.Id)
|
|
})
|
|
|
|
t.Run("channel member counts", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.IncludeChannelMemberCount = th.BasicChannel.Id
|
|
opts.IncludeTimezones = true
|
|
opts.Q = "-fOo"
|
|
opts.IncludeMemberCount = true
|
|
opts.Source = model.GroupSourceCustom // Switch to custom source to get group2
|
|
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, groups, 1)
|
|
assert.Equal(t, *groups[0].MemberCount, int(0))
|
|
assert.Equal(t, *groups[0].ChannelMemberCount, int(0))
|
|
|
|
_, appErr = th.App.UpsertGroupMember(group2.Id, th.BasicUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
groups, resp, err = th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
require.Len(t, groups, 1)
|
|
assert.Equal(t, *groups[0].MemberCount, int(1))
|
|
assert.Equal(t, *groups[0].ChannelMemberCount, int(1))
|
|
})
|
|
|
|
t.Run("custom groups disabled", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableCustomGroups = false
|
|
})
|
|
|
|
t.Run("custom source not allowed", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.Source = model.GroupSourceCustom
|
|
groups, response, err := th.Client.GetGroups(context.Background(), opts)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
assert.Nil(t, groups)
|
|
})
|
|
|
|
t.Run("ldap source allowed", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.Source = model.GroupSourceLdap
|
|
groups, resp, err := th.Client.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, groups, 1)
|
|
assert.Equal(t, groups[0].Source, model.GroupSourceLdap)
|
|
})
|
|
|
|
t.Run("no source specified", func(t *testing.T) {
|
|
opts := baseOpts
|
|
opts.Source = ""
|
|
groups, resp, err := th.Client.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.Len(t, groups, 1)
|
|
assert.Equal(t, groups[0].Source, model.GroupSourceLdap)
|
|
})
|
|
})
|
|
|
|
t.Run("only_syncable_sources parameter", func(t *testing.T) {
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableCustomGroups = true
|
|
})
|
|
|
|
// Create a syncable group with the plugin prefix
|
|
id := model.NewId()
|
|
_, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourcePluginPrefix + "keycloak",
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
require.Nil(t, appErr)
|
|
|
|
// First test without only_syncable_sources
|
|
opts := model.GroupSearchOpts{
|
|
PageOpts: &model.PageOpts{
|
|
Page: 0,
|
|
PerPage: 60,
|
|
},
|
|
}
|
|
groups, resp, err := th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
// Should return all groups regardless of source when not specified
|
|
assert.Len(t, groups, 5)
|
|
|
|
// Test with custom groups disabled and only_syncable_sources=true
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableCustomGroups = false
|
|
})
|
|
groups, resp, err = th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
// Should still only return LDAP groups
|
|
assert.Len(t, groups, 4)
|
|
for _, g := range groups {
|
|
assert.True(t, g.Source == model.GroupSourceLdap || strings.HasPrefix(string(g.Source), string(model.GroupSourcePluginPrefix)))
|
|
}
|
|
|
|
// Reset config
|
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
|
*cfg.ServiceSettings.EnableCustomGroups = true
|
|
})
|
|
|
|
// Test with only_syncable_sources=true
|
|
opts.OnlySyncableSources = true
|
|
groups, resp, err = th.SystemAdminClient.GetGroups(context.Background(), opts)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
|
|
// Should only return groups from syncable sources (LDAP and plugin_ groups)
|
|
assert.Len(t, groups, 4)
|
|
for _, g := range groups {
|
|
assert.True(t, g.Source == model.GroupSourceLdap || strings.HasPrefix(string(g.Source), string(model.GroupSourcePluginPrefix)))
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGetGroupsByNames(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
// make sure "createdDate" for next group is after one created in InitBasic()
|
|
time.Sleep(2 * time.Millisecond)
|
|
id := model.NewId()
|
|
groupName := model.NewPointer("name" + id)
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: groupName,
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
id2 := model.NewId()
|
|
group2Name := model.NewPointer("name" + id2)
|
|
group2, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id2,
|
|
Name: group2Name,
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id2,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
// Create a group with AllowReference=false
|
|
id3 := model.NewId()
|
|
group3Name := model.NewPointer("name" + id3)
|
|
group3, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id3,
|
|
Name: group3Name,
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id3,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
t.Run("without license", func(t *testing.T) {
|
|
th.App.Srv().SetLicense(nil)
|
|
groups, resp, err := th.SystemAdminClient.GetGroupsByNames(context.Background(), []string{*groupName})
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, resp)
|
|
assert.Nil(t, groups)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
t.Run("search for one group", func(t *testing.T) {
|
|
groups, resp, err := th.SystemAdminClient.GetGroupsByNames(context.Background(), []string{*groupName})
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, []*model.Group{group}, groups)
|
|
assert.Nil(t, groups[0].MemberCount)
|
|
})
|
|
|
|
t.Run("search for multiple groups only finding one", func(t *testing.T) {
|
|
searchTerms := []string{*group2Name, "fakename", "fakename2"}
|
|
groups, resp, err := th.SystemAdminClient.GetGroupsByNames(context.Background(), searchTerms)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, []*model.Group{group2}, groups)
|
|
assert.Nil(t, groups[0].MemberCount)
|
|
})
|
|
|
|
t.Run("search for multiple groups returning all three", func(t *testing.T) {
|
|
searchTerms := []string{*groupName, *group2Name, *group3Name}
|
|
groups, resp, err := th.SystemAdminClient.GetGroupsByNames(context.Background(), searchTerms)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, []*model.Group{group, group2, group3}, groups)
|
|
assert.Nil(t, groups[0].MemberCount)
|
|
})
|
|
|
|
t.Run("search for more groups than existing returning existing", func(t *testing.T) {
|
|
searchTerms := []string{*groupName, *group2Name, *group3Name, "fakename", "fakename2"}
|
|
groups, resp, err := th.SystemAdminClient.GetGroupsByNames(context.Background(), searchTerms)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, []*model.Group{group, group2, group3}, groups)
|
|
assert.Nil(t, groups[0].MemberCount)
|
|
})
|
|
|
|
t.Run("search for groups with invalid names", func(t *testing.T) {
|
|
searchTerms := []string{"fakename", "fakename2"}
|
|
groups, resp, err := th.SystemAdminClient.GetGroupsByNames(context.Background(), searchTerms)
|
|
require.NoError(t, err)
|
|
require.Empty(t, groups, "no groups should be returned")
|
|
CheckOKStatus(t, resp)
|
|
})
|
|
|
|
t.Run("search for groups is empty", func(t *testing.T) {
|
|
searchTerms := []string{}
|
|
groups, resp, err := th.SystemAdminClient.GetGroupsByNames(context.Background(), searchTerms)
|
|
require.NoError(t, err)
|
|
require.Empty(t, groups, "no groups should be returned")
|
|
CheckOKStatus(t, resp)
|
|
})
|
|
|
|
t.Run("attempt search without session", func(t *testing.T) {
|
|
_, err := th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
searchTerms := []string{*groupName}
|
|
_, resp, err := th.Client.GetGroupsByNames(context.Background(), searchTerms)
|
|
require.Error(t, err)
|
|
CheckUnauthorizedStatus(t, resp)
|
|
})
|
|
}
|
|
|
|
func TestGetGroupsByNamesAllowReference(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
// Create group with AllowReference=true
|
|
id1 := model.NewId()
|
|
groupAllowRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-allow_" + id1,
|
|
Name: model.NewPointer("allow" + id1),
|
|
Source: model.GroupSourceLdap,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
require.Nil(t, appErr)
|
|
|
|
// Create group with AllowReference=false
|
|
id2 := model.NewId()
|
|
groupNoRef, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-noref_" + id2,
|
|
Name: model.NewPointer("noref" + id2),
|
|
Source: model.GroupSourceLdap,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: false,
|
|
})
|
|
require.Nil(t, appErr)
|
|
|
|
// Login as regular user
|
|
th.LoginBasic(t)
|
|
|
|
tests := []struct {
|
|
name string
|
|
client *model.Client4
|
|
searchNames []string
|
|
expectedGroups []*model.Group
|
|
description string
|
|
}{
|
|
{
|
|
name: "admin sees all groups",
|
|
client: th.SystemAdminClient,
|
|
searchNames: []string{*groupAllowRef.Name, *groupNoRef.Name},
|
|
expectedGroups: []*model.Group{groupAllowRef, groupNoRef},
|
|
description: "admin with sysconsole permission should see all groups",
|
|
},
|
|
{
|
|
name: "admin sees group with AllowReference=false",
|
|
client: th.SystemAdminClient,
|
|
searchNames: []string{*groupNoRef.Name},
|
|
expectedGroups: []*model.Group{groupNoRef},
|
|
description: "admin should see group even when AllowReference=false",
|
|
},
|
|
{
|
|
name: "regular user sees only AllowReference=true",
|
|
client: th.Client,
|
|
searchNames: []string{*groupAllowRef.Name, *groupNoRef.Name},
|
|
expectedGroups: []*model.Group{groupAllowRef},
|
|
description: "regular user should only see groups with AllowReference=true",
|
|
},
|
|
{
|
|
name: "regular user cannot see AllowReference=false group",
|
|
client: th.Client,
|
|
searchNames: []string{*groupNoRef.Name},
|
|
expectedGroups: []*model.Group{},
|
|
description: "regular user should not see groups with AllowReference=false",
|
|
},
|
|
{
|
|
name: "regular user sees AllowReference=true group",
|
|
client: th.Client,
|
|
searchNames: []string{*groupAllowRef.Name},
|
|
expectedGroups: []*model.Group{groupAllowRef},
|
|
description: "regular user should see groups with AllowReference=true",
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
groups, resp, err := tc.client.GetGroupsByNames(context.Background(), tc.searchNames)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, resp)
|
|
assert.ElementsMatch(t, tc.expectedGroups, groups, tc.description)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetGroupsByUserId(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group1, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
user1, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SystemUserRoleId})
|
|
assert.Nil(t, appErr)
|
|
user1.Password = "test-password-1"
|
|
_, appErr = th.App.UpsertGroupMember(group1.Id, user1.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
id = model.NewId()
|
|
group2, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, appErr = th.App.UpsertGroupMember(group2.Id, user1.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
th.App.Srv().SetLicense(nil)
|
|
_, response, err := th.SystemAdminClient.GetGroupsByUserId(context.Background(), user1.Id)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
_, response, err = th.SystemAdminClient.GetGroupsByUserId(context.Background(), "")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.GetGroupsByUserId(context.Background(), "notvaliduserid")
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
|
|
groups, _, err := th.SystemAdminClient.GetGroupsByUserId(context.Background(), user1.Id)
|
|
require.NoError(t, err)
|
|
assert.ElementsMatch(t, []*model.Group{group1, group2}, groups)
|
|
|
|
// test permissions
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, _, err = th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
_, response, err = th.Client.GetGroupsByUserId(context.Background(), user1.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
_, err = th.Client.Logout(context.Background())
|
|
require.NoError(t, err)
|
|
_, _, err = th.Client.Login(context.Background(), user1.Email, user1.Password)
|
|
require.NoError(t, err)
|
|
groups, _, err = th.Client.GetGroupsByUserId(context.Background(), user1.Id)
|
|
require.NoError(t, err)
|
|
assert.ElementsMatch(t, []*model.Group{group1, group2}, groups)
|
|
}
|
|
|
|
func TestGetGroupMembers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: false,
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
user1, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SystemUserRoleId})
|
|
assert.Nil(t, appErr)
|
|
|
|
user2, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user2", Password: "test-password-2", Username: "test-user-2", Roles: model.SystemUserRoleId})
|
|
assert.Nil(t, appErr)
|
|
|
|
_, appErr = th.App.UpsertGroupMembers(group.Id, []string{user1.Id, user2.Id})
|
|
require.Nil(t, appErr)
|
|
|
|
t.Run("Requires ldap license", func(t *testing.T) {
|
|
members, response, err := th.SystemAdminClient.GetGroupMembers(context.Background(), group.Id)
|
|
assert.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
assert.Nil(t, members)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
t.Run("Non admins are not allowed to get members for LDAP groups when allow reference is false", func(t *testing.T) {
|
|
members, response, err := th.Client.GetGroupMembers(context.Background(), group.Id)
|
|
assert.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, members)
|
|
})
|
|
|
|
t.Run("Admins are allowed to get members for LDAP groups", func(t *testing.T) {
|
|
members, response, err := th.SystemAdminClient.GetGroupMembers(context.Background(), group.Id)
|
|
assert.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
require.NotNil(t, members)
|
|
assert.Equal(t, 2, members.Count)
|
|
})
|
|
|
|
t.Run("If AllowReference is enabled, non admins are allowed to get members for LDAP groups", func(t *testing.T) {
|
|
group.AllowReference = true
|
|
group, appErr = th.App.UpdateGroup(group)
|
|
assert.Nil(t, appErr)
|
|
|
|
t.Cleanup(func() {
|
|
group.AllowReference = false
|
|
group, appErr = th.App.UpdateGroup(group)
|
|
assert.Nil(t, appErr)
|
|
})
|
|
|
|
members, response, err := th.Client.GetGroupMembers(context.Background(), group.Id)
|
|
assert.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
require.NotNil(t, members)
|
|
assert.Equal(t, 2, members.Count)
|
|
})
|
|
}
|
|
|
|
func TestGetGroupStats(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
id := model.NewId()
|
|
group, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn-foo_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
assert.Nil(t, appErr)
|
|
|
|
t.Run("Requires ldap license", func(t *testing.T) {
|
|
_, response, err := th.SystemAdminClient.GetGroupStats(context.Background(), group.Id)
|
|
require.Error(t, err)
|
|
CheckNotImplementedStatus(t, response)
|
|
})
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
t.Run("Requires manage system permission to access group stats", func(t *testing.T) {
|
|
_, _, err := th.Client.Login(context.Background(), th.BasicUser.Email, th.BasicUser.Password)
|
|
require.NoError(t, err)
|
|
_, response, err := th.Client.GetGroupStats(context.Background(), group.Id)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
})
|
|
|
|
t.Run("Returns stats for a group with no members", func(t *testing.T) {
|
|
stats, _, err := th.SystemAdminClient.GetGroupStats(context.Background(), group.Id)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, stats.GroupID, group.Id)
|
|
assert.Equal(t, stats.TotalMemberCount, int64(0))
|
|
})
|
|
|
|
user1, err := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SystemUserRoleId})
|
|
assert.Nil(t, err)
|
|
_, appErr = th.App.UpsertGroupMember(group.Id, user1.Id)
|
|
assert.Nil(t, appErr)
|
|
|
|
t.Run("Returns stats for a group with members", func(t *testing.T) {
|
|
stats, _, _ := th.SystemAdminClient.GetGroupStats(context.Background(), group.Id)
|
|
assert.Equal(t, stats.GroupID, group.Id)
|
|
assert.Equal(t, stats.TotalMemberCount, int64(1))
|
|
})
|
|
}
|
|
|
|
func TestGetGroupsGroupConstrainedParentTeam(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
var groups []*model.Group
|
|
for i := range 4 {
|
|
id := model.NewId()
|
|
group, err := th.App.CreateGroup(&model.Group{
|
|
DisplayName: fmt.Sprintf("dn-foo_%d", i),
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
require.Nil(t, err)
|
|
groups = append(groups, group)
|
|
}
|
|
|
|
team := th.CreateTeam(t)
|
|
|
|
id := model.NewId()
|
|
channel := &model.Channel{
|
|
DisplayName: "dn_" + id,
|
|
Name: "name" + id,
|
|
Type: model.ChannelTypePrivate,
|
|
TeamId: team.Id,
|
|
GroupConstrained: model.NewPointer(true),
|
|
}
|
|
channel, appErr := th.App.CreateChannel(th.Context, channel, false)
|
|
require.Nil(t, appErr)
|
|
|
|
// normal result of groups are returned if the team is not group-constrained
|
|
apiGroups, _, err := th.SystemAdminClient.GetGroups(context.Background(), model.GroupSearchOpts{NotAssociatedToChannel: channel.Id})
|
|
require.NoError(t, err)
|
|
require.Contains(t, apiGroups, groups[0])
|
|
require.Contains(t, apiGroups, groups[1])
|
|
require.Contains(t, apiGroups, groups[2])
|
|
|
|
team.GroupConstrained = model.NewPointer(true)
|
|
team, appErr = th.App.UpdateTeam(team)
|
|
require.Nil(t, appErr)
|
|
|
|
// team is group-constrained but has no associated groups
|
|
apiGroups, _, err = th.SystemAdminClient.GetGroups(context.Background(), model.GroupSearchOpts{NotAssociatedToChannel: channel.Id, FilterParentTeamPermitted: true})
|
|
require.NoError(t, err)
|
|
require.Len(t, apiGroups, 0)
|
|
|
|
for _, group := range []*model.Group{groups[0], groups[2], groups[3]} {
|
|
_, appErr = th.App.UpsertGroupSyncable(model.NewGroupTeam(group.Id, team.Id, false))
|
|
require.Nil(t, appErr)
|
|
}
|
|
|
|
// set of the teams groups are returned
|
|
apiGroups, _, err = th.SystemAdminClient.GetGroups(context.Background(), model.GroupSearchOpts{NotAssociatedToChannel: channel.Id, FilterParentTeamPermitted: true})
|
|
require.NoError(t, err)
|
|
require.Contains(t, apiGroups, groups[0])
|
|
require.NotContains(t, apiGroups, groups[1])
|
|
require.Contains(t, apiGroups, groups[2])
|
|
|
|
// paged results function as expected
|
|
apiGroups, _, err = th.SystemAdminClient.GetGroups(context.Background(), model.GroupSearchOpts{NotAssociatedToChannel: channel.Id, FilterParentTeamPermitted: true, PageOpts: &model.PageOpts{PerPage: 2, Page: 0}})
|
|
require.NoError(t, err)
|
|
require.Len(t, apiGroups, 2)
|
|
require.Equal(t, apiGroups[0].Id, groups[0].Id)
|
|
require.Equal(t, apiGroups[1].Id, groups[2].Id)
|
|
|
|
apiGroups, _, err = th.SystemAdminClient.GetGroups(context.Background(), model.GroupSearchOpts{NotAssociatedToChannel: channel.Id, FilterParentTeamPermitted: true, PageOpts: &model.PageOpts{PerPage: 2, Page: 1}})
|
|
require.NoError(t, err)
|
|
require.Len(t, apiGroups, 1)
|
|
require.Equal(t, apiGroups[0].Id, groups[3].Id)
|
|
|
|
_, appErr = th.App.UpsertGroupSyncable(model.NewGroupChannel(groups[0].Id, channel.Id, false))
|
|
require.Nil(t, appErr)
|
|
|
|
// as usual it doesn't return groups already associated to the channel
|
|
apiGroups, _, err = th.SystemAdminClient.GetGroups(context.Background(), model.GroupSearchOpts{NotAssociatedToChannel: channel.Id})
|
|
require.NoError(t, err)
|
|
require.NotContains(t, apiGroups, groups[0])
|
|
require.Contains(t, apiGroups, groups[2])
|
|
}
|
|
|
|
func TestAddMembersToGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Set license for all tests
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
// setup creates a fresh group and users for each test
|
|
setup := func(t *testing.T) (*model.Group, []*model.User) {
|
|
// Create custom group
|
|
id := model.NewId()
|
|
group, err := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + id,
|
|
})
|
|
require.Nil(t, err)
|
|
|
|
// Create test users with random usernames to prevent collisions
|
|
users := make([]*model.User, 3)
|
|
for i := range 3 {
|
|
randomId := model.NewId()
|
|
user, appErr := th.App.CreateUser(th.Context, &model.User{
|
|
Email: th.GenerateTestEmail(),
|
|
Nickname: fmt.Sprintf("test user%d-%s", i+1, randomId),
|
|
Password: fmt.Sprintf("test-password-%d", i+1),
|
|
Username: fmt.Sprintf("test-user-%d-%s", i+1, randomId),
|
|
Roles: model.SystemUserRoleId,
|
|
})
|
|
require.Nil(t, appErr)
|
|
users[i] = user
|
|
}
|
|
|
|
return group, users
|
|
}
|
|
|
|
t.Run("empty group members returns bad request", func(t *testing.T) {
|
|
group, _ := setup(t)
|
|
|
|
_, resp, err := th.SystemAdminClient.UpsertGroupMembers(context.Background(), group.Id, nil)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("successfully add members to custom group", func(t *testing.T) {
|
|
group, users := setup(t)
|
|
|
|
members := &model.GroupModifyMembers{
|
|
UserIds: []string{users[0].Id, users[1].Id},
|
|
}
|
|
|
|
groupMembers, response, err := th.SystemAdminClient.UpsertGroupMembers(context.Background(), group.Id, members)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
require.Len(t, groupMembers, 2)
|
|
|
|
count, countErr := th.App.GetGroupMemberCount(group.Id, nil)
|
|
require.Nil(t, countErr)
|
|
require.Equal(t, int64(2), count)
|
|
})
|
|
|
|
t.Run("adding existing members", func(t *testing.T) {
|
|
group, users := setup(t)
|
|
|
|
// First, add two users to the group
|
|
initialMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{users[0].Id, users[1].Id},
|
|
}
|
|
|
|
returnedMembers, response, err := th.SystemAdminClient.UpsertGroupMembers(context.Background(), group.Id, initialMembers)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
require.Len(t, returnedMembers, 2)
|
|
|
|
// Try to add a user that's already in the group
|
|
existingMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{users[0].Id},
|
|
}
|
|
|
|
groupMembers, response, err := th.SystemAdminClient.UpsertGroupMembers(context.Background(), group.Id, existingMembers)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
// Should return empty array since no new members were added
|
|
require.Len(t, groupMembers, 1)
|
|
|
|
// Verify the group still has the original member count
|
|
count, countErr := th.App.GetGroupMemberCount(group.Id, nil)
|
|
require.Nil(t, countErr)
|
|
require.Equal(t, int64(2), count)
|
|
|
|
// Try with multiple users - one already in group, one not
|
|
mixedMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{users[0].Id, users[2].Id},
|
|
}
|
|
|
|
groupMembers, response, err = th.SystemAdminClient.UpsertGroupMembers(context.Background(), group.Id, mixedMembers)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
// Should only return the new member
|
|
require.Len(t, groupMembers, 2)
|
|
|
|
// Verify the group now has 3 members
|
|
count, countErr = th.App.GetGroupMemberCount(group.Id, nil)
|
|
require.Nil(t, countErr)
|
|
require.Equal(t, int64(3), count)
|
|
})
|
|
|
|
t.Run("invalid group ID", func(t *testing.T) {
|
|
_, users := setup(t)
|
|
|
|
members := &model.GroupModifyMembers{
|
|
UserIds: []string{users[0].Id, users[1].Id},
|
|
}
|
|
|
|
_, response, err := th.Client.UpsertGroupMembers(context.Background(), "abc123", members)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
|
|
t.Run("invalid user ID format", func(t *testing.T) {
|
|
group, _ := setup(t)
|
|
|
|
invalidMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{"abc123"},
|
|
}
|
|
|
|
_, response, err := th.SystemAdminClient.UpsertGroupMembers(context.Background(), group.Id, invalidMembers)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
|
|
t.Run("non-existent user ID", func(t *testing.T) {
|
|
group, _ := setup(t)
|
|
|
|
nonExistentID := model.NewId()
|
|
nonExistentMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{nonExistentID},
|
|
}
|
|
|
|
_, response, err := th.SystemAdminClient.UpsertGroupMembers(context.Background(), group.Id, nonExistentMembers)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
require.Contains(t, err.Error(), fmt.Sprintf(`User with username "%s" could not be found.`, nonExistentID))
|
|
})
|
|
|
|
t.Run("ldap group rejects adding members", func(t *testing.T) {
|
|
_, users := setup(t)
|
|
|
|
// Create LDAP group
|
|
ldapId := model.NewId()
|
|
ldapGroup, err := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + ldapId,
|
|
Name: model.NewPointer("name" + ldapId),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + ldapId,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
})
|
|
require.Nil(t, err)
|
|
|
|
members := &model.GroupModifyMembers{
|
|
UserIds: []string{users[0].Id, users[1].Id},
|
|
}
|
|
|
|
_, response, upsertErr := th.SystemAdminClient.UpsertGroupMembers(context.Background(), ldapGroup.Id, members)
|
|
require.Error(t, upsertErr)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
}
|
|
|
|
func TestDeleteMembersFromGroup(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t)
|
|
|
|
// Create test users
|
|
user1, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user1", Password: "test-password-1", Username: "test-user-1", Roles: model.SystemUserRoleId})
|
|
require.Nil(t, appErr)
|
|
|
|
user2, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user2", Password: "test-password-2", Username: "test-user-2", Roles: model.SystemUserRoleId})
|
|
require.Nil(t, appErr)
|
|
|
|
user3, appErr := th.App.CreateUser(th.Context, &model.User{Email: th.GenerateTestEmail(), Nickname: "test user3", Password: "test-password-3", Username: "test-user-3", Roles: model.SystemUserRoleId})
|
|
require.Nil(t, appErr)
|
|
|
|
// Create custom group with two members
|
|
id := model.NewId()
|
|
g := &model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceCustom,
|
|
Description: "description_" + id,
|
|
}
|
|
group, err := th.App.CreateGroupWithUserIds(&model.GroupWithUserIds{
|
|
Group: *g,
|
|
UserIds: []string{user1.Id, user2.Id},
|
|
})
|
|
require.Nil(t, err)
|
|
|
|
// Create LDAP group with the same members
|
|
ldapId := model.NewId()
|
|
g1 := &model.Group{
|
|
DisplayName: "dn_" + ldapId,
|
|
Name: model.NewPointer("name" + ldapId),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + ldapId,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
}
|
|
ldapGroup, err := th.App.CreateGroupWithUserIds(&model.GroupWithUserIds{
|
|
Group: *g1,
|
|
UserIds: []string{user1.Id, user2.Id},
|
|
})
|
|
require.Nil(t, err)
|
|
|
|
// Set license
|
|
th.App.Srv().SetLicense(model.NewTestLicenseSKU(model.LicenseShortSkuProfessional))
|
|
|
|
t.Run("Fail with nil member list", func(t *testing.T) {
|
|
_, resp, err := th.SystemAdminClient.DeleteGroupMembers(context.Background(), group.Id, nil)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, resp)
|
|
})
|
|
|
|
t.Run("Success with valid member removal", func(t *testing.T) {
|
|
members := &model.GroupModifyMembers{
|
|
UserIds: []string{user1.Id},
|
|
}
|
|
|
|
groupMembers, response, err := th.SystemAdminClient.DeleteGroupMembers(context.Background(), group.Id, members)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
require.Len(t, groupMembers, 1)
|
|
require.Equal(t, groupMembers[0].UserId, user1.Id)
|
|
|
|
// Verify only one user remains in the group
|
|
users, usersErr := th.App.GetGroupMemberUsers(group.Id)
|
|
require.Nil(t, usersErr)
|
|
require.Len(t, users, 1)
|
|
require.Equal(t, users[0].Id, user2.Id)
|
|
})
|
|
|
|
t.Run("Fail with invalid group ID", func(t *testing.T) {
|
|
members := &model.GroupModifyMembers{
|
|
UserIds: []string{user1.Id},
|
|
}
|
|
|
|
_, response, err := th.Client.DeleteGroupMembers(context.Background(), "abc123", members)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
|
|
t.Run("Fail with invalid user ID format", func(t *testing.T) {
|
|
invalidMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{"abc123"},
|
|
}
|
|
|
|
_, response, err := th.SystemAdminClient.DeleteGroupMembers(context.Background(), group.Id, invalidMembers)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
|
|
t.Run("Fail with non-existent user ID", func(t *testing.T) {
|
|
nonExistentID := model.NewId()
|
|
nonExistentMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{nonExistentID},
|
|
}
|
|
|
|
_, response, err := th.SystemAdminClient.DeleteGroupMembers(context.Background(), group.Id, nonExistentMembers)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
require.Contains(t, err.Error(), fmt.Sprintf(`User with username "%s" could not be found.`, nonExistentID))
|
|
})
|
|
|
|
t.Run("Fail with user not in group", func(t *testing.T) {
|
|
validNonMemberMembers := &model.GroupModifyMembers{
|
|
UserIds: []string{user3.Id},
|
|
}
|
|
|
|
_, response, err := th.SystemAdminClient.DeleteGroupMembers(context.Background(), group.Id, validNonMemberMembers)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
require.Contains(t, err.Error(), fmt.Sprintf(`User with username "%s" could not be found.`, user3.Id))
|
|
})
|
|
|
|
t.Run("Fail with LDAP source group", func(t *testing.T) {
|
|
members := &model.GroupModifyMembers{
|
|
UserIds: []string{user1.Id},
|
|
}
|
|
|
|
_, response, err := th.SystemAdminClient.DeleteGroupMembers(context.Background(), ldapGroup.Id, members)
|
|
require.Error(t, err)
|
|
CheckBadRequestStatus(t, response)
|
|
})
|
|
}
|
|
|
|
// newSchemeAdminTestLdapGroup creates a fresh LDAP-source group with
|
|
// AllowReference=true.
|
|
func newSchemeAdminTestLdapGroup(t *testing.T, th *TestHelper) *model.Group {
|
|
t.Helper()
|
|
id := model.NewId()
|
|
g, appErr := th.App.CreateGroup(&model.Group{
|
|
DisplayName: "dn_" + id,
|
|
Name: model.NewPointer("name" + id),
|
|
Source: model.GroupSourceLdap,
|
|
Description: "description_" + id,
|
|
RemoteId: model.NewPointer(model.NewId()),
|
|
AllowReference: true,
|
|
})
|
|
require.Nil(t, appErr)
|
|
return g
|
|
}
|
|
|
|
// findPersistedGroupSyncable returns the persisted GroupSyncable for a
|
|
// given (groupID, syncableID, syncableType) tuple, including SchemeAdmin.
|
|
func findPersistedGroupSyncable(t *testing.T, th *TestHelper, groupID, syncableID string, syncableType model.GroupSyncableType) *model.GroupSyncable {
|
|
t.Helper()
|
|
syncables, appErr := th.App.GetGroupSyncables(groupID, syncableType)
|
|
require.Nil(t, appErr)
|
|
for _, s := range syncables {
|
|
if s.SyncableId == syncableID {
|
|
return s
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestLinkGroupTeam_SchemeAdminRequiresElevatedPermission(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
schemeAdminTrue := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(true),
|
|
}
|
|
|
|
t.Run("regular team user with invite_user must NOT be able to set scheme_admin: true", func(t *testing.T) {
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminTrue)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
if persisted != nil {
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
}
|
|
})
|
|
|
|
t.Run("system admin can still set scheme_admin: true", func(t *testing.T) {
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminTrue)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular team user can still link with scheme_admin omitted", func(t *testing.T) {
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
require.NotNil(t, groupSyncable)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular team user must NOT be able to link with scheme_admin: false explicitly", func(t *testing.T) {
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(false),
|
|
}
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
if persisted != nil {
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestLinkGroupChannel_SchemeAdminRequiresElevatedPermission(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
// A regular user can only link a channel syncable when the group is
|
|
// already linked to the parent team, so seed the team link as sysadmin.
|
|
mkLinkedGroup := func(t *testing.T) *model.Group {
|
|
t.Helper()
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
return g
|
|
}
|
|
|
|
schemeAdminTrue := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(true),
|
|
}
|
|
|
|
t.Run("regular channel user with manage_*_channel_members must NOT be able to set scheme_admin: true", func(t *testing.T) {
|
|
g := mkLinkedGroup(t)
|
|
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminTrue)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
if persisted != nil {
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
}
|
|
})
|
|
|
|
t.Run("system admin can still set scheme_admin: true", func(t *testing.T) {
|
|
g := mkLinkedGroup(t)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminTrue)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular channel user can still link with scheme_admin omitted", func(t *testing.T) {
|
|
g := mkLinkedGroup(t)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
require.NotNil(t, groupSyncable)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular channel user must NOT be able to link with scheme_admin: false explicitly", func(t *testing.T) {
|
|
g := mkLinkedGroup(t)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(false),
|
|
}
|
|
groupSyncable, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
assert.Nil(t, groupSyncable)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
if persisted != nil {
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPatchGroupTeam_SchemeAdminRequiresElevatedPermission(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
// schemeAdmin controls the seeded SchemeAdmin value on the team syncable.
|
|
setupLinkedGroup := func(t *testing.T, schemeAdmin bool) *model.Group {
|
|
t.Helper()
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(schemeAdmin),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
return g
|
|
}
|
|
|
|
schemeAdminTrue := &model.GroupSyncablePatch{
|
|
SchemeAdmin: model.NewPointer(true),
|
|
}
|
|
|
|
schemeAdminFalse := &model.GroupSyncablePatch{
|
|
SchemeAdmin: model.NewPointer(false),
|
|
}
|
|
|
|
t.Run("regular team user with invite_user must NOT be able to patch scheme_admin: true", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, false)
|
|
|
|
_, response, err := th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminTrue)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("system admin can still patch scheme_admin: true", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, false)
|
|
|
|
_, response, err := th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminTrue)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular team user can still patch other fields with scheme_admin omitted", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, true)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(false),
|
|
}
|
|
_, response, err := th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.AutoAdd)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular team user must NOT be able to patch scheme_admin: false", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, true)
|
|
|
|
_, response, err := th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminFalse)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("system admin can still patch scheme_admin: false", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, true)
|
|
|
|
_, response, err := th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminFalse)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("sysconsole_write_user_management_groups holder can patch scheme_admin in either direction", func(t *testing.T) {
|
|
// system_manager bundles sysconsole_write_user_management_groups,
|
|
// the override honoured by verifySchemeAdminAssignmentPermission.
|
|
th.LoginSystemManager(t)
|
|
|
|
gPromote := setupLinkedGroup(t, false)
|
|
_, response, err := th.SystemManagerClient.PatchGroupSyncable(context.Background(), gPromote.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminTrue)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
persistedPromote := findPersistedGroupSyncable(t, th, gPromote.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persistedPromote)
|
|
assert.True(t, persistedPromote.SchemeAdmin)
|
|
|
|
gDemote := setupLinkedGroup(t, true)
|
|
_, response, err = th.SystemManagerClient.PatchGroupSyncable(context.Background(), gDemote.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, schemeAdminFalse)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
persistedDemote := findPersistedGroupSyncable(t, th, gDemote.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persistedDemote)
|
|
assert.False(t, persistedDemote.SchemeAdmin)
|
|
})
|
|
}
|
|
|
|
func TestPatchGroupChannel_SchemeAdminRequiresElevatedPermission(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
// schemeAdmin controls the seeded SchemeAdmin value on the channel
|
|
// syncable. The team syncable is seeded so the channel link succeeds.
|
|
setupLinkedGroup := func(t *testing.T, schemeAdmin bool) *model.Group {
|
|
t.Helper()
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(schemeAdmin),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
return g
|
|
}
|
|
|
|
schemeAdminTrue := &model.GroupSyncablePatch{
|
|
SchemeAdmin: model.NewPointer(true),
|
|
}
|
|
|
|
schemeAdminFalse := &model.GroupSyncablePatch{
|
|
SchemeAdmin: model.NewPointer(false),
|
|
}
|
|
|
|
t.Run("regular channel user with manage_*_channel_members must NOT be able to patch scheme_admin: true", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, false)
|
|
|
|
_, response, err := th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminTrue)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("system admin can still patch scheme_admin: true", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, false)
|
|
|
|
_, response, err := th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminTrue)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular channel user can still patch other fields with scheme_admin omitted", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, true)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(false),
|
|
}
|
|
_, response, err := th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.AutoAdd)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular channel user must NOT be able to patch scheme_admin: false", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, true)
|
|
|
|
_, response, err := th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminFalse)
|
|
require.Error(t, err)
|
|
CheckForbiddenStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("system admin can still patch scheme_admin: false", func(t *testing.T) {
|
|
g := setupLinkedGroup(t, true)
|
|
|
|
_, response, err := th.SystemAdminClient.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminFalse)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("sysconsole_write_user_management_groups holder can patch scheme_admin in either direction", func(t *testing.T) {
|
|
// system_manager bundles sysconsole_write_user_management_groups,
|
|
// the override honoured by verifySchemeAdminAssignmentPermission.
|
|
th.LoginSystemManager(t)
|
|
|
|
gPromote := setupLinkedGroup(t, false)
|
|
_, response, err := th.SystemManagerClient.PatchGroupSyncable(context.Background(), gPromote.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminTrue)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
persistedPromote := findPersistedGroupSyncable(t, th, gPromote.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persistedPromote)
|
|
assert.True(t, persistedPromote.SchemeAdmin)
|
|
|
|
gDemote := setupLinkedGroup(t, true)
|
|
_, response, err = th.SystemManagerClient.PatchGroupSyncable(context.Background(), gDemote.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, schemeAdminFalse)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
persistedDemote := findPersistedGroupSyncable(t, th, gDemote.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persistedDemote)
|
|
assert.False(t, persistedDemote.SchemeAdmin)
|
|
})
|
|
}
|
|
|
|
func TestLinkGroupTeam_LinkOnExistingPreservesSchemeAdmin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
seedSchemeAdminTrue := func(t *testing.T) *model.Group {
|
|
t.Helper()
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
require.True(t, persisted.SchemeAdmin)
|
|
return g
|
|
}
|
|
|
|
t.Run("regular team user calling LINK with scheme_admin omitted must not change persisted scheme_admin", func(t *testing.T) {
|
|
g := seedSchemeAdminTrue(t)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
_, _, _ = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular team user calling LINK with scheme_admin: false must not change persisted scheme_admin", func(t *testing.T) {
|
|
g := seedSchemeAdminTrue(t)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(false),
|
|
}
|
|
_, _, _ = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
}
|
|
|
|
func TestLinkGroupChannel_LinkOnExistingPreservesSchemeAdmin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
seedSchemeAdminTrue := func(t *testing.T) *model.Group {
|
|
t.Helper()
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
require.True(t, persisted.SchemeAdmin)
|
|
return g
|
|
}
|
|
|
|
t.Run("regular channel user calling LINK with scheme_admin omitted must not change persisted scheme_admin", func(t *testing.T) {
|
|
g := seedSchemeAdminTrue(t)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
_, _, _ = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
|
|
t.Run("regular channel user calling LINK with scheme_admin: false must not change persisted scheme_admin", func(t *testing.T) {
|
|
g := seedSchemeAdminTrue(t)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(false),
|
|
}
|
|
_, _, _ = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel)
|
|
require.NotNil(t, persisted)
|
|
assert.True(t, persisted.SchemeAdmin)
|
|
})
|
|
}
|
|
|
|
func TestLinkGroupTeam_LinkOnSoftDeletedDoesNotPreserveSchemeAdmin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
t.Run("regular team user re-linking a soft-deleted syncable with scheme_admin omitted must persist scheme_admin: false", func(t *testing.T) {
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
response, err = th.SystemAdminClient.UnlinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
_, response, err = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
persisted := findPersistedGroupSyncable(t, th, g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam)
|
|
require.NotNil(t, persisted)
|
|
assert.False(t, persisted.SchemeAdmin)
|
|
})
|
|
}
|
|
|
|
func TestPatchGroupTeam_OmittedSchemeAdminDoesNotDemoteDirectAdmin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
th.UpdateUserToTeamAdmin(t, th.BasicUser2, th.BasicTeam)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(false),
|
|
}
|
|
_, response, err = th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
tm, appErr := th.App.GetTeamMember(th.Context, th.BasicTeam.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
assert.True(t, tm.SchemeAdmin)
|
|
}
|
|
|
|
func TestPatchGroupChannel_OmittedSchemeAdminDoesNotDemoteDirectAdmin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
_, response, err = th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
th.MakeUserChannelAdmin(t, th.BasicUser2, th.BasicChannel)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(false),
|
|
}
|
|
_, response, err = th.Client.PatchGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckOKStatus(t, response)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
cm, appErr := th.App.GetChannelMember(th.Context, th.BasicChannel.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
assert.True(t, cm.SchemeAdmin)
|
|
}
|
|
|
|
func TestLinkGroupTeam_OmittedSchemeAdminDoesNotDemoteDirectAdmin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
th.UpdateUserToTeamAdmin(t, th.BasicUser2, th.BasicTeam)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
_, response, err := th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
tm, appErr := th.App.GetTeamMember(th.Context, th.BasicTeam.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
assert.True(t, tm.SchemeAdmin)
|
|
}
|
|
|
|
func TestLinkGroupChannel_OmittedSchemeAdminDoesNotDemoteDirectAdmin(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
th.MakeUserChannelAdmin(t, th.BasicUser2, th.BasicChannel)
|
|
|
|
patch := &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
}
|
|
_, response, err = th.Client.LinkGroupSyncable(context.Background(), g.Id, th.BasicChannel.Id, model.GroupSyncableTypeChannel, patch)
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
cm, appErr := th.App.GetChannelMember(th.Context, th.BasicChannel.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
assert.True(t, cm.SchemeAdmin)
|
|
}
|
|
|
|
func TestLinkGroupTeam_SchemeAdminTruePromotesGroupMembers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
_, appErr := th.App.UpsertGroupMember(g.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
SchemeAdmin: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
tm, appErr := th.App.GetTeamMember(th.Context, th.BasicTeam.Id, th.BasicUser2.Id)
|
|
require.Nil(t, appErr)
|
|
assert.True(t, tm.SchemeAdmin)
|
|
}
|
|
|
|
func TestLinkGroupTeam_AutoAddOnlyAddsGroupMembers(t *testing.T) {
|
|
mainHelper.Parallel(t)
|
|
th := Setup(t).InitBasic(t)
|
|
|
|
th.App.Srv().SetLicense(model.NewTestLicense("ldap"))
|
|
|
|
g := newSchemeAdminTestLdapGroup(t, th)
|
|
|
|
newUser := th.CreateUser(t)
|
|
_, appErr := th.App.UpsertGroupMember(g.Id, newUser.Id)
|
|
require.Nil(t, appErr)
|
|
|
|
_, appErr = th.App.GetTeamMember(th.Context, th.BasicTeam.Id, newUser.Id)
|
|
require.NotNil(t, appErr)
|
|
|
|
_, response, err := th.SystemAdminClient.LinkGroupSyncable(context.Background(), g.Id, th.BasicTeam.Id, model.GroupSyncableTypeTeam, &model.GroupSyncablePatch{
|
|
AutoAdd: model.NewPointer(true),
|
|
})
|
|
require.NoError(t, err)
|
|
CheckCreatedStatus(t, response)
|
|
|
|
time.Sleep(2 * time.Second)
|
|
|
|
tm, appErr := th.App.GetTeamMember(th.Context, th.BasicTeam.Id, newUser.Id)
|
|
require.Nil(t, appErr)
|
|
assert.Equal(t, newUser.Id, tm.UserId)
|
|
}
|