mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 18:07:31 +00:00
feat: new projects (#1207)
* fix: project events * fix: project events * fix: project events * fix: eventmapper * fix: project commands * fix: project role commands * fix: project command side * fix: oidc application * fix: oidc application * fix: reduce * fix: reduce * fix: project member * fix: project grant command side * fix: application command side * fix: project grant member remove * Update internal/v2/command/project.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/v2/command/project.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/v2/command/project_application.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/v2/command/project_application.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * Update internal/v2/command/project_application.go Co-authored-by: Livio Amstutz <livio.a@gmail.com> * fix: oidc application string pw * fix: project events * fix: project grant member * feat: change application to interface Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
@@ -14,12 +14,23 @@ func (r *CommandSide) getOrg(ctx context.Context, orgID string) (*domain.Org, er
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if writeModel.State == domain.OrgStateActive {
|
||||
if writeModel.State == domain.OrgStateUnspecified || writeModel.State == domain.OrgStateRemoved {
|
||||
return nil, caos_errs.ThrowInternal(err, "COMMAND-4M9sf", "Errors.Org.NotFound")
|
||||
}
|
||||
return orgWriteModelToOrg(writeModel), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) checkOrgExists(ctx context.Context, orgID string) error {
|
||||
orgWriteModel, err := r.getOrgWriteModelByID(ctx, orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if orgWriteModel.State == domain.OrgStateUnspecified || orgWriteModel.State == domain.OrgStateRemoved {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0fs", "Errors.Org.NotFound")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) SetUpOrg(ctx context.Context, organisation *domain.Org, admin *domain.Human) error {
|
||||
orgAgg, userAgg, orgMemberAgg, err := r.setUpOrg(ctx, organisation, admin)
|
||||
if err != nil {
|
||||
@@ -36,13 +47,10 @@ func (r *CommandSide) AddOrg(ctx context.Context, name, userID, resourceOwner st
|
||||
return nil, err
|
||||
}
|
||||
|
||||
active, err := r.checkUserExists(ctx, userID, resourceOwner)
|
||||
err = r.checkUserExists(ctx, userID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !active {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(err, "ORG-HBR2z", "Errors.User.NotFound")
|
||||
}
|
||||
addedMember := NewOrgMemberWriteModel(orgAgg.ID(), userID)
|
||||
err = r.addOrgMember(ctx, orgAgg, addedMember, domain.NewMember(orgAgg.ID(), userID, domain.RoleOrgOwner))
|
||||
if err != nil {
|
||||
|
@@ -32,13 +32,17 @@ func (r *CommandSide) addProject(ctx context.Context, projectAdd *domain.Project
|
||||
addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel)
|
||||
|
||||
projectRole := domain.RoleOrgOwner
|
||||
//if global { //TODO: !
|
||||
// projectRole = domain.RoleProjectOwnerGlobal
|
||||
//}
|
||||
projectRole := domain.RoleProjectOwner
|
||||
iam, err := r.GetIAM(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if iam.GlobalOrgID == resourceOwner {
|
||||
projectRole = domain.RoleProjectOwnerGlobal
|
||||
}
|
||||
projectAgg.PushEvents(
|
||||
project.NewProjectAddedEvent(ctx, projectAdd.Name, resourceOwner),
|
||||
project.NewMemberAddedEvent(ctx, ownerUserID, projectRole),
|
||||
project.NewProjectMemberAddedEvent(ctx, ownerUserID, projectRole),
|
||||
)
|
||||
return projectAgg, addedProject, nil
|
||||
}
|
||||
@@ -65,6 +69,101 @@ func (r *CommandSide) checkProjectExists(ctx context.Context, projectID, resourc
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) ChangeProject(ctx context.Context, projectChange *domain.Project, resourceOwner string) (*domain.Project, error) {
|
||||
if !projectChange.IsValid() && projectChange.AggregateID != "" {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
}
|
||||
|
||||
existingProject, err := r.getProjectWriteModelByID(ctx, projectChange.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
|
||||
}
|
||||
|
||||
changedEvent, hasChanged, err := existingProject.NewChangedEvent(ctx, projectChange.Name, projectChange.ProjectRoleAssertion, projectChange.ProjectRoleCheck)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
projectAgg.PushEvents(changedEvent)
|
||||
|
||||
err = r.eventstore.PushAggregate(ctx, existingProject, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return projectWriteModelToProject(existingProject), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) DeactivateProject(ctx context.Context, projectID string, resourceOwner string) error {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-88iF0", "Errors.Project.ProjectIDMissing")
|
||||
}
|
||||
|
||||
existingProject, err := r.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound")
|
||||
}
|
||||
if existingProject.State != domain.ProjectStateActive {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
projectAgg.PushEvents(project.NewProjectDeactivatedEvent(ctx))
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, existingProject, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) ReactivateProject(ctx context.Context, projectID string, resourceOwner string) error {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.ProjectIDMissing")
|
||||
}
|
||||
|
||||
existingProject, err := r.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
|
||||
}
|
||||
if existingProject.State != domain.ProjectStateInactive {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInctive")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
projectAgg.PushEvents(project.NewProjectDeactivatedEvent(ctx))
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, existingProject, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) RemoveProject(ctx context.Context, projectID, resourceOwner string) error {
|
||||
if projectID == "" || resourceOwner == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing")
|
||||
}
|
||||
|
||||
existingProject, err := r.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "COMMAND-3M9sd", "Errors.Project.NotFound")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
||||
projectAgg.PushEvents(project.NewProjectRemovedEvent(ctx, existingProject.Name, existingProject.ResourceOwner))
|
||||
//TODO: Remove User Grants by ProjectID
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, existingProject, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) getProjectWriteModelByID(ctx context.Context, projectID, resourceOwner string) (*ProjectWriteModel, error) {
|
||||
projectWriteModel := NewProjectWriteModel(projectID, resourceOwner)
|
||||
err := r.eventstore.FilterToQueryReducer(ctx, projectWriteModel)
|
||||
|
@@ -8,66 +8,99 @@ import (
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
)
|
||||
|
||||
func (r *CommandSide) AddApplication(ctx context.Context, application *domain.Application, resourceOwner string) (_ *domain.Application, err error) {
|
||||
project, err := r.getProjectByID(ctx, application.AggregateID, resourceOwner)
|
||||
func (r *CommandSide) ChangeApplication(ctx context.Context, projectID string, appChange domain.Application, resourceOwner string) (domain.Application, error) {
|
||||
if appChange.GetAppID() == "" || appChange.GetApplicationName() == "" {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
existingApp, err := r.getApplicationWriteModel(ctx, projectID, appChange.GetAppID(), resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedApplication := NewApplicationWriteModel(application.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
|
||||
err = r.addApplication(ctx, projectAgg, project, application)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if existingApp.State == domain.AppStateUnspecified || existingApp.State == domain.AppStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-28di9", "Errors.Project.App.NotExisting")
|
||||
}
|
||||
err = r.eventstore.PushAggregate(ctx, addedApplication, projectAgg)
|
||||
if existingApp.Name == appChange.GetApplicationName() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2m8vx", "Errors.NoChangesFound")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
projectAgg.PushEvents(
|
||||
project.NewApplicationChangedEvent(ctx, appChange.GetAppID(), existingApp.Name, appChange.GetApplicationName(), projectID),
|
||||
)
|
||||
|
||||
err = r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return applicationWriteModelToApplication(addedApplication), nil
|
||||
return applicationWriteModelToApplication(existingApp), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) addApplication(ctx context.Context, projectAgg *project.Aggregate, proj *domain.Project, application *domain.Application) (err error) {
|
||||
if !application.IsValid(true) {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-Bff2g", "Errors.Application.Invalid")
|
||||
func (r *CommandSide) DeactivateApplication(ctx context.Context, projectID, appID, resourceOwner string) error {
|
||||
if projectID == "" || appID == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-88fi0", "Errors.IDMissing")
|
||||
}
|
||||
application.AppID, err = r.idGenerator.Next()
|
||||
|
||||
existingApp, err := r.getApplicationWriteModel(ctx, projectID, appID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectAgg.PushEvents(project.NewApplicationAddedEvent(ctx, application.AppID, application.Name, application.Type))
|
||||
|
||||
var stringPw string
|
||||
if application.OIDCConfig != nil {
|
||||
application.OIDCConfig.AppID = application.AppID
|
||||
err = application.OIDCConfig.GenerateNewClientID(r.idGenerator, proj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stringPw, err = application.OIDCConfig.GenerateClientSecretIfNeeded(r.applicationSecretGenerator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectAgg.PushEvents(project.NewOIDCConfigAddedEvent(ctx,
|
||||
application.OIDCConfig.OIDCVersion,
|
||||
application.OIDCConfig.AppID,
|
||||
application.OIDCConfig.ClientID,
|
||||
application.OIDCConfig.ClientSecret,
|
||||
application.OIDCConfig.RedirectUris,
|
||||
application.OIDCConfig.ResponseTypes,
|
||||
application.OIDCConfig.GrantTypes,
|
||||
application.OIDCConfig.ApplicationType,
|
||||
application.OIDCConfig.AuthMethodType,
|
||||
application.OIDCConfig.PostLogoutRedirectUris,
|
||||
application.OIDCConfig.DevMode,
|
||||
application.OIDCConfig.AccessTokenType,
|
||||
application.OIDCConfig.AccessTokenRoleAssertion,
|
||||
application.OIDCConfig.IDTokenRoleAssertion,
|
||||
application.OIDCConfig.IDTokenUserinfoAssertion,
|
||||
application.OIDCConfig.ClockSkew))
|
||||
if existingApp.State == domain.AppStateUnspecified || existingApp.State == domain.AppStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "COMMAND-ov9d3", "Errors.Project.App.NotExisting")
|
||||
}
|
||||
_ = stringPw
|
||||
if existingApp.State != domain.AppStateActive {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-dsh35", "Errors.Project.App.NotActive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
projectAgg.PushEvents(project.NewApplicationDeactivatedEvent(ctx, appID))
|
||||
|
||||
return nil
|
||||
return r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) ReactivateApplication(ctx context.Context, projectID, appID, resourceOwner string) error {
|
||||
if projectID == "" || appID == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-983dF", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
existingApp, err := r.getApplicationWriteModel(ctx, projectID, appID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingApp.State == domain.AppStateUnspecified || existingApp.State == domain.AppStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "COMMAND-ov9d3", "Errors.Project.App.NotExisting")
|
||||
}
|
||||
if existingApp.State != domain.AppStateInactive {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1n8cM", "Errors.Project.App.NotInactive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
projectAgg.PushEvents(project.NewApplicationReactivatedEvent(ctx, appID))
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) RemoveApplication(ctx context.Context, projectID, appID, resourceOwner string) error {
|
||||
if projectID == "" || appID == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1b7Jf", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
existingApp, err := r.getApplicationWriteModel(ctx, projectID, appID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingApp.State == domain.AppStateUnspecified || existingApp.State == domain.AppStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "COMMAND-0po9s", "Errors.Project.App.NotExisting")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
projectAgg.PushEvents(project.NewApplicationRemovedEvent(ctx, appID, existingApp.Name, projectID))
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, existingApp, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) getApplicationWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*ApplicationWriteModel, error) {
|
||||
appWriteModel := NewApplicationWriteModelWithAppIDC(projectID, appID, resourceOwner)
|
||||
err := r.eventstore.FilterToQueryReducer(ctx, appWriteModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appWriteModel, nil
|
||||
}
|
||||
|
@@ -9,11 +9,19 @@ import (
|
||||
type ApplicationWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
AppID string
|
||||
State domain.AppState
|
||||
Name string
|
||||
Type domain.AppType
|
||||
OIDCConfig *domain.OIDCConfig
|
||||
AppID string
|
||||
State domain.AppState
|
||||
Name string
|
||||
}
|
||||
|
||||
func NewApplicationWriteModelWithAppIDC(projectID, appID, resourceOwner string) *ApplicationWriteModel {
|
||||
return &ApplicationWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: projectID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
AppID: appID,
|
||||
}
|
||||
}
|
||||
|
||||
func NewApplicationWriteModel(projectID, resourceOwner string) *ApplicationWriteModel {
|
||||
@@ -24,12 +32,35 @@ func NewApplicationWriteModel(projectID, resourceOwner string) *ApplicationWrite
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *ApplicationWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
wm.WriteModel.AppendEvents(events...)
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *project.ApplicationAddedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationChangedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationDeactivatedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationReactivatedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationRemovedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
@@ -41,15 +72,37 @@ func (wm *ApplicationWriteModel) Reduce() error {
|
||||
case *project.ApplicationAddedEvent:
|
||||
wm.Name = e.Name
|
||||
wm.State = domain.AppStateActive
|
||||
//case *project.ApplicationChangedEvent:
|
||||
// wm.Name = e.Name
|
||||
case *project.ApplicationChangedEvent:
|
||||
wm.Name = e.Name
|
||||
case *project.ApplicationDeactivatedEvent:
|
||||
if wm.State == domain.AppStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.AppStateInactive
|
||||
case *project.ApplicationReactivatedEvent:
|
||||
if wm.State == domain.AppStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.AppStateActive
|
||||
case *project.ApplicationRemovedEvent:
|
||||
wm.State = domain.AppStateRemoved
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.State = domain.AppStateRemoved
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *ApplicationWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner)
|
||||
//EventTypes(
|
||||
// project.ApplicationAddedType,
|
||||
// project.ApplicationChangedType,
|
||||
// project.ApplicationDeactivatedType,
|
||||
// project.ApplicationReactivatedType,
|
||||
// project.ApplicationRemovedType,
|
||||
// project.ProjectRemovedType,
|
||||
//)
|
||||
}
|
||||
|
157
internal/v2/command/project_application_oidc.go
Normal file
157
internal/v2/command/project_application_oidc.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
)
|
||||
|
||||
func (r *CommandSide) AddOIDCApplication(ctx context.Context, application *domain.OIDCApp, resourceOwner string) (_ *domain.OIDCApp, err error) {
|
||||
project, err := r.getProjectByID(ctx, application.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedApplication := NewOIDCApplicationWriteModel(application.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
|
||||
stringPw, err := r.addOIDCApplication(ctx, projectAgg, project, application, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedApplication.AppID = application.AppID
|
||||
err = r.eventstore.PushAggregate(ctx, addedApplication, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := oidcWriteModelToOIDCConfig(addedApplication)
|
||||
result.ClientSecretString = stringPw
|
||||
result.FillCompliance()
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) addOIDCApplication(ctx context.Context, projectAgg *project.Aggregate, proj *domain.Project, oidcApp *domain.OIDCApp, resourceOwner string) (stringPW string, err error) {
|
||||
if !oidcApp.IsValid() {
|
||||
return "", caos_errs.ThrowPreconditionFailed(nil, "PROJECT-Bff2g", "Errors.Application.Invalid")
|
||||
}
|
||||
oidcApp.AppID, err = r.idGenerator.Next()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
projectAgg.PushEvents(project.NewApplicationAddedEvent(ctx, oidcApp.AppID, oidcApp.AppName, resourceOwner))
|
||||
|
||||
var stringPw string
|
||||
err = oidcApp.GenerateNewClientID(r.idGenerator, proj)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
stringPw, err = oidcApp.GenerateClientSecretIfNeeded(r.applicationSecretGenerator)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
projectAgg.PushEvents(project.NewOIDCConfigAddedEvent(ctx,
|
||||
oidcApp.OIDCVersion,
|
||||
oidcApp.AppID,
|
||||
oidcApp.ClientID,
|
||||
oidcApp.ClientSecret,
|
||||
oidcApp.RedirectUris,
|
||||
oidcApp.ResponseTypes,
|
||||
oidcApp.GrantTypes,
|
||||
oidcApp.ApplicationType,
|
||||
oidcApp.AuthMethodType,
|
||||
oidcApp.PostLogoutRedirectUris,
|
||||
oidcApp.DevMode,
|
||||
oidcApp.AccessTokenType,
|
||||
oidcApp.AccessTokenRoleAssertion,
|
||||
oidcApp.IDTokenRoleAssertion,
|
||||
oidcApp.IDTokenUserinfoAssertion,
|
||||
oidcApp.ClockSkew))
|
||||
|
||||
return stringPw, nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCApp, resourceOwner string) (*domain.OIDCApp, error) {
|
||||
if !oidc.IsValid() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1m900", "Errors.Project.App.OIDCConfigInvalid")
|
||||
}
|
||||
|
||||
existingOIDC, err := r.getOIDCAppWriteModel(ctx, oidc.AggregateID, oidc.AppID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingOIDC.State == domain.AppStateUnspecified || existingOIDC.State == domain.AppStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-2n8uU", "Errors.Project.App.NotExisting")
|
||||
}
|
||||
changedEvent, hasChanged, err := existingOIDC.NewChangedEvent(
|
||||
ctx,
|
||||
oidc.AppID,
|
||||
oidc.ClientID,
|
||||
oidc.RedirectUris,
|
||||
oidc.PostLogoutRedirectUris,
|
||||
oidc.ResponseTypes,
|
||||
oidc.GrantTypes,
|
||||
oidc.ApplicationType,
|
||||
oidc.AuthMethodType,
|
||||
oidc.OIDCVersion,
|
||||
oidc.AccessTokenType,
|
||||
oidc.DevMode,
|
||||
oidc.AccessTokenRoleAssertion,
|
||||
oidc.IDTokenRoleAssertion,
|
||||
oidc.IDTokenUserinfoAssertion,
|
||||
oidc.ClockSkew)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !hasChanged {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1m88i", "Errors.NoChangesFound")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
|
||||
projectAgg.PushEvents(changedEvent)
|
||||
|
||||
err = r.eventstore.PushAggregate(ctx, existingOIDC, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := oidcWriteModelToOIDCConfig(existingOIDC)
|
||||
result.FillCompliance()
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) ChangeOIDCApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string) (*domain.OIDCApp, error) {
|
||||
if projectID == "" || appID == "" {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-99i83", "Errors.IDMissing")
|
||||
}
|
||||
|
||||
existingOIDC, err := r.getOIDCAppWriteModel(ctx, projectID, appID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingOIDC.State == domain.AppStateUnspecified || existingOIDC.State == domain.AppStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-2g66f", "Errors.Project.App.NotExisting")
|
||||
}
|
||||
cryptoSecret, stringPW, err := domain.NewClientSecret(r.applicationSecretGenerator)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
|
||||
projectAgg.PushEvents(project.NewOIDCConfigSecretChangedEvent(ctx, appID, cryptoSecret))
|
||||
|
||||
err = r.eventstore.PushAggregate(ctx, existingOIDC, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := oidcWriteModelToOIDCConfig(existingOIDC)
|
||||
result.ClientSecretString = stringPW
|
||||
return result, err
|
||||
}
|
||||
func (r *CommandSide) getOIDCAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*OIDCApplicationWriteModel, error) {
|
||||
appWriteModel := NewOIDCApplicationWriteModelWithAppIDC(projectID, appID, resourceOwner)
|
||||
err := r.eventstore.FilterToQueryReducer(ctx, appWriteModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return appWriteModel, nil
|
||||
}
|
289
internal/v2/command/project_application_oidc_model.go
Normal file
289
internal/v2/command/project_application_oidc_model.go
Normal file
@@ -0,0 +1,289 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type OIDCApplicationWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
AppID string
|
||||
AppName string
|
||||
ClientID string
|
||||
ClientSecret *crypto.CryptoValue
|
||||
ClientSecretString string
|
||||
RedirectUris []string
|
||||
ResponseTypes []domain.OIDCResponseType
|
||||
GrantTypes []domain.OIDCGrantType
|
||||
ApplicationType domain.OIDCApplicationType
|
||||
AuthMethodType domain.OIDCAuthMethodType
|
||||
PostLogoutRedirectUris []string
|
||||
OIDCVersion domain.OIDCVersion
|
||||
Compliance *domain.Compliance
|
||||
DevMode bool
|
||||
AccessTokenType domain.OIDCTokenType
|
||||
AccessTokenRoleAssertion bool
|
||||
IDTokenRoleAssertion bool
|
||||
IDTokenUserinfoAssertion bool
|
||||
ClockSkew time.Duration
|
||||
State domain.AppState
|
||||
}
|
||||
|
||||
func NewOIDCApplicationWriteModelWithAppIDC(projectID, appID, resourceOwner string) *OIDCApplicationWriteModel {
|
||||
return &OIDCApplicationWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: projectID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
AppID: appID,
|
||||
}
|
||||
}
|
||||
|
||||
func NewOIDCApplicationWriteModel(projectID, resourceOwner string) *OIDCApplicationWriteModel {
|
||||
return &OIDCApplicationWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: projectID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
}
|
||||
}
|
||||
func (wm *OIDCApplicationWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *project.ApplicationAddedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationChangedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationDeactivatedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationReactivatedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ApplicationRemovedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.OIDCConfigAddedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.OIDCConfigChangedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.OIDCConfigSecretChangedEvent:
|
||||
if e.AppID != wm.AppID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OIDCApplicationWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *project.ApplicationAddedEvent:
|
||||
wm.AppName = e.Name
|
||||
wm.State = domain.AppStateActive
|
||||
case *project.ApplicationChangedEvent:
|
||||
wm.AppName = e.Name
|
||||
case *project.ApplicationDeactivatedEvent:
|
||||
if wm.State == domain.AppStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.AppStateInactive
|
||||
case *project.ApplicationReactivatedEvent:
|
||||
if wm.State == domain.AppStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.AppStateActive
|
||||
case *project.ApplicationRemovedEvent:
|
||||
wm.State = domain.AppStateRemoved
|
||||
case *project.OIDCConfigAddedEvent:
|
||||
wm.appendAddOIDCEvent(e)
|
||||
case *project.OIDCConfigChangedEvent:
|
||||
wm.appendChangeOIDCEvent(e)
|
||||
case *project.OIDCConfigSecretChangedEvent:
|
||||
wm.ClientSecret = e.ClientSecret
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.State = domain.AppStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *OIDCApplicationWriteModel) appendAddOIDCEvent(e *project.OIDCConfigAddedEvent) {
|
||||
wm.ClientID = e.ClientID
|
||||
wm.ClientSecret = e.ClientSecret
|
||||
wm.RedirectUris = e.RedirectUris
|
||||
wm.ResponseTypes = e.ResponseTypes
|
||||
wm.GrantTypes = e.GrantTypes
|
||||
wm.ApplicationType = e.ApplicationType
|
||||
wm.AuthMethodType = e.AuthMethodType
|
||||
wm.PostLogoutRedirectUris = e.PostLogoutRedirectUris
|
||||
wm.OIDCVersion = e.Version
|
||||
wm.DevMode = e.DevMode
|
||||
wm.AccessTokenType = e.AccessTokenType
|
||||
wm.AccessTokenRoleAssertion = e.AccessTokenRoleAssertion
|
||||
wm.IDTokenRoleAssertion = e.IDTokenRoleAssertion
|
||||
wm.IDTokenUserinfoAssertion = e.IDTokenUserinfoAssertion
|
||||
wm.ClockSkew = e.ClockSkew
|
||||
}
|
||||
|
||||
func (wm *OIDCApplicationWriteModel) appendChangeOIDCEvent(e *project.OIDCConfigChangedEvent) {
|
||||
if e.ClientID != nil {
|
||||
wm.ClientID = *e.ClientID
|
||||
}
|
||||
if e.RedirectUris != nil {
|
||||
wm.RedirectUris = *e.RedirectUris
|
||||
}
|
||||
if e.ResponseTypes != nil {
|
||||
wm.ResponseTypes = *e.ResponseTypes
|
||||
}
|
||||
if e.GrantTypes != nil {
|
||||
wm.GrantTypes = *e.GrantTypes
|
||||
}
|
||||
if e.ApplicationType != nil {
|
||||
wm.ApplicationType = *e.ApplicationType
|
||||
}
|
||||
if e.AuthMethodType != nil {
|
||||
wm.AuthMethodType = *e.AuthMethodType
|
||||
}
|
||||
if e.PostLogoutRedirectUris != nil {
|
||||
wm.PostLogoutRedirectUris = *e.PostLogoutRedirectUris
|
||||
}
|
||||
if e.Version != nil {
|
||||
wm.OIDCVersion = *e.Version
|
||||
}
|
||||
if e.DevMode != nil {
|
||||
wm.DevMode = *e.DevMode
|
||||
}
|
||||
if e.AccessTokenType != nil {
|
||||
wm.AccessTokenType = *e.AccessTokenType
|
||||
}
|
||||
if e.AccessTokenRoleAssertion != nil {
|
||||
wm.AccessTokenRoleAssertion = *e.AccessTokenRoleAssertion
|
||||
}
|
||||
if e.IDTokenRoleAssertion != nil {
|
||||
wm.IDTokenRoleAssertion = *e.IDTokenRoleAssertion
|
||||
}
|
||||
if e.IDTokenUserinfoAssertion != nil {
|
||||
wm.IDTokenUserinfoAssertion = *e.IDTokenUserinfoAssertion
|
||||
}
|
||||
if e.ClockSkew != nil {
|
||||
wm.ClockSkew = *e.ClockSkew
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *OIDCApplicationWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner)
|
||||
//EventTypes(
|
||||
// project.ApplicationAddedType,
|
||||
// project.ApplicationChangedType,
|
||||
// project.ApplicationDeactivatedType,
|
||||
// project.ApplicationReactivatedType,
|
||||
// project.ApplicationRemovedType,
|
||||
// project.OIDCConfigAddedType,
|
||||
// project.OIDCConfigChangedType,
|
||||
// project.OIDCConfigSecretChangedType,
|
||||
// project.ProjectRemovedType,
|
||||
//)
|
||||
}
|
||||
|
||||
func (wm *OIDCApplicationWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
appID,
|
||||
clientID string,
|
||||
redirectURIS,
|
||||
postLogoutRedirectURIs []string,
|
||||
responseTypes []domain.OIDCResponseType,
|
||||
grantTypes []domain.OIDCGrantType,
|
||||
appType domain.OIDCApplicationType,
|
||||
authMethodType domain.OIDCAuthMethodType,
|
||||
oidcVersion domain.OIDCVersion,
|
||||
accessTokenType domain.OIDCTokenType,
|
||||
devMode,
|
||||
accessTokenRoleAssertion,
|
||||
idTokenRoleAssertion,
|
||||
idTokenUserinfoAssertion bool,
|
||||
clockSkew time.Duration,
|
||||
) (*project.OIDCConfigChangedEvent, bool, error) {
|
||||
changes := make([]project.OIDCConfigChanges, 0)
|
||||
var err error
|
||||
|
||||
if wm.ClientID != clientID {
|
||||
changes = append(changes, project.ChangeClientID(clientID))
|
||||
}
|
||||
if !reflect.DeepEqual(wm.RedirectUris, redirectURIS) {
|
||||
changes = append(changes, project.ChangeRedirectURIs(redirectURIS))
|
||||
}
|
||||
if !reflect.DeepEqual(wm.ResponseTypes, responseTypes) {
|
||||
changes = append(changes, project.ChangeResponseTypes(responseTypes))
|
||||
}
|
||||
if !reflect.DeepEqual(wm.GrantTypes, grantTypes) {
|
||||
changes = append(changes, project.ChangeGrantTypes(grantTypes))
|
||||
}
|
||||
if wm.ApplicationType != appType {
|
||||
changes = append(changes, project.ChangeApplicationType(appType))
|
||||
}
|
||||
if wm.AuthMethodType != authMethodType {
|
||||
changes = append(changes, project.ChangeAuthMethodType(authMethodType))
|
||||
}
|
||||
if !reflect.DeepEqual(wm.PostLogoutRedirectUris, postLogoutRedirectURIs) {
|
||||
changes = append(changes, project.ChangePostLogoutRedirectURIs(postLogoutRedirectURIs))
|
||||
}
|
||||
if wm.OIDCVersion != oidcVersion {
|
||||
changes = append(changes, project.ChangeVersion(oidcVersion))
|
||||
}
|
||||
if wm.DevMode != devMode {
|
||||
changes = append(changes, project.ChangeDevMode(devMode))
|
||||
}
|
||||
if wm.AccessTokenType != accessTokenType {
|
||||
changes = append(changes, project.ChangeAccessTokenType(accessTokenType))
|
||||
}
|
||||
if wm.AccessTokenRoleAssertion != accessTokenRoleAssertion {
|
||||
changes = append(changes, project.ChangeAccessTokenRoleAssertion(accessTokenRoleAssertion))
|
||||
}
|
||||
if wm.IDTokenRoleAssertion != idTokenRoleAssertion {
|
||||
changes = append(changes, project.ChangeIDTokenRoleAssertion(idTokenRoleAssertion))
|
||||
}
|
||||
if wm.IDTokenUserinfoAssertion != idTokenUserinfoAssertion {
|
||||
changes = append(changes, project.ChangeIDTokenUserinfoAssertion(idTokenUserinfoAssertion))
|
||||
}
|
||||
if wm.ClockSkew != clockSkew {
|
||||
changes = append(changes, project.ChangeClockSkew(clockSkew))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
changeEvent, err := project.NewOIDCConfigChangedEvent(ctx, appID, changes)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return changeEvent, true, nil
|
||||
}
|
@@ -13,13 +13,62 @@ func projectWriteModelToProject(writeModel *ProjectWriteModel) *domain.Project {
|
||||
}
|
||||
}
|
||||
|
||||
func applicationWriteModelToApplication(writeModel *ApplicationWriteModel) *domain.Application {
|
||||
return &domain.Application{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
AppID: writeModel.AggregateID,
|
||||
State: writeModel.State,
|
||||
Name: writeModel.Name,
|
||||
Type: writeModel.Type,
|
||||
//TODO: OIDC Config
|
||||
func projectGrantWriteModelToProjectGrant(writeModel *ProjectGrantWriteModel) *domain.ProjectGrant {
|
||||
return &domain.ProjectGrant{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
GrantID: writeModel.GrantID,
|
||||
GrantedOrgID: writeModel.GrantedOrgID,
|
||||
RoleKeys: writeModel.RoleKeys,
|
||||
State: writeModel.State,
|
||||
}
|
||||
}
|
||||
|
||||
func applicationWriteModelToApplication(writeModel *ApplicationWriteModel) domain.Application {
|
||||
return &domain.ChangeApp{
|
||||
AppID: writeModel.AppID,
|
||||
AppName: writeModel.Name,
|
||||
State: writeModel.State,
|
||||
}
|
||||
}
|
||||
|
||||
func oidcWriteModelToOIDCConfig(writeModel *OIDCApplicationWriteModel) *domain.OIDCApp {
|
||||
return &domain.OIDCApp{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
AppID: writeModel.AggregateID,
|
||||
AppName: writeModel.AppName,
|
||||
State: writeModel.State,
|
||||
ClientID: writeModel.ClientID,
|
||||
ClientSecret: writeModel.ClientSecret,
|
||||
RedirectUris: writeModel.RedirectUris,
|
||||
ResponseTypes: writeModel.ResponseTypes,
|
||||
GrantTypes: writeModel.GrantTypes,
|
||||
ApplicationType: writeModel.ApplicationType,
|
||||
AuthMethodType: writeModel.AuthMethodType,
|
||||
PostLogoutRedirectUris: writeModel.PostLogoutRedirectUris,
|
||||
OIDCVersion: writeModel.OIDCVersion,
|
||||
DevMode: writeModel.DevMode,
|
||||
AccessTokenType: writeModel.AccessTokenType,
|
||||
AccessTokenRoleAssertion: writeModel.AccessTokenRoleAssertion,
|
||||
IDTokenRoleAssertion: writeModel.IDTokenRoleAssertion,
|
||||
IDTokenUserinfoAssertion: writeModel.IDTokenUserinfoAssertion,
|
||||
ClockSkew: writeModel.ClockSkew,
|
||||
}
|
||||
}
|
||||
|
||||
func roleWriteModelToRole(writeModel *ProjectRoleWriteModel) *domain.ProjectRole {
|
||||
return &domain.ProjectRole{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
Key: writeModel.Key,
|
||||
DisplayName: writeModel.DisplayName,
|
||||
Group: writeModel.Group,
|
||||
}
|
||||
}
|
||||
|
||||
func memberWriteModelToProjectGrantMember(writeModel *ProjectGrantMemberWriteModel) *domain.ProjectGrantMember {
|
||||
return &domain.ProjectGrantMember{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
Roles: writeModel.Roles,
|
||||
GrantID: writeModel.GrantID,
|
||||
UserID: writeModel.UserID,
|
||||
}
|
||||
}
|
||||
|
145
internal/v2/command/project_grant.go
Normal file
145
internal/v2/command/project_grant.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func (r *CommandSide) AddProjectGrant(ctx context.Context, grant *domain.ProjectGrant, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
if !grant.IsValid() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-Bff2g", "Errors.Project.Grant.Invalid")
|
||||
}
|
||||
grant.GrantID, err = r.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = r.checkProjectExists(ctx, grant.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = r.checkOrgExists(ctx, grant.GrantedOrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedGrant := NewProjectGrantWriteModel(grant.GrantID, grant.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedGrant.WriteModel)
|
||||
|
||||
projectAgg.PushEvents(project.NewGrantAddedEvent(ctx, grant.GrantID, grant.GrantedOrgID, grant.AggregateID, grant.RoleKeys))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = r.eventstore.PushAggregate(ctx, addedGrant, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return projectGrantWriteModelToProjectGrant(addedGrant), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) ChangeProjectGrant(ctx context.Context, grant *domain.ProjectGrant, resourceOwner string) (_ *domain.ProjectGrant, err error) {
|
||||
if grant.GrantID == "" {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-1j83s", "Errors.IDMissing")
|
||||
}
|
||||
err = r.checkProjectExists(ctx, grant.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
existingGrant, err := r.projectGrantWriteModelByID(ctx, grant.GrantID, grant.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
|
||||
if reflect.DeepEqual(existingGrant.RoleKeys, grant.RoleKeys) {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-0o0pL", "Errors.NoChangesFoundc")
|
||||
}
|
||||
projectAgg.PushEvents(project.NewGrantChangedEvent(ctx, grant.GrantID, grant.RoleKeys))
|
||||
//TODO: Change UserGrants (if role removed should be removed from user grant)
|
||||
err = r.eventstore.PushAggregate(ctx, existingGrant, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return projectGrantWriteModelToProjectGrant(existingGrant), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) DeactivateProjectGrant(ctx context.Context, projectID, grantID, resourceOwner string) (err error) {
|
||||
if grantID == "" || projectID == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-p0s4V", "Errors.IDMissing")
|
||||
}
|
||||
err = r.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingGrant, err := r.projectGrantWriteModelByID(ctx, grantID, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingGrant.State != domain.ProjectGrantStateActive {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-47fu8", "Errors.Project.Grant.NotActive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
|
||||
projectAgg.PushEvents(project.NewGrantDeactivateEvent(ctx, grantID))
|
||||
return r.eventstore.PushAggregate(ctx, existingGrant, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) ReactivateProjectGrant(ctx context.Context, projectID, grantID, resourceOwner string) (err error) {
|
||||
if grantID == "" || projectID == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-p0s4V", "Errors.IDMissing")
|
||||
}
|
||||
err = r.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingGrant, err := r.projectGrantWriteModelByID(ctx, grantID, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingGrant.State != domain.ProjectGrantStateInactive {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-47fu8", "Errors.Project.Grant.NotInactive")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
projectAgg.PushEvents(project.NewGrantReactivatedEvent(ctx, grantID))
|
||||
return r.eventstore.PushAggregate(ctx, existingGrant, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) RemoveProjectGrant(ctx context.Context, projectID, grantID, resourceOwner string) (err error) {
|
||||
if grantID == "" || projectID == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-1m9fJ", "Errors.IDMissing")
|
||||
}
|
||||
err = r.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
existingGrant, err := r.projectGrantWriteModelByID(ctx, grantID, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingGrant.WriteModel)
|
||||
projectAgg.PushEvents(project.NewGrantRemovedEvent(ctx, grantID, existingGrant.GrantedOrgID, projectID))
|
||||
//TODO: Cascade Remove usergrants
|
||||
return r.eventstore.PushAggregate(ctx, existingGrant, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) projectGrantWriteModelByID(ctx context.Context, grantID, projectID, resourceOwner string) (member *ProjectGrantWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel := NewProjectGrantWriteModel(grantID, projectID, resourceOwner)
|
||||
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if writeModel.State == domain.ProjectGrantStateUnspecified || writeModel.State == domain.ProjectGrantStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "PROJECT-D8JxR", "Errors.Project.Grant.NotFound")
|
||||
}
|
||||
|
||||
return writeModel, nil
|
||||
}
|
100
internal/v2/command/project_grant_member.go
Normal file
100
internal/v2/command/project_grant_member.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/telemetry/tracing"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
)
|
||||
|
||||
func (r *CommandSide) AddProjectGrantMember(ctx context.Context, member *domain.ProjectGrantMember, resourceOwner string) (*domain.ProjectGrantMember, error) {
|
||||
if !member.IsValid() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-8fi7G", "Errors.Project.Member.Invalid")
|
||||
}
|
||||
err := r.checkUserExists(ctx, member.UserID, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedMember := NewProjectGrantMemberWriteModel(member.AggregateID, member.UserID, member.GrantID)
|
||||
err = r.eventstore.FilterToQueryReducer(ctx, addedMember)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if addedMember.State == domain.MemberStateActive {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-16dVN", "Errors.Project.Member.AlreadyExists")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedMember.WriteModel)
|
||||
projectAgg.PushEvents(project.NewProjectGrantMemberAddedEvent(ctx, member.AggregateID, member.UserID, member.GrantID, member.Roles...))
|
||||
|
||||
err = r.eventstore.PushAggregate(ctx, addedMember, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return memberWriteModelToProjectGrantMember(addedMember), nil
|
||||
}
|
||||
|
||||
//ChangeProjectGrantMember updates an existing member
|
||||
func (r *CommandSide) ChangeProjectGrantMember(ctx context.Context, member *domain.ProjectGrantMember, resourceOwner string) (*domain.ProjectGrantMember, error) {
|
||||
//TODO: check if roles valid
|
||||
|
||||
if !member.IsValid() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-109fs", "Errors.Project.Member.Invalid")
|
||||
}
|
||||
|
||||
existingMember, err := r.projectGrantMemberWriteModelByID(ctx, member.AggregateID, member.UserID, member.GrantID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(existingMember.Roles, member.Roles) {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-2n8vx", "Errors.Project.Member.RolesNotChanged")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingMember.WriteModel)
|
||||
projectAgg.PushEvents(project.NewProjectGrantMemberChangedEvent(ctx, member.UserID, member.GrantID, member.Roles...))
|
||||
|
||||
events, err := r.eventstore.PushAggregates(ctx, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingMember.AppendEvents(events...)
|
||||
if err = existingMember.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return memberWriteModelToProjectGrantMember(existingMember), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) RemoveProjectGrantMember(ctx context.Context, projectID, userID, grantID, resourceOwner string) error {
|
||||
m, err := r.projectGrantMemberWriteModelByID(ctx, projectID, userID, grantID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&m.WriteModel)
|
||||
projectAgg.PushEvents(project.NewProjectGrantMemberRemovedEvent(ctx, projectID, userID, grantID))
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, m, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) projectGrantMemberWriteModelByID(ctx context.Context, projectID, userID, grantID string) (member *ProjectGrantMemberWriteModel, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
writeModel := NewProjectGrantMemberWriteModel(projectID, userID, grantID)
|
||||
err = r.eventstore.FilterToQueryReducer(ctx, writeModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if writeModel.State == domain.MemberStateUnspecified || writeModel.State == domain.MemberStateRemoved {
|
||||
return nil, errors.ThrowNotFound(nil, "PROJECT-37fug", "Errors.NotFound")
|
||||
}
|
||||
|
||||
return writeModel, nil
|
||||
}
|
82
internal/v2/command/project_grant_member_model.go
Normal file
82
internal/v2/command/project_grant_member_model.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
)
|
||||
|
||||
type ProjectGrantMemberWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
GrantID string
|
||||
UserID string
|
||||
Roles []string
|
||||
|
||||
State domain.MemberState
|
||||
}
|
||||
|
||||
func NewProjectGrantMemberWriteModel(projectID, userID, grantID string) *ProjectGrantMemberWriteModel {
|
||||
return &ProjectGrantMemberWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: projectID,
|
||||
},
|
||||
UserID: userID,
|
||||
GrantID: grantID,
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *ProjectGrantMemberWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *project.GrantMemberAddedEvent:
|
||||
if e.UserID != wm.UserID || e.GrantID != wm.GrantID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.GrantMemberChangedEvent:
|
||||
if e.UserID != wm.UserID || e.GrantID != wm.GrantID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.GrantMemberRemovedEvent:
|
||||
if e.UserID != wm.UserID || e.GrantID != wm.GrantID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
case *project.GrantRemovedEvent:
|
||||
if e.GrantID != wm.GrantID {
|
||||
continue
|
||||
}
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *ProjectGrantMemberWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *project.GrantMemberAddedEvent:
|
||||
wm.Roles = e.Roles
|
||||
wm.State = domain.MemberStateActive
|
||||
case *project.GrantMemberChangedEvent:
|
||||
wm.Roles = e.Roles
|
||||
case *project.GrantMemberRemovedEvent:
|
||||
wm.State = domain.MemberStateRemoved
|
||||
case *project.GrantRemovedEvent, *project.ProjectRemovedEvent:
|
||||
wm.State = domain.MemberStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *ProjectGrantMemberWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
|
||||
AggregateIDs(wm.AggregateID)
|
||||
//EventTypes(
|
||||
// project.GrantMemberAddedType,
|
||||
// project.GrantMemberChangedType,
|
||||
// project.GrantMemberRemovedType,
|
||||
// project.GrantRemovedType,
|
||||
// project.ProjectRemovedType)
|
||||
}
|
104
internal/v2/command/project_grant_model.go
Normal file
104
internal/v2/command/project_grant_model.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
)
|
||||
|
||||
type ProjectGrantWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
GrantID string
|
||||
GrantedOrgID string
|
||||
RoleKeys []string
|
||||
State domain.ProjectGrantState
|
||||
}
|
||||
|
||||
func NewProjectGrantWriteModel(grantID, projectID, resourceOwner string) *ProjectGrantWriteModel {
|
||||
return &ProjectGrantWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: projectID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
GrantID: grantID,
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *ProjectGrantWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *project.GrantAddedEvent:
|
||||
if e.GrantID == wm.GrantID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.GrantChangedEvent:
|
||||
if e.GrantID == wm.GrantID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.GrantCascadeChangedEvent:
|
||||
if e.GrantID == wm.GrantID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.GrantDeactivateEvent:
|
||||
if e.GrantID == wm.GrantID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.GrantReactivatedEvent:
|
||||
if e.GrantID == wm.GrantID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.GrantRemovedEvent:
|
||||
if e.GrantID == wm.GrantID {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *ProjectGrantWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *project.GrantAddedEvent:
|
||||
wm.GrantID = e.GrantID
|
||||
wm.GrantedOrgID = e.GrantedOrgID
|
||||
wm.RoleKeys = e.RoleKeys
|
||||
wm.State = domain.ProjectGrantStateActive
|
||||
case *project.GrantChangedEvent:
|
||||
wm.RoleKeys = e.RoleKeys
|
||||
case *project.GrantCascadeChangedEvent:
|
||||
wm.RoleKeys = e.RoleKeys
|
||||
case *project.GrantDeactivateEvent:
|
||||
if wm.State == domain.ProjectGrantStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.ProjectGrantStateInactive
|
||||
case *project.GrantReactivatedEvent:
|
||||
if wm.State == domain.ProjectGrantStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.ProjectGrantStateActive
|
||||
case *project.GrantRemovedEvent:
|
||||
wm.State = domain.ProjectGrantStateRemoved
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.State = domain.ProjectGrantStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *ProjectGrantWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner)
|
||||
//EventTypes(
|
||||
// project.GrantAddedType,
|
||||
// project.GrantChangedType,
|
||||
// project.GrantCascadeChangedType,
|
||||
// project.GrantDeactivatedType,
|
||||
// project.GrantReactivatedType,
|
||||
// project.GrantRemovedType,
|
||||
// project.ProjectRemovedType)
|
||||
}
|
@@ -31,10 +31,14 @@ func (r *CommandSide) addProjectMember(ctx context.Context, projectAgg *project.
|
||||
//TODO: check if roles valid
|
||||
|
||||
if !member.IsValid() {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-W8m4l", "Errors.Project.MemberInvalid")
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "PROJECT-W8m4l", "Errors.Project.Member.Invalid")
|
||||
}
|
||||
|
||||
err := r.eventstore.FilterToQueryReducer(ctx, addedMember)
|
||||
err := r.checkUserExists(ctx, addedMember.UserID, "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = r.eventstore.FilterToQueryReducer(ctx, addedMember)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -42,7 +46,7 @@ func (r *CommandSide) addProjectMember(ctx context.Context, projectAgg *project.
|
||||
return errors.ThrowAlreadyExists(nil, "PROJECT-PtXi1", "Errors.Project.Member.AlreadyExists")
|
||||
}
|
||||
|
||||
projectAgg.PushEvents(project.NewMemberAddedEvent(ctx, member.UserID, member.Roles...))
|
||||
projectAgg.PushEvents(project.NewProjectMemberAddedEvent(ctx, member.UserID, member.Roles...))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -52,7 +56,7 @@ func (r *CommandSide) ChangeProjectMember(ctx context.Context, member *domain.Me
|
||||
//TODO: check if roles valid
|
||||
|
||||
if !member.IsValid() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-LiaZi", "Errors.Project.MemberInvalid")
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-LiaZi", "Errors.Project.Member.Invalid")
|
||||
}
|
||||
|
||||
existingMember, err := r.projectMemberWriteModelByID(ctx, member.AggregateID, member.UserID, resourceOwner)
|
||||
@@ -64,7 +68,7 @@ func (r *CommandSide) ChangeProjectMember(ctx context.Context, member *domain.Me
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "PROJECT-LiaZi", "Errors.Project.Member.RolesNotChanged")
|
||||
}
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingMember.MemberWriteModel.WriteModel)
|
||||
projectAgg.PushEvents(project.NewMemberChangedEvent(ctx, member.UserID, member.Roles...))
|
||||
projectAgg.PushEvents(project.NewProjectMemberChangedEvent(ctx, member.UserID, member.Roles...))
|
||||
|
||||
events, err := r.eventstore.PushAggregates(ctx, projectAgg)
|
||||
if err != nil {
|
||||
@@ -89,7 +93,7 @@ func (r *CommandSide) RemoveProjectMember(ctx context.Context, projectID, userID
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&m.MemberWriteModel.WriteModel)
|
||||
projectAgg.PushEvents(project.NewMemberRemovedEvent(ctx, userID))
|
||||
projectAgg.PushEvents(project.NewProjectMemberRemovedEvent(ctx, userID))
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, m, projectAgg)
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
@@ -33,12 +34,34 @@ func (wm *ProjectWriteModel) Reduce() error {
|
||||
switch e := event.(type) {
|
||||
case *project.ProjectAddedEvent:
|
||||
wm.Name = e.Name
|
||||
wm.ProjectRoleAssertion = e.ProjectRoleAssertion
|
||||
wm.ProjectRoleCheck = e.ProjectRoleCheck
|
||||
wm.State = domain.ProjectStateActive
|
||||
//case *project.ProjectChangedEvent:
|
||||
// wm.Name = e.Name
|
||||
case *project.ProjectChangeEvent:
|
||||
if e.Name != nil {
|
||||
wm.Name = *e.Name
|
||||
}
|
||||
if e.ProjectRoleAssertion != nil {
|
||||
wm.ProjectRoleAssertion = *e.ProjectRoleAssertion
|
||||
}
|
||||
if e.ProjectRoleCheck != nil {
|
||||
wm.ProjectRoleCheck = *e.ProjectRoleCheck
|
||||
}
|
||||
case *project.ProjectDeactivatedEvent:
|
||||
if wm.State == domain.ProjectStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.ProjectStateInactive
|
||||
case *project.ProjectReactivatedEvent:
|
||||
if wm.State == domain.ProjectStateRemoved {
|
||||
continue
|
||||
}
|
||||
wm.State = domain.ProjectStateActive
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.State = domain.ProjectStateRemoved
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *ProjectWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
@@ -47,6 +70,34 @@ func (wm *ProjectWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
ResourceOwner(wm.ResourceOwner)
|
||||
}
|
||||
|
||||
func (wm *ProjectWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
name string,
|
||||
projectRoleAssertion,
|
||||
projectRoleCheck bool,
|
||||
) (*project.ProjectChangeEvent, bool, error) {
|
||||
changes := make([]project.ProjectChanges, 0)
|
||||
var err error
|
||||
|
||||
if wm.Name != name {
|
||||
changes = append(changes, project.ChangeName(name))
|
||||
}
|
||||
if wm.ProjectRoleAssertion != projectRoleAssertion {
|
||||
changes = append(changes, project.ChangeProjectRoleAssertion(projectRoleAssertion))
|
||||
}
|
||||
if wm.ProjectRoleCheck != projectRoleCheck {
|
||||
changes = append(changes, project.ChangeProjectRoleCheck(projectRoleCheck))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
changeEvent, err := project.NewProjectChangeEvent(ctx, changes)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return changeEvent, true, nil
|
||||
}
|
||||
|
||||
func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *project.Aggregate {
|
||||
return &project.Aggregate{
|
||||
Aggregate: *eventstore.AggregateFromWriteModel(wm, project.AggregateType, project.AggregateVersion),
|
||||
|
121
internal/v2/command/project_role.go
Normal file
121
internal/v2/command/project_role.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
)
|
||||
|
||||
func (r *CommandSide) AddProjectRole(ctx context.Context, projectRole *domain.ProjectRole, resourceOwner string) (_ *domain.ProjectRole, err error) {
|
||||
err = r.checkProjectExists(ctx, projectRole.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
roleWriteModel := NewProjectRoleWriteModelWithKey(projectRole.Key, projectRole.AggregateID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
|
||||
r.addProjectRoles(ctx, projectAgg, projectRole.AggregateID, resourceOwner, projectRole)
|
||||
|
||||
err = r.eventstore.PushAggregate(ctx, roleWriteModel, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleWriteModelToRole(roleWriteModel), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) BulkAddProjectRole(ctx context.Context, projectID, resourceOwner string, projectRoles []*domain.ProjectRole) (err error) {
|
||||
err = r.checkProjectExists(ctx, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
roleWriteModel := NewProjectRoleWriteModel(projectID, resourceOwner)
|
||||
projectAgg := ProjectAggregateFromWriteModel(&roleWriteModel.WriteModel)
|
||||
r.addProjectRoles(ctx, projectAgg, projectID, resourceOwner, projectRoles...)
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, roleWriteModel, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) addProjectRoles(ctx context.Context, projectAgg *project.Aggregate, projectID, resourceOwner string, projectRoles ...*domain.ProjectRole) error {
|
||||
for _, projectRole := range projectRoles {
|
||||
if !projectRole.IsValid() {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
}
|
||||
projectAgg.PushEvents(
|
||||
project.NewRoleAddedEvent(
|
||||
ctx,
|
||||
projectRole.Key,
|
||||
projectRole.DisplayName,
|
||||
projectRole.Group,
|
||||
projectID,
|
||||
resourceOwner,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) ChangeProjectRole(ctx context.Context, projectRole *domain.ProjectRole, resourceOwner string) (_ *domain.ProjectRole, err error) {
|
||||
if !projectRole.IsValid() {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
||||
}
|
||||
err = r.checkProjectExists(ctx, projectRole.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existingRole, err := r.getProjectRoleWriteModelByID(ctx, projectRole.Key, projectRole.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if existingRole.State == domain.ProjectRoleStateUnspecified || existingRole.State == domain.ProjectRoleStateRemoved {
|
||||
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-vv8M9", "Errors.Project.Role.NotExisting")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
|
||||
|
||||
changeEvent, changed, err := existingRole.NewProjectRoleChangedEvent(ctx, projectRole.Key, projectRole.DisplayName, projectRole.Group)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !changed {
|
||||
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M0cs", "Errors.NoChangesFound")
|
||||
}
|
||||
projectAgg.PushEvents(changeEvent)
|
||||
|
||||
err = r.eventstore.PushAggregate(ctx, existingRole, projectAgg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return roleWriteModelToRole(existingRole), nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) RemoveProjectRole(ctx context.Context, projectID, key, resourceOwner string) (err error) {
|
||||
if projectID == "" || key == "" {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4m9vS", "Errors.Project.Role.Invalid")
|
||||
}
|
||||
existingRole, err := r.getProjectRoleWriteModelByID(ctx, key, projectID, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existingRole.State == domain.ProjectRoleStateUnspecified || existingRole.State == domain.ProjectRoleStateRemoved {
|
||||
return caos_errs.ThrowNotFound(nil, "COMMAND-m9vMf", "Errors.Project.Role.NotExisting")
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingRole.WriteModel)
|
||||
projectAgg.PushEvents(project.NewRoleRemovedEvent(ctx, key, projectID, existingRole.ResourceOwner))
|
||||
//TODO: Update UserGrants (remove roles if on usergrants)
|
||||
|
||||
return r.eventstore.PushAggregate(ctx, existingRole, projectAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) getProjectRoleWriteModelByID(ctx context.Context, key, projectID, resourceOwner string) (*ProjectRoleWriteModel, error) {
|
||||
projectRoleWriteModel := NewProjectRoleWriteModelWithKey(key, projectID, resourceOwner)
|
||||
err := r.eventstore.FilterToQueryReducer(ctx, projectRoleWriteModel)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return projectRoleWriteModel, nil
|
||||
}
|
121
internal/v2/command/project_role_model.go
Normal file
121
internal/v2/command/project_role_model.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
"github.com/caos/zitadel/internal/v2/repository/project"
|
||||
)
|
||||
|
||||
type ProjectRoleWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
Key string
|
||||
DisplayName string
|
||||
Group string
|
||||
State domain.ProjectRoleState
|
||||
}
|
||||
|
||||
func NewProjectRoleWriteModelWithKey(key, projectID, resourceOwner string) *ProjectRoleWriteModel {
|
||||
return &ProjectRoleWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: projectID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
Key: key,
|
||||
}
|
||||
}
|
||||
|
||||
func NewProjectRoleWriteModel(projectID, resourceOwner string) *ProjectRoleWriteModel {
|
||||
return &ProjectRoleWriteModel{
|
||||
WriteModel: eventstore.WriteModel{
|
||||
AggregateID: projectID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *ProjectRoleWriteModel) AppendEvents(events ...eventstore.EventReader) {
|
||||
for _, event := range events {
|
||||
switch e := event.(type) {
|
||||
case *project.RoleAddedEvent:
|
||||
if e.Key == wm.Key {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.RoleChangedEvent:
|
||||
if e.Key == wm.Key {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.RoleRemovedEvent:
|
||||
if e.Key == wm.Key {
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.WriteModel.AppendEvents(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *ProjectRoleWriteModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *project.RoleAddedEvent:
|
||||
wm.Key = e.Key
|
||||
wm.DisplayName = e.DisplayName
|
||||
wm.Group = e.Group
|
||||
wm.State = domain.ProjectRoleStateActive
|
||||
case *project.RoleChangedEvent:
|
||||
wm.Key = e.Key
|
||||
if e.DisplayName != nil {
|
||||
wm.DisplayName = *e.DisplayName
|
||||
}
|
||||
if e.Group != nil {
|
||||
wm.Group = *e.Group
|
||||
}
|
||||
case *project.RoleRemovedEvent:
|
||||
wm.State = domain.ProjectRoleStateRemoved
|
||||
case *project.ProjectRemovedEvent:
|
||||
wm.State = domain.ProjectRoleStateRemoved
|
||||
}
|
||||
}
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *ProjectRoleWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
//types := []eventstore.EventType{
|
||||
// project.RoleAddedType,
|
||||
// project.RoleChangedType,
|
||||
// project.RoleRemovedType,
|
||||
// project.ProjectRemovedType,
|
||||
//}
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner)
|
||||
//EventTypes(types...)
|
||||
}
|
||||
|
||||
func (wm *ProjectRoleWriteModel) NewProjectRoleChangedEvent(
|
||||
ctx context.Context,
|
||||
key,
|
||||
displayName,
|
||||
group string,
|
||||
) (*project.RoleChangedEvent, bool, error) {
|
||||
changes := make([]project.RoleChanges, 0)
|
||||
var err error
|
||||
changes = append(changes, project.ChangeKey(key))
|
||||
|
||||
if wm.DisplayName != displayName {
|
||||
changes = append(changes, project.ChangeDisplayName(displayName))
|
||||
}
|
||||
if wm.Group != group {
|
||||
changes = append(changes, project.ChangeGroup(group))
|
||||
}
|
||||
if len(changes) == 0 {
|
||||
return nil, false, nil
|
||||
}
|
||||
changeEvent, err := project.NewRoleChangedEvent(ctx, changes)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
return changeEvent, true, nil
|
||||
}
|
@@ -2,11 +2,11 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
caos_errs "github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
iam_repo "github.com/caos/zitadel/internal/v2/repository/iam"
|
||||
@@ -159,7 +159,7 @@ func (r *CommandSide) SetupStep1(ctx context.Context, step1 *Step1) error {
|
||||
}
|
||||
//create applications
|
||||
for _, app := range proj.OIDCApps {
|
||||
err = setUpApplication(ctx, r, projectAgg, project, app)
|
||||
err = setUpApplication(ctx, r, projectAgg, project, app, orgAgg.ID())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -177,27 +177,25 @@ func (r *CommandSide) SetupStep1(ctx context.Context, step1 *Step1) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func setUpApplication(ctx context.Context, r *CommandSide, projectAgg *project.Aggregate, project *domain.Project, oidcApp OIDCApp) error {
|
||||
app := &domain.Application{
|
||||
func setUpApplication(ctx context.Context, r *CommandSide, projectAgg *project.Aggregate, project *domain.Project, oidcApp OIDCApp, resourceOwner string) error {
|
||||
app := &domain.OIDCApp{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: projectAgg.ID(),
|
||||
},
|
||||
Name: oidcApp.Name,
|
||||
Type: domain.AppTypeOIDC,
|
||||
OIDCConfig: &domain.OIDCConfig{
|
||||
RedirectUris: oidcApp.RedirectUris,
|
||||
ResponseTypes: getOIDCResponseTypes(oidcApp.ResponseTypes),
|
||||
GrantTypes: getOIDCGrantTypes(oidcApp.GrantTypes),
|
||||
ApplicationType: getOIDCApplicationType(oidcApp.ApplicationType),
|
||||
AuthMethodType: getOIDCAuthMethod(oidcApp.AuthMethodType),
|
||||
DevMode: oidcApp.DevMode,
|
||||
},
|
||||
AppName: oidcApp.Name,
|
||||
RedirectUris: oidcApp.RedirectUris,
|
||||
ResponseTypes: getOIDCResponseTypes(oidcApp.ResponseTypes),
|
||||
GrantTypes: getOIDCGrantTypes(oidcApp.GrantTypes),
|
||||
ApplicationType: getOIDCApplicationType(oidcApp.ApplicationType),
|
||||
AuthMethodType: getOIDCAuthMethod(oidcApp.AuthMethodType),
|
||||
DevMode: oidcApp.DevMode,
|
||||
}
|
||||
err := r.addApplication(ctx, projectAgg, project, app)
|
||||
|
||||
_, err := r.addOIDCApplication(ctx, projectAgg, project, app, resourceOwner)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logging.LogWithFields("SETUP-Edgw4", "name", app.Name, "clientID", app.OIDCConfig.ClientID).Info("application set up")
|
||||
logging.LogWithFields("SETUP-Edgw4", "name", app.AppName, "clientID", app.ClientID).Info("application set up")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -139,12 +139,15 @@ func (r *CommandSide) RemoveUser(ctx context.Context, userID, resourceOwner stri
|
||||
return r.eventstore.PushAggregate(ctx, existingUser, userAgg)
|
||||
}
|
||||
|
||||
func (r *CommandSide) checkUserExists(ctx context.Context, userID, resourceOwner string) (bool, error) {
|
||||
func (r *CommandSide) checkUserExists(ctx context.Context, userID, resourceOwner string) error {
|
||||
userWriteModel, err := r.userWriteModelByID(ctx, userID, resourceOwner)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return err
|
||||
}
|
||||
return userWriteModel.UserState != domain.UserStateUnspecified && userWriteModel.UserState != domain.UserStateDeleted, nil
|
||||
if userWriteModel.UserState == domain.UserStateUnspecified || userWriteModel.UserState == domain.UserStateDeleted {
|
||||
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0fs", "Errors.User.NotFound")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CommandSide) userWriteModelByID(ctx context.Context, userID, resourceOwner string) (writeModel *UserWriteModel, err error) {
|
||||
|
@@ -31,13 +31,10 @@ func (r *CommandSide) addUserGrant(ctx context.Context, userGrant *domain.UserGr
|
||||
if !userGrant.IsValid() {
|
||||
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0fs", "Errors.UserGrant.Invalid")
|
||||
}
|
||||
exists, err := r.checkUserExists(ctx, userGrant.UserID, resourceOwner)
|
||||
err = r.checkUserExists(ctx, userGrant.UserID, "")
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if !exists {
|
||||
return nil, nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-4M0fs", "Errors.User.NotFound")
|
||||
}
|
||||
err = r.checkProjectExists(ctx, userGrant.ProjectID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@@ -58,7 +58,7 @@ func (wm *UserGrantWriteModel) Reduce() error {
|
||||
wm.State = domain.UserGrantStateRemoved
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return wm.WriteModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *UserGrantWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
|
@@ -68,9 +68,12 @@ func (wm *UserWriteModel) Reduce() error {
|
||||
}
|
||||
|
||||
func (wm *UserWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
ResourceOwner(wm.ResourceOwner)
|
||||
query := eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, user.AggregateType).
|
||||
AggregateIDs(wm.AggregateID)
|
||||
if wm.ResourceOwner != "" {
|
||||
query.ResourceOwner(wm.ResourceOwner)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func UserAggregateFromWriteModel(wm *eventstore.WriteModel) *user.Aggregate {
|
||||
|
@@ -1,17 +1,9 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type Application struct {
|
||||
models.ObjectRoot
|
||||
|
||||
AppID string
|
||||
State AppState
|
||||
Name string
|
||||
Type AppType
|
||||
OIDCConfig *OIDCConfig
|
||||
type Application interface {
|
||||
GetAppID() string
|
||||
GetApplicationName() string
|
||||
GetState() AppState
|
||||
}
|
||||
|
||||
type AppState int32
|
||||
@@ -23,27 +15,20 @@ const (
|
||||
AppStateRemoved
|
||||
)
|
||||
|
||||
type AppType int32
|
||||
|
||||
const (
|
||||
AppTypeUnspecified AppType = iota
|
||||
AppTypeOIDC
|
||||
AppTypeSAML
|
||||
)
|
||||
|
||||
func NewApplication(projectID, appID string) *Application {
|
||||
return &Application{ObjectRoot: models.ObjectRoot{AggregateID: projectID}, AppID: appID, State: AppStateActive}
|
||||
type ChangeApp struct {
|
||||
AppID string
|
||||
AppName string
|
||||
State AppState
|
||||
}
|
||||
|
||||
func (a *Application) IsValid(includeConfig bool) bool {
|
||||
if a.Name == "" || a.AggregateID == "" {
|
||||
return false
|
||||
}
|
||||
if !includeConfig {
|
||||
return true
|
||||
}
|
||||
if a.Type == AppTypeOIDC && !a.OIDCConfig.IsValid() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
func (a *ChangeApp) GetAppID() string {
|
||||
return a.AppID
|
||||
}
|
||||
|
||||
func (a *ChangeApp) GetApplicationName() string {
|
||||
return a.AppName
|
||||
}
|
||||
|
||||
func (a *ChangeApp) GetState() AppState {
|
||||
return a.State
|
||||
}
|
||||
|
327
internal/v2/domain/application_oidc.go
Normal file
327
internal/v2/domain/application_oidc.go
Normal file
@@ -0,0 +1,327 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
)
|
||||
|
||||
const (
|
||||
http = "http://"
|
||||
httpLocalhost = "http://localhost:"
|
||||
httpLocalhost2 = "http://localhost/"
|
||||
https = "https://"
|
||||
)
|
||||
|
||||
type OIDCApp struct {
|
||||
models.ObjectRoot
|
||||
|
||||
AppID string
|
||||
AppName string
|
||||
ClientID string
|
||||
ClientSecret *crypto.CryptoValue
|
||||
ClientSecretString string
|
||||
RedirectUris []string
|
||||
ResponseTypes []OIDCResponseType
|
||||
GrantTypes []OIDCGrantType
|
||||
ApplicationType OIDCApplicationType
|
||||
AuthMethodType OIDCAuthMethodType
|
||||
PostLogoutRedirectUris []string
|
||||
OIDCVersion OIDCVersion
|
||||
Compliance *Compliance
|
||||
DevMode bool
|
||||
AccessTokenType OIDCTokenType
|
||||
AccessTokenRoleAssertion bool
|
||||
IDTokenRoleAssertion bool
|
||||
IDTokenUserinfoAssertion bool
|
||||
ClockSkew time.Duration
|
||||
|
||||
State AppState
|
||||
}
|
||||
|
||||
func (h OIDCApp) GetUsername() string {
|
||||
return h.AppName
|
||||
}
|
||||
|
||||
func (h OIDCApp) GetState() AppState {
|
||||
return h.State
|
||||
}
|
||||
|
||||
type OIDCVersion int32
|
||||
|
||||
const (
|
||||
OIDCVersionV1 OIDCVersion = iota
|
||||
)
|
||||
|
||||
type OIDCResponseType int32
|
||||
|
||||
const (
|
||||
OIDCResponseTypeCode OIDCResponseType = iota
|
||||
OIDCResponseTypeIDToken
|
||||
OIDCResponseTypeIDTokenToken
|
||||
)
|
||||
|
||||
type OIDCGrantType int32
|
||||
|
||||
const (
|
||||
OIDCGrantTypeAuthorizationCode OIDCGrantType = iota
|
||||
OIDCGrantTypeImplicit
|
||||
OIDCGrantTypeRefreshToken
|
||||
)
|
||||
|
||||
type OIDCApplicationType int32
|
||||
|
||||
const (
|
||||
OIDCApplicationTypeWeb OIDCApplicationType = iota
|
||||
OIDCApplicationTypeUserAgent
|
||||
OIDCApplicationTypeNative
|
||||
)
|
||||
|
||||
type OIDCAuthMethodType int32
|
||||
|
||||
const (
|
||||
OIDCAuthMethodTypeBasic OIDCAuthMethodType = iota
|
||||
OIDCAuthMethodTypePost
|
||||
OIDCAuthMethodTypeNone
|
||||
)
|
||||
|
||||
type Compliance struct {
|
||||
NoneCompliant bool
|
||||
Problems []string
|
||||
}
|
||||
|
||||
type OIDCTokenType int32
|
||||
|
||||
const (
|
||||
OIDCTokenTypeBearer OIDCTokenType = iota
|
||||
OIDCTokenTypeJWT
|
||||
)
|
||||
|
||||
func (c *OIDCApp) IsValid() bool {
|
||||
grantTypes := c.getRequiredGrantTypes()
|
||||
for _, grantType := range grantTypes {
|
||||
ok := containsOIDCGrantType(c.GrantTypes, grantType)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//ClientID random_number@projectname (eg. 495894098234@zitadel)
|
||||
func (c *OIDCApp) GenerateNewClientID(idGenerator id.Generator, project *Project) error {
|
||||
rndID, err := idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.ClientID = fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_"))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OIDCApp) GenerateClientSecretIfNeeded(generator crypto.Generator) (string, error) {
|
||||
if c.AuthMethodType == OIDCAuthMethodTypeNone {
|
||||
return "", nil
|
||||
}
|
||||
return c.GenerateNewClientSecret(generator)
|
||||
}
|
||||
|
||||
func (c *OIDCApp) GenerateNewClientSecret(generator crypto.Generator) (string, error) {
|
||||
cryptoValue, stringSecret, err := NewClientSecret(generator)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
c.ClientSecret = cryptoValue
|
||||
return stringSecret, nil
|
||||
}
|
||||
|
||||
func NewClientSecret(generator crypto.Generator) (*crypto.CryptoValue, string, error) {
|
||||
cryptoValue, stringSecret, err := crypto.NewCode(generator)
|
||||
if err != nil {
|
||||
logging.Log("MODEL-UpnTI").OnError(err).Error("unable to create client secret")
|
||||
return nil, "", errors.ThrowInternal(err, "MODEL-gH2Wl", "Errors.Project.CouldNotGenerateClientSecret")
|
||||
}
|
||||
return cryptoValue, stringSecret, nil
|
||||
}
|
||||
|
||||
func (c *OIDCApp) getRequiredGrantTypes() []OIDCGrantType {
|
||||
grantTypes := make([]OIDCGrantType, 0)
|
||||
implicit := false
|
||||
for _, r := range c.ResponseTypes {
|
||||
switch r {
|
||||
case OIDCResponseTypeCode:
|
||||
grantTypes = append(grantTypes, OIDCGrantTypeAuthorizationCode)
|
||||
case OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken:
|
||||
if !implicit {
|
||||
implicit = true
|
||||
grantTypes = append(grantTypes, OIDCGrantTypeImplicit)
|
||||
}
|
||||
}
|
||||
}
|
||||
return grantTypes
|
||||
}
|
||||
|
||||
func containsOIDCGrantType(grantTypes []OIDCGrantType, grantType OIDCGrantType) bool {
|
||||
for _, gt := range grantTypes {
|
||||
if gt == grantType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *OIDCApp) FillCompliance() {
|
||||
c.Compliance = GetOIDCCompliance(c.OIDCVersion, c.ApplicationType, c.GrantTypes, c.ResponseTypes, c.AuthMethodType, c.RedirectUris)
|
||||
}
|
||||
|
||||
func GetOIDCCompliance(version OIDCVersion, appType OIDCApplicationType, grantTypes []OIDCGrantType, responseTypes []OIDCResponseType, authMethod OIDCAuthMethodType, redirectUris []string) *Compliance {
|
||||
switch version {
|
||||
case OIDCVersionV1:
|
||||
return GetOIDCV1Compliance(appType, grantTypes, authMethod, redirectUris)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetOIDCV1Compliance(appType OIDCApplicationType, grantTypes []OIDCGrantType, authMethod OIDCAuthMethodType, redirectUris []string) *Compliance {
|
||||
compliance := &Compliance{NoneCompliant: false}
|
||||
if redirectUris == nil || len(redirectUris) == 0 {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append([]string{"Application.OIDC.V1.NoRedirectUris"}, compliance.Problems...)
|
||||
}
|
||||
if containsOIDCGrantType(grantTypes, OIDCGrantTypeImplicit) && containsOIDCGrantType(grantTypes, OIDCGrantTypeAuthorizationCode) {
|
||||
CheckRedirectUrisImplicitAndCode(compliance, appType, redirectUris)
|
||||
} else {
|
||||
if containsOIDCGrantType(grantTypes, OIDCGrantTypeImplicit) {
|
||||
CheckRedirectUrisImplicit(compliance, appType, redirectUris)
|
||||
}
|
||||
if containsOIDCGrantType(grantTypes, OIDCGrantTypeAuthorizationCode) {
|
||||
CheckRedirectUrisCode(compliance, appType, redirectUris)
|
||||
}
|
||||
}
|
||||
|
||||
switch appType {
|
||||
case OIDCApplicationTypeNative:
|
||||
GetOIDCV1NativeApplicationCompliance(compliance, authMethod)
|
||||
case OIDCApplicationTypeUserAgent:
|
||||
GetOIDCV1UserAgentApplicationCompliance(compliance, authMethod)
|
||||
}
|
||||
if compliance.NoneCompliant {
|
||||
compliance.Problems = append([]string{"Application.OIDC.V1.NotCompliant"}, compliance.Problems...)
|
||||
}
|
||||
return compliance
|
||||
}
|
||||
|
||||
func GetOIDCV1NativeApplicationCompliance(compliance *Compliance, authMethod OIDCAuthMethodType) {
|
||||
if authMethod != OIDCAuthMethodTypeNone {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Native.AuthMethodType.NotNone")
|
||||
}
|
||||
}
|
||||
|
||||
func GetOIDCV1UserAgentApplicationCompliance(compliance *Compliance, authMethod OIDCAuthMethodType) {
|
||||
if authMethod != OIDCAuthMethodTypeNone {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.UserAgent.AuthMethodType.NotNone")
|
||||
}
|
||||
}
|
||||
|
||||
func CheckRedirectUrisCode(compliance *Compliance, appType OIDCApplicationType, redirectUris []string) {
|
||||
if urlsAreHttps(redirectUris) {
|
||||
return
|
||||
}
|
||||
if urlContainsPrefix(redirectUris, http) && appType != OIDCApplicationTypeWeb {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Code.RedirectUris.HttpOnlyForWeb")
|
||||
}
|
||||
if containsCustom(redirectUris) && appType != OIDCApplicationTypeNative {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Code.RedirectUris.CustomOnlyForNative")
|
||||
}
|
||||
}
|
||||
|
||||
func CheckRedirectUrisImplicit(compliance *Compliance, appType OIDCApplicationType, redirectUris []string) {
|
||||
if urlsAreHttps(redirectUris) {
|
||||
return
|
||||
}
|
||||
if containsCustom(redirectUris) {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Implicit.RedirectUris.CustomNotAllowed")
|
||||
}
|
||||
if urlContainsPrefix(redirectUris, http) {
|
||||
if appType == OIDCApplicationTypeNative {
|
||||
if !onlyLocalhostIsHttp(redirectUris) {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Implicit.RedirectUris.NativeShouldBeHttpLocalhost")
|
||||
}
|
||||
return
|
||||
}
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Implicit.RedirectUris.HttpNotAllowed")
|
||||
}
|
||||
}
|
||||
|
||||
func CheckRedirectUrisImplicitAndCode(compliance *Compliance, appType OIDCApplicationType, redirectUris []string) {
|
||||
if urlsAreHttps(redirectUris) {
|
||||
return
|
||||
}
|
||||
if containsCustom(redirectUris) && appType != OIDCApplicationTypeNative {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Implicit.RedirectUris.CustomNotAllowed")
|
||||
}
|
||||
if (urlContainsPrefix(redirectUris, httpLocalhost) || urlContainsPrefix(redirectUris, httpLocalhost2)) && appType != OIDCApplicationTypeNative {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Implicit.RedirectUris.HttpLocalhostOnlyForNative")
|
||||
}
|
||||
if urlContainsPrefix(redirectUris, http) && !(urlContainsPrefix(redirectUris, httpLocalhost) || urlContainsPrefix(redirectUris, httpLocalhost2)) && appType != OIDCApplicationTypeWeb {
|
||||
compliance.NoneCompliant = true
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.Code.RedirectUris.HttpOnlyForWeb")
|
||||
}
|
||||
if !compliance.NoneCompliant {
|
||||
compliance.Problems = append(compliance.Problems, "Application.OIDC.V1.NotAllCombinationsAreAllowed")
|
||||
}
|
||||
}
|
||||
|
||||
func urlsAreHttps(uris []string) bool {
|
||||
for _, uri := range uris {
|
||||
if !strings.HasPrefix(uri, https) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func urlContainsPrefix(uris []string, prefix string) bool {
|
||||
for _, uri := range uris {
|
||||
if strings.HasPrefix(uri, prefix) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func containsCustom(uris []string) bool {
|
||||
for _, uri := range uris {
|
||||
if !strings.HasPrefix(uri, http) && !strings.HasPrefix(uri, https) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func onlyLocalhostIsHttp(uris []string) bool {
|
||||
for _, uri := range uris {
|
||||
if strings.HasPrefix(uri, http) {
|
||||
if !strings.HasPrefix(uri, httpLocalhost) && !strings.HasPrefix(uri, httpLocalhost2) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
@@ -1,152 +0,0 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caos/logging"
|
||||
|
||||
"github.com/caos/zitadel/internal/crypto"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/models"
|
||||
"github.com/caos/zitadel/internal/id"
|
||||
)
|
||||
|
||||
type OIDCConfig struct {
|
||||
models.ObjectRoot
|
||||
|
||||
AppID string
|
||||
ClientID string
|
||||
ClientSecret *crypto.CryptoValue
|
||||
ClientSecretString string
|
||||
RedirectUris []string
|
||||
ResponseTypes []OIDCResponseType
|
||||
GrantTypes []OIDCGrantType
|
||||
ApplicationType OIDCApplicationType
|
||||
AuthMethodType OIDCAuthMethodType
|
||||
PostLogoutRedirectUris []string
|
||||
OIDCVersion OIDCVersion
|
||||
Compliance *Compliance
|
||||
DevMode bool
|
||||
AccessTokenType OIDCTokenType
|
||||
AccessTokenRoleAssertion bool
|
||||
IDTokenRoleAssertion bool
|
||||
IDTokenUserinfoAssertion bool
|
||||
ClockSkew time.Duration
|
||||
}
|
||||
|
||||
type OIDCVersion int32
|
||||
|
||||
const (
|
||||
OIDCVersionV1 OIDCVersion = iota
|
||||
)
|
||||
|
||||
type OIDCResponseType int32
|
||||
|
||||
const (
|
||||
OIDCResponseTypeCode OIDCResponseType = iota
|
||||
OIDCResponseTypeIDToken
|
||||
OIDCResponseTypeIDTokenToken
|
||||
)
|
||||
|
||||
type OIDCGrantType int32
|
||||
|
||||
const (
|
||||
OIDCGrantTypeAuthorizationCode OIDCGrantType = iota
|
||||
OIDCGrantTypeImplicit
|
||||
OIDCGrantTypeRefreshToken
|
||||
)
|
||||
|
||||
type OIDCApplicationType int32
|
||||
|
||||
const (
|
||||
OIDCApplicationTypeWeb OIDCApplicationType = iota
|
||||
OIDCApplicationTypeUserAgent
|
||||
OIDCApplicationTypeNative
|
||||
)
|
||||
|
||||
type OIDCAuthMethodType int32
|
||||
|
||||
const (
|
||||
OIDCAuthMethodTypeBasic OIDCAuthMethodType = iota
|
||||
OIDCAuthMethodTypePost
|
||||
OIDCAuthMethodTypeNone
|
||||
)
|
||||
|
||||
type Compliance struct {
|
||||
NoneCompliant bool
|
||||
Problems []string
|
||||
}
|
||||
|
||||
type OIDCTokenType int32
|
||||
|
||||
const (
|
||||
OIDCTokenTypeBearer OIDCTokenType = iota
|
||||
OIDCTokenTypeJWT
|
||||
)
|
||||
|
||||
func (c *OIDCConfig) IsValid() bool {
|
||||
grantTypes := c.getRequiredGrantTypes()
|
||||
for _, grantType := range grantTypes {
|
||||
ok := containsOIDCGrantType(c.GrantTypes, grantType)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//ClientID random_number@projectname (eg. 495894098234@zitadel)
|
||||
func (c *OIDCConfig) GenerateNewClientID(idGenerator id.Generator, project *Project) error {
|
||||
rndID, err := idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.ClientID = fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_"))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *OIDCConfig) GenerateClientSecretIfNeeded(generator crypto.Generator) (string, error) {
|
||||
if c.AuthMethodType == OIDCAuthMethodTypeNone {
|
||||
return "", nil
|
||||
}
|
||||
return c.GenerateNewClientSecret(generator)
|
||||
}
|
||||
|
||||
func (c *OIDCConfig) GenerateNewClientSecret(generator crypto.Generator) (string, error) {
|
||||
cryptoValue, stringSecret, err := crypto.NewCode(generator)
|
||||
if err != nil {
|
||||
logging.Log("MODEL-UpnTI").OnError(err).Error("unable to create client secret")
|
||||
return "", errors.ThrowInternal(err, "MODEL-gH2Wl", "Errors.Project.CouldNotGenerateClientSecret")
|
||||
}
|
||||
c.ClientSecret = cryptoValue
|
||||
return stringSecret, nil
|
||||
}
|
||||
|
||||
func (c *OIDCConfig) getRequiredGrantTypes() []OIDCGrantType {
|
||||
grantTypes := make([]OIDCGrantType, 0)
|
||||
implicit := false
|
||||
for _, r := range c.ResponseTypes {
|
||||
switch r {
|
||||
case OIDCResponseTypeCode:
|
||||
grantTypes = append(grantTypes, OIDCGrantTypeAuthorizationCode)
|
||||
case OIDCResponseTypeIDToken, OIDCResponseTypeIDTokenToken:
|
||||
if !implicit {
|
||||
implicit = true
|
||||
grantTypes = append(grantTypes, OIDCGrantTypeImplicit)
|
||||
}
|
||||
}
|
||||
}
|
||||
return grantTypes
|
||||
}
|
||||
|
||||
func containsOIDCGrantType(grantTypes []OIDCGrantType, grantType OIDCGrantType) bool {
|
||||
for _, gt := range grantTypes {
|
||||
if gt == grantType {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
30
internal/v2/domain/project_grant.go
Normal file
30
internal/v2/domain/project_grant.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package domain
|
||||
|
||||
import es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
|
||||
type ProjectGrant struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
GrantID string
|
||||
GrantedOrgID string
|
||||
State ProjectGrantState
|
||||
RoleKeys []string
|
||||
}
|
||||
|
||||
type ProjectGrantIDs struct {
|
||||
ProjectID string
|
||||
GrantID string
|
||||
}
|
||||
|
||||
type ProjectGrantState int32
|
||||
|
||||
const (
|
||||
ProjectGrantStateUnspecified ProjectGrantState = iota
|
||||
ProjectGrantStateActive
|
||||
ProjectGrantStateInactive
|
||||
ProjectGrantStateRemoved
|
||||
)
|
||||
|
||||
func (p *ProjectGrant) IsValid() bool {
|
||||
return p.GrantedOrgID != ""
|
||||
}
|
28
internal/v2/domain/project_grant_member.go
Normal file
28
internal/v2/domain/project_grant_member.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
es_models "github.com/caos/zitadel/internal/eventstore/models"
|
||||
)
|
||||
|
||||
type ProjectGrantMember struct {
|
||||
es_models.ObjectRoot
|
||||
|
||||
GrantID string
|
||||
UserID string
|
||||
Roles []string
|
||||
}
|
||||
|
||||
func NewProjectGrantMember(aggregateID, userID, grantID string, roles ...string) *ProjectGrantMember {
|
||||
return &ProjectGrantMember{
|
||||
ObjectRoot: es_models.ObjectRoot{
|
||||
AggregateID: aggregateID,
|
||||
},
|
||||
GrantID: grantID,
|
||||
UserID: userID,
|
||||
Roles: roles,
|
||||
}
|
||||
}
|
||||
|
||||
func (i *ProjectGrantMember) IsValid() bool {
|
||||
return i.AggregateID != "" && i.GrantID != "" && i.UserID != "" && len(i.Roles) != 0
|
||||
}
|
@@ -12,6 +12,14 @@ type ProjectRole struct {
|
||||
Group string
|
||||
}
|
||||
|
||||
type ProjectRoleState int32
|
||||
|
||||
const (
|
||||
ProjectRoleStateUnspecified ProjectRoleState = iota
|
||||
ProjectRoleStateActive
|
||||
ProjectRoleStateRemoved
|
||||
)
|
||||
|
||||
func NewProjectRole(projectID, key string) *ProjectRole {
|
||||
return &ProjectRole{ObjectRoot: models.ObjectRoot{AggregateID: projectID}, Key: key}
|
||||
}
|
||||
|
@@ -24,14 +24,14 @@ type OrgnameUniqueConstraint struct {
|
||||
action eventstore.UniqueConstraintAction
|
||||
}
|
||||
|
||||
func NewAddOrgnameUniqueConstraint(orgName string) *eventstore.EventUniqueConstraint {
|
||||
func NewAddOrgNameUniqueConstraint(orgName string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewAddEventUniqueConstraint(
|
||||
uniqueOrgname,
|
||||
orgName,
|
||||
"Errors.Org.AlreadyExists")
|
||||
}
|
||||
|
||||
func NewRemoveUsernameUniqueConstraint(orgName string) *eventstore.EventUniqueConstraint {
|
||||
func NewRemoveOrgNameUniqueConstraint(orgName string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewRemoveEventUniqueConstraint(
|
||||
uniqueOrgname,
|
||||
orgName)
|
||||
@@ -48,7 +48,7 @@ func (e *OrgAddedEvent) Data() interface{} {
|
||||
}
|
||||
|
||||
func (e *OrgAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewAddOrgnameUniqueConstraint(e.Name)}
|
||||
return []*eventstore.EventUniqueConstraint{NewAddOrgNameUniqueConstraint(e.Name)}
|
||||
}
|
||||
|
||||
func NewOrgAddedEvent(ctx context.Context, name string) *OrgAddedEvent {
|
||||
@@ -174,3 +174,38 @@ func OrgReactivatedEventMapper(event *repository.Event) (eventstore.EventReader,
|
||||
|
||||
return orgChanged, nil
|
||||
}
|
||||
|
||||
type OrgRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
name string
|
||||
}
|
||||
|
||||
func (e *OrgRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *OrgRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewRemoveOrgNameUniqueConstraint(e.name)}
|
||||
}
|
||||
|
||||
func NewOrgRemovedEvent(ctx context.Context, name string) *OrgRemovedEvent {
|
||||
return &OrgRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
OrgRemovedEventType,
|
||||
),
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func OrgRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
orgChanged := &OrgRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
err := json.Unmarshal(event.Data, orgChanged)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "ORG-DAfbs", "unable to unmarshal org deactivated")
|
||||
}
|
||||
|
||||
return orgChanged, nil
|
||||
}
|
||||
|
@@ -3,28 +3,42 @@ package project
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2/repository"
|
||||
"github.com/caos/zitadel/internal/v2/domain"
|
||||
)
|
||||
|
||||
const (
|
||||
uniqueAppNameType = "appname"
|
||||
applicationEventTypePrefix = projectEventTypePrefix + "application."
|
||||
ApplicationAdded = applicationEventTypePrefix + "added"
|
||||
ApplicationChanged = applicationEventTypePrefix + "changed"
|
||||
ApplicationDeactivated = applicationEventTypePrefix + "deactivated"
|
||||
ApplicationReactivated = applicationEventTypePrefix + "reactivated"
|
||||
ApplicationRemoved = applicationEventTypePrefix + "removed"
|
||||
ApplicationAddedType = applicationEventTypePrefix + "added"
|
||||
ApplicationChangedType = applicationEventTypePrefix + "changed"
|
||||
ApplicationDeactivatedType = applicationEventTypePrefix + "deactivated"
|
||||
ApplicationReactivatedType = applicationEventTypePrefix + "reactivated"
|
||||
ApplicationRemovedType = applicationEventTypePrefix + "removed"
|
||||
)
|
||||
|
||||
func NewAddApplicationUniqueConstraint(name, projectID string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewAddEventUniqueConstraint(
|
||||
uniqueAppNameType,
|
||||
fmt.Sprintf("%s:%s", name, projectID),
|
||||
"Errors.Project.App.AlreadyExists")
|
||||
}
|
||||
|
||||
func NewRemoveApplicationUniqueConstraint(name, projectID string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewRemoveEventUniqueConstraint(
|
||||
uniqueAppNameType,
|
||||
fmt.Sprintf("%s:%s", name, projectID))
|
||||
}
|
||||
|
||||
type ApplicationAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
AppType domain.AppType `json:"appType,omitempty"`
|
||||
AppID string `json:"appId,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *ApplicationAddedEvent) Data() interface{} {
|
||||
@@ -32,18 +46,18 @@ func (e *ApplicationAddedEvent) Data() interface{} {
|
||||
}
|
||||
|
||||
func (e *ApplicationAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
return []*eventstore.EventUniqueConstraint{NewAddApplicationUniqueConstraint(e.Name, e.projectID)}
|
||||
}
|
||||
|
||||
func NewApplicationAddedEvent(ctx context.Context, appID, name string, appType domain.AppType) *ApplicationAddedEvent {
|
||||
func NewApplicationAddedEvent(ctx context.Context, appID, name, projectID string) *ApplicationAddedEvent {
|
||||
return &ApplicationAddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ApplicationAdded,
|
||||
ApplicationAddedType,
|
||||
),
|
||||
AppID: appID,
|
||||
Name: name,
|
||||
AppType: appType,
|
||||
AppID: appID,
|
||||
Name: name,
|
||||
projectID: projectID,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,3 +73,164 @@ func ApplicationAddedEventMapper(event *repository.Event) (eventstore.EventReade
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type ApplicationChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
oldName string
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *ApplicationChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *ApplicationChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{
|
||||
NewRemoveApplicationUniqueConstraint(e.oldName, e.projectID),
|
||||
NewAddApplicationUniqueConstraint(e.Name, e.projectID),
|
||||
}
|
||||
}
|
||||
|
||||
func NewApplicationChangedEvent(ctx context.Context, appID, oldName, newName, projectID string) *ApplicationChangedEvent {
|
||||
return &ApplicationChangedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ApplicationChangedType,
|
||||
),
|
||||
AppID: appID,
|
||||
Name: newName,
|
||||
oldName: oldName,
|
||||
projectID: projectID,
|
||||
}
|
||||
}
|
||||
|
||||
func ApplicationChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &ApplicationChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "APPLICATION-9l0cs", "unable to unmarshal application")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type ApplicationDeactivatedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId,omitempty"`
|
||||
}
|
||||
|
||||
func (e *ApplicationDeactivatedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *ApplicationDeactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewApplicationDeactivatedEvent(ctx context.Context, appID string) *ApplicationDeactivatedEvent {
|
||||
return &ApplicationDeactivatedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ApplicationDeactivatedType,
|
||||
),
|
||||
AppID: appID,
|
||||
}
|
||||
}
|
||||
|
||||
func ApplicationDeactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &ApplicationDeactivatedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "APPLICATION-0p9fB", "unable to unmarshal application")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type ApplicationReactivatedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId,omitempty"`
|
||||
}
|
||||
|
||||
func (e *ApplicationReactivatedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *ApplicationReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewApplicationReactivatedEvent(ctx context.Context, appID string) *ApplicationReactivatedEvent {
|
||||
return &ApplicationReactivatedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ApplicationReactivatedType,
|
||||
),
|
||||
AppID: appID,
|
||||
}
|
||||
}
|
||||
|
||||
func ApplicationReactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &ApplicationReactivatedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "APPLICATION-1m9e3", "unable to unmarshal application")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type ApplicationRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId,omitempty"`
|
||||
name string
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *ApplicationRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *ApplicationRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewRemoveApplicationUniqueConstraint(e.name, e.projectID)}
|
||||
}
|
||||
|
||||
func NewApplicationRemovedEvent(ctx context.Context, appID, name, projectID string) *ApplicationRemovedEvent {
|
||||
return &ApplicationRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ApplicationRemovedType,
|
||||
),
|
||||
AppID: appID,
|
||||
name: name,
|
||||
projectID: projectID,
|
||||
}
|
||||
}
|
||||
|
||||
func ApplicationRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &ApplicationRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "APPLICATION-1m9e3", "unable to unmarshal application")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
@@ -5,5 +5,34 @@ import (
|
||||
)
|
||||
|
||||
func RegisterEventMappers(es *eventstore.Eventstore) {
|
||||
es.RegisterFilterEventMapper(ProjectAddedType, ProjectAddedEventMapper)
|
||||
es.RegisterFilterEventMapper(ProjectAddedType, ProjectAddedEventMapper).
|
||||
RegisterFilterEventMapper(ProjectChangedType, ProjectChangeEventMapper).
|
||||
RegisterFilterEventMapper(ProjectDeactivatedType, ProjectDeactivatedEventMapper).
|
||||
RegisterFilterEventMapper(ProjectReactivatedType, ProjectReactivatedEventMapper).
|
||||
RegisterFilterEventMapper(ProjectRemovedType, ProjectRemovedEventMapper).
|
||||
RegisterFilterEventMapper(MemberAddedType, MemberAddedEventMapper).
|
||||
RegisterFilterEventMapper(MemberChangedType, MemberChangedEventMapper).
|
||||
RegisterFilterEventMapper(MemberRemovedType, MemberRemovedEventMapper).
|
||||
RegisterFilterEventMapper(RoleAddedType, RoleAddedEventMapper).
|
||||
RegisterFilterEventMapper(RoleChangedType, RoleChangedEventMapper).
|
||||
RegisterFilterEventMapper(RoleRemovedType, RoleRemovedEventMapper).
|
||||
RegisterFilterEventMapper(GrantAddedType, GrantAddedEventMapper).
|
||||
RegisterFilterEventMapper(GrantChangedType, GrantChangedEventMapper).
|
||||
RegisterFilterEventMapper(GrantCascadeChangedType, GrantChangedEventMapper).
|
||||
RegisterFilterEventMapper(GrantDeactivatedType, GrantDeactivateEventMapper).
|
||||
RegisterFilterEventMapper(GrantReactivatedType, GrantReactivatedEventMapper).
|
||||
RegisterFilterEventMapper(GrantRemovedType, GrantRemovedEventMapper).
|
||||
RegisterFilterEventMapper(GrantMemberAddedType, GrantMemberAddedEventMapper).
|
||||
RegisterFilterEventMapper(GrantMemberChangedType, GrantMemberChangedEventMapper).
|
||||
RegisterFilterEventMapper(GrantMemberRemovedType, GrantMemberRemovedEventMapper).
|
||||
RegisterFilterEventMapper(ApplicationAddedType, ApplicationAddedEventMapper).
|
||||
RegisterFilterEventMapper(ApplicationChangedType, ApplicationAddedEventMapper).
|
||||
RegisterFilterEventMapper(ApplicationRemovedType, ApplicationRemovedEventMapper).
|
||||
RegisterFilterEventMapper(ApplicationDeactivatedType, ApplicationDeactivatedEventMapper).
|
||||
RegisterFilterEventMapper(ApplicationReactivatedType, ApplicationReactivatedEventMapper).
|
||||
RegisterFilterEventMapper(OIDCConfigAddedType, OIDCConfigAddedEventMapper).
|
||||
RegisterFilterEventMapper(OIDCConfigChangedType, OIDCConfigChangedEventMapper).
|
||||
RegisterFilterEventMapper(OIDCConfigSecretChangedType, OIDCConfigSecretChangedEventMapper).
|
||||
RegisterFilterEventMapper(OIDCClientSecretCheckSucceededType, OIDCConfigSecretCheckSucceededEventMapper).
|
||||
RegisterFilterEventMapper(OIDCClientSecretCheckFailedType, OIDCConfigSecretCheckFailedEventMapper)
|
||||
}
|
||||
|
270
internal/v2/repository/project/grant.go
Normal file
270
internal/v2/repository/project/grant.go
Normal file
@@ -0,0 +1,270 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2/repository"
|
||||
)
|
||||
|
||||
var (
|
||||
uniqueGrantType = "project_Grant"
|
||||
grantEventTypePrefix = projectEventTypePrefix + "grant."
|
||||
GrantAddedType = grantEventTypePrefix + "added"
|
||||
GrantChangedType = grantEventTypePrefix + "changed"
|
||||
GrantCascadeChangedType = grantEventTypePrefix + "cascade.changed"
|
||||
GrantDeactivatedType = grantEventTypePrefix + "deactivated"
|
||||
GrantReactivatedType = grantEventTypePrefix + "reactivated"
|
||||
GrantRemovedType = grantEventTypePrefix + "removed"
|
||||
)
|
||||
|
||||
func NewAddProjectGrantUniqueConstraint(grantedOrgID, projectID string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewAddEventUniqueConstraint(
|
||||
uniqueRoleType,
|
||||
fmt.Sprintf("%s:%s", grantedOrgID, projectID),
|
||||
"Errors.Project.Grant.AlreadyExists")
|
||||
}
|
||||
|
||||
func NewRemoveProjectGrantUniqueConstraint(grantedOrgID, projectID string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewRemoveEventUniqueConstraint(
|
||||
uniqueRoleType,
|
||||
fmt.Sprintf("%s:%s", grantedOrgID, projectID))
|
||||
}
|
||||
|
||||
type GrantAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
GrantedOrgID string `json:"grantedOrgId,omitempty"`
|
||||
RoleKeys []string `json:"roleKeys,omitempty"`
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *GrantAddedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewAddProjectGrantUniqueConstraint(e.GrantedOrgID, e.projectID)}
|
||||
}
|
||||
|
||||
func NewGrantAddedEvent(ctx context.Context, grantID, grantedOrgID, projectID string, roleKeys []string) *GrantAddedEvent {
|
||||
return &GrantAddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantAddedType,
|
||||
),
|
||||
GrantID: grantID,
|
||||
GrantedOrgID: grantedOrgID,
|
||||
RoleKeys: roleKeys,
|
||||
projectID: projectID,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantAddedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-mL0vs", "unable to unmarshal project grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GrantChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
RoleKeys []string `json:"roleKeys,omitempty"`
|
||||
}
|
||||
|
||||
func (e *GrantChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewGrantChangedEvent(ctx context.Context, grantID string, roleKeys []string) *GrantChangedEvent {
|
||||
return &GrantChangedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantChangedType,
|
||||
),
|
||||
GrantID: grantID,
|
||||
RoleKeys: roleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-mL0vs", "unable to unmarshal project grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GrantCascadeChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
RoleKeys []string `json:"roleKeys,omitempty"`
|
||||
}
|
||||
|
||||
func (e *GrantCascadeChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantCascadeChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewGrantCascadeChangedEvent(ctx context.Context, grantID string, roleKeys []string) *GrantCascadeChangedEvent {
|
||||
return &GrantCascadeChangedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantCascadeChangedType,
|
||||
),
|
||||
GrantID: grantID,
|
||||
RoleKeys: roleKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantCascadeChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantCascadeChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-9o0se", "unable to unmarshal project grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GrantDeactivateEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
}
|
||||
|
||||
func (e *GrantDeactivateEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantDeactivateEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewGrantDeactivateEvent(ctx context.Context, grantID string) *GrantDeactivateEvent {
|
||||
return &GrantDeactivateEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantDeactivatedType,
|
||||
),
|
||||
GrantID: grantID,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantDeactivateEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantDeactivateEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-9o0se", "unable to unmarshal project grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GrantReactivatedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
}
|
||||
|
||||
func (e *GrantReactivatedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewGrantReactivatedEvent(ctx context.Context, grantID string) *GrantReactivatedEvent {
|
||||
return &GrantReactivatedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantReactivatedType,
|
||||
),
|
||||
GrantID: grantID,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantReactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantReactivatedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-78f7D", "unable to unmarshal project grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GrantRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
GrantID string `json:"grantId,omitempty"`
|
||||
grantedOrgID string
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *GrantRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewRemoveProjectGrantUniqueConstraint(e.grantedOrgID, e.projectID)}
|
||||
}
|
||||
|
||||
func NewGrantRemovedEvent(ctx context.Context, grantID, grantedOrgID, projectID string) *GrantRemovedEvent {
|
||||
return &GrantRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantRemovedType,
|
||||
),
|
||||
GrantID: grantID,
|
||||
projectID: projectID,
|
||||
grantedOrgID: grantedOrgID,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-28jM8", "unable to unmarshal project grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
173
internal/v2/repository/project/grant_member.go
Normal file
173
internal/v2/repository/project/grant_member.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2/repository"
|
||||
"github.com/caos/zitadel/internal/v2/repository/member"
|
||||
)
|
||||
|
||||
var (
|
||||
uniqueProjectGrantType = "project_grant"
|
||||
GrantMemberAddedType = grantEventTypePrefix + member.AddedEventType
|
||||
GrantMemberChangedType = grantEventTypePrefix + member.ChangedEventType
|
||||
GrantMemberRemovedType = grantEventTypePrefix + member.RemovedEventType
|
||||
)
|
||||
|
||||
func NewAddProjectGrantMemberUniqueConstraint(projectID, userID, grantID string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewAddEventUniqueConstraint(
|
||||
uniqueProjectGrantType,
|
||||
fmt.Sprintf("%s:%s:%s", projectID, userID, grantID),
|
||||
"Errors.Project.Member.AlreadyExists")
|
||||
}
|
||||
|
||||
func NewRemoveProjectGrantMemberUniqueConstraint(projectID, userID, grantID string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewRemoveEventUniqueConstraint(
|
||||
uniqueProjectGrantType,
|
||||
fmt.Sprintf("%s:%s:%s", projectID, userID, grantID),
|
||||
)
|
||||
}
|
||||
|
||||
type GrantMemberAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Roles []string `json:"roles"`
|
||||
UserID string `json:"userId"`
|
||||
GrantID string `json:"grantId"`
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *GrantMemberAddedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantMemberAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewAddProjectGrantMemberUniqueConstraint(e.projectID, e.UserID, e.GrantID)}
|
||||
}
|
||||
|
||||
func NewProjectGrantMemberAddedEvent(
|
||||
ctx context.Context,
|
||||
projectID,
|
||||
userID,
|
||||
grantID string,
|
||||
roles ...string,
|
||||
) *GrantMemberAddedEvent {
|
||||
return &GrantMemberAddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantMemberAddedType,
|
||||
),
|
||||
projectID: projectID,
|
||||
UserID: userID,
|
||||
GrantID: grantID,
|
||||
Roles: roles,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantMemberAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantMemberAddedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-9f0sf", "unable to unmarshal label policy")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GrantMemberChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Roles []string `json:"roles"`
|
||||
GrantID string `json:"grantId"`
|
||||
UserID string `json:"userId"`
|
||||
}
|
||||
|
||||
func (e *GrantMemberChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantMemberChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewProjectGrantMemberChangedEvent(
|
||||
ctx context.Context,
|
||||
userID,
|
||||
grantID string,
|
||||
roles ...string,
|
||||
) *GrantMemberChangedEvent {
|
||||
return &GrantMemberChangedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantMemberAddedType,
|
||||
),
|
||||
UserID: userID,
|
||||
GrantID: grantID,
|
||||
Roles: roles,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantMemberChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantMemberChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-39fi8", "unable to unmarshal label policy")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type GrantMemberRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
UserID string `json:"userId"`
|
||||
GrantID string `json:"grantId"`
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *GrantMemberRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *GrantMemberRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewRemoveProjectGrantMemberUniqueConstraint(e.projectID, e.UserID, e.GrantID)}
|
||||
}
|
||||
|
||||
func NewProjectGrantMemberRemovedEvent(
|
||||
ctx context.Context,
|
||||
projectID,
|
||||
userID,
|
||||
grantID string,
|
||||
) *GrantMemberRemovedEvent {
|
||||
return &GrantMemberRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
GrantMemberRemovedType,
|
||||
),
|
||||
UserID: userID,
|
||||
GrantID: grantID,
|
||||
projectID: projectID,
|
||||
}
|
||||
}
|
||||
|
||||
func GrantMemberRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &GrantMemberRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-173fM", "unable to unmarshal label policy")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
@@ -3,20 +3,21 @@ package project
|
||||
import (
|
||||
"context"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2/repository"
|
||||
"github.com/caos/zitadel/internal/v2/repository/member"
|
||||
)
|
||||
|
||||
var (
|
||||
MemberAddedEventType = projectEventTypePrefix + member.AddedEventType
|
||||
MemberChangedEventType = projectEventTypePrefix + member.ChangedEventType
|
||||
MemberRemovedEventType = projectEventTypePrefix + member.RemovedEventType
|
||||
MemberAddedType = projectEventTypePrefix + member.AddedEventType
|
||||
MemberChangedType = projectEventTypePrefix + member.ChangedEventType
|
||||
MemberRemovedType = projectEventTypePrefix + member.RemovedEventType
|
||||
)
|
||||
|
||||
type MemberAddedEvent struct {
|
||||
member.MemberAddedEvent
|
||||
}
|
||||
|
||||
func NewMemberAddedEvent(
|
||||
func NewProjectMemberAddedEvent(
|
||||
ctx context.Context,
|
||||
userID string,
|
||||
roles ...string,
|
||||
@@ -25,7 +26,7 @@ func NewMemberAddedEvent(
|
||||
MemberAddedEvent: *member.NewMemberAddedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
MemberAddedEventType,
|
||||
MemberAddedType,
|
||||
),
|
||||
userID,
|
||||
roles...,
|
||||
@@ -33,11 +34,20 @@ func NewMemberAddedEvent(
|
||||
}
|
||||
}
|
||||
|
||||
func MemberAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e, err := member.MemberAddedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MemberAddedEvent{MemberAddedEvent: *e.(*member.MemberAddedEvent)}, nil
|
||||
}
|
||||
|
||||
type MemberChangedEvent struct {
|
||||
member.MemberChangedEvent
|
||||
}
|
||||
|
||||
func NewMemberChangedEvent(
|
||||
func NewProjectMemberChangedEvent(
|
||||
ctx context.Context,
|
||||
userID string,
|
||||
roles ...string,
|
||||
@@ -47,7 +57,7 @@ func NewMemberChangedEvent(
|
||||
MemberChangedEvent: *member.NewMemberChangedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
MemberChangedEventType,
|
||||
MemberChangedType,
|
||||
),
|
||||
userID,
|
||||
roles...,
|
||||
@@ -55,11 +65,20 @@ func NewMemberChangedEvent(
|
||||
}
|
||||
}
|
||||
|
||||
func MemberChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e, err := member.ChangedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MemberChangedEvent{MemberChangedEvent: *e.(*member.MemberChangedEvent)}, nil
|
||||
}
|
||||
|
||||
type MemberRemovedEvent struct {
|
||||
member.MemberRemovedEvent
|
||||
}
|
||||
|
||||
func NewMemberRemovedEvent(
|
||||
func NewProjectMemberRemovedEvent(
|
||||
ctx context.Context,
|
||||
userID string,
|
||||
) *MemberRemovedEvent {
|
||||
@@ -68,9 +87,18 @@ func NewMemberRemovedEvent(
|
||||
MemberRemovedEvent: *member.NewRemovedEvent(
|
||||
eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
MemberRemovedEventType,
|
||||
MemberRemovedType,
|
||||
),
|
||||
userID,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func MemberRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e, err := member.RemovedEventMapper(event)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &MemberRemovedEvent{MemberRemovedEvent: *e.(*member.MemberRemovedEvent)}, nil
|
||||
}
|
||||
|
@@ -13,11 +13,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
OIDCConfigAdded = applicationEventTypePrefix + "config.oidc.added"
|
||||
OIDCConfigChanged = applicationEventTypePrefix + "config.oidc.changed"
|
||||
OIDCConfigSecretChanged = applicationEventTypePrefix + "config.oidc.secret.changed"
|
||||
OIDCClientSecretCheckSucceeded = applicationEventTypePrefix + "oidc.secret.check.succeeded"
|
||||
OIDCClientSecretCheckFailed = applicationEventTypePrefix + "oidc.secret.check.failed"
|
||||
OIDCConfigAddedType = applicationEventTypePrefix + "config.oidc.added"
|
||||
OIDCConfigChangedType = applicationEventTypePrefix + "config.oidc.changed"
|
||||
OIDCConfigSecretChangedType = applicationEventTypePrefix + "config.oidc.secret.changed"
|
||||
OIDCClientSecretCheckSucceededType = applicationEventTypePrefix + "oidc.secret.check.succeeded"
|
||||
OIDCClientSecretCheckFailedType = applicationEventTypePrefix + "oidc.secret.check.failed"
|
||||
)
|
||||
|
||||
type OIDCConfigAddedEvent struct {
|
||||
@@ -71,7 +71,7 @@ func NewOIDCConfigAddedEvent(
|
||||
return &OIDCConfigAddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
OIDCConfigAdded,
|
||||
OIDCConfigAddedType,
|
||||
),
|
||||
Version: version,
|
||||
AppID: appID,
|
||||
@@ -104,3 +104,276 @@ func OIDCConfigAddedEventMapper(event *repository.Event) (eventstore.EventReader
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type OIDCConfigChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Version *domain.OIDCVersion `json:"oidcVersion,omitempty"`
|
||||
AppID string `json:"appId"`
|
||||
ClientID *string `json:"clientId,omitempty"`
|
||||
ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
|
||||
RedirectUris *[]string `json:"redirectUris,omitempty"`
|
||||
ResponseTypes *[]domain.OIDCResponseType `json:"responseTypes,omitempty"`
|
||||
GrantTypes *[]domain.OIDCGrantType `json:"grantTypes,omitempty"`
|
||||
ApplicationType *domain.OIDCApplicationType `json:"applicationType,omitempty"`
|
||||
AuthMethodType *domain.OIDCAuthMethodType `json:"authMethodType,omitempty"`
|
||||
PostLogoutRedirectUris *[]string `json:"postLogoutRedirectUris,omitempty"`
|
||||
DevMode *bool `json:"devMode,omitempty"`
|
||||
AccessTokenType *domain.OIDCTokenType `json:"accessTokenType,omitempty"`
|
||||
AccessTokenRoleAssertion *bool `json:"accessTokenRoleAssertion,omitempty"`
|
||||
IDTokenRoleAssertion *bool `json:"idTokenRoleAssertion,omitempty"`
|
||||
IDTokenUserinfoAssertion *bool `json:"idTokenUserinfoAssertion,omitempty"`
|
||||
ClockSkew *time.Duration `json:"clockSkew,omitempty"`
|
||||
}
|
||||
|
||||
func (e *OIDCConfigChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *OIDCConfigChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewOIDCConfigChangedEvent(
|
||||
ctx context.Context,
|
||||
appID string,
|
||||
changes []OIDCConfigChanges,
|
||||
) (*OIDCConfigChangedEvent, error) {
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "OIDC-i8idç", "Errors.NoChangesFound")
|
||||
}
|
||||
|
||||
changeEvent := &OIDCConfigChangedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
OIDCConfigChangedType,
|
||||
),
|
||||
AppID: appID,
|
||||
}
|
||||
for _, change := range changes {
|
||||
change(changeEvent)
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type OIDCConfigChanges func(event *OIDCConfigChangedEvent)
|
||||
|
||||
func ChangeVersion(version domain.OIDCVersion) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.Version = &version
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeClientID(clientID string) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.ClientID = &clientID
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeRedirectURIs(uris []string) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.RedirectUris = &uris
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeResponseTypes(responseTypes []domain.OIDCResponseType) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.ResponseTypes = &responseTypes
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeGrantTypes(grantTypes []domain.OIDCGrantType) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.GrantTypes = &grantTypes
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeApplicationType(appType domain.OIDCApplicationType) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.ApplicationType = &appType
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeAuthMethodType(authMethodType domain.OIDCAuthMethodType) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.AuthMethodType = &authMethodType
|
||||
}
|
||||
}
|
||||
|
||||
func ChangePostLogoutRedirectURIs(logoutRedirects []string) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.PostLogoutRedirectUris = &logoutRedirects
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeDevMode(devMode bool) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.DevMode = &devMode
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeAccessTokenType(accessTokenType domain.OIDCTokenType) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.AccessTokenType = &accessTokenType
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeAccessTokenRoleAssertion(accessTokenRoleAssertion bool) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.AccessTokenRoleAssertion = &accessTokenRoleAssertion
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeIDTokenRoleAssertion(idTokenRoleAssertion bool) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.IDTokenRoleAssertion = &idTokenRoleAssertion
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeIDTokenUserinfoAssertion(idTokenUserinfoAssertion bool) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.IDTokenUserinfoAssertion = &idTokenUserinfoAssertion
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeClockSkew(clockSkew time.Duration) func(event *OIDCConfigChangedEvent) {
|
||||
return func(e *OIDCConfigChangedEvent) {
|
||||
e.ClockSkew = &clockSkew
|
||||
}
|
||||
}
|
||||
|
||||
func OIDCConfigChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &OIDCConfigChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "OIDC-BFd15", "unable to unmarshal oidc config")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type OIDCConfigSecretChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId"`
|
||||
ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"`
|
||||
}
|
||||
|
||||
func (e *OIDCConfigSecretChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *OIDCConfigSecretChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewOIDCConfigSecretChangedEvent(
|
||||
ctx context.Context,
|
||||
appID string,
|
||||
clientSecret *crypto.CryptoValue,
|
||||
) *OIDCConfigSecretChangedEvent {
|
||||
return &OIDCConfigSecretChangedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
OIDCConfigSecretChangedType,
|
||||
),
|
||||
AppID: appID,
|
||||
ClientSecret: clientSecret,
|
||||
}
|
||||
}
|
||||
|
||||
func OIDCConfigSecretChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &OIDCConfigSecretChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "OIDC-M893d", "unable to unmarshal oidc config")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type OIDCConfigSecretCheckSucceededEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId"`
|
||||
}
|
||||
|
||||
func (e *OIDCConfigSecretCheckSucceededEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *OIDCConfigSecretCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewOIDCConfigSecretCheckSucceededEvent(
|
||||
ctx context.Context,
|
||||
appID string,
|
||||
) *OIDCConfigSecretCheckSucceededEvent {
|
||||
return &OIDCConfigSecretCheckSucceededEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
OIDCClientSecretCheckSucceededType,
|
||||
),
|
||||
AppID: appID,
|
||||
}
|
||||
}
|
||||
|
||||
func OIDCConfigSecretCheckSucceededEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &OIDCConfigSecretCheckSucceededEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "OIDC-837gV", "unable to unmarshal oidc config")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type OIDCConfigSecretCheckFailedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
AppID string `json:"appId"`
|
||||
}
|
||||
|
||||
func (e *OIDCConfigSecretCheckFailedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *OIDCConfigSecretCheckFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewOIDCConfigSecretCheckFailedEvent(
|
||||
ctx context.Context,
|
||||
appID string,
|
||||
) *OIDCConfigSecretCheckFailedEvent {
|
||||
return &OIDCConfigSecretCheckFailedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
OIDCClientSecretCheckFailedType,
|
||||
),
|
||||
AppID: appID,
|
||||
}
|
||||
}
|
||||
|
||||
func OIDCConfigSecretCheckFailedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &OIDCConfigSecretCheckFailedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "OIDC-987g%", "unable to unmarshal oidc config")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
@@ -10,25 +10,25 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
uniqueProjectnameTable = "project_names"
|
||||
uniqueProjectnameType = "project_names"
|
||||
projectEventTypePrefix = eventstore.EventType("project.")
|
||||
ProjectAddedType = projectEventTypePrefix + "added"
|
||||
ProjectChanged = projectEventTypePrefix + "changed"
|
||||
ProjectDeactivated = projectEventTypePrefix + "deactivated"
|
||||
ProjectReactivated = projectEventTypePrefix + "reactivated"
|
||||
ProjectRemoved = projectEventTypePrefix + "removed"
|
||||
ProjectChangedType = projectEventTypePrefix + "changed"
|
||||
ProjectDeactivatedType = projectEventTypePrefix + "deactivated"
|
||||
ProjectReactivatedType = projectEventTypePrefix + "reactivated"
|
||||
ProjectRemovedType = projectEventTypePrefix + "removed"
|
||||
)
|
||||
|
||||
func NewAddProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewAddEventUniqueConstraint(
|
||||
uniqueProjectnameTable,
|
||||
uniqueProjectnameType,
|
||||
projectName+resourceOwner,
|
||||
"Errors.Project.AlreadyExists")
|
||||
}
|
||||
|
||||
func NewRemoveProjectNameUniqueConstraint(projectName, resourceOwner string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewRemoveEventUniqueConstraint(
|
||||
uniqueProjectnameTable,
|
||||
uniqueProjectnameType,
|
||||
projectName+resourceOwner)
|
||||
}
|
||||
|
||||
@@ -71,3 +71,155 @@ func ProjectAddedEventMapper(event *repository.Event) (eventstore.EventReader, e
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type ProjectChangeEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Name *string `json:"name,omitempty"`
|
||||
ProjectRoleAssertion *bool `json:"projectRoleAssertion,omitempty"`
|
||||
ProjectRoleCheck *bool `json:"projectRoleCheck,omitempty"`
|
||||
}
|
||||
|
||||
func (e *ProjectChangeEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *ProjectChangeEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewProjectChangeEvent(
|
||||
ctx context.Context,
|
||||
changes []ProjectChanges) (*ProjectChangeEvent, error) {
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "PROJECT-mV9xc", "Errors.NoChangesFound")
|
||||
}
|
||||
changeEvent := &ProjectChangeEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ProjectChangedType,
|
||||
),
|
||||
}
|
||||
for _, change := range changes {
|
||||
change(changeEvent)
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type ProjectChanges func(event *ProjectChangeEvent)
|
||||
|
||||
func ChangeName(name string) func(event *ProjectChangeEvent) {
|
||||
return func(e *ProjectChangeEvent) {
|
||||
e.Name = &name
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeProjectRoleAssertion(projectRoleAssertion bool) func(event *ProjectChangeEvent) {
|
||||
return func(e *ProjectChangeEvent) {
|
||||
e.ProjectRoleAssertion = &projectRoleAssertion
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeProjectRoleCheck(projectRoleCheck bool) func(event *ProjectChangeEvent) {
|
||||
return func(e *ProjectChangeEvent) {
|
||||
e.ProjectRoleCheck = &projectRoleCheck
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectChangeEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &ProjectChangeEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-M9osd", "unable to unmarshal project")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type ProjectDeactivatedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
}
|
||||
|
||||
func (e *ProjectDeactivatedEvent) Data() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ProjectDeactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewProjectDeactivatedEvent(ctx context.Context) *ProjectDeactivatedEvent {
|
||||
return &ProjectDeactivatedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ProjectDeactivatedType,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectDeactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
return &ProjectDeactivatedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ProjectReactivatedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
}
|
||||
|
||||
func (e *ProjectReactivatedEvent) Data() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ProjectReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewProjectReactivatedEvent(ctx context.Context) *ProjectReactivatedEvent {
|
||||
return &ProjectReactivatedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
ProjectReactivatedType,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectReactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
return &ProjectReactivatedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type ProjectRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Name string
|
||||
}
|
||||
|
||||
func (e *ProjectRemovedEvent) Data() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *ProjectRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewRemoveProjectNameUniqueConstraint(e.Name, e.ResourceOwner())}
|
||||
}
|
||||
|
||||
func NewProjectRemovedEvent(ctx context.Context, name, resourceOwner string) *ProjectRemovedEvent {
|
||||
return &ProjectRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
|
||||
ctx,
|
||||
ProjectRemovedType,
|
||||
resourceOwner,
|
||||
),
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func ProjectRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
return &ProjectRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}, nil
|
||||
}
|
||||
|
181
internal/v2/repository/project/role.go
Normal file
181
internal/v2/repository/project/role.go
Normal file
@@ -0,0 +1,181 @@
|
||||
package project
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/caos/zitadel/internal/errors"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2"
|
||||
"github.com/caos/zitadel/internal/eventstore/v2/repository"
|
||||
)
|
||||
|
||||
var (
|
||||
uniqueRoleType = "project_role"
|
||||
roleEventTypePrefix = projectEventTypePrefix + "role."
|
||||
RoleAddedType = roleEventTypePrefix + "added"
|
||||
RoleChangedType = roleEventTypePrefix + "changed"
|
||||
RoleRemovedType = roleEventTypePrefix + "removed"
|
||||
)
|
||||
|
||||
func NewAddProjectRoleUniqueConstraint(roleKey, projectID, resourceOwner string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewAddEventUniqueConstraint(
|
||||
uniqueRoleType,
|
||||
fmt.Sprintf("%s:%s:%s", roleKey, projectID, resourceOwner),
|
||||
"Errors.Project.Role.AlreadyExists")
|
||||
}
|
||||
|
||||
func NewRemoveProjectRoleUniqueConstraint(roleKey, projectID, resourceOwner string) *eventstore.EventUniqueConstraint {
|
||||
return eventstore.NewRemoveEventUniqueConstraint(
|
||||
uniqueRoleType,
|
||||
fmt.Sprintf("%s:%s:%s", roleKey, projectID, resourceOwner))
|
||||
}
|
||||
|
||||
type RoleAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Key string `json:"key,omitempty"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
Group string `json:"group,omitempty"`
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *RoleAddedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *RoleAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewAddProjectRoleUniqueConstraint(e.Key, e.projectID, e.ResourceOwner())}
|
||||
}
|
||||
|
||||
func NewRoleAddedEvent(ctx context.Context, key, displayName, group, projectID, resourceOwner string) *RoleAddedEvent {
|
||||
return &RoleAddedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
|
||||
ctx,
|
||||
RoleAddedType,
|
||||
resourceOwner,
|
||||
),
|
||||
Key: key,
|
||||
DisplayName: displayName,
|
||||
Group: group,
|
||||
projectID: projectID,
|
||||
}
|
||||
}
|
||||
|
||||
func RoleAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &RoleAddedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-2M0xy", "unable to unmarshal project role")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type RoleChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Key string `json:"key,omitempty"`
|
||||
DisplayName *string `json:"displayName,omitempty"`
|
||||
Group *string `json:"group,omitempty"`
|
||||
}
|
||||
|
||||
func (e *RoleChangedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *RoleChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewRoleChangedEvent(
|
||||
ctx context.Context,
|
||||
changes []RoleChanges) (*RoleChangedEvent, error) {
|
||||
if len(changes) == 0 {
|
||||
return nil, errors.ThrowPreconditionFailed(nil, "PROJECT-eR9vx", "Errors.NoChangesFound")
|
||||
}
|
||||
changeEvent := &RoleChangedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPush(
|
||||
ctx,
|
||||
RoleChangedType,
|
||||
),
|
||||
}
|
||||
for _, change := range changes {
|
||||
change(changeEvent)
|
||||
}
|
||||
return changeEvent, nil
|
||||
}
|
||||
|
||||
type RoleChanges func(event *RoleChangedEvent)
|
||||
|
||||
func ChangeKey(key string) func(event *RoleChangedEvent) {
|
||||
return func(e *RoleChangedEvent) {
|
||||
e.Key = key
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeDisplayName(displayName string) func(event *RoleChangedEvent) {
|
||||
return func(e *RoleChangedEvent) {
|
||||
e.DisplayName = &displayName
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeGroup(group string) func(event *RoleChangedEvent) {
|
||||
return func(e *RoleChangedEvent) {
|
||||
e.Group = &group
|
||||
}
|
||||
}
|
||||
func RoleChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &RoleChangedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-3M0vx", "unable to unmarshal project role")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type RoleRemovedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
Key string `json:"key,omitempty"`
|
||||
projectID string
|
||||
}
|
||||
|
||||
func (e *RoleRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *RoleRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewRemoveProjectRoleUniqueConstraint(e.Key, e.projectID, e.ResourceOwner())}
|
||||
}
|
||||
|
||||
func NewRoleRemovedEvent(ctx context.Context, key, projectID, resourceOwner string) *RoleRemovedEvent {
|
||||
return &RoleRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
|
||||
ctx,
|
||||
RoleRemovedType,
|
||||
resourceOwner,
|
||||
),
|
||||
Key: key,
|
||||
projectID: projectID,
|
||||
}
|
||||
}
|
||||
|
||||
func RoleRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &RoleRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "PROJECT-1M0xs", "unable to unmarshal project role")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
@@ -167,7 +167,7 @@ type UserGrantRemovedEvent struct {
|
||||
}
|
||||
|
||||
func (e *UserGrantRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *UserGrantRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
@@ -187,16 +187,9 @@ func NewUserGrantRemovedEvent(ctx context.Context, resourceOwner, userID, projec
|
||||
}
|
||||
|
||||
func UserGrantRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &UserGrantRemovedEvent{
|
||||
return &UserGrantRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "UGRANT-M0sdf", "unable to unmarshal user grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
type UserGrantCascadeRemovedEvent struct {
|
||||
@@ -206,18 +199,18 @@ type UserGrantCascadeRemovedEvent struct {
|
||||
}
|
||||
|
||||
func (e *UserGrantCascadeRemovedEvent) Data() interface{} {
|
||||
return e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *UserGrantCascadeRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{NewRemoveUserGrantUniqueConstraint(e.ResourceOwner(), e.userID, e.projectID)}
|
||||
}
|
||||
|
||||
func NewUserGrantCascadeRemovedEvent(ctx context.Context, resourceOwner, userID, projectID string) *UserGrantRemovedEvent {
|
||||
return &UserGrantRemovedEvent{
|
||||
func NewUserGrantCascadeRemovedEvent(ctx context.Context, resourceOwner, userID, projectID string) *UserGrantCascadeRemovedEvent {
|
||||
return &UserGrantCascadeRemovedEvent{
|
||||
BaseEvent: *eventstore.NewBaseEventForPushWithResourceOwner(
|
||||
ctx,
|
||||
UserGrantRemovedType,
|
||||
UserGrantCascadeRemovedType,
|
||||
resourceOwner,
|
||||
),
|
||||
userID: userID,
|
||||
@@ -226,16 +219,9 @@ func NewUserGrantCascadeRemovedEvent(ctx context.Context, resourceOwner, userID,
|
||||
}
|
||||
|
||||
func UserGrantCascadeRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &UserGrantRemovedEvent{
|
||||
return &UserGrantCascadeRemovedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "UGRANT-E7urs", "unable to unmarshal user grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
type UserGrantDeactivatedEvent struct {
|
||||
@@ -243,7 +229,7 @@ type UserGrantDeactivatedEvent struct {
|
||||
}
|
||||
|
||||
func (e *UserGrantDeactivatedEvent) Data() interface{} {
|
||||
return e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *UserGrantDeactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
@@ -260,16 +246,9 @@ func NewUserGrantDeactivatedEvent(ctx context.Context) *UserGrantDeactivatedEven
|
||||
}
|
||||
|
||||
func UserGrantDeactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &UserGrantDeactivatedEvent{
|
||||
return &UserGrantDeactivatedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "UGRANT-pL0ds", "unable to unmarshal user grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
type UserGrantReactivatedEvent struct {
|
||||
@@ -277,7 +256,7 @@ type UserGrantReactivatedEvent struct {
|
||||
}
|
||||
|
||||
func (e *UserGrantReactivatedEvent) Data() interface{} {
|
||||
return e
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *UserGrantReactivatedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
@@ -294,14 +273,7 @@ func NewUserGrantReactivatedEvent(ctx context.Context) *UserGrantReactivatedEven
|
||||
}
|
||||
|
||||
func UserGrantReactivatedEventMapper(event *repository.Event) (eventstore.EventReader, error) {
|
||||
e := &UserGrantReactivatedEvent{
|
||||
return &UserGrantReactivatedEvent{
|
||||
BaseEvent: *eventstore.BaseEventFromRepo(event),
|
||||
}
|
||||
|
||||
err := json.Unmarshal(event.Data, e)
|
||||
if err != nil {
|
||||
return nil, errors.ThrowInternal(err, "UGRANT-M0sdf", "unable to unmarshal user grant")
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user