MM-52476 Fix guest users access to playbooks. (#23279)
* Fix guest users access to playbooks. * Fix guest access. * Add guests list restriction.
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
4d41365fbe
Коммит
3b0d0d7179
@@ -63,6 +63,11 @@ func (r *PlaybookRootResolver) Playbooks(ctx context.Context, args struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isGuest, err := app.IsGuest(userID, c.api)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
requesterInfo := app.RequesterInfo{
|
requesterInfo := app.RequesterInfo{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
TeamID: args.TeamID,
|
TeamID: args.TeamID,
|
||||||
@@ -74,7 +79,7 @@ func (r *PlaybookRootResolver) Playbooks(ctx context.Context, args struct {
|
|||||||
Direction: app.SortDirection(args.Direction),
|
Direction: app.SortDirection(args.Direction),
|
||||||
SearchTerm: args.SearchTerm,
|
SearchTerm: args.SearchTerm,
|
||||||
WithArchived: args.WithArchived,
|
WithArchived: args.WithArchived,
|
||||||
WithMembershipOnly: args.WithMembershipOnly,
|
WithMembershipOnly: isGuest || args.WithMembershipOnly, // Guests can only see playbooks if they are invited to them
|
||||||
Page: 0,
|
Page: 0,
|
||||||
PerPage: 10000,
|
PerPage: 10000,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -345,6 +345,16 @@ func (h *PlaybookHandler) getPlaybooks(c *Context, w http.ResponseWriter, r *htt
|
|||||||
IsAdmin: app.IsSystemAdmin(userID, h.api),
|
IsAdmin: app.IsSystemAdmin(userID, h.api),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isGuest, err := app.IsGuest(userID, h.api)
|
||||||
|
if err != nil {
|
||||||
|
h.HandleErrorWithCode(w, c.logger, http.StatusForbidden, "", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if isGuest {
|
||||||
|
opts.WithMembershipOnly = true
|
||||||
|
}
|
||||||
|
|
||||||
playbookResults, err := h.playbookService.GetPlaybooksForTeam(requesterInfo, teamID, opts)
|
playbookResults, err := h.playbookService.GetPlaybooksForTeam(requesterInfo, teamID, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.HandleError(w, c.logger, err)
|
h.HandleError(w, c.logger, err)
|
||||||
|
|||||||
@@ -607,3 +607,85 @@ func TestGraphQLPlaybooksMetrics(t *testing.T) {
|
|||||||
require.Len(t, updatedPlaybook.Metrics, 1)
|
require.Len(t, updatedPlaybook.Metrics, 1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func gqlTestPlaybookUpdateGuest(e *TestEnvironment, t *testing.T, playbookID string, updates map[string]interface{}) error {
|
||||||
|
testPlaybookMutateQuery := `
|
||||||
|
mutation UpdatePlaybook($id: String!, $updates: PlaybookUpdates!) {
|
||||||
|
updatePlaybook(id: $id, updates: $updates)
|
||||||
|
}
|
||||||
|
`
|
||||||
|
var response graphql.Response
|
||||||
|
err := e.PlaybooksClientGuest.DoGraphql(context.Background(), &client.GraphQLInput{
|
||||||
|
Query: testPlaybookMutateQuery,
|
||||||
|
OperationName: "UpdatePlaybook",
|
||||||
|
Variables: map[string]interface{}{"id": playbookID, "updates": updates},
|
||||||
|
}, &response)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "gqlTestPlaybookUpdate graphql failure")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(response.Errors) != 0 {
|
||||||
|
return errors.Errorf("gqlTestPlaybookUpdate graphql failure %+v", response.Errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGraphQLPlaybooksGuests(t *testing.T) {
|
||||||
|
e := Setup(t)
|
||||||
|
e.SetE20Licence()
|
||||||
|
e.CreateBasic()
|
||||||
|
e.CreateGuest()
|
||||||
|
|
||||||
|
t.Run("update playbook guest not member", func(t *testing.T) {
|
||||||
|
err := gqlTestPlaybookUpdateGuest(e, t, e.BasicPlaybook.ID, map[string]interface{}{"title": "mutated"})
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("basic get guest not member", func(t *testing.T) {
|
||||||
|
testPlaybookQuery := `
|
||||||
|
query Playbook($id: String!) {
|
||||||
|
playbook(id: $id) {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
var response graphql.Response
|
||||||
|
err := e.PlaybooksClientGuest.DoGraphql(context.Background(), &client.GraphQLInput{
|
||||||
|
Query: testPlaybookQuery,
|
||||||
|
OperationName: "Playbook",
|
||||||
|
Variables: map[string]interface{}{"id": e.BasicPlaybook.ID},
|
||||||
|
}, &response)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotZero(t, len(response.Errors))
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("list guest", func(t *testing.T) {
|
||||||
|
var pbResultTest struct {
|
||||||
|
Data struct {
|
||||||
|
Playbooks []struct {
|
||||||
|
ID string
|
||||||
|
Title string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testPlaybookQuery := `
|
||||||
|
query Playbooks {
|
||||||
|
playbooks {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
err := e.PlaybooksClientGuest.DoGraphql(context.Background(), &client.GraphQLInput{
|
||||||
|
Query: testPlaybookQuery,
|
||||||
|
OperationName: "Playbooks",
|
||||||
|
}, &pbResultTest)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
assert.Len(t, pbResultTest.Data.Playbooks, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1514,3 +1514,30 @@ func TestPlaybookChecklistCleanup(t *testing.T) {
|
|||||||
require.Equal(t, pb.Checklists, actual)
|
require.Equal(t, pb.Checklists, actual)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPlaybooksGuests(t *testing.T) {
|
||||||
|
e := Setup(t)
|
||||||
|
e.SetE20Licence()
|
||||||
|
e.CreateBasic()
|
||||||
|
e.CreateGuest()
|
||||||
|
|
||||||
|
t.Run("guests can't create playbooks", func(t *testing.T) {
|
||||||
|
_, err := e.PlaybooksClientGuest.Playbooks.Create(context.Background(), client.PlaybookCreateOptions{
|
||||||
|
Title: "test4",
|
||||||
|
TeamID: e.BasicTeam.Id,
|
||||||
|
Public: false,
|
||||||
|
})
|
||||||
|
assert.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get playbook guest", func(t *testing.T) {
|
||||||
|
_, err := e.PlaybooksClientGuest.Playbooks.Get(context.Background(), e.BasicPlaybook.ID)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("update playbook properties", func(t *testing.T) {
|
||||||
|
e.BasicPlaybook.Description = "This is the updated description"
|
||||||
|
err := e.PlaybooksClientGuest.Playbooks.Update(context.Background(), *e.BasicPlaybook)
|
||||||
|
require.Error(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -69,10 +69,13 @@ func (p *PermissionsService) getPlaybookRole(userID string, playbook Playbook) [
|
|||||||
|
|
||||||
// Public playbooks
|
// Public playbooks
|
||||||
if playbook.Public {
|
if playbook.Public {
|
||||||
if playbook.DefaultPlaybookMemberRole == "" {
|
// Public playbooks are public to those who can list channels on a team. (Not guests)
|
||||||
return []string{playbook.DefaultPlaybookMemberRole}
|
if p.api.HasPermissionToTeam(userID, playbook.TeamID, model.PermissionListTeamChannels) {
|
||||||
|
if playbook.DefaultPlaybookMemberRole == "" {
|
||||||
|
return []string{playbook.DefaultPlaybookMemberRole}
|
||||||
|
}
|
||||||
|
return []string{PlaybookRoleMember}
|
||||||
}
|
}
|
||||||
return []string{PlaybookRoleMember}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return []string{}
|
return []string{}
|
||||||
@@ -103,6 +106,7 @@ func (p *PermissionsService) canViewTeam(userID string, teamID string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is list team channels so that Guests are excluded.
|
||||||
return p.api.HasPermissionToTeam(userID, teamID, model.PermissionViewTeam)
|
return p.api.HasPermissionToTeam(userID, teamID, model.PermissionViewTeam)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,9 +367,10 @@ func (p *PermissionsService) PlaybookViewWithPlaybook(userID string, playbook Pl
|
|||||||
return errors.Wrapf(noAccessErr, "no playbook access; no team view permission for team `%s`", playbook.TeamID)
|
return errors.Wrapf(noAccessErr, "no playbook access; no team view permission for team `%s`", playbook.TeamID)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the playbook is public team access is enough to view
|
|
||||||
if p.PlaybookIsPublic(playbook) {
|
if p.PlaybookIsPublic(playbook) {
|
||||||
return nil
|
if p.hasPermissionsToPlaybook(userID, playbook, model.PermissionPublicPlaybookView) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.hasPermissionsToPlaybook(userID, playbook, model.PermissionPrivatePlaybookView) {
|
if p.hasPermissionsToPlaybook(userID, playbook, model.PermissionPrivatePlaybookView) {
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ type TestEnvironment struct {
|
|||||||
PlaybooksClient *client.Client
|
PlaybooksClient *client.Client
|
||||||
PlaybooksClient2 *client.Client
|
PlaybooksClient2 *client.Client
|
||||||
PlaybooksClientNotInTeam *client.Client
|
PlaybooksClientNotInTeam *client.Client
|
||||||
|
PlaybooksClientGuest *client.Client
|
||||||
|
|
||||||
UnauthenticatedPlaybooksClient *client.Client
|
UnauthenticatedPlaybooksClient *client.Client
|
||||||
|
|
||||||
@@ -78,6 +79,7 @@ type TestEnvironment struct {
|
|||||||
RegularUser *model.User
|
RegularUser *model.User
|
||||||
RegularUser2 *model.User
|
RegularUser2 *model.User
|
||||||
RegularUserNotInTeam *model.User
|
RegularUserNotInTeam *model.User
|
||||||
|
GuestUser *model.User
|
||||||
}
|
}
|
||||||
|
|
||||||
func getEnvWithDefault(name, defaultValue string) string {
|
func getEnvWithDefault(name, defaultValue string) string {
|
||||||
@@ -430,6 +432,37 @@ func (e *TestEnvironment) CreateAdditionalPlaybooks() {
|
|||||||
e.ArchivedPlaybook = archivedPlaybook
|
e.ArchivedPlaybook = archivedPlaybook
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *TestEnvironment) CreateGuest() {
|
||||||
|
cfg := e.Srv.Config()
|
||||||
|
cfg.GuestAccountsSettings.Enable = model.NewBool(true)
|
||||||
|
_, _, err := e.ServerAdminClient.UpdateConfig(cfg)
|
||||||
|
require.NoError(e.T, err)
|
||||||
|
|
||||||
|
userPassword := "password123!"
|
||||||
|
guest, appErr := e.A.CreateGuest(request.EmptyContext(e.logger), &model.User{
|
||||||
|
Email: "playbookguest@example.com",
|
||||||
|
Username: "playbookguest",
|
||||||
|
Password: userPassword,
|
||||||
|
})
|
||||||
|
require.Nil(e.T, appErr)
|
||||||
|
e.GuestUser = guest
|
||||||
|
|
||||||
|
_, _, err = e.ServerAdminClient.AddTeamMember(e.BasicPublicChannel.TeamId, e.GuestUser.Id)
|
||||||
|
require.NoError(e.T, err)
|
||||||
|
|
||||||
|
_, _, err = e.ServerAdminClient.AddChannelMember(e.BasicPublicChannel.Id, e.GuestUser.Id)
|
||||||
|
require.NoError(e.T, err)
|
||||||
|
|
||||||
|
siteURL := fmt.Sprintf("http://localhost:%v", e.A.Srv().ListenAddr.Port)
|
||||||
|
serverClientGuest := model.NewAPIv4Client(siteURL)
|
||||||
|
_, _, err = serverClientGuest.Login(e.GuestUser.Email, userPassword)
|
||||||
|
require.NoError(e.T, err)
|
||||||
|
|
||||||
|
playbooksClientGuest, err := client.New(serverClientGuest)
|
||||||
|
require.NoError(e.T, err)
|
||||||
|
e.PlaybooksClientGuest = playbooksClientGuest
|
||||||
|
}
|
||||||
|
|
||||||
func (e *TestEnvironment) RemoveLicence() {
|
func (e *TestEnvironment) RemoveLicence() {
|
||||||
e.Srv.SetLicense(nil)
|
e.Srv.SetLicense(nil)
|
||||||
}
|
}
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user