feat: delete (#243)

* feat: project role remove

* feat: search queries

* feat: search queries

* feat: cascade remove/change project role

* fix: comment in project grant

* fix: remove projecr grant

* fix: only search usergrants of my org

* fix: delete usergrants

* fix: delete usergrants

* fix: check if role exists on project grant

* feat: bulk add project role

* fix: tests

* fix: update user grants on project update

* fix: return roles

* feat: add resourceowner name on project grants

* fix: migration number

* fix: tests

* fix: generate protos

* fix: some unnecessary code
This commit is contained in:
Fabi 2020-06-19 15:32:03 +02:00 committed by GitHub
parent 8f49f2c2d8
commit 710652ef24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 4404 additions and 2668 deletions

View File

@ -14,11 +14,13 @@ InternalAuthZ:
- "user.delete"
- "user.grant.read"
- "user.grant.write"
- "user.grant.delete"
- "policy.read"
- "policy.write"
- "policy.delete"
- "project.read"
- "project.write"
- "project.delete"
- "project.member.read"
- "project.member.write"
- "project.member.delete"
@ -27,8 +29,10 @@ InternalAuthZ:
- "project.role.delete"
- "project.app.read"
- "project.app.write"
- "project.app.delete"
- "project.grant.read"
- "project.grant.write"
- "project.grant.delete"
- "project.grant.member.read"
- "project.grant.member.write"
- "project.grant.member.delete"
@ -47,11 +51,13 @@ InternalAuthZ:
- "user.delete"
- "user.grant.read"
- "user.grant.write"
- "user.grant.delete"
- "policy.read"
- "policy.write"
- "policy.delete"
- "project.read"
- "project.write"
- "project.delete"
- "project.member.read"
- "project.member.write"
- "project.member.delete"
@ -62,6 +68,7 @@ InternalAuthZ:
- "project.app.write"
- "project.grant.read"
- "project.grant.write"
- "project.grant.delete"
- "project.grant.member.read"
- "project.grant.member.write"
- "project.grant.member.delete"
@ -98,8 +105,10 @@ InternalAuthZ:
- "project.role.delete"
- "project.app.read"
- "project.app.write"
- "project.app.delete"
- "project.grant.read"
- "project.grant.write"
- "project.grant.delete"
- "project.grant.member.read"
- "project.grant.member.write"
- "project.grant.member.delete"
@ -116,6 +125,7 @@ InternalAuthZ:
- "project.read"
- "project.member.read"
- "project.member.write"
- "project.member.delete"
- "project.grant.member.delete"
- Role: 'ORG_PROJECT_MEMBER_VIEWER'
Permissions:
@ -136,6 +146,7 @@ InternalAuthZ:
- "project.read"
- "project.app.read"
- "project.app.write"
- "project.app.delete"
- Role: 'ORG_PROJECT_APP_VIEWER'
Permissions:
- "project.read"
@ -177,6 +188,7 @@ InternalAuthZ:
- "user.read"
- "user.grant.read"
- "user.grant.write"
- "user.grant.delete"
- "project.read"
- Role: 'ORG_USER_GRANT_VIEWER'
Permissions:
@ -194,6 +206,7 @@ InternalAuthZ:
Permissions:
- "project.read"
- "project.write"
- "project.delete"
- "project.member.read"
- "project.member.write"
- "project.member.delete"
@ -202,8 +215,10 @@ InternalAuthZ:
- "project.role.delete"
- "project.app.read"
- "project.app.write"
- "project.app.delete"
- "project.grant.read"
- "project.grant.write"
- "project.grant.delete"
- "project.grant.member.read"
- "project.grant.member.write"
- "project.grant.member.delete"
@ -240,6 +255,7 @@ InternalAuthZ:
- "project.read"
- "project.grant.read"
- "project.grant.write"
- "project.grant.delete"
- Role: 'PROJECT_GRANT_VIEWER'
Permissions:
- "project.read"

View File

@ -89,6 +89,7 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
}
err = u.fillData(grant, event.ResourceOwner)
case grant_es_model.UserGrantChanged,
grant_es_model.UserGrantCascadeChanged,
grant_es_model.UserGrantDeactivated,
grant_es_model.UserGrantReactivated:
grant, err = u.view.UserGrantByID(event.AggregateID)
@ -96,8 +97,8 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
return err
}
err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved:
err = u.view.DeleteUserGrant(event.AggregateID, event.Sequence)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
return u.view.DeleteUserGrant(event.AggregateID, event.Sequence)
default:
return u.view.ProcessedUserGrantSequence(event.Sequence)
}
@ -204,7 +205,6 @@ func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suf
} else {
grant.RoleKeys = newRoles
}
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate

View File

@ -123,7 +123,6 @@ func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suf
} else {
grant.RoleKeys = newRoles
}
}
grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate

View File

@ -59,6 +59,9 @@ func PushAggregates(ctx context.Context, push pushFunc, appender appendFunc, agg
if err != nil {
return err
}
if appender == nil {
return nil
}
return appendAggregates(appender, aggregates)
}

View File

