Skip to content

Commit

Permalink
[MM-58492][MM-58523] Fixed some access control bugs around archived c…
Browse files Browse the repository at this point in the history
…hannels by replacing the permission check with HasPermissionToReadChannel (mattermost#27409)

* [MM-58492][MM-58523] Fixed some access control bugs around archived channels by replacing the permission check with HasPermissionToReadChannel

* Fix lint, add ChannelId to uploads

* Fix MMCTL tests and remove unnecessary check for the error message that doesn't work anyways

* Include channel map for getting flagged posts

---------

Co-authored-by: Mattermost Build <[email protected]>
  • Loading branch information
devinbinnie and mattermost-build committed Jul 29, 2024
1 parent 6ddf796 commit aa85a13
Show file tree
Hide file tree
Showing 17 changed files with 161 additions and 42 deletions.
7 changes: 6 additions & 1 deletion server/channels/api4/channel.go
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,12 @@ func getPinnedPosts(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionReadChannelContent) {
channel, err := c.App.GetChannel(c.AppContext, c.Params.ChannelId)
if err != nil {
c.Err = err
return
}
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}
Expand Down
7 changes: 6 additions & 1 deletion server/channels/api4/channel_bookmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,12 @@ func listChannelBookmarksForChannel(c *Context, w http.ResponseWriter, r *http.R
return
}

if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), c.Params.ChannelId, model.PermissionReadChannelContent) {
channel, appErr := c.App.GetChannel(c.AppContext, c.Params.ChannelId)
if appErr != nil {
c.Err = appErr
return
}
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}
Expand Down
2 changes: 1 addition & 1 deletion server/channels/api4/channel_bookmark_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1375,7 +1375,7 @@ func TestListChannelBookmarksForChannel(t *testing.T) {

// an open channel for which the guest is a member but the basic
// user is not
onlyGuestChannel := th.CreateChannelWithClient(th.SystemAdminClient, model.ChannelTypeOpen)
onlyGuestChannel := th.CreateChannelWithClient(th.SystemAdminClient, model.ChannelTypePrivate)
th.AddUserToChannel(guest, onlyGuestChannel)
guestBookmark := createBookmark("guest", onlyGuestChannel.Id)

Expand Down
2 changes: 1 addition & 1 deletion server/channels/api4/channel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2916,7 +2916,7 @@ func TestGetPinnedPosts(t *testing.T) {

_, resp, err = client.GetPinnedPosts(context.Background(), GenerateTestID(), "")
require.Error(t, err)
CheckForbiddenStatus(t, resp)
CheckNotFoundStatus(t, resp)

_, resp, err = client.GetPinnedPosts(context.Background(), "junk", "")
require.Error(t, err)
Expand Down
35 changes: 30 additions & 5 deletions server/channels/api4/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,12 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
}
audit.AddEventParameterAuditable(auditRec, "file", info)

perm := c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), info.ChannelId, model.PermissionReadChannelContent)
channel, err := c.App.GetChannel(c.AppContext, info.ChannelId)
if err != nil {
c.Err = err
return
}
perm := c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel)
if info.CreatorId == model.BookmarkFileOwner {
if !perm {
c.SetPermissionError(model.PermissionReadChannelContent)
Expand Down Expand Up @@ -521,7 +526,12 @@ func getFileThumbnail(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

perm := c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), info.ChannelId, model.PermissionReadChannelContent)
channel, err := c.App.GetChannel(c.AppContext, info.ChannelId)
if err != nil {
c.Err = err
return
}
perm := c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel)
if info.CreatorId == model.BookmarkFileOwner {
if !perm {
c.SetPermissionError(model.PermissionReadChannelContent)
Expand Down Expand Up @@ -570,7 +580,12 @@ func getFileLink(c *Context, w http.ResponseWriter, r *http.Request) {
}
audit.AddEventParameterAuditable(auditRec, "file", info)

perm := c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), info.ChannelId, model.PermissionReadChannelContent)
channel, err := c.App.GetChannel(c.AppContext, info.ChannelId)
if err != nil {
c.Err = err
return
}
perm := c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel)
if info.CreatorId == model.BookmarkFileOwner {
if !perm {
c.SetPermissionError(model.PermissionReadChannelContent)
Expand Down Expand Up @@ -609,7 +624,12 @@ func getFilePreview(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

perm := c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), info.ChannelId, model.PermissionReadChannelContent)
channel, err := c.App.GetChannel(c.AppContext, info.ChannelId)
if err != nil {
c.Err = err
return
}
perm := c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel)
if info.CreatorId == model.BookmarkFileOwner {
if !perm {
c.SetPermissionError(model.PermissionReadChannelContent)
Expand Down Expand Up @@ -649,7 +669,12 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

perm := c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), info.ChannelId, model.PermissionReadChannelContent)
channel, err := c.App.GetChannel(c.AppContext, info.ChannelId)
if err != nil {
c.Err = err
return
}
perm := c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel)
if info.CreatorId == model.BookmarkFileOwner {
if !perm {
c.SetPermissionError(model.PermissionReadChannelContent)
Expand Down
14 changes: 12 additions & 2 deletions server/channels/api4/integration_action.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,12 @@ func doPostAction(c *Context, w http.ResponseWriter, r *http.Request) {
c.Err = model.NewAppError("DoPostAction", "api.post.do_action.action_integration.app_error", nil, "", http.StatusBadRequest).Wrap(err)
return
}
if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), cookie.ChannelId, model.PermissionReadChannelContent) {
channel, err := c.App.GetChannel(c.AppContext, cookie.ChannelId)
if err != nil {
c.Err = err
return
}
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}
Expand Down Expand Up @@ -108,7 +113,12 @@ func submitDialog(c *Context, w http.ResponseWriter, r *http.Request) {

submit.UserId = c.AppContext.Session().UserId

if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), submit.ChannelId, model.PermissionReadChannelContent) {
channel, err := c.App.GetChannel(c.AppContext, submit.ChannelId)
if err != nil {
c.Err = err
return
}
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}
Expand Down
2 changes: 1 addition & 1 deletion server/channels/api4/integration_action_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ func TestSubmitDialog(t *testing.T) {
submit.ChannelId = model.NewId()
submitResp, resp, err = client.SubmitInteractiveDialog(context.Background(), submit)
require.Error(t, err)
CheckForbiddenStatus(t, resp)
CheckNotFoundStatus(t, resp)
assert.Nil(t, submitResp)

submit.URL = ts.URL
Expand Down
77 changes: 57 additions & 20 deletions server/channels/api4/post.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,20 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), channelId, model.PermissionReadChannelContent) {
channel, err := c.App.GetChannel(c.AppContext, channelId)
if err != nil {
c.Err = err
return
}
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}

