mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-17 21:37:35 +00:00
43fb3fd1a6
* fix: potential memory leak * feat(actions): possibility to parse json feat(actions): possibility to perform http calls * add query call * feat(api): list flow and trigger types fix(api): switch flow and trigger types to dynamic objects * fix(translations): add action translations * use `domain.FlowType` * localizers * localization * trigger types * options on `query.Action` * add functions for actions * feat: management api: add list flow and trigger (#4352) * console changes * cleanup * fix: wrong localization Co-authored-by: Max Peintner <max@caos.ch> * id token works * check if claims not nil * feat(actions): metadata api * refactor(actions): modules * fix: allow prerelease * fix: test * feat(actions): deny list for http hosts * feat(actions): deny list for http hosts * refactor: actions * fix: different error ids * fix: rename statusCode to status * Actions objects as options (#4418) * fix: rename statusCode to status * fix(actions): objects as options * fix(actions): objects as options * fix(actions): set fields * add http client to old actions * fix(actions): add log module * fix(actions): add user to context where possible * fix(actions): add user to ctx in external authorization/pre creation * fix(actions): query correct flow in claims * test: actions * fix(id-generator): panic if no machine id * tests * maybe this? * fix linting * refactor: improve code * fix: metadata and usergrant usage in actions * fix: appendUserGrant * fix: allowedToFail and timeout in action execution * fix: allowed to fail in token complement flow * docs: add action log claim * Update defaults.yaml * fix log claim * remove prerelease build Co-authored-by: Max Peintner <max@caos.ch> Co-authored-by: Livio Spring <livio.a@gmail.com>
333 lines
12 KiB
Go
333 lines
12 KiB
Go
package command
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"github.com/zitadel/logging"
|
|
|
|
"github.com/zitadel/zitadel/internal/command/preparation"
|
|
"github.com/zitadel/zitadel/internal/domain"
|
|
"github.com/zitadel/zitadel/internal/errors"
|
|
caos_errs "github.com/zitadel/zitadel/internal/errors"
|
|
"github.com/zitadel/zitadel/internal/eventstore"
|
|
"github.com/zitadel/zitadel/internal/repository/project"
|
|
)
|
|
|
|
func (c *Commands) AddProjectWithID(ctx context.Context, project *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) {
|
|
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if existingProject.State != domain.ProjectStateUnspecified {
|
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-opamwu", "Errors.Project.AlreadyExisting")
|
|
}
|
|
return c.addProjectWithID(ctx, project, resourceOwner, projectID)
|
|
}
|
|
|
|
func (c *Commands) AddProject(ctx context.Context, project *domain.Project, resourceOwner, ownerUserID string) (_ *domain.Project, err error) {
|
|
if !project.IsValid() {
|
|
return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
|
}
|
|
|
|
projectID, err := c.idGenerator.Next()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return c.addProjectWithIDWithOwner(ctx, project, resourceOwner, ownerUserID, projectID)
|
|
}
|
|
|
|
func (c *Commands) addProjectWithID(ctx context.Context, projectAdd *domain.Project, resourceOwner, projectID string) (_ *domain.Project, err error) {
|
|
projectAdd.AggregateID = projectID
|
|
addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner)
|
|
projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel)
|
|
|
|
events := []eventstore.Command{
|
|
project.NewProjectAddedEvent(
|
|
ctx,
|
|
projectAgg,
|
|
projectAdd.Name,
|
|
projectAdd.ProjectRoleAssertion,
|
|
projectAdd.ProjectRoleCheck,
|
|
projectAdd.HasProjectCheck,
|
|
projectAdd.PrivateLabelingSetting),
|
|
}
|
|
|
|
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = AppendAndReduce(addedProject, pushedEvents...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return projectWriteModelToProject(addedProject), nil
|
|
}
|
|
|
|
func (c *Commands) addProjectWithIDWithOwner(ctx context.Context, projectAdd *domain.Project, resourceOwner, ownerUserID, projectID string) (_ *domain.Project, err error) {
|
|
if !projectAdd.IsValid() {
|
|
return nil, caos_errs.ThrowInvalidArgument(nil, "PROJECT-IOVCC", "Errors.Project.Invalid")
|
|
}
|
|
projectAdd.AggregateID = projectID
|
|
addedProject := NewProjectWriteModel(projectAdd.AggregateID, resourceOwner)
|
|
projectAgg := ProjectAggregateFromWriteModel(&addedProject.WriteModel)
|
|
|
|
projectRole := domain.RoleProjectOwner
|
|
events := []eventstore.Command{
|
|
project.NewProjectAddedEvent(
|
|
ctx,
|
|
projectAgg,
|
|
projectAdd.Name,
|
|
projectAdd.ProjectRoleAssertion,
|
|
projectAdd.ProjectRoleCheck,
|
|
projectAdd.HasProjectCheck,
|
|
projectAdd.PrivateLabelingSetting),
|
|
project.NewProjectMemberAddedEvent(ctx, projectAgg, ownerUserID, projectRole),
|
|
}
|
|
|
|
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = AppendAndReduce(addedProject, pushedEvents...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return projectWriteModelToProject(addedProject), nil
|
|
}
|
|
|
|
func AddProjectCommand(
|
|
a *project.Aggregate,
|
|
name string,
|
|
owner string,
|
|
projectRoleAssertion bool,
|
|
projectRoleCheck bool,
|
|
hasProjectCheck bool,
|
|
privateLabelingSetting domain.PrivateLabelingSetting,
|
|
) preparation.Validation {
|
|
return func() (preparation.CreateCommands, error) {
|
|
if name = strings.TrimSpace(name); name == "" {
|
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-C01yo", "Errors.Invalid.Argument")
|
|
}
|
|
if !privateLabelingSetting.Valid() {
|
|
return nil, errors.ThrowInvalidArgument(nil, "PROJE-AO52V", "Errors.Invalid.Argument")
|
|
}
|
|
if owner == "" {
|
|
return nil, errors.ThrowPreconditionFailed(nil, "PROJE-hzxwo", "Errors.Invalid.Argument")
|
|
}
|
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
|
return []eventstore.Command{
|
|
project.NewProjectAddedEvent(ctx, &a.Aggregate,
|
|
name,
|
|
projectRoleAssertion,
|
|
projectRoleCheck,
|
|
hasProjectCheck,
|
|
privateLabelingSetting,
|
|
),
|
|
project.NewProjectMemberAddedEvent(ctx, &a.Aggregate,
|
|
owner,
|
|
domain.RoleProjectOwner),
|
|
}, nil
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
func projectWriteModel(ctx context.Context, filter preparation.FilterToQueryReducer, projectID, resourceOwner string) (project *ProjectWriteModel, err error) {
|
|
project = NewProjectWriteModel(projectID, resourceOwner)
|
|
events, err := filter(ctx, project.Query())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
project.AppendEvents(events...)
|
|
if err := project.Reduce(); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return project, nil
|
|
}
|
|
|
|
func (c *Commands) getProjectByID(ctx context.Context, projectID, resourceOwner string) (*domain.Project, error) {
|
|
projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if projectWriteModel.State == domain.ProjectStateUnspecified || projectWriteModel.State == domain.ProjectStateRemoved {
|
|
return nil, caos_errs.ThrowNotFound(nil, "PROJECT-Gd2hh", "Errors.Project.NotFound")
|
|
}
|
|
return projectWriteModelToProject(projectWriteModel), nil
|
|
}
|
|
|
|
func (c *Commands) checkProjectExists(ctx context.Context, projectID, resourceOwner string) error {
|
|
projectWriteModel, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if projectWriteModel.State == domain.ProjectStateUnspecified || projectWriteModel.State == domain.ProjectStateRemoved {
|
|
return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-EbFMN", "Errors.Project.NotFound")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (c *Commands) ChangeProject(ctx context.Context, projectChange *domain.Project, resourceOwner string) (*domain.Project, error) {
|
|
if !projectChange.IsValid() || projectChange.AggregateID == "" {
|
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.Invalid")
|
|
}
|
|
|
|
existingProject, err := c.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")
|
|
}
|
|
|
|
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
|
changedEvent, hasChanged, err := existingProject.NewChangedEvent(
|
|
ctx,
|
|
projectAgg,
|
|
projectChange.Name,
|
|
projectChange.ProjectRoleAssertion,
|
|
projectChange.ProjectRoleCheck,
|
|
projectChange.HasProjectCheck,
|
|
projectChange.PrivateLabelingSetting)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if !hasChanged {
|
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-2M0fs", "Errors.NoChangesFound")
|
|
}
|
|
pushedEvents, err := c.eventstore.Push(ctx, changedEvent)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = AppendAndReduce(existingProject, pushedEvents...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return projectWriteModelToProject(existingProject), nil
|
|
}
|
|
|
|
func (c *Commands) DeactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
|
if projectID == "" || resourceOwner == "" {
|
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-88iF0", "Errors.Project.ProjectIDMissing")
|
|
}
|
|
|
|
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, resourceOwner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if existingProject.State == domain.ProjectStateUnspecified || existingProject.State == domain.ProjectStateRemoved {
|
|
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-112M9", "Errors.Project.NotFound")
|
|
}
|
|
if existingProject.State != domain.ProjectStateActive {
|
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-mki55", "Errors.Project.NotActive")
|
|
}
|
|
|
|
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
|
pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectDeactivatedEvent(ctx, projectAgg))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = AppendAndReduce(existingProject, pushedEvents...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
|
}
|
|
|
|
func (c *Commands) ReactivateProject(ctx context.Context, projectID string, resourceOwner string) (*domain.ObjectDetails, error) {
|
|
if projectID == "" || resourceOwner == "" {
|
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-3ihsF", "Errors.Project.ProjectIDMissing")
|
|
}
|
|
|
|
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, 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")
|
|
}
|
|
if existingProject.State != domain.ProjectStateInactive {
|
|
return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-5M9bs", "Errors.Project.NotInactive")
|
|
}
|
|
|
|
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
|
pushedEvents, err := c.eventstore.Push(ctx, project.NewProjectReactivatedEvent(ctx, projectAgg))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = AppendAndReduce(existingProject, pushedEvents...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
|
}
|
|
|
|
func (c *Commands) RemoveProject(ctx context.Context, projectID, resourceOwner string, cascadingUserGrantIDs ...string) (*domain.ObjectDetails, error) {
|
|
if projectID == "" || resourceOwner == "" {
|
|
return nil, caos_errs.ThrowInvalidArgument(nil, "COMMAND-66hM9", "Errors.Project.ProjectIDMissing")
|
|
}
|
|
|
|
existingProject, err := c.getProjectWriteModelByID(ctx, projectID, 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")
|
|
}
|
|
|
|
samlEntityIDsAgg, err := c.getSAMLEntityIdsWriteModelByProjectID(ctx, projectID, resourceOwner)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
uniqueConstraints := make([]*eventstore.EventUniqueConstraint, len(samlEntityIDsAgg.EntityIDs))
|
|
for i, entityID := range samlEntityIDsAgg.EntityIDs {
|
|
uniqueConstraints[i] = project.NewRemoveSAMLConfigEntityIDUniqueConstraint(entityID.EntityID)
|
|
}
|
|
|
|
projectAgg := ProjectAggregateFromWriteModel(&existingProject.WriteModel)
|
|
events := []eventstore.Command{
|
|
project.NewProjectRemovedEvent(ctx, projectAgg, existingProject.Name, uniqueConstraints),
|
|
}
|
|
|
|
for _, grantID := range cascadingUserGrantIDs {
|
|
event, _, err := c.removeUserGrant(ctx, grantID, "", true)
|
|
if err != nil {
|
|
logging.LogWithFields("COMMAND-b8Djf", "usergrantid", grantID).WithError(err).Warn("could not cascade remove user grant")
|
|
continue
|
|
}
|
|
events = append(events, event)
|
|
}
|
|
|
|
pushedEvents, err := c.eventstore.Push(ctx, events...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = AppendAndReduce(existingProject, pushedEvents...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return writeModelToObjectDetails(&existingProject.WriteModel), nil
|
|
}
|
|
|
|
func (c *Commands) getProjectWriteModelByID(ctx context.Context, projectID, resourceOwner string) (*ProjectWriteModel, error) {
|
|
projectWriteModel := NewProjectWriteModel(projectID, resourceOwner)
|
|
err := c.eventstore.FilterToQueryReducer(ctx, projectWriteModel)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return projectWriteModel, nil
|
|
}
|
|
|
|
func (c *Commands) getSAMLEntityIdsWriteModelByProjectID(ctx context.Context, projectID, resourceOwner string) (*SAMLEntityIDsWriteModel, error) {
|
|
samlEntityIDsAgg := NewSAMLEntityIDsWriteModel(projectID, resourceOwner)
|
|
err := c.eventstore.FilterToQueryReducer(ctx, samlEntityIDsAgg)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return samlEntityIDsAgg, nil
|
|
}
|