@ -2,6 +2,14 @@ package eventstore
import (
"context"
caos_errs "github.com/caos/zitadel/internal/errors"
es_int "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
es_proj_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model"
usr_grant_model "github.com/caos/zitadel/internal/usergrant/model"
usr_grant_event "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing"
"strings"
"github.com/caos/zitadel/internal/api/auth"
@ -15,10 +23,12 @@ import (
)
type ProjectRepo struct {
SearchLimit uint64
ProjectEvents *proj_event.ProjectEventstore
View *view.View
Roles []string
es_int.Eventstore
SearchLimit uint64
ProjectEvents *proj_event.ProjectEventstore
UserGrantEvents *usr_grant_event.UserGrantEventStore
View *view.View
Roles []string
}
func (repo *ProjectRepo) ProjectByID(ctx context.Context, id string) (project *proj_model.Project, err error) {
@ -48,7 +58,7 @@ func (repo *ProjectRepo) SearchProjects(ctx context.Context, request *proj_model
permissions := auth.GetPermissionsFromCtx(ctx)
if !auth.HasGlobalPermission(permissions) {
ids := auth.GetPermissionCtxIDs(permissions)
request.Queries = append(request.Queries, &proj_model.ProjectViewSearchQuery{Key: proj_model.PROJECTSEARCHKEY_PROJECTID, Method: global_model.SEARCHMETHOD_IN, Value: ids})
request.Queries = append(request.Queries, &proj_model.ProjectViewSearchQuery{Key: proj_model.PROJECTSEARCHKEY_PROJECTID, Method: global_model.SEARCHMETHOD_IS_ONE_OF, Value: ids})
}
projects, count, err := repo.View.SearchProjects(request)
@ -103,8 +113,13 @@ func (repo *ProjectRepo) SearchProjectMembers(ctx context.Context, request *proj
}, nil
}
func (repo *ProjectRepo) AddProjectRole(ctx context.Context, member *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
return repo.ProjectEvents.AddProjectRole(ctx, member)
func (repo *ProjectRepo) AddProjectRole(ctx context.Context, role *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
return repo.ProjectEvents.AddProjectRoles(ctx, role)
}
func (repo *ProjectRepo) BulkAddProjectRole(ctx context.Context, roles []*proj_model.ProjectRole) error {
_, err := repo.ProjectEvents.AddProjectRoles(ctx, roles...)
return err
}
func (repo *ProjectRepo) ChangeProjectRole(ctx context.Context, member *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
@ -112,8 +127,40 @@ func (repo *ProjectRepo) ChangeProjectRole(ctx context.Context, member *proj_mod
}
func (repo *ProjectRepo) RemoveProjectRole(ctx context.Context, projectID, key string) error {
member := proj_model.NewProjectRole(projectID, key)
return repo.ProjectEvents.RemoveProjectRole(ctx, member)
role := proj_model.NewProjectRole(projectID, key)
aggregates := make([]*es_models.Aggregate, 0)
project, agg, err := repo.ProjectEvents.PrepareRemoveProjectRole(ctx, role)
if err != nil {
return err
}
aggregates = append(aggregates, agg)
usergrants, err := repo.View.UserGrantsByProjectIDAndRoleKey(projectID, key)
if err != nil {
return err
}
for _, grant := range usergrants {
changed := &usr_grant_model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: grant.ID, Sequence: grant.Sequence, ResourceOwner: grant.ResourceOwner},
RoleKeys: grant.RoleKeys,
ProjectID: grant.ProjectID,
UserID: grant.UserID,
}
changed.RemoveRoleKeyIfExisting(key)
_, agg, err := repo.UserGrantEvents.PrepareChangeUserGrant(ctx, changed, true)
if err != nil {
return err
}
aggregates = append(aggregates, agg)
}
if err != nil {
return err
}
err = es_sdk.PushAggregates(ctx, repo.Eventstore.PushAggregates, project.AppendEvents, aggregates...)
if err != nil {
return err
}
return nil
}
func (repo *ProjectRepo) SearchProjectRoles(ctx context.Context, request *proj_model.ProjectRoleSearchRequest) (*proj_model.ProjectRoleSearchResponse, error) {
@ -211,25 +258,100 @@ func (repo *ProjectRepo) SearchProjectGrants(ctx context.Context, request *proj_
}, nil
}
func (repo *ProjectRepo) AddProjectGrant(ctx context.Context, app *proj_model.ProjectGrant) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.AddProjectGrant(ctx, app)
func (repo *ProjectRepo) AddProjectGrant(ctx context.Context, grant *proj_model.ProjectGrant) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.AddProjectGrant(ctx, grant)
}
func (repo *ProjectRepo) ChangeProjectGrant(ctx context.Context, app *proj_model.ProjectGrant) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.ChangeProjectGrant(ctx, app)
func (repo *ProjectRepo) ChangeProjectGrant(ctx context.Context, grant *proj_model.ProjectGrant) (*proj_model.ProjectGrant, error) {
project, aggFunc, removedRoles, err := repo.ProjectEvents.PrepareChangeProjectGrant(ctx, grant)
if err != nil {
return nil, err
}
agg, err := aggFunc(ctx)
if err != nil {
return nil, err
}
aggregates := make([]*es_models.Aggregate, 0)
aggregates = append(aggregates, agg)
usergrants, err := repo.View.UserGrantsByProjectID(grant.AggregateID)
if err != nil {
return nil, err
}
for _, grant := range usergrants {
changed := &usr_grant_model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: grant.ID, Sequence: grant.Sequence, ResourceOwner: grant.ResourceOwner},
RoleKeys: grant.RoleKeys,
ProjectID: grant.ProjectID,
UserID: grant.UserID,
}
existing := changed.RemoveRoleKeysIfExisting(removedRoles)
if existing {
_, agg, err := repo.UserGrantEvents.PrepareChangeUserGrant(ctx, changed, true)
if err != nil {
return nil, err
}
aggregates = append(aggregates, agg)
}
}
if err != nil {
return nil, err
}
err = es_sdk.PushAggregates(ctx, repo.Eventstore.PushAggregates, project.AppendEvents, aggregates...)
if err != nil {
return nil, err
}
if _, g := es_proj_model.GetProjectGrant(project.Grants, grant.GrantID); g != nil {
return es_proj_model.GrantToModel(g), nil
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-dksi8", "Could not find app in list")
}
func (repo *ProjectRepo) DeactivateProjectGrant(ctx context.Context, projectID, appID string) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.DeactivateProjectGrant(ctx, projectID, appID)
func (repo *ProjectRepo) DeactivateProjectGrant(ctx context.Context, projectID, grantID string) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.DeactivateProjectGrant(ctx, projectID, grantID)
}
func (repo *ProjectRepo) ReactivateProjectGrant(ctx context.Context, projectID, appID string) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.ReactivateProjectGrant(ctx, projectID, appID)
func (repo *ProjectRepo) ReactivateProjectGrant(ctx context.Context, projectID, grantID string) (*proj_model.ProjectGrant, error) {
return repo.ProjectEvents.ReactivateProjectGrant(ctx, projectID, grantID)
}
func (repo *ProjectRepo) RemoveProjectGrant(ctx context.Context, projectID, appID string) error {
app := proj_model.NewProjectGrant(projectID, appID)
return repo.ProjectEvents.RemoveProjectGrant(ctx, app)
func (repo *ProjectRepo) RemoveProjectGrant(ctx context.Context, projectID, grantID string) error {
grant, err := repo.ProjectEvents.ProjectGrantByIDs(ctx, projectID, grantID)
if err != nil {
return err
}
aggregates := make([]*es_models.Aggregate, 0)
project, aggFunc, err := repo.ProjectEvents.PrepareRemoveProjectGrant(ctx, grant)
if err != nil {
return err
}
agg, err := aggFunc(ctx)
if err != nil {
return err
}
aggregates = append(aggregates, agg)
usergrants, err := repo.View.UserGrantsByOrgIDAndProjectID(grant.GrantedOrgID, projectID)
if err != nil {
return err
}
for _, grant := range usergrants {
_, grantAggregates, err := repo.UserGrantEvents.PrepareRemoveUserGrant(ctx, grant.ID, true)
if err != nil {
return err
}
for _, agg := range grantAggregates {
aggregates = append(aggregates, agg)
}
}
if err != nil {
return err
}
err = es_sdk.PushAggregates(ctx, repo.Eventstore.PushAggregates, project.AppendEvents, aggregates...)
if err != nil {
return err
}
return nil
}
func (repo *ProjectRepo) ProjectGrantMemberByID(ctx context.Context, projectID, grantID, userID string) (member *proj_model.ProjectGrantMember, err error) {

View File

@ -38,6 +38,18 @@ func (repo *UserGrantRepo) RemoveUserGrant(ctx context.Context, grantID string)
return repo.UserGrantEvents.RemoveUserGrant(ctx, grantID)
}
func (repo *UserGrantRepo) BulkAddUserGrant(ctx context.Context, grants ...*grant_model.UserGrant) error {
return repo.UserGrantEvents.AddUserGrants(ctx, grants...)
}
func (repo *UserGrantRepo) BulkChangeUserGrant(ctx context.Context, grants ...*grant_model.UserGrant) error {
return repo.UserGrantEvents.ChangeUserGrants(ctx, grants...)
}
func (repo *UserGrantRepo) BulkRemoveUserGrant(ctx context.Context, grantIDs ...string) error {
return repo.UserGrantEvents.RemoveUserGrants(ctx, grantIDs...)
}
func (repo *UserGrantRepo) SearchUserGrants(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.UserGrantSearchResponse, error) {
request.EnsureLimit(repo.SearchLimit)
grants, count, err := repo.View.SearchUserGrants(request)

View File

@ -66,8 +66,12 @@ func (p *ProjectGrant) Process(event *models.Event) (err error) {
if err != nil {
return err
}
p.fillOrgData(grantedProject, org)
case es_model.ProjectGrantChanged:
resourceOwner, err := p.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(grantedProject.ResourceOwner))
if err != nil {
return err
}
p.fillOrgData(grantedProject, org, resourceOwner)
case es_model.ProjectGrantChanged, es_model.ProjectGrantCascadeChanged:
grant := new(view_model.ProjectGrant)
err := grant.SetData(event)
if err != nil {
@ -94,8 +98,9 @@ func (p *ProjectGrant) Process(event *models.Event) (err error) {
return p.view.PutProjectGrant(grantedProject)
}
func (p *ProjectGrant) fillOrgData(grantedProject *view_model.ProjectGrantView, org *org_model.Org) {
func (p *ProjectGrant) fillOrgData(grantedProject *view_model.ProjectGrantView, org, resourceOwner *org_model.Org) {
grantedProject.OrgName = org.Name
grantedProject.ResourceOwnerName = resourceOwner.Name
}
func (p *ProjectGrant) getProject(projectID string) (*proj_model.Project, error) {

View File

@ -56,7 +56,7 @@ func (p *ProjectRole) Process(event *models.Event) (err error) {
if err != nil {
return err
}
err = p.removeRoleFromAllResourceowners(event, role)
return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence)
case es_model.ProjectGrantAdded:
return p.addGrantRoles(event)
case es_model.ProjectGrantChanged:

View File

@ -73,6 +73,7 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
}
err = u.fillData(grant, event.ResourceOwner)
case grant_es_model.UserGrantChanged,
grant_es_model.UserGrantCascadeChanged,
grant_es_model.UserGrantDeactivated,
grant_es_model.UserGrantReactivated:
grant, err = u.view.UserGrantByID(event.AggregateID)
@ -80,8 +81,8 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
return err
}
err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved:
err = u.view.DeleteUserGrant(event.AggregateID, event.Sequence)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
return u.view.DeleteUserGrant(event.AggregateID, event.Sequence)
default:
return u.view.ProcessedUserGrantSequence(event.Sequence)
}

View File

@ -96,7 +96,7 @@ func Start(conf Config, systemDefaults sd.SystemDefaults, roles []string) (*EsRe
return &EsRepository{
spooler: spool,
OrgRepository: eventstore.OrgRepository{conf.SearchLimit, org, view, roles},
ProjectRepo: eventstore.ProjectRepo{conf.SearchLimit, project, view, roles},
ProjectRepo: eventstore.ProjectRepo{es, conf.SearchLimit, project, usergrant, view, roles},
UserRepo: eventstore.UserRepo{conf.SearchLimit, user, policy, org, view},
UserGrantRepo: eventstore.UserGrantRepo{conf.SearchLimit, usergrant, view},
PolicyRepo: eventstore.PolicyRepo{policy},

View File

@ -23,6 +23,10 @@ func (v *View) ProjectGrantsByProjectID(projectID string) ([]*model.ProjectGrant
return view.ProjectGrantsByProjectID(v.Db, grantedProjectTable, projectID)
}
func (v *View) ProjectGrantsByProjectIDAndRoleKey(projectID, key string) ([]*model.ProjectGrantView, error) {
return view.ProjectGrantsByProjectIDAndRoleKey(v.Db, grantedProjectTable, projectID, key)
}
func (v *View) SearchProjectGrants(request *proj_model.ProjectGrantViewSearchRequest) ([]*model.ProjectGrantView, int, error) {
return view.SearchProjectGrants(v.Db, grantedProjectTable, request)
}
@ -38,7 +42,7 @@ func (v *View) PutProjectGrant(project *model.ProjectGrantView) error {
func (v *View) DeleteProjectGrant(grantID string, eventSequence uint64) error {
err := view.DeleteProjectGrant(v.Db, grantedProjectTable, grantID)
if err != nil {
return nil
return err
}
return v.ProcessedProjectGrantSequence(eventSequence)
}

View File

@ -31,6 +31,14 @@ func (v *View) UserGrantsByOrgID(orgID string) ([]*model.UserGrantView, error) {
return view.UserGrantsByOrgID(v.Db, userGrantTable, orgID)
}
func (v *View) UserGrantsByProjectIDAndRoleKey(projectID, roleKey string) ([]*model.UserGrantView, error) {
return view.UserGrantsByProjectIDAndRole(v.Db, userGrantTable, projectID, roleKey)
}
func (v *View) UserGrantsByOrgIDAndProjectID(orgID, projectID string) ([]*model.UserGrantView, error) {
return view.UserGrantsByOrgIDAndProjectID(v.Db, userGrantTable, orgID, projectID)
}
func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error {
err := view.PutUserGrant(v.Db, userGrantTable, grant)
if err != nil {

View File

@ -28,6 +28,7 @@ type ProjectRepository interface {
RemoveProjectRole(ctx context.Context, projectID, key string) error
SearchProjectRoles(ctx context.Context, request *model.ProjectRoleSearchRequest) (*model.ProjectRoleSearchResponse, error)
ProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64) (*model.ProjectChanges, error)
BulkAddProjectRole(ctx context.Context, role []*model.ProjectRole) error
ApplicationByID(ctx context.Context, projectID, appID string) (*model.Application, error)
AddApplication(ctx context.Context, app *model.Application) (*model.Application, error)
@ -41,8 +42,8 @@ type ProjectRepository interface {
ApplicationChanges(ctx context.Context, id string, secId string, lastSequence uint64, limit uint64) (*model.ApplicationChanges, error)
ProjectGrantByID(ctx context.Context, projectID, grantID string) (*model.ProjectGrant, error)
AddProjectGrant(ctx context.Context, app *model.ProjectGrant) (*model.ProjectGrant, error)
ChangeProjectGrant(ctx context.Context, app *model.ProjectGrant) (*model.ProjectGrant, error)
AddProjectGrant(ctx context.Context, grant *model.ProjectGrant) (*model.ProjectGrant, error)
ChangeProjectGrant(ctx context.Context, grant *model.ProjectGrant) (*model.ProjectGrant, error)
DeactivateProjectGrant(ctx context.Context, projectID, grantID string) (*model.ProjectGrant, error)
ReactivateProjectGrant(ctx context.Context, projectID, grantID string) (*model.ProjectGrant, error)
RemoveProjectGrant(ctx context.Context, projectID, grantID string) error

View File

@ -13,4 +13,8 @@ type UserGrantRepository interface {
ReactivateUserGrant(ctx context.Context, grantID string) (*model.UserGrant, error)
RemoveUserGrant(ctx context.Context, grantID string) error
SearchUserGrants(ctx context.Context, request *model.UserGrantSearchRequest) (*model.UserGrantSearchResponse, error)
BulkAddUserGrant(ctx context.Context, grant ...*model.UserGrant) error
BulkChangeUserGrant(ctx context.Context, grant ...*model.UserGrant) error
BulkRemoveUserGrant(ctx context.Context, grantIDs ...string) error
}

View File

@ -12,6 +12,6 @@ const (
SEARCHMETHOD_NOT_EQUALS
SEARCHMETHOD_GREATER_THAN
SEARCHMETHOD_LESS_THAN
SEARCHMETHOD_IN
SEARCHMETHOD_EQUALS_IN_ARRAY
SEARCHMETHOD_IS_ONE_OF
SEARCHMETHOD_LIST_CONTAINS
)

View File

@ -14,6 +14,11 @@ type ProjectGrant struct {
Members []*ProjectGrantMember
}
type ProjectGrantIDs struct {
ProjectID string
GrantID string
}
type ProjectGrantState int32
const (
@ -41,3 +46,22 @@ func (p *ProjectGrant) GetMember(userID string) (int, *ProjectGrantMember) {
}
return -1, nil
}
func (p *ProjectGrant) GetRemovedRoles(roleKeys []string) []string {
removed := make([]string, 0)
for _, role := range p.RoleKeys {
if !containsKey(roleKeys, role) {
removed = append(removed, role)
}
}
return removed
}
func containsKey(roles []string, key string) bool {
for _, role := range roles {
if role == key {
return true
}
}
return false
}

View File

@ -6,18 +6,19 @@ import (
)
type ProjectGrantView struct {
ProjectID string
Name string
CreationDate time.Time
ChangeDate time.Time
State ProjectState
ResourceOwner string
OrgID string
OrgName string
OrgDomain string
Sequence uint64
GrantID string
GrantedRoleKeys []string
ProjectID string
Name string
CreationDate time.Time
ChangeDate time.Time
State ProjectState
ResourceOwner string
ResourceOwnerName string
OrgID string
OrgName string
OrgDomain string
Sequence uint64
GrantID string
GrantedRoleKeys []string
}
type ProjectGrantViewSearchRequest struct {
@ -37,6 +38,7 @@ const (
GRANTEDPROJECTSEARCHKEY_GRANTID
GRANTEDPROJECTSEARCHKEY_ORGID
GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER
GRANTEDPROJECTSEARCHKEY_ROLE_KEYS
)
type ProjectGrantViewSearchQuery struct {

View File

@ -248,28 +248,37 @@ func (es *ProjectEventstore) RemoveProjectMember(ctx context.Context, member *pr
return err
}
func (es *ProjectEventstore) AddProjectRole(ctx context.Context, role *proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
if !role.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-idue3", "Key is required")
func (es *ProjectEventstore) AddProjectRoles(ctx context.Context, roles ...*proj_model.ProjectRole) (*proj_model.ProjectRole, error) {
if roles == nil || len(roles) == 0 {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-idue3", "must be at least one role")
}
existing, err := es.ProjectByID(ctx, role.AggregateID)
for _, role := range roles {
if !role.IsValid() {
return nil, caos_errs.ThrowPreconditionFailedf(nil, "EVENT-idue3", "role is invalid %v", role)
}
}
existing, err := es.ProjectByID(ctx, roles[0].AggregateID)
if err != nil {
return nil, err
}
if existing.ContainsRole(role) {
return nil, caos_errs.ThrowAlreadyExists(nil, "EVENT-sk35t", "Project contains role with same key")
for _, role := range roles {
if existing.ContainsRole(role) {
return nil, caos_errs.ThrowAlreadyExists(nil, "EVENT-sk35t", "Project contains role with same key")
}
}
repoProject := model.ProjectFromModel(existing)
repoRole := model.ProjectRoleFromModel(role)
projectAggregate := ProjectRoleAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoRole)
repoRoles := model.ProjectRolesFromModel(roles)
projectAggregate := ProjectRoleAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoRoles...)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
if len(repoRoles) > 1 {
return nil, nil
}
es.projectCache.cacheProject(repoProject)
if _, r := model.GetProjectRole(repoProject.Roles, role.Key); r != nil {
if _, r := model.GetProjectRole(repoProject.Roles, repoRoles[0].Key); r != nil {
return model.ProjectRoleToModel(r), nil
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-sie83", "Could not find role in list")
@ -302,25 +311,52 @@ func (es *ProjectEventstore) ChangeProjectRole(ctx context.Context, role *proj_m
return nil, caos_errs.ThrowInternal(nil, "EVENT-sl1or", "Could not find role in list")
}
func (es *ProjectEventstore) RemoveProjectRole(ctx context.Context, role *proj_model.ProjectRole) error {
func (es *ProjectEventstore) PrepareRemoveProjectRole(ctx context.Context, role *proj_model.ProjectRole) (*model.Project, *es_models.Aggregate, error) {
if role.Key == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-id823", "Key is required")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-id823", "Key is required")
}
existing, err := es.ProjectByID(ctx, role.AggregateID)
if err != nil {
return err
return nil, nil, err
}
if !existing.ContainsRole(role) {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-oe823", "Role doesn't exist on project")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-oe823", "Role doesn't exist on project")
}
repoProject := model.ProjectFromModel(existing)
repoRole := model.ProjectRoleFromModel(role)
projectAggregate := ProjectRoleRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoRole)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
grants := es.RemoveRoleFromGrants(repoProject, role.Key)
projectAggregate, err := ProjectRoleRemovedAggregate(ctx, es.Eventstore.AggregateCreator(), repoProject, repoRole, grants)
if err != nil {
return nil, nil, err
}
return repoProject, projectAggregate, nil
}
func (es *ProjectEventstore) RemoveRoleFromGrants(existing *model.Project, roleKey string) []*model.ProjectGrant {
grants := make([]*model.ProjectGrant, 0)
for _, grant := range existing.Grants {
for i, role := range grant.RoleKeys {
if role == roleKey {
grant.RoleKeys[i] = grant.RoleKeys[len(grant.RoleKeys)-1]
grant.RoleKeys[len(grant.RoleKeys)-1] = ""
grant.RoleKeys = grant.RoleKeys[:len(grant.RoleKeys)-1]
grants = append(grants, grant)
}
}
}
return grants
}
func (es *ProjectEventstore) RemoveProjectRole(ctx context.Context, role *proj_model.ProjectRole) error {
project, aggregate, err := es.PrepareRemoveProjectRole(ctx, role)
if err != nil {
return err
}
es.projectCache.cacheProject(repoProject)
err = es_sdk.PushAggregates(ctx, es.PushAggregates, project.AppendEvents, aggregate)
if err != nil {
return err
}
es.projectCache.cacheProject(project)
return nil
}
@ -766,50 +802,34 @@ func (es *ProjectEventstore) AddProjectGrant(ctx context.Context, grant *proj_mo
return nil, caos_errs.ThrowInternal(nil, "EVENT-sk3t5", "Could not find grant in list")
}
func (es *ProjectEventstore) ChangeProjectGrant(ctx context.Context, grant *proj_model.ProjectGrant) (*proj_model.ProjectGrant, error) {
func (es *ProjectEventstore) PrepareChangeProjectGrant(ctx context.Context, grant *proj_model.ProjectGrant) (*model.Project, func(ctx context.Context) (*es_models.Aggregate, error), []string, error) {
if grant == nil && grant.GrantID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-8sie3", "invalid grant")
return nil, nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-8sie3", "invalid grant")
}
existing, err := es.ProjectByID(ctx, grant.AggregateID)
if err != nil {
return nil, err
return nil, nil, nil, err
}
if _, g := existing.GetGrant(grant.GrantID); g == nil {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die83", "Grant not existing on project")
_, existingGrant := existing.GetGrant(grant.GrantID)
if existingGrant == nil {
return nil, nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-die83", "Grant not existing on project")
}
if !existing.ContainsRoles(grant.RoleKeys) {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-di83d", "One role doesnt exist in Project")
return nil, nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-di83d", "One role doesnt exist in Project")
}
removedRoles := existingGrant.GetRemovedRoles(grant.RoleKeys)
repoProject := model.ProjectFromModel(existing)
repoGrant := model.GrantFromModel(grant)
projectAggregate := ProjectGrantChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoGrant)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return nil, err
}
es.projectCache.cacheProject(repoProject)
if _, g := model.GetProjectGrant(repoProject.Grants, grant.GrantID); g != nil {
return model.GrantToModel(g), nil
}
return nil, caos_errs.ThrowInternal(nil, "EVENT-dksi8", "Could not find app in list")
return repoProject, projectAggregate, removedRoles, nil
}
func (es *ProjectEventstore) RemoveProjectGrant(ctx context.Context, grant *proj_model.ProjectGrant) error {
if grant.GrantID == "" {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-8eud6", "GrantId is required")
}
existing, err := es.ProjectByID(ctx, grant.AggregateID)
repoProject, projectAggregate, err := es.PrepareRemoveProjectGrant(ctx, grant)
if err != nil {
return err
}
if _, g := existing.GetGrant(grant.GrantID); g == nil {
return caos_errs.ThrowPreconditionFailed(nil, "EVENT-9ie3s", "Grant doesn't exist on project")
}
repoProject := model.ProjectFromModel(existing)
grantRepo := model.GrantFromModel(grant)
projectAggregate := ProjectGrantRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, grantRepo)
err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate)
if err != nil {
return err
@ -818,6 +838,39 @@ func (es *ProjectEventstore) RemoveProjectGrant(ctx context.Context, grant *proj
return nil
}
func (es *ProjectEventstore) RemoveProjectGrants(ctx context.Context, grants ...*proj_model.ProjectGrant) error {
aggregates := make([]*es_models.Aggregate, len(grants))
for i, grant := range grants {
_, projectAggregate, err := es.PrepareRemoveProjectGrant(ctx, grant)
if err != nil {
return err
}
agg, err := projectAggregate(ctx)
if err != nil {
return err
}
aggregates[i] = agg
}
return es_sdk.PushAggregates(ctx, es.PushAggregates, nil, aggregates...)
}
func (es *ProjectEventstore) PrepareRemoveProjectGrant(ctx context.Context, grant *proj_model.ProjectGrant) (*model.Project, func(ctx context.Context) (*es_models.Aggregate, error), error) {
if grant.GrantID == "" {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-8eud6", "GrantId is required")
}
existing, err := es.ProjectByID(ctx, grant.AggregateID)
if err != nil {
return nil, nil, err
}
if _, g := existing.GetGrant(grant.GrantID); g == nil {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9ie3s", "Grant doesn't exist on project")
}
repoProject := model.ProjectFromModel(existing)
grantRepo := model.GrantFromModel(grant)
projectAggregate := ProjectGrantRemovedAggregate(es.Eventstore.AggregateCreator(), repoProject, grantRepo)
return repoProject, projectAggregate, nil
}
func (es *ProjectEventstore) DeactivateProjectGrant(ctx context.Context, projectID, grantID string) (*proj_model.ProjectGrant, error) {
if grantID == "" {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-7due2", "grantID missing")

View File

@ -3,7 +3,6 @@ package eventsourcing
import (
"context"
"encoding/json"
"reflect"
"testing"
"github.com/caos/zitadel/internal/api/auth"
@ -707,9 +706,9 @@ func TestRemoveProjectMember(t *testing.T) {
func TestAddProjectRole(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *ProjectEventstore
ctx context.Context
role *model.ProjectRole
es *ProjectEventstore
ctx context.Context
roles []*model.ProjectRole
}
type res struct {
result *model.ProjectRole
@ -724,9 +723,9 @@ func TestAddProjectRole(t *testing.T) {
{
name: "add project role, ok",
args: args{
es: GetMockManipulateProject(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
role: &model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Key: "Key", DisplayName: "DisplayName", Group: "Group"},
es: GetMockManipulateProject(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
roles: []*model.ProjectRole{&model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Key: "Key", DisplayName: "DisplayName", Group: "Group"}},
},
res: res{
result: &model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Key: "Key", DisplayName: "DisplayName", Group: "Group"},
@ -735,9 +734,9 @@ func TestAddProjectRole(t *testing.T) {
{
name: "no key",
args: args{
es: GetMockManipulateProject(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
role: &model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, DisplayName: "DisplayName", Group: "Group"},
es: GetMockManipulateProject(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
roles: []*model.ProjectRole{&model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, DisplayName: "DisplayName", Group: "Group"}},
},
res: res{
wantErr: true,
@ -747,9 +746,9 @@ func TestAddProjectRole(t *testing.T) {
{
name: "role already existing",
args: args{
es: GetMockManipulateProjectWithRole(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
role: &model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Key: "Key", DisplayName: "DisplayName", Group: "Group"},
es: GetMockManipulateProjectWithRole(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
roles: []*model.ProjectRole{&model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Key: "Key", DisplayName: "DisplayName", Group: "Group"}},
},
res: res{
wantErr: true,
@ -759,9 +758,9 @@ func TestAddProjectRole(t *testing.T) {
{
name: "existing project not found",
args: args{
es: GetMockManipulateProjectNoEvents(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
role: &model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Key: "Key", DisplayName: "DisplayName", Group: "Group"},
es: GetMockManipulateProjectNoEvents(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
roles: []*model.ProjectRole{&model.ProjectRole{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}, Key: "Key", DisplayName: "DisplayName", Group: "Group"}},
},
res: res{
wantErr: true,
@ -771,7 +770,7 @@ func TestAddProjectRole(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.AddProjectRole(tt.args.ctx, tt.args.role)
result, err := tt.args.es.AddProjectRoles(tt.args.ctx, tt.args.roles...)
if !tt.res.wantErr && result.AggregateID == "" {
t.Errorf("result has no id")
@ -1950,126 +1949,6 @@ func TestAddProjectGrant(t *testing.T) {
}
}
func TestChangeProjectGrant(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {
es *ProjectEventstore
ctx context.Context
grant *model.ProjectGrant
}
type res struct {
result *model.ProjectGrant
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
args args
res res
}{
{
name: "change grant, ok",
args: args{
es: GetMockManipulateProjectWithGrantExistingRole(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
grant: &model.ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID", Sequence: 1},
GrantID: "GrantID",
GrantedOrgID: "GrantedOrgID",
RoleKeys: []string{"KeyChanged"},
},
},
res: res{
result: &model.ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID", Sequence: 1},
GrantID: "GrantID",
GrantedOrgID: "GrantedOrgID",
RoleKeys: []string{"KeyChanged"},
},
},
},
{
name: "invalid grant",
args: args{
es: GetMockManipulateProject(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
grant: &model.ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID", Sequence: 1},
GrantID: "GrantID",
RoleKeys: []string{"KeyChanged"},
},
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "grant not existing",
args: args{
es: GetMockManipulateProject(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
grant: &model.ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID", Sequence: 1},
GrantID: "GrantID",
GrantedOrgID: "GrantedOrgID",
RoleKeys: []string{"KeyChanged"},
},
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "role not existing",
args: args{
es: GetMockManipulateProjectWithGrant(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
grant: &model.ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID", Sequence: 1},
GrantID: "GrantID",
GrantedOrgID: "GrantedOrgID",
RoleKeys: []string{"KeyChanged"},
},
},
res: res{
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
name: "existing project not found",
args: args{
es: GetMockManipulateProjectNoEvents(ctrl),
ctx: auth.NewMockContext("orgID", "userID"),
grant: &model.ProjectGrant{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID", Sequence: 1},
GrantID: "GrantID",
GrantedOrgID: "GrantedOrgID",
RoleKeys: []string{"KeyChanged"},
},
},
res: res{
wantErr: true,
errFunc: caos_errs.IsNotFound,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result, err := tt.args.es.ChangeProjectGrant(tt.args.ctx, tt.args.grant)
if !tt.res.wantErr && result.AggregateID == "" {
t.Errorf("result has no id")
}
if !tt.res.wantErr && result.GrantID != tt.res.result.GrantID {
t.Errorf("got wrong result GrantID: expected: %v, actual: %v ", tt.res.result.GrantID, result.GrantID)
}
if !tt.res.wantErr && !reflect.DeepEqual(result.RoleKeys, tt.res.result.RoleKeys) {
t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.result.RoleKeys, result.GrantID)
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}
})
}
}
func TestRemoveProjectGrant(t *testing.T) {
ctrl := gomock.NewController(t)
type args struct {

View File

@ -127,7 +127,7 @@ func (p *Project) AppendEvent(event *es_models.Event) error {
return p.appendChangeOIDCConfigEvent(event)
case ProjectGrantAdded:
return p.appendAddGrantEvent(event)
case ProjectGrantChanged:
case ProjectGrantChanged, ProjectGrantCascadeChanged:
return p.appendChangeGrantEvent(event)
case ProjectGrantDeactivated:
return p.appendGrantStateEvent(event, model.PROJECTGRANTSTATE_INACTIVE)

View File

@ -31,9 +31,9 @@ func GetProjectGrant(grants []*ProjectGrant, id string) (int, *ProjectGrant) {
return -1, nil
}
func GetProjectGrantByResourceOwner(grants []*ProjectGrant, resourceOwner string) (int, *ProjectGrant) {
func GetProjectGrantByOrgID(grants []*ProjectGrant, resourceOwner string) (int, *ProjectGrant) {
for i, g := range grants {
if g.ResourceOwner == resourceOwner {
if g.GrantedOrgID == resourceOwner {
return i, g
}
}

View File

@ -19,11 +19,12 @@ const (
ProjectRoleChanged models.EventType = "project.role.changed"
ProjectRoleRemoved models.EventType = "project.role.removed"
ProjectGrantAdded models.EventType = "project.grant.added"
ProjectGrantChanged models.EventType = "project.grant.changed"
ProjectGrantRemoved models.EventType = "project.grant.removed"
ProjectGrantDeactivated models.EventType = "project.grant.deactivated"
ProjectGrantReactivated models.EventType = "project.grant.reactivated"
ProjectGrantAdded models.EventType = "project.grant.added"
ProjectGrantChanged models.EventType = "project.grant.changed"
ProjectGrantRemoved models.EventType = "project.grant.removed"
ProjectGrantDeactivated models.EventType = "project.grant.deactivated"
ProjectGrantReactivated models.EventType = "project.grant.reactivated"
ProjectGrantCascadeChanged models.EventType = "project.grant.cascade.changed"
ProjectGrantMemberAdded models.EventType = "project.grant.member.added"
ProjectGrantMemberChanged models.EventType = "project.grant.member.changed"

View File

@ -144,16 +144,22 @@ func ProjectMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, exist
}
}
func ProjectRoleAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, role *model.ProjectRole) func(ctx context.Context) (*es_models.Aggregate, error) {
func ProjectRoleAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, roles ...*model.ProjectRole) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if role == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sleo9", "role should not be nil")
if roles == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-sleo9", "roles should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.ProjectRoleAdded, role)
for _, role := range roles {
agg, err = agg.AppendEvent(model.ProjectRoleAdded, role)
if err != nil {
return nil, err
}
}
return agg, nil
}
}
@ -170,17 +176,29 @@ func ProjectRoleChangedAggregate(aggCreator *es_models.AggregateCreator, existin
}
}
func ProjectRoleRemovedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, role *model.ProjectRole) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if role == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d8eis", "member should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
return agg.AppendEvent(model.ProjectRoleRemoved, role)
func ProjectRoleRemovedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Project, role *model.ProjectRole, grants []*model.ProjectGrant) (*es_models.Aggregate, error) {
if role == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d8eis", "member should not be nil")
}
agg, err := ProjectAggregate(ctx, aggCreator, existing)
if err != nil {
return nil, err
}
agg, err = agg.AppendEvent(model.ProjectRoleRemoved, role)
if err != nil {
return nil, err
}
for _, grant := range grants {
var changes map[string]interface{}
if _, g := model.GetProjectGrant(existing.Grants, grant.GrantID); grant != nil {
changes = g.Changes(grant)
agg, err = agg.AppendEvent(model.ProjectGrantCascadeChanged, changes)
if err != nil {
return nil, err
}
}
}
return agg, nil
}
func ApplicationAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, app *model.Application) func(ctx context.Context) (*es_models.Aggregate, error) {

View File

@ -694,7 +694,7 @@ func TestProjectRoleAddedAggregate(t *testing.T) {
type args struct {
ctx context.Context
existing *model.Project
new *model.ProjectRole
new []*model.ProjectRole
aggCreator *models.AggregateCreator
}
type res struct {
@ -713,7 +713,7 @@ func TestProjectRoleAddedAggregate(t *testing.T) {
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Project{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Name: "ProjectName", State: int32(proj_model.PROJECTSTATE_ACTIVE)},
new: &model.ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Key: "Key"},
new: []*model.ProjectRole{&model.ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Key: "Key"}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
@ -721,6 +721,22 @@ func TestProjectRoleAddedAggregate(t *testing.T) {
eventType: model.ProjectRoleAdded,
},
},
{
name: "projectrole multiple added ok",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Project{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Name: "ProjectName", State: int32(proj_model.PROJECTSTATE_ACTIVE)},
new: []*model.ProjectRole{
&model.ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Key: "Key"},
&model.ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Key: "Key2"},
},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 2,
eventType: model.ProjectRoleAdded,
},
},
{
name: "existing project nil",
args: args{
@ -753,7 +769,7 @@ func TestProjectRoleAddedAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := ProjectRoleAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
agg, err := ProjectRoleAddedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new...)(tt.args.ctx)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
@ -857,13 +873,14 @@ func TestProjectRoleRemovedAggregate(t *testing.T) {
ctx context.Context
existing *model.Project
new *model.ProjectRole
grants []*model.ProjectGrant
aggCreator *models.AggregateCreator
}
type res struct {
eventLen int
eventType models.EventType
wantErr bool
errFunc func(err error) bool
eventLen int
eventTypes []models.EventType
wantErr bool
errFunc func(err error) bool
}
tests := []struct {
name string
@ -879,8 +896,27 @@ func TestProjectRoleRemovedAggregate(t *testing.T) {
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.ProjectRoleRemoved,
eventLen: 1,
eventTypes: []models.EventType{model.ProjectRoleRemoved},
},
},
{
name: "projectrole changed with grant",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.Project{
ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"},
Name: "ProjectName",
State: int32(proj_model.PROJECTSTATE_ACTIVE),
Grants: []*model.ProjectGrant{&model.ProjectGrant{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{"ROLE"}}},
},
new: &model.ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: "AggregateID"}, Key: "Key"},
grants: []*model.ProjectGrant{&model.ProjectGrant{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, GrantID: "GrantID", GrantedOrgID: "OrgID", RoleKeys: []string{}}},
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 2,
eventTypes: []models.EventType{model.ProjectRoleRemoved, model.ProjectGrantCascadeChanged},
},
},
{
@ -891,10 +927,8 @@ func TestProjectRoleRemovedAggregate(t *testing.T) {
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.ProjectRoleRemoved,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
{
@ -906,26 +940,29 @@ func TestProjectRoleRemovedAggregate(t *testing.T) {
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventType: model.ProjectRoleRemoved,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
wantErr: true,
errFunc: caos_errs.IsPreconditionFailed,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := ProjectRoleRemovedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
agg, err := ProjectRoleRemovedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.new, tt.args.grants)
if !tt.res.wantErr && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
}
if !tt.res.wantErr && agg.Events[0].Type != tt.res.eventType {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String())
}
if !tt.res.wantErr && agg.Events[0].Data == nil {
t.Errorf("should have data in event")
if agg != nil {
for i, _ := range agg.Events {
if !tt.res.wantErr && agg.Events[i].Type != tt.res.eventTypes[i] {
t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String())
}
if !tt.res.wantErr && agg.Events[i].Data == nil {
t.Errorf("should have data in event")
}
}
}
if tt.res.wantErr && !tt.res.errFunc(err) {
t.Errorf("got wrong err: %v ", err)
}

View File

@ -17,20 +17,22 @@ const (
ProjectGrantKeyOrgID = "org_id"
ProjectGrantKeyResourceOwner = "resource_owner"
ProjectGrantKeyName = "project_name"
ProjectGrantKeyRoleKeys = "granted_role_keys"
)
type ProjectGrantView struct {
GrantID string `json:"-" gorm:"column:grant_id;primary_key"`
ProjectID string `json:"-" gorm:"column:project_id"`
OrgID string `json:"-" gorm:"column:org_id"`
Name string `json:"name" gorm:"column:project_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
State int32 `json:"-" gorm:"column:project_state"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
OrgName string `json:"-" gorm:"column:org_name"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
GrantedRoleKeys pq.StringArray `json:"-" gorm:"column:granted_role_keys"`
GrantID string `json:"-" gorm:"column:grant_id;primary_key"`
ProjectID string `json:"-" gorm:"column:project_id"`
OrgID string `json:"-" gorm:"column:org_id"`
Name string `json:"name" gorm:"column:project_name"`
CreationDate time.Time `json:"-" gorm:"column:creation_date"`
ChangeDate time.Time `json:"-" gorm:"column:change_date"`
State int32 `json:"-" gorm:"column:project_state"`
ResourceOwner string `json:"-" gorm:"column:resource_owner"`
ResourceOwnerName string `json:"-" gorm:"column:resource_owner_name"`
OrgName string `json:"-" gorm:"column:org_name"`
Sequence uint64 `json:"-" gorm:"column:sequence"`
GrantedRoleKeys pq.StringArray `json:"-" gorm:"column:granted_role_keys"`
}
type ProjectGrant struct {
@ -41,32 +43,35 @@ type ProjectGrant struct {
func ProjectGrantFromModel(project *model.ProjectGrantView) *ProjectGrantView {
return &ProjectGrantView{
ProjectID: project.ProjectID,
OrgID: project.OrgID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: int32(project.State),
ResourceOwner: project.ResourceOwner,
OrgName: project.OrgName,
GrantID: project.GrantID,
GrantedRoleKeys: project.GrantedRoleKeys,
Sequence: project.Sequence,
ProjectID: project.ProjectID,
OrgID: project.OrgID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: int32(project.State),
ResourceOwner: project.ResourceOwner,
ResourceOwnerName: project.ResourceOwnerName,
OrgName: project.OrgName,
GrantID: project.GrantID,
GrantedRoleKeys: project.GrantedRoleKeys,
Sequence: project.Sequence,
}
}
func ProjectGrantToModel(project *ProjectGrantView) *model.ProjectGrantView {
return &model.ProjectGrantView{
ProjectID: project.ProjectID,
OrgID: project.OrgID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: model.ProjectState(project.State),
ResourceOwner: project.ResourceOwner,
OrgName: project.OrgName,
GrantID: project.GrantID,
Sequence: project.Sequence,
ProjectID: project.ProjectID,
OrgID: project.OrgID,
Name: project.Name,
ChangeDate: project.ChangeDate,
CreationDate: project.CreationDate,
State: model.ProjectState(project.State),
ResourceOwner: project.ResourceOwner,
ResourceOwnerName: project.ResourceOwnerName,
OrgName: project.OrgName,
GrantID: project.GrantID,
Sequence: project.Sequence,
GrantedRoleKeys: project.GrantedRoleKeys,
}
}
@ -87,7 +92,7 @@ func (p *ProjectGrantView) AppendEvent(event *models.Event) (err error) {
p.CreationDate = event.CreationDate
p.setRootData(event)
err = p.setProjectGrantData(event)
case es_model.ProjectGrantChanged:
case es_model.ProjectGrantChanged, es_model.ProjectGrantCascadeChanged:
err = p.setProjectGrantData(event)
case es_model.ProjectGrantDeactivated:
p.State = int32(model.PROJECTSTATE_INACTIVE)

View File

@ -61,6 +61,8 @@ func (key ProjectGrantSearchKey) ToColumnName() string {
return ProjectGrantKeyProjectID
case proj_model.GRANTEDPROJECTSEARCHKEY_RESOURCE_OWNER:
return ProjectGrantKeyResourceOwner
case proj_model.GRANTEDPROJECTSEARCHKEY_ROLE_KEYS:
return ProjectGrantKeyRoleKeys
default:
return ""
}

View File

@ -39,6 +39,20 @@ func ProjectGrantsByProjectID(db *gorm.DB, table, projectID string) ([]*model.Pr
return projects, nil
}
func ProjectGrantsByProjectIDAndRoleKey(db *gorm.DB, table, projectID, roleKey string) ([]*model.ProjectGrantView, error) {
projects := make([]*model.ProjectGrantView, 0)
queries := []*proj_model.ProjectGrantViewSearchQuery{
&proj_model.ProjectGrantViewSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS},
&proj_model.ProjectGrantViewSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_ROLE_KEYS, Value: roleKey, Method: global_model.SEARCHMETHOD_LIST_CONTAINS},
}
query := view.PrepareSearchQuery(table, model.ProjectGrantSearchRequest{Queries: queries})
_, err := query(db, &projects)
if err != nil {
return nil, err
}
return projects, nil
}
func SearchProjectGrants(db *gorm.DB, table string, req *proj_model.ProjectGrantViewSearchRequest) ([]*model.ProjectGrantView, int, error) {
projects := make([]*model.ProjectGrantView, 0)
query := view.PrepareSearchQuery(table, model.ProjectGrantSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries})
@ -55,6 +69,6 @@ func PutProjectGrant(db *gorm.DB, table string, project *model.ProjectGrantView)
}
func DeleteProjectGrant(db *gorm.DB, table, grantID string) error {
delete := view.PrepareDeleteByKey(table, model.ProjectSearchKey(proj_model.PROJECTGRANTMEMBERSEARCHKEY_GRANT_ID), grantID)
delete := view.PrepareDeleteByKey(table, model.ProjectSearchKey(proj_model.GRANTEDPROJECTSEARCHKEY_GRANTID), grantID)
return delete(db)
}

View File

@ -65,6 +65,7 @@ func Run(generator ProtocGenerator) {
}
registry := descriptor.NewRegistry()
registry.SetAllowDeleteBody(true)
if err = registry.Load(req); err != nil {
glog.Fatal(err)
}

View File

@ -83,7 +83,7 @@ func templatesAuth_method_mappingGoTmpl() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "templates/auth_method_mapping.go.tmpl", size: 1013, mode: os.FileMode(420), modTime: time.Unix(1586333177, 0)}
info := bindataFileInfo{name: "templates/auth_method_mapping.go.tmpl", size: 1013, mode: os.FileMode(420), modTime: time.Unix(1585815980, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@ -182,6 +182,7 @@ type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"templates": &bintree{nil, map[string]*bintree{
"auth_method_mapping.go.tmpl": &bintree{templatesAuth_method_mappingGoTmpl, map[string]*bintree{}},
@ -234,4 +235,3 @@ func _filePath(dir, name string) string {
cannonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}

View File

@ -34,7 +34,7 @@ func UserByLoginName(db *gorm.DB, table, loginName string) (*model.UserView, err
user := new(model.UserView)
loginNameQuery := &model.UserSearchQuery{
Key: usr_model.USERSEARCHKEY_LOGIN_NAMES,
Method: global_model.SEARCHMETHOD_EQUALS_IN_ARRAY,
Method: global_model.SEARCHMETHOD_LIST_CONTAINS,
Value: pq.Array([]string{loginName}),
}
query := view.PrepareGetByQuery(table, loginNameQuery)

View File

@ -30,3 +30,26 @@ func (u *UserGrant) IsActive() bool {
func (u *UserGrant) IsInactive() bool {
return u.State == USERGRANTSTATE_INACTIVE
}
func (u *UserGrant) RemoveRoleKeyIfExisting(key string) bool {
for i, role := range u.RoleKeys {
if role == key {
u.RoleKeys[i] = u.RoleKeys[len(u.RoleKeys)-1]
u.RoleKeys[len(u.RoleKeys)-1] = ""
u.RoleKeys = u.RoleKeys[:len(u.RoleKeys)-1]
return true
}
}
return false
}
func (u *UserGrant) RemoveRoleKeysIfExisting(keys []string) bool {
exists := false
for _, key := range keys {
keyExists := u.RemoveRoleKeyIfExisting(key)
if keyExists {
exists = true
}
}
return exists
}

View File

@ -44,12 +44,13 @@ const (
USERGRANTSEARCHKEY_STATE
USERGRANTSEARCHKEY_GRANT_ID
USERGRANTSEARCHKEY_ORG_NAME
USERGRANTSEARCHKEY_ROLE_KEY
)
type UserGrantSearchQuery struct {
Key UserGrantSearchKey
Method model.SearchMethod
Value string
Value interface{}
}
type UserGrantSearchResponse struct {

View File

@ -6,6 +6,7 @@ import (
caos_errs "github.com/caos/zitadel/internal/errors"
es_int "github.com/caos/zitadel/internal/eventstore"
"github.com/caos/zitadel/internal/eventstore/models"
es_models "github.com/caos/zitadel/internal/eventstore/models"
es_sdk "github.com/caos/zitadel/internal/eventstore/sdk"
"github.com/caos/zitadel/internal/id"
grant_model "github.com/caos/zitadel/internal/usergrant/model"
@ -54,18 +55,7 @@ func (es *UserGrantEventStore) UserGrantByID(ctx context.Context, id string) (*g
}
func (es *UserGrantEventStore) AddUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*grant_model.UserGrant, error) {
if grant == nil || !grant.IsValid() {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-sdiw3", "User grant invalid")
}
id, err := es.idGenerator.Next()
if err != nil {
return nil, err
}
grant.AggregateID = id
repoGrant := model.UserGrantFromModel(grant)
addAggregates, err := UserGrantAddedAggregate(ctx, es.Eventstore.AggregateCreator(), repoGrant)
repoGrant, addAggregates, err := es.PrepareAddUserGrant(ctx, grant)
if err != nil {
return nil, err
}
@ -76,19 +66,65 @@ func (es *UserGrantEventStore) AddUserGrant(ctx context.Context, grant *grant_mo
return model.UserGrantToModel(repoGrant), nil
}
func (es *UserGrantEventStore) ChangeUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*grant_model.UserGrant, error) {
func (es *UserGrantEventStore) AddUserGrants(ctx context.Context, grants ...*grant_model.UserGrant) error {
aggregates := make([]*es_models.Aggregate, 0)
for _, grant := range grants {
_, addAggregates, err := es.PrepareAddUserGrant(ctx, grant)
if err != nil {
return err
}
for _, agg := range addAggregates {
aggregates = append(aggregates, agg)
}
}
return es_sdk.PushAggregates(ctx, es.PushAggregates, nil, aggregates...)
}
func (es *UserGrantEventStore) PrepareAddUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*model.UserGrant, []*es_models.Aggregate, error) {
if grant == nil || !grant.IsValid() {
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-sdiw3", "User grant invalid")
}
id, err := es.idGenerator.Next()
if err != nil {
return nil, nil, err
}
grant.AggregateID = id
repoGrant := model.UserGrantFromModel(grant)
addAggregates, err := UserGrantAddedAggregate(ctx, es.Eventstore.AggregateCreator(), repoGrant)
if err != nil {
return nil, nil, err
}
return repoGrant, addAggregates, nil
}
func (es *UserGrantEventStore) PrepareChangeUserGrant(ctx context.Context, grant *grant_model.UserGrant, cascade bool) (*model.UserGrant, *es_models.Aggregate, error) {
if grant == nil {
return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-lo0s9", "invalid grant")
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-lo0s9", "invalid grant")
}
existing, err := es.UserGrantByID(ctx, grant.AggregateID)
if err != nil {
return nil, err
return nil, nil, err
}
repoExisting := model.UserGrantFromModel(existing)
repoGrant := model.UserGrantFromModel(grant)
projectAggregate := UserGrantChangedAggregate(es.Eventstore.AggregateCreator(), repoExisting, repoGrant)
err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, projectAggregate)
aggFunc := UserGrantChangedAggregate(es.Eventstore.AggregateCreator(), repoExisting, repoGrant, cascade)
projectAggregate, err := aggFunc(ctx)
if err != nil {
return nil, nil, err
}
return repoExisting, projectAggregate, err
}
func (es *UserGrantEventStore) ChangeUserGrant(ctx context.Context, grant *grant_model.UserGrant) (*grant_model.UserGrant, error) {
repoExisting, agg, err := es.PrepareChangeUserGrant(ctx, grant, false)
if err != nil {
return nil, err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoExisting.AppendEvents, agg)
if err != nil {
return nil, err
}
@ -96,23 +132,57 @@ func (es *UserGrantEventStore) ChangeUserGrant(ctx context.Context, grant *grant
return model.UserGrantToModel(repoExisting), nil
}
func (es *UserGrantEventStore) ChangeUserGrants(ctx context.Context, grants ...*grant_model.UserGrant) error {
aggregates := make([]*es_models.Aggregate, len(grants))
for i, grant := range grants {
_, agg, err := es.PrepareChangeUserGrant(ctx, grant, false)
if err != nil {
return err
}
aggregates[i] = agg
}
return es_sdk.PushAggregates(ctx, es.PushAggregates, nil, aggregates...)
}
func (es *UserGrantEventStore) RemoveUserGrant(ctx context.Context, grantID string) error {
existing, err := es.UserGrantByID(ctx, grantID)
existing, projectAggregates, err := es.PrepareRemoveUserGrant(ctx, grantID, false)
if err != nil {
return err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, existing.AppendEvents, projectAggregates...)
if err != nil {
return err
}
es.userGrantCache.cacheUserGrant(existing)
return nil
}
func (es *UserGrantEventStore) RemoveUserGrants(ctx context.Context, grantIDs ...string) error {
aggregates := make([]*es_models.Aggregate, 0)
for _, grantID := range grantIDs {
_, aggs, err := es.PrepareRemoveUserGrant(ctx, grantID, false)
if err != nil {
return err
}
for _, agg := range aggs {
aggregates = append(aggregates, agg)
}
}
return es_sdk.PushAggregates(ctx, es.PushAggregates, nil, aggregates...)
}
func (es *UserGrantEventStore) PrepareRemoveUserGrant(ctx context.Context, grantID string, cascade bool) (*model.UserGrant, []*es_models.Aggregate, error) {
existing, err := es.UserGrantByID(ctx, grantID)
if err != nil {
return nil, nil, err
}
repoExisting := model.UserGrantFromModel(existing)
repoGrant := &model.UserGrant{ObjectRoot: models.ObjectRoot{AggregateID: grantID}}
projectAggregates, err := UserGrantRemovedAggregate(ctx, es.Eventstore.AggregateCreator(), repoExisting, repoGrant)
projectAggregates, err := UserGrantRemovedAggregate(ctx, es.Eventstore.AggregateCreator(), repoExisting, repoGrant, cascade)
if err != nil {
return err
return nil, nil, err
}
err = es_sdk.PushAggregates(ctx, es.PushAggregates, repoExisting.AppendEvents, projectAggregates...)
if err != nil {
return err
}
es.userGrantCache.cacheUserGrant(repoExisting)
return nil
return repoExisting, projectAggregates, nil
}
func (es *UserGrantEventStore) DeactivateUserGrant(ctx context.Context, grantID string) (*grant_model.UserGrant, error) {

View File

@ -13,4 +13,7 @@ const (
UserGrantReactivated models.EventType = "user.grant.reactivated"
UserGrantReserved models.EventType = "user.grant.reserved"
UserGrantReleased models.EventType = "user.grant.released"
UserGrantCascadeRemoved models.EventType = "user.grant.cascade.removed"
UserGrantCascadeChanged models.EventType = "user.grant.cascade.changed"
)

View File

@ -68,13 +68,15 @@ func (g *UserGrant) AppendEvent(event *es_models.Event) error {
g.ObjectRoot.AppendEvent(event)
switch event.Type {
case UserGrantAdded,
UserGrantChanged:
UserGrantChanged,
UserGrantCascadeChanged:
return g.setData(event)
case UserGrantDeactivated:
g.appendGrantStateEvent(model.USERGRANTSTATE_INACTIVE)
case UserGrantReactivated:
g.appendGrantStateEvent(model.USERGRANTSTATE_ACTIVE)
case UserGrantRemoved:
case UserGrantRemoved,
UserGrantCascadeRemoved:
g.appendGrantStateEvent(model.USERGRANTSTATE_REMOVED)
}
return nil

View File

@ -95,7 +95,7 @@ func releasedUniqueUserGrantAggregate(ctx context.Context, aggCreator *es_models
return aggregate.SetPrecondition(UserGrantUniqueQuery(grant.ResourceOwner, grant.ProjectID, grant.UserID), isEventValidation(aggregate, model.UserGrantReleased)), nil
}
func UserGrantChangedAggregate(aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant) func(ctx context.Context) (*es_models.Aggregate, error) {
func UserGrantChangedAggregate(aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant, cascade bool) func(ctx context.Context) (*es_models.Aggregate, error) {
return func(ctx context.Context) (*es_models.Aggregate, error) {
if grant == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-osl8x", "grant should not be nil")
@ -105,7 +105,10 @@ func UserGrantChangedAggregate(aggCreator *es_models.AggregateCreator, existing
return nil, err
}
changes := existing.Changes(grant)
return agg.AppendEvent(model.UserGrantChanged, changes)
if !cascade {
return agg.AppendEvent(model.UserGrantChanged, changes)
}
return agg.AppendEvent(model.UserGrantCascadeChanged, changes)
}
}
@ -135,7 +138,7 @@ func UserGrantReactivatedAggregate(aggCreator *es_models.AggregateCreator, exist
}
}
func UserGrantRemovedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant) ([]*es_models.Aggregate, error) {
func UserGrantRemovedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.UserGrant, grant *model.UserGrant, cascade bool) ([]*es_models.Aggregate, error) {
if grant == nil {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-lo21s", "grant should not be nil")
}
@ -143,7 +146,11 @@ func UserGrantRemovedAggregate(ctx context.Context, aggCreator *es_models.Aggreg
if err != nil {
return nil, err
}
agg, err = agg.AppendEvent(model.UserGrantRemoved, nil)
eventType := model.UserGrantRemoved
if cascade {
eventType = model.UserGrantCascadeRemoved
}
agg, err = agg.AppendEvent(eventType, nil)
if err != nil {
return nil, err
}
@ -196,37 +203,43 @@ func addUserGrantValidation(resourceOwner string, grant *model.UserGrant) func(.
project.AppendEvent(event)
}
}
if existsOrg && existsUser && checkProjectConditions(resourceOwner, grant, project) {
return nil
if !existsOrg {
return errors.ThrowPreconditionFailed(nil, "EVENT-3OfIm", "org doesn't exist")
}
return errors.ThrowPreconditionFailed(nil, "EVENT-3OfIm", "conditions not met")
if !existsUser {
return errors.ThrowPreconditionFailed(nil, "EVENT-Sl8uS", "user doesn't exist")
}
if err := checkProjectConditions(resourceOwner, grant, project); err != nil {
return err
}
return nil
}
}
func checkProjectConditions(resourceOwner string, grant *model.UserGrant, project *proj_es_model.Project) bool {
func checkProjectConditions(resourceOwner string, grant *model.UserGrant, project *proj_es_model.Project) error {
if project.State == int32(proj_model.PROJECTSTATE_REMOVED) {
return false
return errors.ThrowPreconditionFailed(nil, "EVENT-Lxp0s", "project doesn't exist")
}
if resourceOwner == project.ResourceOwner {
return checkIfProjectHasRoles(grant.RoleKeys, project.Roles)
}
if _, projectGrant := proj_es_model.GetProjectGrantByResourceOwner(project.Grants, resourceOwner); projectGrant != nil {
if _, projectGrant := proj_es_model.GetProjectGrantByOrgID(project.Grants, resourceOwner); projectGrant != nil {
return checkIfProjectGrantHasRoles(grant.RoleKeys, projectGrant.RoleKeys)
}
return false
return nil
}
func checkIfProjectHasRoles(roles []string, existing []*proj_es_model.ProjectRole) bool {
func checkIfProjectHasRoles(roles []string, existing []*proj_es_model.ProjectRole) error {
for _, roleKey := range roles {
if _, role := proj_es_model.GetProjectRole(existing, roleKey); role == nil {
return false
return errors.ThrowPreconditionFailedf(nil, "EVENT-Lxp0s", "project doesn't have role %v", roleKey)
}
}
return true
return nil
}
func checkIfProjectGrantHasRoles(roles []string, existing []string) bool {
func checkIfProjectGrantHasRoles(roles []string, existing []string) error {
roleExists := false
for _, roleKey := range roles {
for _, existingRoleKey := range existing {
@ -236,8 +249,8 @@ func checkIfProjectGrantHasRoles(roles []string, existing []string) bool {
}
}
if !roleExists {
return false
return errors.ThrowPreconditionFailed(nil, "EVENT-LSpwi", "project grant doesn't have role")
}
}
return true
return nil
}

View File

@ -74,6 +74,7 @@ func TestUserGrantChangedAggregate(t *testing.T) {
ctx context.Context
existing *model.UserGrant
new *model.UserGrant
cascade bool
aggCreator *models.AggregateCreator
}
type res struct {
@ -108,6 +109,29 @@ func TestUserGrantChangedAggregate(t *testing.T) {
eventTypes: []models.EventType{model.UserGrantChanged},
},
},
{
name: "change project grant cascade",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
UserID: "UserID",
ProjectID: "ProjectID",
RoleKeys: []string{"Key"}},
new: &model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
UserID: "UserID",
ProjectID: "ProjectID",
RoleKeys: []string{"KeyChanged"},
},
cascade: true,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.UserGrantCascadeChanged},
},
},
{
name: "existing grant nil",
args: args{
@ -143,7 +167,7 @@ func TestUserGrantChangedAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
agg, err := UserGrantChangedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new)(tt.args.ctx)
agg, err := UserGrantChangedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.new, tt.args.cascade)(tt.args.ctx)
if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events))
@ -169,6 +193,7 @@ func TestUserGrantRemovedAggregate(t *testing.T) {
ctx context.Context
existing *model.UserGrant
new *model.UserGrant
cascade bool
aggCreator *models.AggregateCreator
}
type res struct {
@ -200,6 +225,26 @@ func TestUserGrantRemovedAggregate(t *testing.T) {
eventTypes: []models.EventType{model.UserGrantRemoved},
},
},
{
name: "remove app cascade",
args: args{
ctx: auth.NewMockContext("orgID", "userID"),
existing: &model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
UserID: "UserID",
ProjectID: "ProjectID",
RoleKeys: []string{"Key"}},
new: &model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: "ID"},
},
cascade: true,
aggCreator: models.NewAggregateCreator("Test"),
},
res: res{
eventLen: 1,
eventTypes: []models.EventType{model.UserGrantCascadeRemoved},
},
},
{
name: "existing project nil",
args: args{
@ -230,7 +275,7 @@ func TestUserGrantRemovedAggregate(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
aggregates, err := UserGrantRemovedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.new)
aggregates, err := UserGrantRemovedAggregate(tt.args.ctx, tt.args.aggCreator, tt.args.existing, tt.args.new, tt.args.cascade)
if tt.res.errFunc == nil && len(aggregates[0].Events) != tt.res.eventLen {
t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(aggregates[0].Events))

View File

@ -19,6 +19,7 @@ const (
UserGrantKeyResourceOwner = "resource_owner"
UserGrantKeyState = "state"
UserGrantKeyOrgName = "org_name"
UserGrantKeyRole = "role_keys"
)
type UserGrantView struct {
@ -98,7 +99,7 @@ func (g *UserGrantView) AppendEvent(event *models.Event) (err error) {
g.CreationDate = event.CreationDate
g.setRootData(event)
err = g.setData(event)
case es_model.UserGrantChanged:
case es_model.UserGrantChanged, es_model.UserGrantCascadeChanged:
err = g.setData(event)
case es_model.UserGrantDeactivated:
g.State = int32(model.USERGRANTSTATE_INACTIVE)

View File

@ -63,6 +63,8 @@ func (key UserGrantSearchKey) ToColumnName() string {
return UserGrantKeyID
case grant_model.USERGRANTSEARCHKEY_ORG_NAME:
return UserGrantKeyOrgName
case grant_model.USERGRANTSEARCHKEY_ROLE_KEY:
return UserGrantKeyRole
default:
return ""
}

View File

@ -62,6 +62,34 @@ func UserGrantsByProjectID(db *gorm.DB, table, projectID string) ([]*model.UserG
return users, nil
}
func UserGrantsByProjectIDAndRole(db *gorm.DB, table, projectID, roleKey string) ([]*model.UserGrantView, error) {
users := make([]*model.UserGrantView, 0)
queries := []*grant_model.UserGrantSearchQuery{
&grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_PROJECT_ID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS},
&grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_ROLE_KEY, Value: roleKey, Method: global_model.SEARCHMETHOD_LIST_CONTAINS},
}
query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Queries: queries})
_, err := query(db, &users)
if err != nil {
return nil, err
}
return users, nil
}
func UserGrantsByOrgIDAndProjectID(db *gorm.DB, table, orgID, projectID string) ([]*model.UserGrantView, error) {
users := make([]*model.UserGrantView, 0)
queries := []*grant_model.UserGrantSearchQuery{
&grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, Value: orgID, Method: global_model.SEARCHMETHOD_EQUALS},
&grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_PROJECT_ID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS},
}
query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Queries: queries})
_, err := query(db, &users)
if err != nil {
return nil, err
}
return users, nil
}
func UserGrantsByOrgID(db *gorm.DB, table, orgID string) ([]*model.UserGrantView, error) {
users := make([]*model.UserGrantView, 0)
queries := []*grant_model.UserGrantSearchQuery{

View File

@ -5,6 +5,7 @@ import (
caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/model"
"github.com/jinzhu/gorm"
"github.com/lib/pq"
)
type SearchRequest interface {
@ -102,10 +103,14 @@ func SetQuery(query *gorm.DB, key ColumnKey, value interface{}, method model.Sea
query = query.Where(column+" > ?", value)
case model.SEARCHMETHOD_LESS_THAN:
query = query.Where(column+" < ?", value)
case model.SEARCHMETHOD_IN:
case model.SEARCHMETHOD_IS_ONE_OF:
query = query.Where(column+" IN (?)", value)
case model.SEARCHMETHOD_EQUALS_IN_ARRAY:
query = query.Where("? <@ "+column, value)
case model.SEARCHMETHOD_LIST_CONTAINS:
valueText, ok := value.(string)
if !ok {
return nil, caos_errs.ThrowInvalidArgument(nil, "VIEW-Psois", "list contains only possible for strings")
}
query = query.Where("? <@ "+column, pq.Array([]string{valueText}))
default:
return nil, nil
}

View File

@ -0,0 +1,5 @@
BEGIN;
ALTER TABLE management.project_grants ADD COLUMN resource_owner_name TEXT;
COMMIT;

View File

@ -1,4 +1,4 @@
package grpc
//go:generate protoc -I$GOPATH/src -I../proto -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis -I${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate -I${GOPATH}/src/github.com/caos/zitadel/internal/protoc/protoc-gen-authoption --go_out=plugins=grpc:$GOPATH/src --grpc-gateway_out=logtostderr=true:$GOPATH/src --swagger_out=logtostderr=true:. --authoption_out=. ../proto/management.proto
//go:generate protoc -I$GOPATH/src -I../proto -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway -I$GOPATH/src/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis -I${GOPATH}/src/github.com/envoyproxy/protoc-gen-validate -I${GOPATH}/src/github.com/caos/zitadel/internal/protoc/protoc-gen-authoption --go_out=plugins=grpc:$GOPATH/src --grpc-gateway_out=logtostderr=true,allow_delete_body=true:$GOPATH/src --swagger_out=logtostderr=true,allow_delete_body=true:. --authoption_out=:. ../proto/management.proto
//go:generate mockgen -package api -destination ./mock/management.proto.mock.go github.com/caos/zitadel/pkg/management/api/grpc ManagementServiceClient

View File

@ -355,6 +355,11 @@ var ManagementService_AuthMethods = utils_auth.MethodMapping{
CheckParam: "Id",
},
"/caos.zitadel.management.api.v1.ManagementService/BulkAddProjectRole": utils_auth.Option{
Permission: "project.role.write",
CheckParam: "Id",
},
"/caos.zitadel.management.api.v1.ManagementService/ChangeProjectRole": utils_auth.Option{
Permission: "project.role.write",
CheckParam: "Id",
@ -505,6 +510,21 @@ var ManagementService_AuthMethods = utils_auth.MethodMapping{
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/BulkCreateUserGrant": utils_auth.Option{
Permission: "user.grant.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/BulkUpdateUserGrant": utils_auth.Option{
Permission: "user.grant.write",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/BulkRemoveUserGrant": utils_auth.Option{
Permission: "user.grant.delete",
CheckParam: "",
},
"/caos.zitadel.management.api.v1.ManagementService/SearchProjectUserGrants": utils_auth.Option{
Permission: "project.user.grant.read",
CheckParam: "ProjectId",

File diff suppressed because it is too large Load Diff

View File

@ -1844,6 +1844,41 @@ func request_ManagementService_AddProjectRole_0(ctx context.Context, marshaler r
}
func request_ManagementService_BulkAddProjectRole_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectRoleAddBulk
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
var (
val string
ok bool
err error
_ = err
)
val, ok = pathParams["id"]
if !ok {
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "id")
}
protoReq.Id, err = runtime.String(val)
if err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "id", err)
}
msg, err := client.BulkAddProjectRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ManagementService_ChangeProjectRole_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectRoleChange
var metadata runtime.ServerMetadata
@ -3061,6 +3096,57 @@ func request_ManagementService_RemoveUserGrant_0(ctx context.Context, marshaler
}
func request_ManagementService_BulkCreateUserGrant_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UserGrantCreateBulk
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.BulkCreateUserGrant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ManagementService_BulkUpdateUserGrant_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UserGrantUpdateBulk
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.BulkUpdateUserGrant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ManagementService_BulkRemoveUserGrant_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq UserGrantRemoveBulk
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.BulkRemoveUserGrant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_ManagementService_SearchProjectUserGrants_0(ctx context.Context, marshaler runtime.Marshaler, client ManagementServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ProjectUserGrantSearchRequest
var metadata runtime.ServerMetadata
@ -5138,6 +5224,26 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se
})
mux.Handle("POST", pattern_ManagementService_BulkAddProjectRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_BulkAddProjectRole_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_BulkAddProjectRole_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PUT", pattern_ManagementService_ChangeProjectRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -5738,6 +5844,66 @@ func RegisterManagementServiceHandlerClient(ctx context.Context, mux *runtime.Se
})
mux.Handle("POST", pattern_ManagementService_BulkCreateUserGrant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_BulkCreateUserGrant_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_BulkCreateUserGrant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("PUT", pattern_ManagementService_BulkUpdateUserGrant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_BulkUpdateUserGrant_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_BulkUpdateUserGrant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("DELETE", pattern_ManagementService_BulkRemoveUserGrant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ManagementService_BulkRemoveUserGrant_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_ManagementService_BulkRemoveUserGrant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ManagementService_SearchProjectUserGrants_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@ -6144,6 +6310,8 @@ var (
pattern_ManagementService_AddProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2}, []string{"projects", "id", "roles"}, ""))
pattern_ManagementService_BulkAddProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 2, 3}, []string{"projects", "id", "roles", "_bulk"}, ""))
pattern_ManagementService_ChangeProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"projects", "id", "roles", "key"}, ""))
pattern_ManagementService_RemoveProjectRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"projects", "id", "roles", "key"}, ""))
@ -6204,6 +6372,12 @@ var (
pattern_ManagementService_RemoveUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"users", "user_id", "grants", "id"}, ""))
pattern_ManagementService_BulkCreateUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"usergrants", "_bulk"}, ""))
pattern_ManagementService_BulkUpdateUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"usergrants", "_bulk"}, ""))
pattern_ManagementService_BulkRemoveUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"usersgrants", "_bulk"}, ""))
pattern_ManagementService_SearchProjectUserGrants_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 2, 3, 2, 4}, []string{"projects", "project_id", "users", "grants", "_search"}, ""))
pattern_ManagementService_ProjectUserGrantByID_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1, 2, 2, 1, 0, 4, 1, 5, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"projects", "project_id", "users", "user_id", "grants", "id"}, ""))
@ -6374,6 +6548,8 @@ var (
forward_ManagementService_AddProjectRole_0 = runtime.ForwardResponseMessage
forward_ManagementService_BulkAddProjectRole_0 = runtime.ForwardResponseMessage
forward_ManagementService_ChangeProjectRole_0 = runtime.ForwardResponseMessage
forward_ManagementService_RemoveProjectRole_0 = runtime.ForwardResponseMessage
@ -6434,6 +6610,12 @@ var (
forward_ManagementService_RemoveUserGrant_0 = runtime.ForwardResponseMessage
forward_ManagementService_BulkCreateUserGrant_0 = runtime.ForwardResponseMessage
forward_ManagementService_BulkUpdateUserGrant_0 = runtime.ForwardResponseMessage
forward_ManagementService_BulkRemoveUserGrant_0 = runtime.ForwardResponseMessage
forward_ManagementService_SearchProjectUserGrants_0 = runtime.ForwardResponseMessage
forward_ManagementService_ProjectUserGrantByID_0 = runtime.ForwardResponseMessage

View File

@ -1496,8 +1496,41 @@
]
}
},
"/projects/{id}/roles/_bulk": {
"post": {
"operationId": "BulkAddProjectRole",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"type": "string"
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1ProjectRoleAddBulk"
}
}
],
"tags": [
"ManagementService"
]
}
},
"/projects/{id}/roles/{key}": {
"delete": {
"summary": "RemoveProjectRole removes role from UserGrants, ProjectGrants and from Project",
"operationId": "RemoveProjectRole",
"responses": {
"200": {
@ -2580,6 +2613,56 @@
]
}
},
"/usergrants/_bulk": {
"post": {
"operationId": "BulkCreateUserGrant",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1UserGrantCreateBulk"
}
}
],
"tags": [
"ManagementService"
]
},
"put": {
"operationId": "BulkUpdateUserGrant",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1UserGrantUpdateBulk"
}
}
],
"tags": [
"ManagementService"
]
}
},
"/users": {
"post": {
"operationId": "CreateUser",
@ -3485,6 +3568,32 @@
]
}
},
"/usersgrants/_bulk": {
"delete": {
"operationId": "BulkRemoveUserGrant",
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"properties": {}
}
}
},
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v1UserGrantRemoveBulk"
}
}
],
"tags": [
"ManagementService"
]
}
},
"/validate": {
"get": {
"operationId": "Validate",
@ -5109,6 +5218,29 @@
}
}
},
"v1ProjectGrantSearchKey": {
"type": "string",
"enum": [
"PROJECTGRANTSEARCHKEY_UNSPECIFIED",
"PROJECTGRANTSEARCHKEY_PROJECT_NAME",
"PROJECTGRANTSEARCHKEY_ROLE_KEY"
],
"default": "PROJECTGRANTSEARCHKEY_UNSPECIFIED"
},
"v1ProjectGrantSearchQuery": {
"type": "object",
"properties": {
"key": {
"$ref": "#/definitions/v1ProjectGrantSearchKey"
},
"method": {
"$ref": "#/definitions/v1SearchMethod"
},
"value": {
"type": "string"
}
}
},
"v1ProjectGrantSearchRequest": {
"type": "object",
"properties": {
@ -5122,6 +5254,12 @@
"limit": {
"type": "string",
"format": "uint64"
},
"queries": {
"type": "array",
"items": {
"$ref": "#/definitions/v1ProjectGrantSearchQuery"
}
}
}
},
@ -5268,9 +5406,6 @@
"granted_org_name": {
"type": "string"
},
"granted_org_domain": {
"type": "string"
},
"role_keys": {
"type": "array",
"items": {
@ -5294,6 +5429,12 @@
"sequence": {
"type": "string",
"format": "uint64"
},
"resource_owner": {
"type": "string"
},
"resource_owner_name": {
"type": "string"
}
}
},
@ -5531,6 +5672,20 @@
}
}
},
"v1ProjectRoleAddBulk": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"project_roles": {
"type": "array",
"items": {
"$ref": "#/definitions/v1ProjectRoleAdd"
}
}
}
},
"v1ProjectRoleChange": {
"type": "object",
"properties": {
@ -5818,7 +5973,12 @@
"SEARCHMETHOD_CONTAINS",
"SEARCHMETHOD_EQUALS_IGNORE_CASE",
"SEARCHMETHOD_STARTS_WITH_IGNORE_CASE",
"SEARCHMETHOD_CONTAINS_IGNORE_CASE"
"SEARCHMETHOD_CONTAINS_IGNORE_CASE",
"SEARCHMETHOD_NOT_EQUALS",
"SEARCHMETHOD_GREATER_THAN",
"SEARCHMETHOD_LESS_THAN",
"SEARCHMETHOD_IS_ONE_OF",
"SEARCHMETHOD_LIST_CONTAINS"
],
"default": "SEARCHMETHOD_EQUALS"
},
@ -6170,6 +6330,17 @@
}
}
},
"v1UserGrantCreateBulk": {
"type": "object",
"properties": {
"user_grants": {
"type": "array",
"items": {
"$ref": "#/definitions/v1UserGrantCreate"
}
}
}
},
"v1UserGrantID": {
"type": "object",
"properties": {
@ -6181,13 +6352,25 @@
}
}
},
"v1UserGrantRemoveBulk": {
"type": "object",
"properties": {
"ids": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"v1UserGrantSearchKey": {
"type": "string",
"enum": [
"USERGRANTSEARCHKEY_UNSPECIFIED",
"USERGRANTSEARCHKEY_PROJECT_ID",
"USERGRANTSEARCHKEY_USER_ID",
"USERGRANTSEARCHKEY_ORG_ID"
"USERGRANTSEARCHKEY_ORG_ID",
"USERGRANTSEARCHKEY_ROLE_KEY"
],
"default": "USERGRANTSEARCHKEY_UNSPECIFIED"
},
@ -6273,6 +6456,17 @@
}
}
},
"v1UserGrantUpdateBulk": {
"type": "object",
"properties": {
"user_grants": {
"type": "array",
"items": {
"$ref": "#/definitions/v1UserGrantUpdate"
}
}
}
},
"v1UserGrantView": {
"type": "object",
"properties": {

View File

@ -177,6 +177,86 @@ func (mr *MockManagementServiceClientMockRecorder) ApplicationChanges(arg0, arg1
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplicationChanges", reflect.TypeOf((*MockManagementServiceClient)(nil).ApplicationChanges), varargs...)
}
// BulkAddProjectRole mocks base method
func (m *MockManagementServiceClient) BulkAddProjectRole(arg0 context.Context, arg1 *grpc.ProjectRoleAddBulk, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "BulkAddProjectRole", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BulkAddProjectRole indicates an expected call of BulkAddProjectRole
func (mr *MockManagementServiceClientMockRecorder) BulkAddProjectRole(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkAddProjectRole", reflect.TypeOf((*MockManagementServiceClient)(nil).BulkAddProjectRole), varargs...)
}
// BulkCreateUserGrant mocks base method
func (m *MockManagementServiceClient) BulkCreateUserGrant(arg0 context.Context, arg1 *grpc.UserGrantCreateBulk, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "BulkCreateUserGrant", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BulkCreateUserGrant indicates an expected call of BulkCreateUserGrant
func (mr *MockManagementServiceClientMockRecorder) BulkCreateUserGrant(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkCreateUserGrant", reflect.TypeOf((*MockManagementServiceClient)(nil).BulkCreateUserGrant), varargs...)
}
// BulkRemoveUserGrant mocks base method
func (m *MockManagementServiceClient) BulkRemoveUserGrant(arg0 context.Context, arg1 *grpc.UserGrantRemoveBulk, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "BulkRemoveUserGrant", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BulkRemoveUserGrant indicates an expected call of BulkRemoveUserGrant
func (mr *MockManagementServiceClientMockRecorder) BulkRemoveUserGrant(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkRemoveUserGrant", reflect.TypeOf((*MockManagementServiceClient)(nil).BulkRemoveUserGrant), varargs...)
}
// BulkUpdateUserGrant mocks base method
func (m *MockManagementServiceClient) BulkUpdateUserGrant(arg0 context.Context, arg1 *grpc.UserGrantUpdateBulk, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) {
m.ctrl.T.Helper()
varargs := []interface{}{arg0, arg1}
for _, a := range arg2 {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "BulkUpdateUserGrant", varargs...)
ret0, _ := ret[0].(*emptypb.Empty)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// BulkUpdateUserGrant indicates an expected call of BulkUpdateUserGrant
func (mr *MockManagementServiceClientMockRecorder) BulkUpdateUserGrant(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
varargs := append([]interface{}{arg0, arg1}, arg2...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BulkUpdateUserGrant", reflect.TypeOf((*MockManagementServiceClient)(nil).BulkUpdateUserGrant), varargs...)
}
// ChangeMyOrgMember mocks base method
func (m *MockManagementServiceClient) ChangeMyOrgMember(arg0 context.Context, arg1 *grpc.ChangeOrgMemberRequest, arg2 ...grpc0.CallOption) (*grpc.OrgMember, error) {
m.ctrl.T.Helper()

View File

@ -81,6 +81,12 @@ func (s *Server) AddProjectRole(ctx context.Context, in *ProjectRoleAdd) (*Proje
}
return projectRoleFromModel(role), nil
}
func (s *Server) BulkAddProjectRole(ctx context.Context, in *ProjectRoleAddBulk) (*empty.Empty, error) {
err := s.project.BulkAddProjectRole(ctx, projectRoleAddBulkToModel(in))
return &empty.Empty{}, err
}
func (s *Server) ChangeProjectRole(ctx context.Context, in *ProjectRoleChange) (*ProjectRole, error) {
role, err := s.project.ChangeProjectRole(ctx, projectRoleChangeToModel(in))
if err != nil {

View File

@ -131,6 +131,21 @@ func projectRoleFromModel(role *proj_model.ProjectRole) *ProjectRole {
}
}
func projectRoleAddBulkToModel(bulk *ProjectRoleAddBulk) []*proj_model.ProjectRole {
roles := make([]*proj_model.ProjectRole, len(bulk.ProjectRoles))
for i, role := range bulk.ProjectRoles {
roles[i] = &proj_model.ProjectRole{
ObjectRoot: models.ObjectRoot{
AggregateID: bulk.Id,
},
Key: role.Key,
DisplayName: role.DisplayName,
Group: role.Group,
}
}
return roles
}
func projectRoleAddToModel(role *ProjectRoleAdd) *proj_model.ProjectRole {
return &proj_model.ProjectRole{
ObjectRoot: models.ObjectRoot{

View File

@ -51,17 +51,40 @@ func projectGrantSearchRequestsToModel(request *ProjectGrantSearchRequest) *proj
return &proj_model.ProjectGrantViewSearchRequest{
Offset: request.Offset,
Limit: request.Limit,
Queries: projectGrantSearchQueriesToModel(request.ProjectId),
Queries: projectGrantSearchQueriesToModel(request.ProjectId, request.Queries),
}
}
func projectGrantSearchQueriesToModel(projectId string) []*proj_model.ProjectGrantViewSearchQuery {
func projectGrantSearchQueriesToModel(projectId string, queries []*ProjectGrantSearchQuery) []*proj_model.ProjectGrantViewSearchQuery {
converted := make([]*proj_model.ProjectGrantViewSearchQuery, 0)
return append(converted, &proj_model.ProjectGrantViewSearchQuery{
converted = append(converted, &proj_model.ProjectGrantViewSearchQuery{
Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID,
Method: model.SEARCHMETHOD_EQUALS,
Value: projectId,
})
for i, query := range queries {
converted[i] = projectGrantSearchQueryToModel(query)
}
return converted
}
func projectGrantSearchQueryToModel(query *ProjectGrantSearchQuery) *proj_model.ProjectGrantViewSearchQuery {
return &proj_model.ProjectGrantViewSearchQuery{
Key: projectGrantViewSearchKeyToModel(query.Key),
Method: searchMethodToModel(query.Method),
Value: query.Value,
}
}
func projectGrantViewSearchKeyToModel(key ProjectGrantSearchKey) proj_model.ProjectGrantViewSearchKey {
switch key {
case ProjectGrantSearchKey_PROJECTGRANTSEARCHKEY_PROJECT_NAME:
return proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID
case ProjectGrantSearchKey_PROJECTGRANTSEARCHKEY_ROLE_KEY:
return proj_model.GRANTEDPROJECTSEARCHKEY_ROLE_KEYS
default:
return proj_model.GRANTEDPROJECTSEARCHKEY_UNSPECIFIED
}
}
func projectGrantSearchResponseFromModel(response *proj_model.ProjectGrantViewSearchResponse) *ProjectGrantSearchResponse {
@ -89,16 +112,18 @@ func projectGrantFromGrantedProjectModel(project *proj_model.ProjectGrantView) *
logging.Log("GRPC-sope3").OnError(err).Debug("unable to parse timestamp")
return &ProjectGrantView{
ProjectId: project.ProjectID,
State: projectGrantStateFromProjectStateModel(project.State),
CreationDate: creationDate,
ChangeDate: changeDate,
ProjectName: project.Name,
Sequence: project.Sequence,
GrantedOrgId: project.OrgID,
GrantedOrgName: project.OrgName,
GrantedOrgDomain: project.OrgDomain,
Id: project.GrantID,
ProjectId: project.ProjectID,
State: projectGrantStateFromProjectStateModel(project.State),
CreationDate: creationDate,
ChangeDate: changeDate,
ProjectName: project.Name,
Sequence: project.Sequence,
GrantedOrgId: project.OrgID,
GrantedOrgName: project.OrgName,
Id: project.GrantID,
RoleKeys: project.GrantedRoleKeys,
ResourceOwner: project.ResourceOwner,
ResourceOwnerName: project.ResourceOwnerName,
}
}

View File

@ -16,6 +16,12 @@ func searchMethodToModel(method SearchMethod) model.SearchMethod {
return model.SEARCHMETHOD_CONTAINS_IGNORE_CASE
case SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE:
return model.SEARCHMETHOD_STARTS_WITH_IGNORE_CASE
case SearchMethod_SEARCHMETHOD_NOT_EQUALS:
return model.SEARCHMETHOD_NOT_EQUALS
case SearchMethod_SEARCHMETHOD_IS_ONE_OF:
return model.SEARCHMETHOD_IS_ONE_OF
case SearchMethod_SEARCHMETHOD_LIST_CONTAINS:
return model.SEARCHMETHOD_LIST_CONTAINS
default:
return model.SEARCHMETHOD_EQUALS
}

View File

@ -2,12 +2,14 @@ package grpc
import (
"context"
"github.com/caos/zitadel/internal/api/auth"
"github.com/caos/zitadel/internal/errors"
"github.com/golang/protobuf/ptypes/empty"
)
func (s *Server) SearchUserGrants(ctx context.Context, in *UserGrantSearchRequest) (*UserGrantSearchResponse, error) {
request := userGrantSearchRequestsToModel(in)
request.AppendMyOrgQuery(auth.GetCtxData(ctx).OrgID)
response, err := s.usergrant.SearchUserGrants(ctx, request)
if err != nil {
return nil, err
@ -30,6 +32,7 @@ func (s *Server) CreateUserGrant(ctx context.Context, in *UserGrantCreate) (*Use
}
return usergrantFromModel(user), nil
}
func (s *Server) UpdateUserGrant(ctx context.Context, in *UserGrantUpdate) (*UserGrant, error) {
user, err := s.usergrant.ChangeUserGrant(ctx, userGrantUpdateToModel(in))
if err != nil {
@ -57,6 +60,21 @@ func (s *Server) RemoveUserGrant(ctx context.Context, in *UserGrantID) (*empty.E
return &empty.Empty{}, err
}
func (s *Server) BulkCreateUserGrant(ctx context.Context, in *UserGrantCreateBulk) (*empty.Empty, error) {
err := s.usergrant.BulkAddUserGrant(ctx, userGrantCreateBulkToModel(in)...)
return &empty.Empty{}, err
}
func (s *Server) BulkUpdateUserGrant(ctx context.Context, in *UserGrantUpdateBulk) (*empty.Empty, error) {
err := s.usergrant.BulkChangeUserGrant(ctx, userGrantUpdateBulkToModel(in)...)
return &empty.Empty{}, err
}
func (s *Server) BulkRemoveUserGrant(ctx context.Context, in *UserGrantRemoveBulk) (*empty.Empty, error) {
err := s.usergrant.BulkRemoveUserGrant(ctx, userGrantRemoveBulkToModel(in)...)
return &empty.Empty{}, err
}
func (s *Server) SearchProjectUserGrants(ctx context.Context, request *ProjectUserGrantSearchRequest) (*UserGrantSearchResponse, error) {
return nil, errors.ThrowUnimplemented(nil, "GRPC-8jdSw", "Not implemented")
}

View File

@ -26,6 +26,14 @@ func usergrantFromModel(grant *grant_model.UserGrant) *UserGrant {
}
}
func userGrantCreateBulkToModel(u *UserGrantCreateBulk) []*grant_model.UserGrant {
grants := make([]*grant_model.UserGrant, len(u.UserGrants))
for i, grant := range u.UserGrants {
grants[i] = userGrantCreateToModel(grant)
}
return grants
}
func userGrantCreateToModel(u *UserGrantCreate) *grant_model.UserGrant {
return &grant_model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: u.UserId},
@ -35,6 +43,14 @@ func userGrantCreateToModel(u *UserGrantCreate) *grant_model.UserGrant {
}
}
func userGrantUpdateBulkToModel(u *UserGrantUpdateBulk) []*grant_model.UserGrant {
grants := make([]*grant_model.UserGrant, len(u.UserGrants))
for i, grant := range u.UserGrants {
grants[i] = userGrantUpdateToModel(grant)
}
return grants
}
func userGrantUpdateToModel(u *UserGrantUpdate) *grant_model.UserGrant {
return &grant_model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: u.Id},
@ -42,6 +58,14 @@ func userGrantUpdateToModel(u *UserGrantUpdate) *grant_model.UserGrant {
}
}
func userGrantRemoveBulkToModel(u *UserGrantRemoveBulk) []string {
ids := make([]string, len(u.Ids))
for i, id := range u.Ids {
ids[i] = id
}
return ids
}
func projectUserGrantUpdateToModel(u *ProjectUserGrantUpdate) *grant_model.UserGrant {
return &grant_model.UserGrant{
ObjectRoot: models.ObjectRoot{AggregateID: u.Id},
@ -96,6 +120,8 @@ func userGrantSearchKeyToModel(key UserGrantSearchKey) grant_model.UserGrantSear
return grant_model.USERGRANTSEARCHKEY_PROJECT_ID
case UserGrantSearchKey_USERGRANTSEARCHKEY_USER_ID:
return grant_model.USERGRANTSEARCHKEY_USER_ID
case UserGrantSearchKey_USERGRANTSEARCHKEY_ROLE_KEY:
return grant_model.USERGRANTSEARCHKEY_ROLE_KEY
default:
return grant_model.USERGRANTSEARCHKEY_UNSPECIFIED
}

View File

@ -801,6 +801,18 @@ service ManagementService {
};
}
rpc BulkAddProjectRole(ProjectRoleAddBulk) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/projects/{id}/roles/_bulk"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "project.role.write"
check_field_name: "Id"
};
}
rpc ChangeProjectRole(ProjectRoleChange) returns (ProjectRole) {
option (google.api.http) = {
put: "/projects/{id}/roles/{key}"
@ -813,6 +825,7 @@ service ManagementService {
};
}
/* RemoveProjectRole removes role from UserGrants, ProjectGrants and from Project */
rpc RemoveProjectRole(ProjectRoleRemove) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/projects/{id}/roles/{key}"
@ -1137,6 +1150,39 @@ service ManagementService {
};
}
rpc BulkCreateUserGrant(UserGrantCreateBulk) returns (google.protobuf.Empty) {
option (google.api.http) = {
post: "/usergrants/_bulk"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "user.grant.write"
};
}
rpc BulkUpdateUserGrant(UserGrantUpdateBulk) returns (google.protobuf.Empty) {
option (google.api.http) = {
put: "/usergrants/_bulk"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "user.grant.write"
};
}
rpc BulkRemoveUserGrant(UserGrantRemoveBulk) returns (google.protobuf.Empty) {
option (google.api.http) = {
delete: "/usersgrants/_bulk"
body: "*"
};
option (caos.zitadel.utils.v1.auth_option) = {
permission: "user.grant.delete"
};
}
//PROJECT_USER_GRANT
rpc SearchProjectUserGrants(ProjectUserGrantSearchRequest) returns (UserGrantSearchResponse) {
option (google.api.http) = {
@ -1470,6 +1516,11 @@ enum SearchMethod {
SEARCHMETHOD_EQUALS_IGNORE_CASE = 3;
SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4;
SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5;
SEARCHMETHOD_NOT_EQUALS = 6;
SEARCHMETHOD_GREATER_THAN = 7;
SEARCHMETHOD_LESS_THAN = 8;
SEARCHMETHOD_IS_ONE_OF = 9;
SEARCHMETHOD_LIST_CONTAINS = 10;
}
message UserProfile {
@ -1993,6 +2044,11 @@ message ProjectRoleAdd {
string group = 4;
}
message ProjectRoleAddBulk {
string id = 1;
repeated ProjectRoleAdd project_roles = 2;
}
message ProjectRoleChange {
string id = 1;
string key = 2;
@ -2252,13 +2308,14 @@ message ProjectGrantView {
string project_id = 2;
string granted_org_id = 3;
string granted_org_name = 4;
string granted_org_domain = 5;
repeated string role_keys = 6;
ProjectGrantState state = 7;
google.protobuf.Timestamp creation_date = 8;
google.protobuf.Timestamp change_date = 9;
string project_name = 10;
uint64 sequence = 11;
repeated string role_keys = 5;
ProjectGrantState state = 6;
google.protobuf.Timestamp creation_date = 7;
google.protobuf.Timestamp change_date = 8;
string project_name = 9;
uint64 sequence = 10;
string resource_owner = 11;
string resource_owner_name = 12;
}
message ProjectGrantSearchResponse {
@ -2268,18 +2325,32 @@ message ProjectGrantSearchResponse {
repeated ProjectGrantView result = 4;
}
message ProjectGrantSearchRequest {
string project_id = 1;
uint64 offset = 2;
uint64 limit = 3;
}
message GrantedProjectSearchRequest {
uint64 offset = 1;
uint64 limit = 2;
repeated ProjectSearchQuery queries = 3;
}
message ProjectGrantSearchRequest {
string project_id = 1;
uint64 offset = 2;
uint64 limit = 3;
repeated ProjectGrantSearchQuery queries = 4;
}
message ProjectGrantSearchQuery {
ProjectGrantSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];
SearchMethod method = 2;
string value = 3;
}
enum ProjectGrantSearchKey {
PROJECTGRANTSEARCHKEY_UNSPECIFIED = 0;
PROJECTGRANTSEARCHKEY_PROJECT_NAME = 1;
PROJECTGRANTSEARCHKEY_ROLE_KEY = 2;
}
message ProjectGrantMemberRoles {
repeated string roles = 1;
}
@ -2366,18 +2437,30 @@ message UserGrant {
uint64 sequence = 9;
}
message UserGrantCreateBulk {
repeated UserGrantCreate user_grants = 1;
}
message UserGrantCreate {
string user_id = 1;
string project_id = 2;
repeated string role_keys = 3;
}
message UserGrantUpdateBulk {
repeated UserGrantUpdate user_grants = 1;
}
message UserGrantUpdate {
string user_id = 1;
string id = 2;
repeated string role_keys = 3;
}
message UserGrantRemoveBulk {
repeated string ids = 1;
}
message UserGrantID {
string user_id = 1;
string id = 2;
@ -2467,6 +2550,7 @@ enum UserGrantSearchKey {
USERGRANTSEARCHKEY_PROJECT_ID = 1;
USERGRANTSEARCHKEY_USER_ID = 2;
USERGRANTSEARCHKEY_ORG_ID = 3;
USERGRANTSEARCHKEY_ROLE_KEY = 4;
}
message ProjectUserGrantSearchRequest {