if !*c.App.Config().TeamSettings.ExperimentalViewArchivedChannels {
channel, err := c.App.GetChannel(c.AppContext, channelId)
if err != nil {
c.Err = err
channel, appErr := c.App.GetChannel(c.AppContext, channelId)
if appErr != nil {
c.Err = appErr
return
}
if channel.DeleteAt != 0 {
Expand All @@ -275,7 +280,6 @@ func getPostsForChannel(c *Context, w http.ResponseWriter, r *http.Request) {
}

var list *model.PostList
var err *model.AppError
etag := ""

if since > 0 {
Expand Down Expand Up @@ -341,7 +345,12 @@ func getPostsForChannelAroundLastUnread(c *Context, w http.ResponseWriter, r *ht
}

channelId := c.Params.ChannelId
if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), channelId, model.PermissionReadChannelContent) {
channel, err := c.App.GetChannel(c.AppContext, channelId)
if err != nil {
c.Err = err
return
}
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}
Expand Down Expand Up @@ -423,6 +432,20 @@ func getFlaggedPostsForUser(c *Context, w http.ResponseWriter, r *http.Request)
return
}

channelMap := make(map[string]*model.Channel)
channelIds := []string{}
for _, post := range posts.Posts {
channelIds = append(channelIds, post.ChannelId)
}
channels, err := c.App.GetChannels(c.AppContext, channelIds)
if err != nil {
c.Err = err
return
}
for _, channel := range channels {
channelMap[channel.Id] = channel
}

pl := model.NewPostList()
channelReadPermission := make(map[string]bool)

Expand All @@ -432,7 +455,11 @@ func getFlaggedPostsForUser(c *Context, w http.ResponseWriter, r *http.Request)
if !ok {
allowed = false

if c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), post.ChannelId, model.PermissionReadChannelContent) {
channel, ok := channelMap[post.ChannelId]
if !ok {
continue
}
if c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
allowed = true
}

