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:
Fabi
2021-01-28 06:35:26 +01:00
committed by GitHub
parent dfcb96d6a3
commit c65331df1a
58 changed files with 3746 additions and 965 deletions

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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,
//)
}

View 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
}

View 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
}

View File

@@ -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,
}
}

View 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
}

View 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
}

View 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)
}

View 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)
}

View File

@@ -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)
}

View File

@@ -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),

View 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
}

View 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
}

View File

@@ -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
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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
}

View 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
}

View File

@@ -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
}

View 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 != ""
}

View 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
}

View File

@@ -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}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)
}

View 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
}

View 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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View 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
}

View File

@@ -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
}