mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-12 00:55:12 +00:00
feat: usergrant (#489)
* fix: search usergrants only for allowed projects * fix: check permissions * fix: check permissions * fix: check permissions * Update internal/management/repository/eventsourcing/eventstore/project.go Co-authored-by: Silvan <[email protected]> * fix: merge request changes * fix: variable name Co-authored-by: Silvan <[email protected]>
This commit is contained in:
@@ -82,15 +82,38 @@ func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*pro
|
||||
|
||||
func (repo *ProjectRepo) SearchProjects(ctx context.Context, request *proj_model.ProjectViewSearchRequest) (*proj_model.ProjectViewSearchResponse, error) {
|
||||
request.EnsureLimit(repo.SearchLimit)
|
||||
|
||||
permissions := authz.GetPermissionsFromCtx(ctx)
|
||||
if !authz.HasGlobalPermission(permissions) {
|
||||
ids := authz.GetPermissionCtxIDs(permissions)
|
||||
request.Queries = append(request.Queries, &proj_model.ProjectViewSearchQuery{Key: proj_model.ProjectViewSearchKeyProjectID, Method: global_model.SearchMethodIsOneOf, Value: ids})
|
||||
}
|
||||
|
||||
sequence, err := repo.View.GetLatestProjectSequence()
|
||||
logging.Log("EVENT-Edc56").OnError(err).Warn("could not read latest project sequence")
|
||||
|
||||
permissions := authz.GetRequestPermissionsFromCtx(ctx)
|
||||
if !authz.HasGlobalPermission(permissions) {
|
||||
ids := authz.GetAllPermissionCtxIDs(permissions)
|
||||
if _, q := request.GetSearchQuery(proj_model.ProjectViewSearchKeyProjectID); q != nil {
|
||||
containsID := false
|
||||
for _, id := range ids {
|
||||
if id == q.Value {
|
||||
containsID = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !containsID {
|
||||
result := &proj_model.ProjectViewSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(0),
|
||||
Result: []*proj_model.ProjectView{},
|
||||
}
|
||||
if err == nil {
|
||||
result.Sequence = sequence.CurrentSequence
|
||||
result.Timestamp = sequence.CurrentTimestamp
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
} else {
|
||||
request.Queries = append(request.Queries, &proj_model.ProjectViewSearchQuery{Key: proj_model.ProjectViewSearchKeyProjectID, Method: global_model.SearchMethodIsOneOf, Value: ids})
|
||||
}
|
||||
}
|
||||
|
||||
projects, count, err := repo.View.SearchProjects(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -348,6 +371,57 @@ func (repo *ProjectRepo) SearchProjectGrants(ctx context.Context, request *proj_
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (repo *ProjectRepo) SearchGrantedProjects(ctx context.Context, request *proj_model.ProjectGrantViewSearchRequest) (*proj_model.ProjectGrantViewSearchResponse, error) {
|
||||
request.EnsureLimit(repo.SearchLimit)
|
||||
sequence, err := repo.View.GetLatestProjectGrantSequence()
|
||||
logging.Log("EVENT-Skw9f").OnError(err).Warn("could not read latest project grant sequence")
|
||||
|
||||
permissions := authz.GetRequestPermissionsFromCtx(ctx)
|
||||
if !authz.HasGlobalPermission(permissions) {
|
||||
ids := authz.GetAllPermissionCtxIDs(permissions)
|
||||
if _, q := request.GetSearchQuery(proj_model.GrantedProjectSearchKeyGrantID); q != nil {
|
||||
containsID := false
|
||||
for _, id := range ids {
|
||||
if id == q.Value {
|
||||
containsID = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !containsID {
|
||||
result := &proj_model.ProjectGrantViewSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(0),
|
||||
Result: []*proj_model.ProjectGrantView{},
|
||||
}
|
||||
if err == nil {
|
||||
result.Sequence = sequence.CurrentSequence
|
||||
result.Timestamp = sequence.CurrentTimestamp
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
} else {
|
||||
request.Queries = append(request.Queries, &proj_model.ProjectGrantViewSearchQuery{Key: proj_model.GrantedProjectSearchKeyGrantID, Method: global_model.SearchMethodIsOneOf, Value: ids})
|
||||
}
|
||||
}
|
||||
|
||||
projects, count, err := repo.View.SearchProjectGrants(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &proj_model.ProjectGrantViewSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(count),
|
||||
Result: model.ProjectGrantsToModel(projects),
|
||||
}
|
||||
if err == nil {
|
||||
result.Sequence = sequence.CurrentSequence
|
||||
result.Timestamp = sequence.CurrentTimestamp
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (repo *ProjectRepo) AddProjectGrant(ctx context.Context, grant *proj_model.ProjectGrant) (*proj_model.ProjectGrant, error) {
|
||||
return repo.ProjectEvents.AddProjectGrant(ctx, grant)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,18 @@ package eventstore
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/logging"
|
||||
"github.com/caos/zitadel/internal/api/authz"
|
||||
caos_errors "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/management/repository/eventsourcing/view"
|
||||
global_model "github.com/caos/zitadel/internal/model"
|
||||
grant_model "github.com/caos/zitadel/internal/usergrant/model"
|
||||
grant_event "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing"
|
||||
"github.com/caos/zitadel/internal/usergrant/repository/view/model"
|
||||
"github.com/caos/zitadel/internal/view/repository"
|
||||
)
|
||||
|
||||
const (
|
||||
projectReadPerm = "project.read"
|
||||
)
|
||||
|
||||
type UserGrantRepo struct {
|
||||
@@ -24,34 +32,88 @@ func (repo *UserGrantRepo) UserGrantByID(ctx context.Context, grantID string) (*
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) AddUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*grant_model.UserGrant, error) {
|
||||
err := checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserGrantEvents.AddUserGrant(ctx, grant)
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) ChangeUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*grant_model.UserGrant, error) {
|
||||
err := checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserGrantEvents.ChangeUserGrant(ctx, grant)
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) DeactivateUserGrant(ctx context.Context, grantID string) (*grant_model.UserGrant, error) {
|
||||
grant, err := repo.UserGrantByID(ctx, grantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserGrantEvents.DeactivateUserGrant(ctx, grantID)
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) ReactivateUserGrant(ctx context.Context, grantID string) (*grant_model.UserGrant, error) {
|
||||
grant, err := repo.UserGrantByID(ctx, grantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo.UserGrantEvents.ReactivateUserGrant(ctx, grantID)
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) RemoveUserGrant(ctx context.Context, grantID string) error {
|
||||
grant, err := repo.UserGrantByID(ctx, grantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return repo.UserGrantEvents.RemoveUserGrant(ctx, grantID)
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) BulkAddUserGrant(ctx context.Context, grants ...*grant_model.UserGrant) error {
|
||||
for _, grant := range grants {
|
||||
err := checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return repo.UserGrantEvents.AddUserGrants(ctx, grants...)
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) BulkChangeUserGrant(ctx context.Context, grants ...*grant_model.UserGrant) error {
|
||||
for _, grant := range grants {
|
||||
err := checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return repo.UserGrantEvents.ChangeUserGrants(ctx, grants...)
|
||||
}
|
||||
|
||||
func (repo *UserGrantRepo) BulkRemoveUserGrant(ctx context.Context, grantIDs ...string) error {
|
||||
for _, grantID := range grantIDs {
|
||||
grant, err := repo.UserGrantByID(ctx, grantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = checkExplicitPermission(ctx, grant.GrantID, grant.ProjectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return repo.UserGrantEvents.RemoveUserGrants(ctx, grantIDs...)
|
||||
}
|
||||
|
||||
@@ -59,11 +121,18 @@ func (repo *UserGrantRepo) SearchUserGrants(ctx context.Context, request *grant_
|
||||
request.EnsureLimit(repo.SearchLimit)
|
||||
sequence, err := repo.View.GetLatestUserGrantSequence()
|
||||
logging.Log("EVENT-5Viwf").OnError(err).Warn("could not read latest user grant sequence")
|
||||
|
||||
result := handleSearchUserGrantPermissions(ctx, request, sequence)
|
||||
if result != nil {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
grants, count, err := repo.View.SearchUserGrants(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := &grant_model.UserGrantSearchResponse{
|
||||
|
||||
result = &grant_model.UserGrantSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(count),
|
||||
@@ -75,3 +144,67 @@ func (repo *UserGrantRepo) SearchUserGrants(ctx context.Context, request *grant_
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func handleSearchUserGrantPermissions(ctx context.Context, request *grant_model.UserGrantSearchRequest, sequence *repository.CurrentSequence) *grant_model.UserGrantSearchResponse {
|
||||
permissions := authz.GetAllPermissionsFromCtx(ctx)
|
||||
if authz.HasGlobalExplicitPermission(permissions, projectReadPerm) {
|
||||
return nil
|
||||
}
|
||||
|
||||
ids := authz.GetExplicitPermissionCtxIDs(permissions, projectReadPerm)
|
||||
if _, q := request.GetSearchQuery(grant_model.UserGrantSearchKeyProjectID); q != nil {
|
||||
containsID := false
|
||||
for _, id := range ids {
|
||||
if id == q.Value {
|
||||
containsID = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !containsID {
|
||||
result := &grant_model.UserGrantSearchResponse{
|
||||
Offset: request.Offset,
|
||||
Limit: request.Limit,
|
||||
TotalResult: uint64(0),
|
||||
Result: []*grant_model.UserGrantView{},
|
||||
}
|
||||
if sequence != nil {
|
||||
result.Sequence = sequence.CurrentSequence
|
||||
result.Timestamp = sequence.CurrentTimestamp
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.UserGrantSearchKeyProjectID, Method: global_model.SearchMethodIsOneOf, Value: ids})
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkExplicitPermission(ctx context.Context, grantID, projectID string) error {
|
||||
permissions := authz.GetRequestPermissionsFromCtx(ctx)
|
||||
if authz.HasGlobalPermission(permissions) {
|
||||
return nil
|
||||
}
|
||||
ids := authz.GetAllPermissionCtxIDs(permissions)
|
||||
containsID := false
|
||||
if grantID != "" {
|
||||
containsID = listContainsID(ids, grantID)
|
||||
if containsID {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
containsID = listContainsID(ids, projectID)
|
||||
if !containsID {
|
||||
return caos_errors.ThrowPermissionDenied(nil, "EVENT-Shu7e", "Errors.UserGrant.NoPermissionForProject")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func listContainsID(ids []string, id string) bool {
|
||||
containsID := false
|
||||
for _, i := range ids {
|
||||
if i == id {
|
||||
containsID = true
|
||||
break
|
||||
}
|
||||
}
|
||||
return containsID
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ type ProjectRepository interface {
|
||||
ReactivateProject(ctx context.Context, id string) (*model.Project, error)
|
||||
SearchProjects(ctx context.Context, request *model.ProjectViewSearchRequest) (*model.ProjectViewSearchResponse, error)
|
||||
SearchProjectGrants(ctx context.Context, request *model.ProjectGrantViewSearchRequest) (*model.ProjectGrantViewSearchResponse, error)
|
||||
SearchGrantedProjects(ctx context.Context, request *model.ProjectGrantViewSearchRequest) (*model.ProjectGrantViewSearchResponse, error)
|
||||
ProjectGrantViewByID(ctx context.Context, grantID string) (*model.ProjectGrantView, error)
|
||||
|
||||
ProjectMemberByID(ctx context.Context, projectID, userID string) (*model.ProjectMemberView, error)
|
||||
|
||||
Reference in New Issue
Block a user