MM-45535: Batch optimize auth checks in GraphQL (#20634)

We create two new auth checks which take multiple channels
and teams. They can be used to check whenever a user needs
access to multiple entities.

These are then access in dataloaders to ease the load in the
database.

```release-note
NONE
```
Этот коммит содержится в:
Agniva De Sarker
2022-07-12 23:26:48 +05:30
коммит произвёл GitHub
родитель 72346eccb8
Коммит 049e67b863
6 изменённых файлов: 171 добавлений и 28 удалений

Просмотреть файл

@@ -298,10 +298,14 @@ type AppIface interface {
SearchAllTeams(searchOpts *model.TeamSearch) ([]*model.Team, int64, *model.AppError)
// SendNoCardPaymentFailedEmail
SendNoCardPaymentFailedEmail() *model.AppError
// SessionHasPermissionToChannels returns true only if user has access to all channels.
SessionHasPermissionToChannels(session model.Session, channelIDs []string, permission *model.Permission) bool
// SessionHasPermissionToManageBot returns nil if the session has access to manage the given bot.
// This function deviates from other authorization checks in returning an error instead of just
// a boolean, allowing the permission failure to be exposed with more granularity.
SessionHasPermissionToManageBot(session model.Session, botUserId string) *model.AppError
// SessionHasPermissionToTeams returns true only if user has access to all teams.
SessionHasPermissionToTeams(session model.Session, teamIDs []string, permission *model.Permission) bool
// SessionIsRegistered determines if a specific session has been registered
SessionIsRegistered(session model.Session) bool
// SetSessionExpireInHours sets the session's expiry the specified number of hours

Просмотреть файл

@@ -57,6 +57,40 @@ func (a *App) SessionHasPermissionToTeam(session model.Session, teamID string, p
return a.RolesGrantPermission(session.GetUserRoles(), permission.Id)
}
// SessionHasPermissionToTeams returns true only if user has access to all teams.
func (a *App) SessionHasPermissionToTeams(session model.Session, teamIDs []string, permission *model.Permission) bool {
for _, teamID := range teamIDs {
if teamID == "" {
return false
}
}
if session.IsUnrestricted() {
return true
}
// Getting the list of unique roles from all teams.
var roles []string
uniqueRoles := make(map[string]bool)
for _, teamID := range teamIDs {
tm := session.GetTeamByTeamId(teamID)
if tm != nil {
for _, role := range tm.GetRoles() {
uniqueRoles[role] = true
}
}
}
for role := range uniqueRoles {
roles = append(roles, role)
}
if a.RolesGrantPermission(roles, permission.Id) {
return true
}
return a.RolesGrantPermission(session.GetUserRoles(), permission.Id)
}
func (a *App) SessionHasPermissionToChannel(session model.Session, channelID string, permission *model.Permission) bool {
if channelID == "" {
return false
@@ -90,6 +124,65 @@ func (a *App) SessionHasPermissionToChannel(session model.Session, channelID str
return a.SessionHasPermissionTo(session, permission)
}
// SessionHasPermissionToChannels returns true only if user has access to all channels.
func (a *App) SessionHasPermissionToChannels(session model.Session, channelIDs []string, permission *model.Permission) bool {
for _, channelID := range channelIDs {
if channelID == "" {
return false
}
}
if session.IsUnrestricted() {
return true
}
ids, err := a.Srv().Store.Channel().GetAllChannelMembersForUser(session.UserId, true, true)
var channelRoles []string
uniqueRoles := make(map[string]bool)
if err == nil {
for _, channelID := range channelIDs {
if roles, ok := ids[channelID]; ok {
for _, role := range strings.Fields(roles) {
uniqueRoles[role] = true
}
}
}
}
for role := range uniqueRoles {
channelRoles = append(channelRoles, role)
}
if a.RolesGrantPermission(channelRoles, permission.Id) {
return true
}
channels, appErr := a.GetChannels(channelIDs)
if appErr != nil && appErr.StatusCode == http.StatusNotFound {
return false
}
// Get TeamIDs from channels
uniqueTeamIDs := make(map[string]bool)
for _, ch := range channels {
if ch.TeamId != "" {
uniqueTeamIDs[ch.TeamId] = true
}
}
var teamIDs []string
for teamID := range uniqueTeamIDs {
teamIDs = append(teamIDs, teamID)
}
if appErr == nil && len(teamIDs) > 0 {
return a.SessionHasPermissionToTeams(session, teamIDs, permission)
}
return a.SessionHasPermissionTo(session, permission)
}
func (a *App) SessionHasPermissionToGroup(session model.Session, groupID string, permission *model.Permission) bool {
groupMember, err := a.Srv().Store.Group().GetMember(groupID, session.UserId)
// don't reject immediately on ErrNoRows error because there's further authz logic below for non-groupmembers

Просмотреть файл

@@ -15233,6 +15233,23 @@ func (a *OpenTracingAppLayer) SessionHasPermissionToChannelByPost(session model.
return resultVar0
}
func (a *OpenTracingAppLayer) SessionHasPermissionToChannels(session model.Session, channelIDs []string, permission *model.Permission) bool {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToChannels")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.SessionHasPermissionToChannels(session, channelIDs, permission)
return resultVar0
}
func (a *OpenTracingAppLayer) SessionHasPermissionToCreateJob(session model.Session, job *model.Job) (bool, *model.Permission) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToCreateJob")
@@ -15323,6 +15340,23 @@ func (a *OpenTracingAppLayer) SessionHasPermissionToTeam(session model.Session,
return resultVar0
}
func (a *OpenTracingAppLayer) SessionHasPermissionToTeams(session model.Session, teamIDs []string, permission *model.Permission) bool {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToTeams")
a.ctx = newCtx
a.app.Srv().Store.SetContext(newCtx)
defer func() {
a.app.Srv().Store.SetContext(origCtx)
a.ctx = origCtx
}()
defer span.Finish()
resultVar0 := a.app.SessionHasPermissionToTeams(session, teamIDs, permission)
return resultVar0
}
func (a *OpenTracingAppLayer) SessionHasPermissionToUser(session model.Session, userID string) bool {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SessionHasPermissionToUser")