fix: generalise permission check for query user information (#8458)

# Which Problems Are Solved

IDPLinks list and other list endpoints can provide you with empty
results if the used user has no permission for the information.

# How the Problems Are Solved

List endpoints with subelements to users, and provided userIDQuery, will
return a PermissionDenied error if no permission for the user exsists.

# Additional Changes

Function to check for permission is re-used from the GetUserByID.

# Additional Context

Closes #8451
This commit is contained in:
Stefan Benz
2024-08-23 08:44:18 +02:00
committed by GitHub
parent 8051a63147
commit 2847806531
27 changed files with 552 additions and 111 deletions

View File

@@ -3,6 +3,7 @@ package query
import (
"context"
"database/sql"
"slices"
sq "github.com/Masterminds/squirrel"
@@ -42,6 +43,15 @@ func (q *IDPUserLinksSearchQuery) toQuery(query sq.SelectBuilder) sq.SelectBuild
return query
}
func (q *IDPUserLinksSearchQuery) hasUserID() bool {
for _, query := range q.Queries {
if query.Col() == IDPUserLinkUserIDCol {
return true
}
}
return false
}
var (
idpUserLinkTable = table{
name: projection.IDPUserLinkTable,
@@ -89,30 +99,33 @@ var (
}
)
func (l *IDPUserLinks) RemoveNoPermission(ctx context.Context, permissionCheck domain.PermissionCheck) {
removableIndexes := make([]int, 0)
for i := range l.Links {
ctxData := authz.GetCtxData(ctx)
if ctxData.UserID != l.Links[i].UserID {
if err := permissionCheck(ctx, domain.PermissionUserRead, l.Links[i].ResourceOwner, l.Links[i].UserID); err != nil {
removableIndexes = append(removableIndexes, i)
func idpLinksCheckPermission(ctx context.Context, links *IDPUserLinks, permissionCheck domain.PermissionCheck) {
links.Links = slices.DeleteFunc(links.Links,
func(link *IDPUserLink) bool {
return userCheckPermission(ctx, link.ResourceOwner, link.UserID, permissionCheck) != nil
},
)
}
func (q *Queries) IDPUserLinks(ctx context.Context, queries *IDPUserLinksSearchQuery, permissionCheck domain.PermissionCheck) (idps *IDPUserLinks, err error) {
links, err := q.idpUserLinks(ctx, queries, false)
if err != nil {
return nil, err
}
if permissionCheck != nil && len(links.Links) > 0 {
// when userID for query is provided, only one check has to be done
if queries.hasUserID() {
if err := userCheckPermission(ctx, links.Links[0].ResourceOwner, links.Links[0].UserID, permissionCheck); err != nil {
return nil, err
}
} else {
idpLinksCheckPermission(ctx, links, permissionCheck)
}
}
removed := 0
for _, removeIndex := range removableIndexes {
l.Links = removeIDPLink(l.Links, removeIndex-removed)
removed++
}
// reset count as some users could be removed
l.SearchResponse.Count = uint64(len(l.Links))
return links, nil
}
func removeIDPLink(slice []*IDPUserLink, s int) []*IDPUserLink {
return append(slice[:s], slice[s+1:]...)
}
func (q *Queries) IDPUserLinks(ctx context.Context, queries *IDPUserLinksSearchQuery, withOwnerRemoved bool) (idps *IDPUserLinks, err error) {
func (q *Queries) idpUserLinks(ctx context.Context, queries *IDPUserLinksSearchQuery, withOwnerRemoved bool) (idps *IDPUserLinks, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()