Expand Down Expand Up @@ -523,23 +550,28 @@ func getPostsByIds(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

var posts = []*model.Post{}
channelMap := make(map[string]*model.Channel)
channelIds := []string{}
for _, post := range postsList {
channelIds = append(channelIds, post.ChannelId)
}
channels, appErr := c.App.GetChannels(c.AppContext, channelIds)
if appErr != nil {
c.Err = appErr
return
}
for _, channel := range channels {
channelMap[channel.Id] = channel
}

var posts = []*model.Post{}
for _, post := range postsList {
var channel *model.Channel
if val, ok := channelMap[post.ChannelId]; ok {
channel = val
} else {
channel, appErr = c.App.GetChannel(c.AppContext, post.ChannelId)
if appErr != nil {
c.Err = appErr
return
}
channelMap[channel.Id] = channel
channel, ok := channelMap[post.ChannelId]
if !ok {
continue
}

if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), channel.Id, model.PermissionReadChannelContent) {
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
if channel.Type != model.ChannelTypeOpen || (channel.Type == model.ChannelTypeOpen && !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), channel.TeamId, model.PermissionReadPublicChannel)) {
continue
}
Expand Down Expand Up @@ -1031,7 +1063,12 @@ func saveIsPinnedPost(c *Context, w http.ResponseWriter, isPinned bool) {
auditRec.AddEventPriorState(post)
auditRec.AddEventObjectType("post")

if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), post.ChannelId, model.PermissionReadChannelContent) {
channel, err := c.App.GetChannel(c.AppContext, post.ChannelId)
if err != nil {
c.Err = err
return
}
if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}
Expand Down
2 changes: 1 addition & 1 deletion server/channels/api4/post_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1831,7 +1831,7 @@ func TestGetPostsForChannel(t *testing.T) {

_, resp, err := client.GetPostsForChannel(context.Background(), model.NewId(), 0, 60, "", false, false)
require.Error(t, err)
CheckForbiddenStatus(t, resp)
CheckNotFoundStatus(t, resp)

client.Logout(context.Background())
_, resp, err = client.GetPostsForChannel(context.Background(), model.NewId(), 0, 60, "", false, false)
Expand Down
12 changes: 11 additions & 1 deletion server/channels/api4/preference.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ func updatePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
}

var sanitizedPreferences model.Preferences
channelMap := make(map[string]*model.Channel)

for _, pref := range preferences {
if pref.Category == model.PreferenceCategoryFlaggedPost {
Expand All @@ -122,7 +123,16 @@ func updatePreferences(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

if !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), post.ChannelId, model.PermissionReadChannelContent) {
channel, ok := channelMap[post.ChannelId]
if !ok {
channel, err = c.App.GetChannel(c.AppContext, post.ChannelId)
if err != nil {
c.Err = err
return
}
}

if !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.SetPermissionError(model.PermissionReadChannelContent)
return
}
Expand Down
8 changes: 4 additions & 4 deletions server/channels/api4/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func createIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

if channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), channel.Id, model.PermissionReadChannelContent) {
if channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.LogAudit("fail - bad channel permissions")
c.SetPermissionError(model.PermissionReadChannelContent)
return
Expand Down Expand Up @@ -155,7 +155,7 @@ func updateIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
return
}

if channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), channel.Id, model.PermissionReadChannelContent) {
if channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel) {
c.LogAudit("fail - bad channel permissions")
c.SetPermissionError(model.PermissionReadChannelContent)
return
Expand Down Expand Up @@ -260,7 +260,7 @@ func getIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
}

if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), hook.TeamId, model.PermissionManageIncomingWebhooks) ||
(channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), hook.ChannelId, model.PermissionReadChannelContent)) {
(channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel)) {
c.LogAudit("fail - bad permissions")
c.SetPermissionError(model.PermissionManageIncomingWebhooks)
return
Expand Down Expand Up @@ -314,7 +314,7 @@ func deleteIncomingHook(c *Context, w http.ResponseWriter, r *http.Request) {
auditRec.AddMeta("team_id", hook.TeamId)

if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), hook.TeamId, model.PermissionManageIncomingWebhooks) ||
(channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToChannel(c.AppContext, *c.AppContext.Session(), hook.ChannelId, model.PermissionReadChannelContent)) {
(channel.Type != model.ChannelTypeOpen && !c.App.SessionHasPermissionToReadChannel(c.AppContext, *c.AppContext.Session(), channel)) {
c.LogAudit("fail - bad permissions")
c.SetPermissionError(model.PermissionManageIncomingWebhooks)
return
Expand Down
1 change: 1 addition & 0 deletions server/channels/app/app_iface.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions server/channels/app/authorization.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ func (a *App) SessionHasPermissionToManageBot(rctx request.CTX, session model.Se
return nil
}

func (a *App) SessionHasPermissionToReadChannel(c request.CTX, session model.Session, channel *model.Channel) bool {
if session.IsUnrestricted() {
return true
}

return a.HasPermissionToReadChannel(c, session.UserId, channel)
}

func (a *App) HasPermissionToReadChannel(c request.CTX, userID string, channel *model.Channel) bool {
if !*a.Config().TeamSettings.ExperimentalViewArchivedChannels && channel.DeleteAt != 0 {
return false
Expand Down
Loading

0 comments on commit aa85a13

Please sign in to comment.