diff --git a/cmd/zitadel/system-defaults.yaml b/cmd/zitadel/system-defaults.yaml index b9d92f9637..23aefaa57c 100644 --- a/cmd/zitadel/system-defaults.yaml +++ b/cmd/zitadel/system-defaults.yaml @@ -45,7 +45,7 @@ SystemDefaults: IncludeDigits: true IncludeSymbols: false MachineKeySize: 2048 - ClientKeySize: 2048 + ApplicationKeySize: 2048 Multifactors: OTP: Issuer: 'ZITADEL' diff --git a/internal/api/grpc/management/application.go b/internal/api/grpc/management/application.go index 6e0bc7293a..29250b7377 100644 --- a/internal/api/grpc/management/application.go +++ b/internal/api/grpc/management/application.go @@ -2,6 +2,7 @@ package management import ( "context" + "github.com/caos/zitadel/internal/api/authz" "github.com/golang/protobuf/ptypes/empty" @@ -32,13 +33,15 @@ func (s *Server) CreateOIDCApplication(ctx context.Context, in *management.OIDCA } return oidcAppFromDomain(app), nil } + func (s *Server) CreateAPIApplication(ctx context.Context, in *management.APIApplicationCreate) (*management.Application, error) { - app, err := s.project.AddApplication(ctx, apiAppCreateToModel(in)) + app, err := s.command.AddAPIApplication(ctx, apiAppCreateToModel(in), authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } - return appFromModel(app), nil + return apiAppFromDomain(app), nil } + func (s *Server) UpdateApplication(ctx context.Context, in *management.ApplicationUpdate) (*management.Application, error) { app, err := s.command.ChangeApplication(ctx, in.ProjectId, appUpdateToDomain(in), authz.GetCtxData(ctx).OrgID) if err != nil { @@ -46,10 +49,12 @@ func (s *Server) UpdateApplication(ctx context.Context, in *management.Applicati } return appFromDomain(app), nil } + func (s *Server) DeactivateApplication(ctx context.Context, in *management.ApplicationID) (*empty.Empty, error) { err := s.command.DeactivateApplication(ctx, in.ProjectId, in.Id, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err } + func (s *Server) ReactivateApplication(ctx context.Context, in *management.ApplicationID) (*empty.Empty, error) { err := s.command.ReactivateApplication(ctx, in.ProjectId, in.Id, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err @@ -69,15 +74,15 @@ func (s *Server) UpdateApplicationOIDCConfig(ctx context.Context, in *management } func (s *Server) UpdateApplicationAPIConfig(ctx context.Context, in *management.APIConfigUpdate) (*management.APIConfig, error) { - config, err := s.project.ChangeAPIConfig(ctx, apiConfigUpdateToModel(in)) + config, err := s.command.ChangeAPIApplication(ctx, apiConfigUpdateToDomain(in), authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } - return apiConfigFromModel(config), nil + return apiConfigFromDomain(config), nil } func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *management.ApplicationID) (*management.ClientSecret, error) { - config, err := s.command.ChangeOIDCApplicationSecret(ctx, in.ProjectId, in.Id, authz.GetCtxData(ctx).ResourceOwner) + config, err := s.command.ChangeOIDCApplicationSecret(ctx, in.ProjectId, in.Id, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } @@ -85,7 +90,7 @@ func (s *Server) RegenerateOIDCClientSecret(ctx context.Context, in *management. } func (s *Server) RegenerateAPIClientSecret(ctx context.Context, in *management.ApplicationID) (*management.ClientSecret, error) { - config, err := s.project.ChangeAPIConfigSecret(ctx, in.ProjectId, in.Id) + config, err := s.command.ChangeAPIApplicationSecret(ctx, in.ProjectId, in.Id, authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } @@ -117,14 +122,14 @@ func (s *Server) GetClientKey(ctx context.Context, req *management.ClientKeyIDRe } func (s *Server) AddClientKey(ctx context.Context, req *management.AddClientKeyRequest) (*management.AddClientKeyResponse, error) { - key, err := s.project.AddClientKey(ctx, addClientKeyToModel(req)) + key, err := s.command.AddApplicationKey(ctx, addClientKeyToDomain(req), authz.GetCtxData(ctx).OrgID) if err != nil { return nil, err } - return addClientKeyFromModel(key), nil + return addClientKeyFromDomain(key), nil } func (s *Server) DeleteClientKey(ctx context.Context, req *management.ClientKeyIDRequest) (*empty.Empty, error) { - err := s.project.RemoveClientKey(ctx, req.ProjectId, req.ApplicationId, req.KeyId) + err := s.command.RemoveApplicationKey(ctx, req.ProjectId, req.ApplicationId, req.KeyId, authz.GetCtxData(ctx).OrgID) return &empty.Empty{}, err } diff --git a/internal/api/grpc/management/application_converter.go b/internal/api/grpc/management/application_converter.go index 2c0cc243ac..294268a16b 100644 --- a/internal/api/grpc/management/application_converter.go +++ b/internal/api/grpc/management/application_converter.go @@ -61,11 +61,26 @@ func oidcAppFromDomain(app *domain.OIDCApp) *management.Application { } } +func apiAppFromDomain(app *domain.APIApp) *management.Application { + return &management.Application{ + Id: app.AppID, + State: appStateFromDomain(app.State), + ChangeDate: timestamppb.New(app.ChangeDate), + Name: app.AppName, + Sequence: app.Sequence, + AppConfig: apiAppConfigFromDomain(app), + } +} + func oidcAppConfigFromDomain(app *domain.OIDCApp) management.AppConfig { return &management.Application_OidcConfig{ OidcConfig: oidcConfigFromDomain(app), } - return nil +} +func apiAppConfigFromDomain(app *domain.APIApp) management.AppConfig { + return &management.Application_ApiConfig{ + ApiConfig: apiConfigFromDomain(app), + } } func oidcConfigFromDomain(config *domain.OIDCApp) *management.OIDCConfig { @@ -90,6 +105,14 @@ func oidcConfigFromDomain(config *domain.OIDCApp) *management.OIDCConfig { } } +func apiConfigFromDomain(config *domain.APIApp) *management.APIConfig { + return &management.APIConfig{ + ClientId: config.ClientID, + ClientSecret: config.ClientSecretString, + AuthMethodType: apiAuthMethodTypeFromDomain(config.AuthMethodType), + } +} + func apiConfigFromModel(config *proj_model.APIConfig) *management.APIConfig { return &management.APIConfig{ ClientId: config.ClientID, @@ -150,6 +173,16 @@ func oidcAppCreateToDomain(app *management.OIDCApplicationCreate) *domain.OIDCAp } } +func apiAppCreateToModel(app *management.APIApplicationCreate) *domain.APIApp { + return &domain.APIApp{ + ObjectRoot: models.ObjectRoot{ + AggregateID: app.ProjectId, + }, + AppName: app.Name, + AuthMethodType: apiAuthMethodTypeToDomain(app.AuthMethodType), + } +} + func appUpdateToDomain(app *management.ApplicationUpdate) domain.Application { return &domain.ChangeApp{ AppID: app.Id, @@ -157,29 +190,6 @@ func appUpdateToDomain(app *management.ApplicationUpdate) domain.Application { } } -func apiAppCreateToModel(app *management.APIApplicationCreate) *proj_model.Application { - return &proj_model.Application{ - ObjectRoot: models.ObjectRoot{ - AggregateID: app.ProjectId, - }, - Name: app.Name, - Type: proj_model.AppTypeAPI, - APIConfig: &proj_model.APIConfig{ - AuthMethodType: apiAuthMethodTypeToModel(app.AuthMethodType), - }, - } -} - -func appUpdateToModel(app *management.ApplicationUpdate) *proj_model.Application { - return &proj_model.Application{ - ObjectRoot: models.ObjectRoot{ - AggregateID: app.ProjectId, - }, - AppID: app.Id, - Name: app.Name, - } -} - func oidcConfigUpdateToDomain(app *management.OIDCConfigUpdate) *domain.OIDCApp { return &domain.OIDCApp{ ObjectRoot: models.ObjectRoot{ @@ -201,13 +211,43 @@ func oidcConfigUpdateToDomain(app *management.OIDCConfigUpdate) *domain.OIDCApp } } -func apiConfigUpdateToModel(app *management.APIConfigUpdate) *proj_model.APIConfig { - return &proj_model.APIConfig{ +func apiConfigUpdateToDomain(app *management.APIConfigUpdate) *domain.APIApp { + return &domain.APIApp{ ObjectRoot: models.ObjectRoot{ AggregateID: app.ProjectId, }, AppID: app.ApplicationId, - AuthMethodType: apiAuthMethodTypeToModel(app.AuthMethodType), + AuthMethodType: apiAuthMethodTypeToDomain(app.AuthMethodType), + } +} + +func addClientKeyToDomain(key *management.AddClientKeyRequest) *domain.ApplicationKey { + expirationDate := time.Time{} + if key.ExpirationDate != nil { + expirationDate = key.ExpirationDate.AsTime() + } + + return &domain.ApplicationKey{ + ObjectRoot: models.ObjectRoot{ + AggregateID: key.ProjectId, + }, + ExpirationDate: expirationDate, + Type: authNKeyTypeToDomain(key.Type), + ApplicationID: key.ApplicationId, + } +} + +func addClientKeyFromDomain(key *domain.ApplicationKey) *management.AddClientKeyResponse { + detail, err := key.Detail() + logging.Log("MANAG-adt42").OnError(err).Warn("unable to marshal key") + + return &management.AddClientKeyResponse{ + Id: key.KeyID, + CreationDate: timestamppb.New(key.CreationDate), + ExpirationDate: timestamppb.New(key.ExpirationDate), + Sequence: key.Sequence, + KeyDetails: detail, + Type: authNKeyTypeFromDomain(key.Type), } } @@ -485,19 +525,32 @@ func oidcAuthMethodTypeFromDomain(authType domain.OIDCAuthMethodType) management return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_POST case domain.OIDCAuthMethodTypeNone: return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_NONE + case domain.OIDCAuthMethodTypePrivateKeyJWT: + return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_PRIVATE_KEY_JWT default: return management.OIDCAuthMethodType_OIDCAUTHMETHODTYPE_BASIC } } -func apiAuthMethodTypeToModel(authType management.APIAuthMethodType) proj_model.APIAuthMethodType { +func apiAuthMethodTypeToDomain(authType management.APIAuthMethodType) domain.APIAuthMethodType { switch authType { case management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC: - return proj_model.APIAuthMethodTypeBasic + return domain.APIAuthMethodTypeBasic case management.APIAuthMethodType_APIAUTHMETHODTYPE_PRIVATE_KEY_JWT: - return proj_model.APIAuthMethodTypePrivateKeyJWT + return domain.APIAuthMethodTypePrivateKeyJWT default: - return proj_model.APIAuthMethodTypeBasic + return domain.APIAuthMethodTypeBasic + } +} + +func apiAuthMethodTypeFromDomain(authType domain.APIAuthMethodType) management.APIAuthMethodType { + switch authType { + case domain.APIAuthMethodTypeBasic: + return management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC + case domain.APIAuthMethodTypePrivateKeyJWT: + return management.APIAuthMethodType_APIAUTHMETHODTYPE_PRIVATE_KEY_JWT + default: + return management.APIAuthMethodType_APIAUTHMETHODTYPE_BASIC } } @@ -558,6 +611,24 @@ func oidcVersionFromDomain(version domain.OIDCVersion) management.OIDCVersion { } } +func authNKeyTypeToDomain(keyType management.AuthNKeyType) domain.AuthNKeyType { + switch keyType { + case management.AuthNKeyType_AUTHNKEY_JSON: + return domain.AuthNKeyTypeJSON + default: + return domain.AuthNKeyTypeNONE + } +} + +func authNKeyTypeFromDomain(typ domain.AuthNKeyType) management.AuthNKeyType { + switch typ { + case domain.AuthNKeyTypeJSON: + return management.AuthNKeyType_AUTHNKEY_JSON + default: + return management.AuthNKeyType_AUTHNKEY_UNSPECIFIED + } +} + func appChangesToResponse(response *proj_model.ApplicationChanges, offset uint64, limit uint64) (_ *management.Changes) { return &management.Changes{ Limit: limit, @@ -612,63 +683,6 @@ func clientKeyViewFromModel(key *key_model.AuthNKeyView) *management.ClientKeyVi } } -func addClientKeyToModel(key *management.AddClientKeyRequest) *proj_model.ClientKey { - expirationDate := time.Time{} - if key.ExpirationDate != nil { - var err error - expirationDate, err = ptypes.Timestamp(key.ExpirationDate) - logging.Log("MANAG-Dgt42").OnError(err).Debug("unable to parse expiration date") - } - - return &proj_model.ClientKey{ - ExpirationDate: expirationDate, - Type: authNKeyTypeToModel(key.Type), - ApplicationID: key.ApplicationId, - ObjectRoot: models.ObjectRoot{AggregateID: key.ProjectId}, - } -} - -func addClientKeyFromModel(key *proj_model.ClientKey) *management.AddClientKeyResponse { - creationDate, err := ptypes.TimestampProto(key.CreationDate) - logging.Log("MANAG-FBzz4").OnError(err).Debug("unable to parse cretaion date") - - expirationDate, err := ptypes.TimestampProto(key.ExpirationDate) - logging.Log("MANAG-sag21").OnError(err).Debug("unable to parse cretaion date") - - detail, err := json.Marshal(struct { - Type string `json:"type"` - KeyID string `json:"keyId"` - Key string `json:"key"` - AppID string `json:"appId"` - ClientID string `json:"clientID"` - }{ - Type: "application", - KeyID: key.KeyID, - Key: string(key.PrivateKey), - AppID: key.ApplicationID, - ClientID: key.ClientID, - }) - logging.Log("MANAG-adt42").OnError(err).Warn("unable to marshall key") - - return &management.AddClientKeyResponse{ - Id: key.KeyID, - CreationDate: creationDate, - ExpirationDate: expirationDate, - Sequence: key.Sequence, - KeyDetails: detail, - Type: authNKeyTypeFromModel(key.Type), - } -} - -func authNKeyTypeToModel(typ management.AuthNKeyType) key_model.AuthNKeyType { - switch typ { - case management.AuthNKeyType_AUTHNKEY_JSON: - return key_model.AuthNKeyTypeJSON - default: - return key_model.AuthNKeyTypeNONE - } -} - func authNKeyTypeFromModel(typ key_model.AuthNKeyType) management.AuthNKeyType { switch typ { case key_model.AuthNKeyTypeJSON: diff --git a/internal/api/grpc/management/user_machine_converter.go b/internal/api/grpc/management/user_machine_converter.go index cfb19844cd..ab0c565b73 100644 --- a/internal/api/grpc/management/user_machine_converter.go +++ b/internal/api/grpc/management/user_machine_converter.go @@ -116,18 +116,18 @@ func addMachineKeyFromDomain(key *domain.MachineKey) *management.AddMachineKeyRe } } -func machineKeyTypeToDomain(typ management.MachineKeyType) domain.MachineKeyType { +func machineKeyTypeToDomain(typ management.MachineKeyType) domain.AuthNKeyType { switch typ { case management.MachineKeyType_MACHINEKEY_JSON: - return domain.MachineKeyTypeJSON + return domain.AuthNKeyTypeJSON default: - return domain.MachineKeyTypeNONE + return domain.AuthNKeyTypeNONE } } -func machineKeyTypeFromDomain(typ domain.MachineKeyType) management.MachineKeyType { +func machineKeyTypeFromDomain(typ domain.AuthNKeyType) management.MachineKeyType { switch typ { - case domain.MachineKeyTypeJSON: + case domain.AuthNKeyTypeJSON: return management.MachineKeyType_MACHINEKEY_JSON default: return management.MachineKeyType_MACHINEKEY_UNSPECIFIED diff --git a/internal/auth/repository/eventsourcing/eventstore/application.go b/internal/auth/repository/eventsourcing/eventstore/application.go index 95540846fb..c009c51bad 100644 --- a/internal/auth/repository/eventsourcing/eventstore/application.go +++ b/internal/auth/repository/eventsourcing/eventstore/application.go @@ -8,9 +8,11 @@ import ( proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model" "github.com/caos/zitadel/internal/telemetry/tracing" + "github.com/caos/zitadel/internal/v2/command" ) type ApplicationRepo struct { + Commands *command.CommandSide View *view.View ProjectEvents *proj_event.ProjectEventstore } @@ -31,5 +33,5 @@ func (a *ApplicationRepo) AuthorizeOIDCApplication(ctx context.Context, clientID if err != nil { return err } - return a.ProjectEvents.VerifyOIDCClientSecret(ctx, app.ProjectID, app.ID, secret) + return a.Commands.VerifyOIDCClientSecret(ctx, app.ProjectID, app.ID, secret) } diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index 48b8a46966..28cac3540f 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -158,6 +158,7 @@ func Start(conf Config, authZ authz.Config, systemDefaults sd.SystemDefaults, co SigningKeyRotation: systemDefaults.KeyConfig.SigningKeyRotation.Duration, }, eventstore.ApplicationRepo{ + Commands: command, View: view, ProjectEvents: project, }, diff --git a/internal/config/systemdefaults/system_defaults.go b/internal/config/systemdefaults/system_defaults.go index b623aad376..cd3aedf6eb 100644 --- a/internal/config/systemdefaults/system_defaults.go +++ b/internal/config/systemdefaults/system_defaults.go @@ -40,7 +40,7 @@ type SecretGenerators struct { PhoneVerificationCode crypto.GeneratorConfig PasswordVerificationCode crypto.GeneratorConfig MachineKeySize uint32 - ClientKeySize uint32 + ApplicationKeySize uint32 } type MultifactorConfig struct { diff --git a/internal/management/repository/eventsourcing/eventstore/project.go b/internal/management/repository/eventsourcing/eventstore/project.go index feed5543ea..4371f2693b 100644 --- a/internal/management/repository/eventsourcing/eventstore/project.go +++ b/internal/management/repository/eventsourcing/eventstore/project.go @@ -227,10 +227,6 @@ func (repo *ProjectRepo) ApplicationByID(ctx context.Context, projectID, appID s return model.ApplicationViewToModel(app), nil } -func (repo *ProjectRepo) AddApplication(ctx context.Context, app *proj_model.Application) (*proj_model.Application, error) { - return repo.ProjectEvents.AddApplication(ctx, app) -} - func (repo *ProjectRepo) SearchApplications(ctx context.Context, request *proj_model.ApplicationSearchRequest) (*proj_model.ApplicationSearchResponse, error) { request.EnsureLimit(repo.SearchLimit) sequence, sequenceErr := repo.View.GetLatestApplicationSequence() @@ -322,22 +318,6 @@ func (repo *ProjectRepo) GetClientKey(ctx context.Context, projectID, applicatio return key_view_model.AuthNKeyToModel(key), nil } -func (repo *ProjectRepo) AddClientKey(ctx context.Context, key *proj_model.ClientKey) (*proj_model.ClientKey, error) { - return repo.ProjectEvents.AddClientKey(ctx, key) -} - -func (repo *ProjectRepo) RemoveClientKey(ctx context.Context, projectID, applicationID, keyID string) error { - return repo.ProjectEvents.RemoveApplicationKey(ctx, projectID, applicationID, keyID) -} - -func (repo *ProjectRepo) ChangeAPIConfig(ctx context.Context, config *proj_model.APIConfig) (*proj_model.APIConfig, error) { - return repo.ProjectEvents.ChangeAPIConfig(ctx, config) -} - -func (repo *ProjectRepo) ChangeAPIConfigSecret(ctx context.Context, projectID, appID string) (*proj_model.APIConfig, error) { - return repo.ProjectEvents.ChangeAPIConfigSecret(ctx, projectID, appID) -} - func (repo *ProjectRepo) ProjectGrantByID(ctx context.Context, grantID string) (*proj_model.ProjectGrantView, error) { grant, err := repo.View.ProjectGrantByID(grantID) if err != nil { diff --git a/internal/management/repository/project.go b/internal/management/repository/project.go index 0fbed94ba3..4baa59690a 100644 --- a/internal/management/repository/project.go +++ b/internal/management/repository/project.go @@ -24,9 +24,6 @@ type ProjectRepository interface { ProjectChanges(ctx context.Context, id string, lastSequence uint64, limit uint64, sortAscending bool) (*model.ProjectChanges, error) ApplicationByID(ctx context.Context, projectID, appID string) (*model.ApplicationView, error) - AddApplication(ctx context.Context, app *model.Application) (*model.Application, error) - ChangeAPIConfig(ctx context.Context, config *model.APIConfig) (*model.APIConfig, error) - ChangeAPIConfigSecret(ctx context.Context, projectID, appID string) (*model.APIConfig, error) SearchApplications(ctx context.Context, request *model.ApplicationSearchRequest) (*model.ApplicationSearchResponse, error) ApplicationChanges(ctx context.Context, id string, secId string, lastSequence uint64, limit uint64, sortAscending bool) (*model.ApplicationChanges, error) SearchClientKeys(ctx context.Context, request *key_model.AuthNKeySearchRequest) (*key_model.AuthNKeySearchResponse, error) diff --git a/internal/project/repository/eventsourcing/eventstore.go b/internal/project/repository/eventsourcing/eventstore.go index 39df97cdd0..3a44e83e09 100644 --- a/internal/project/repository/eventsourcing/eventstore.go +++ b/internal/project/repository/eventsourcing/eventstore.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "strings" - "time" "github.com/caos/logging" "github.com/golang/protobuf/ptypes" @@ -18,10 +17,8 @@ import ( es_models "github.com/caos/zitadel/internal/eventstore/models" es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/id" - key_model "github.com/caos/zitadel/internal/key/model" proj_model "github.com/caos/zitadel/internal/project/model" "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" - "github.com/caos/zitadel/internal/telemetry/tracing" ) const ( @@ -56,7 +53,7 @@ func StartProject(conf ProjectConfig, systemDefaults sd.SystemDefaults) (*Projec passwordAlg: passwordAlg, pwGenerator: pwGenerator, idGenerator: id.SonyFlakeGenerator, - ClientKeySize: int(systemDefaults.SecretGenerators.ClientKeySize), + ClientKeySize: int(systemDefaults.SecretGenerators.ApplicationKeySize), }, nil } @@ -147,63 +144,19 @@ func ChangesQuery(projectID string, latestSequence, limit uint64, sortAscending return query } -func (es *ProjectEventstore) AddApplication(ctx context.Context, app *proj_model.Application) (*proj_model.Application, error) { - if app == nil || !app.IsValid(true) { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9eidw", "Errors.Project.App.Invalid") +func (es *ProjectEventstore) ApplicationByIDs(ctx context.Context, projectID, appID string) (*proj_model.Application, error) { + if projectID == "" || appID == "" { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-ld93d", "Errors.Project.IDMissing") } - existingProject, err := es.ProjectByID(ctx, app.AggregateID) - if err != nil { - return nil, err - } - app.AppID, err = es.idGenerator.Next() + project, err := es.ProjectByID(ctx, projectID) if err != nil { return nil, err } - var stringPw string - if app.OIDCConfig != nil { - app.OIDCConfig.AppID = app.AppID - err := app.OIDCConfig.GenerateNewClientID(es.idGenerator, existingProject) - if err != nil { - return nil, err - } - stringPw, err = app.OIDCConfig.GenerateClientSecretIfNeeded(es.pwGenerator) - if err != nil { - return nil, err - } + if _, a := project.GetApp(appID); a != nil { + return a, nil } - if app.APIConfig != nil { - app.APIConfig.AppID = app.AppID - err := app.APIConfig.GenerateNewClientID(es.idGenerator, existingProject) - if err != nil { - return nil, err - } - stringPw, err = app.APIConfig.GenerateClientSecretIfNeeded(es.pwGenerator) - if err != nil { - return nil, err - } - } - repoProject := model.ProjectFromModel(existingProject) - repoApp := model.AppFromModel(app) - - addAggregate := ApplicationAddedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoApp) - err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, addAggregate) - if err != nil { - return nil, err - } - es.projectCache.cacheProject(repoProject) - if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil { - converted := model.AppToModel(a) - if converted.OIDCConfig != nil { - converted.OIDCConfig.ClientSecretString = stringPw - converted.OIDCConfig.FillCompliance() - } - if converted.APIConfig != nil { - converted.APIConfig.ClientSecretString = stringPw - } - return converted, nil - } - return nil, caos_errs.ThrowInternal(nil, "EVENT-GvPct", "Errors.Internal") + return nil, caos_errs.ThrowNotFound(nil, "EVENT-8ei2s", "Errors.Project.App.NotFound") } func (es *ProjectEventstore) ApplicationChanges(ctx context.Context, projectID string, appID string, lastSequence uint64, limit uint64, sortAscending bool) (*proj_model.ApplicationChanges, error) { @@ -251,232 +204,3 @@ func (es *ProjectEventstore) ApplicationChanges(ctx context.Context, projectID s LastSequence: lastSequence, }, nil } - -func (es *ProjectEventstore) ChangeAPIConfig(ctx context.Context, config *proj_model.APIConfig) (*proj_model.APIConfig, error) { - if config == nil || !config.IsValid() { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-SDg54", "Errors.Project.APIConfigInvalid") - } - existingProject, err := es.ProjectByID(ctx, config.AggregateID) - if err != nil { - return nil, err - } - var app *proj_model.Application - if _, app = existingProject.GetApp(config.AppID); app == nil { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Rgu63", "Errors.Project.AppNotExisting") - } - if app.Type != proj_model.AppTypeAPI { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-RHj63", "Errors.Project.AppIsNotAPI") - } - repoProject := model.ProjectFromModel(existingProject) - repoConfig := model.APIConfigFromModel(config) - - projectAggregate := APIConfigChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, repoConfig) - err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate) - if err != nil { - return nil, err - } - es.projectCache.cacheProject(repoProject) - if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil { - return model.APIConfigToModel(a.APIConfig), nil - } - return nil, caos_errs.ThrowInternal(nil, "EVENT-aebn5", "Errors.Internal") -} - -func (es *ProjectEventstore) ChangeOIDCConfigSecret(ctx context.Context, projectID, appID string) (*proj_model.OIDCConfig, error) { - if appID == "" { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-7ue34", "Errors.Project.App.OIDCConfigInvalid") - } - existingProject, err := es.ProjectByID(ctx, projectID) - if err != nil { - return nil, err - } - var app *proj_model.Application - if _, app = existingProject.GetApp(appID); app == nil { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-9odi4", "Errors.Project.App.NotExisting") - } - if app.Type != proj_model.AppTypeOIDC { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-dile4", "Errors.Project.App.IsNotOIDC") - } - if app.OIDCConfig.AuthMethodType == proj_model.OIDCAuthMethodTypeNone || app.OIDCConfig.AuthMethodType == proj_model.OIDCAuthMethodTypePrivateKeyJWT { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-GDrg2", "Errors.Project.OIDCAuthMethodNoSecret") - } - repoProject := model.ProjectFromModel(existingProject) - - stringPw, err := app.OIDCConfig.GenerateNewClientSecret(es.pwGenerator) - if err != nil { - return nil, err - } - - projectAggregate := OIDCConfigSecretChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, appID, app.OIDCConfig.ClientSecret) - err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate) - if err != nil { - return nil, err - } - es.projectCache.cacheProject(repoProject) - - if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil { - config := model.OIDCConfigToModel(a.OIDCConfig) - config.ClientSecretString = stringPw - return config, nil - } - - return nil, caos_errs.ThrowInternal(nil, "EVENT-dk87s", "Errors.Internal") -} - -func (es *ProjectEventstore) ChangeAPIConfigSecret(ctx context.Context, projectID, appID string) (*proj_model.APIConfig, error) { - if appID == "" { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-sdfb3", "Errors.Project.APIConfigInvalid") - } - existingProject, err := es.ProjectByID(ctx, projectID) - if err != nil { - return nil, err - } - var app *proj_model.Application - if _, app = existingProject.GetApp(appID); app == nil { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-ADbg3", "Errors.Project.AppNotExisting") - } - if app.Type != proj_model.AppTypeAPI { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Ntwqw", "Errors.Project.AppIsNotAPI") - } - if app.APIConfig.AuthMethodType != proj_model.APIAuthMethodTypeBasic { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-HW4tw", "Errors.Project.APIAuthMethodNoSecret") - } - repoProject := model.ProjectFromModel(existingProject) - - stringPw, err := app.APIConfig.GenerateNewClientSecret(es.pwGenerator) - if err != nil { - return nil, err - } - - projectAggregate := APIConfigSecretChangedAggregate(es.Eventstore.AggregateCreator(), repoProject, appID, app.APIConfig.ClientSecret) - err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, projectAggregate) - if err != nil { - return nil, err - } - es.projectCache.cacheProject(repoProject) - - if _, a := model.GetApplication(repoProject.Applications, app.AppID); a != nil { - config := model.APIConfigToModel(a.APIConfig) - config.ClientSecretString = stringPw - return config, nil - } - - return nil, caos_errs.ThrowInternal(nil, "EVENT-HBfju", "Errors.Internal") -} - -func (es *ProjectEventstore) VerifyOIDCClientSecret(ctx context.Context, projectID, appID string, secret string) (err error) { - ctx, span := tracing.NewSpan(ctx) - defer func() { span.EndWithError(err) }() - if appID == "" { - return caos_errs.ThrowPreconditionFailed(nil, "EVENT-H3RT2", "Errors.Project.RequiredFieldsMissing") - } - existingProject, err := es.ProjectByID(ctx, projectID) - if err != nil { - return err - } - var app *proj_model.Application - if _, app = existingProject.GetApp(appID); app == nil { - return caos_errs.ThrowPreconditionFailed(nil, "EVENT-D6hba", "Errors.Project.AppNoExisting") - } - if app.Type != proj_model.AppTypeOIDC { - return caos_errs.ThrowPreconditionFailed(nil, "EVENT-huywq", "Errors.Project.App.IsNotOIDC") - } - - ctx, spanHash := tracing.NewSpan(ctx) - err = crypto.CompareHash(app.OIDCConfig.ClientSecret, []byte(secret), es.passwordAlg) - spanHash.EndWithError(err) - if err == nil { - err = es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckSucceededAggregate) - logging.Log("EVENT-AE1vf").OnError(err).Warn("could not push event OIDCClientSecretCheckSucceeded") - return nil - } - err = es.setOIDCClientSecretCheckResult(ctx, existingProject, app.AppID, OIDCClientSecretCheckFailedAggregate) - logging.Log("EVENT-GD1gh").OnError(err).Warn("could not push event OIDCClientSecretCheckFailed") - return caos_errs.ThrowInvalidArgument(nil, "EVENT-wg24q", "Errors.Project.OIDCSecretInvalid") -} - -func (es *ProjectEventstore) setOIDCClientSecretCheckResult(ctx context.Context, project *proj_model.Project, appID string, check func(*es_models.AggregateCreator, *model.Project, string) es_sdk.AggregateFunc) error { - repoProject := model.ProjectFromModel(project) - agg := check(es.AggregateCreator(), repoProject, appID) - err := es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, agg) - if err != nil { - return err - } - es.projectCache.cacheProject(repoProject) - return nil -} - -func (es *ProjectEventstore) AddClientKey(ctx context.Context, key *proj_model.ClientKey) (*proj_model.ClientKey, error) { - existingProject, err := es.ProjectByID(ctx, key.AggregateID) - if err != nil { - return nil, err - } - var app *proj_model.Application - if _, app = existingProject.GetApp(key.ApplicationID); app == nil { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Dbf32", "Errors.Project.AppNoExisting") - } - if (app.OIDCConfig == nil || app.OIDCConfig != nil && app.OIDCConfig.AuthMethodType != proj_model.OIDCAuthMethodTypePrivateKeyJWT) && - (app.APIConfig == nil || app.APIConfig != nil && app.APIConfig.AuthMethodType != proj_model.APIAuthMethodTypePrivateKeyJWT) { - return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-Dff54", "Errors.Project.AuthMethodNoPrivateKeyJWT") - } - if app.OIDCConfig != nil { - key.ClientID = app.OIDCConfig.ClientID - } - if app.APIConfig != nil { - key.ClientID = app.APIConfig.ClientID - } - key.KeyID, err = es.idGenerator.Next() - if err != nil { - return nil, err - } - if key.ExpirationDate.IsZero() { - key.ExpirationDate, err = key_model.DefaultExpiration() - if err != nil { - logging.Log("EVENT-Adgf2").WithError(err).Warn("unable to set default date") - return nil, errors.ThrowInternal(err, "EVENT-j68fg", "Errors.Internal") - } - } - if key.ExpirationDate.Before(time.Now()) { - return nil, errors.ThrowInvalidArgument(nil, "EVENT-C6YV5", "Errors.MachineKey.ExpireBeforeNow") - } - - repoProject := model.ProjectFromModel(existingProject) - repoKey := model.ClientKeyFromModel(key) - err = repoKey.GenerateClientKeyPair(es.ClientKeySize) - if err != nil { - return nil, err - } - agg := OIDCApplicationKeyAddedAggregate(es.AggregateCreator(), repoProject, repoKey) - err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, agg) - if err != nil { - return nil, err - } - es.projectCache.cacheProject(repoProject) - - return model.ClientKeyToModel(repoKey), nil -} - -func (es *ProjectEventstore) RemoveApplicationKey(ctx context.Context, projectID, applicationID, keyID string) error { - existingProject, err := es.ProjectByID(ctx, projectID) - if err != nil { - return err - } - var app *proj_model.Application - if _, app = existingProject.GetApp(applicationID); app == nil { - return caos_errs.ThrowPreconditionFailed(nil, "EVENT-ADfzz", "Errors.Project.AppNotExisting") - } - if app.Type != proj_model.AppTypeOIDC { - return caos_errs.ThrowPreconditionFailed(nil, "EVENT-ADffh", "Errors.Project.AppIsNotOIDC") - } - if _, key := app.GetKey(keyID); key == nil { - return caos_errs.ThrowPreconditionFailed(nil, "EVENT-D2Sff", "Errors.Project.AppKeyNotExisting") - } - repoProject := model.ProjectFromModel(existingProject) - agg := OIDCApplicationKeyRemovedAggregate(es.AggregateCreator(), repoProject, keyID) - err = es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, agg) - if err != nil { - return err - } - es.projectCache.cacheProject(repoProject) - return nil -} diff --git a/internal/static/i18n/de.yaml b/internal/static/i18n/de.yaml index 306a37c4a5..ae1e072401 100644 --- a/internal/static/i18n/de.yaml +++ b/internal/static/i18n/de.yaml @@ -197,6 +197,7 @@ Errors: OIDCAuthMethodNoSecret: Gewählte OIDC Auth Method benötigt kein Secret APIAuthMethodNoSecret: Gewählte API Auth Method benötigt kein Secret AuthMethodNoPrivateKeyJWT: Gewählte Auth Method benötigt keinen Key + OIDCSecretInvalid: Client Secret ist ungültig RequiredFieldsMissing: Benötigte Felder fehlen Grant: AlreadyExists: Projekt Grant existiert bereits @@ -207,7 +208,6 @@ Errors: NotActive: Projekt Grant ist nicht aktiv NotInactive: Projekt Grant ist nicht inaktiv UserIDMisisng: User ID fehlt - OIDCSecretInvalid: Client Secret ist ungültig IAM: Member: RolesNotChanged: Rollen wurden nicht verändert diff --git a/internal/static/i18n/en.yaml b/internal/static/i18n/en.yaml index 7a19e2f03d..ab9eb512ea 100644 --- a/internal/static/i18n/en.yaml +++ b/internal/static/i18n/en.yaml @@ -185,9 +185,9 @@ Errors: IDMissing: ID missing App: AlreadyExists: Application already exists + NotFound: Application not found Invalid: Application invalid NotExisting: Application doesn't exist - IsNotOIDC: Application is not type oidc NotActive:: Application is not active NotInactive: Application is not inactive OIDCConfigInvalid: OIDC configuration is invalid @@ -197,6 +197,7 @@ Errors: OIDCAuthMethodNoSecret: Chosen OIDC Auth Method does not require a secret APIAuthMethodNoSecret: Chosen API Auth Method does not require a secret AuthMethodNoPrivateKeyJWT: Chosen Auth Method does not require a key + OIDCSecretInvalid: Client Secret is invalid RequiredFieldsMissing: Some required fields are missing Grant: AlreadyExists: Project grant already exists @@ -207,7 +208,6 @@ Errors: NotActive: Project grant is not active NotInactive: Project grant is not inactive UserIDMisisng: User ID missing - OIDCSecretInvalid: Client Secret is invalid IAM: Member: RolesNotChanged: Roles habe not been changed diff --git a/internal/v2/command/command.go b/internal/v2/command/command.go index 23ba46305c..2e1f6cbd33 100644 --- a/internal/v2/command/command.go +++ b/internal/v2/command/command.go @@ -34,14 +34,15 @@ type CommandSide struct { passwordVerificationCode crypto.Generator machineKeyAlg crypto.EncryptionAlgorithm machineKeySize int + applicationKeySize int applicationSecretGenerator crypto.Generator domainVerificationAlg *crypto.AESCrypto domainVerificationGenerator crypto.Generator domainVerificationValidator func(domain, token, verifier string, checkType http.CheckType) error //TODO: remove global model, or move to domain multifactors global_model.Multifactors - webauthn *webauthn_helper.WebAuthN + webauthn *webauthn_helper.WebAuthN keySize int keyAlgorithm crypto.EncryptionAlgorithm privateKeyLifetime time.Duration @@ -85,6 +86,7 @@ func StartCommandSide(config *Config) (repo *CommandSide, err error) { repo.userPasswordAlg = crypto.NewBCrypt(config.SystemDefaults.SecretGenerators.PasswordSaltCost) repo.machineKeyAlg = userEncryptionAlgorithm repo.machineKeySize = int(config.SystemDefaults.SecretGenerators.MachineKeySize) + repo.applicationKeySize = int(config.SystemDefaults.SecretGenerators.ApplicationKeySize) aesOTPCrypto, err := crypto.NewAESCrypto(config.SystemDefaults.Multifactors.OTP.VerificationKey) if err != nil { diff --git a/internal/v2/command/project_application_api.go b/internal/v2/command/project_application_api.go new file mode 100644 index 0000000000..e9b8a68c53 --- /dev/null +++ b/internal/v2/command/project_application_api.go @@ -0,0 +1,145 @@ +package command + +import ( + "context" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +func (r *CommandSide) AddAPIApplication(ctx context.Context, application *domain.APIApp, resourceOwner string) (_ *domain.APIApp, err error) { + project, err := r.getProjectByID(ctx, application.AggregateID, resourceOwner) + if err != nil { + return nil, err + } + addedApplication := NewAPIApplicationWriteModel(application.AggregateID, resourceOwner) + projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel) + events, stringPw, err := r.addAPIApplication(ctx, projectAgg, project, application, resourceOwner) + if err != nil { + return nil, err + } + addedApplication.AppID = application.AppID + pushedEvents, err := r.eventstore.PushEvents(ctx, events...) + if err != nil { + return nil, err + } + err = AppendAndReduce(addedApplication, pushedEvents...) + if err != nil { + return nil, err + } + result := apiWriteModelToAPIConfig(addedApplication) + result.ClientSecretString = stringPw + return result, nil +} + +func (r *CommandSide) addAPIApplication(ctx context.Context, projectAgg *eventstore.Aggregate, proj *domain.Project, apiAppApp *domain.APIApp, resourceOwner string) (events []eventstore.EventPusher, stringPW string, err error) { + if !apiAppApp.IsValid() { + return nil, "", caos_errs.ThrowPreconditionFailed(nil, "PROJECT-Bff2g", "Errors.Application.Invalid") + } + apiAppApp.AppID, err = r.idGenerator.Next() + if err != nil { + return nil, "", err + } + + events = []eventstore.EventPusher{ + project.NewApplicationAddedEvent(ctx, projectAgg, apiAppApp.AppID, apiAppApp.AppName, resourceOwner), + } + + var stringPw string + err = domain.SetNewClientID(apiAppApp, r.idGenerator, proj) + if err != nil { + return nil, "", err + } + stringPw, err = domain.SetNewClientSecretIfNeeded(apiAppApp, r.applicationSecretGenerator) + if err != nil { + return nil, "", err + } + events = append(events, project.NewAPIConfigAddedEvent(ctx, + projectAgg, + apiAppApp.AppID, + apiAppApp.ClientID, + apiAppApp.ClientSecret, + apiAppApp.AuthMethodType)) + + return events, stringPw, nil +} + +func (r *CommandSide) ChangeAPIApplication(ctx context.Context, apiApp *domain.APIApp, resourceOwner string) (*domain.APIApp, error) { + if !apiApp.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1m900", "Errors.Project.App.APIConfigInvalid") + } + + existingAPI, err := r.getAPIAppWriteModel(ctx, apiApp.AggregateID, apiApp.AppID, resourceOwner) + if err != nil { + return nil, err + } + if existingAPI.State == domain.AppStateUnspecified || existingAPI.State == domain.AppStateRemoved { + return nil, caos_errs.ThrowNotFound(nil, "COMMAND-2n8uU", "Errors.Project.App.NotExisting") + } + projectAgg := ProjectAggregateFromWriteModel(&existingAPI.WriteModel) + changedEvent, hasChanged, err := existingAPI.NewChangedEvent( + ctx, + projectAgg, + apiApp.AppID, + apiApp.AuthMethodType) + if err != nil { + return nil, err + } + if !hasChanged { + return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-1m88i", "Errors.NoChangesFound") + } + + pushedEvents, err := r.eventstore.PushEvents(ctx, changedEvent) + if err != nil { + return nil, err + } + err = AppendAndReduce(existingAPI, pushedEvents...) + if err != nil { + return nil, err + } + + result := apiWriteModelToAPIConfig(existingAPI) + return result, nil +} + +func (r *CommandSide) ChangeAPIApplicationSecret(ctx context.Context, projectID, appID, resourceOwner string) (*domain.APIApp, error) { + if projectID == "" || appID == "" { + return nil, caos_errs.ThrowPreconditionFailed(nil, "COMMAND-99i83", "Errors.IDMissing") + } + + existingAPI, err := r.getAPIAppWriteModel(ctx, projectID, appID, resourceOwner) + if err != nil { + return nil, err + } + if existingAPI.State == domain.AppStateUnspecified || existingAPI.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(&existingAPI.WriteModel) + + pushedEvents, err := r.eventstore.PushEvents(ctx, project.NewAPIConfigSecretChangedEvent(ctx, projectAgg, appID, cryptoSecret)) + if err != nil { + return nil, err + } + err = AppendAndReduce(existingAPI, pushedEvents...) + if err != nil { + return nil, err + } + + result := apiWriteModelToAPIConfig(existingAPI) + result.ClientSecretString = stringPW + return result, err +} +func (r *CommandSide) getAPIAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*APIApplicationWriteModel, error) { + appWriteModel := NewAPIApplicationWriteModelWithAppID(projectID, appID, resourceOwner) + err := r.eventstore.FilterToQueryReducer(ctx, appWriteModel) + if err != nil { + return nil, err + } + return appWriteModel, nil +} diff --git a/internal/v2/command/project_application_api_model.go b/internal/v2/command/project_application_api_model.go new file mode 100644 index 0000000000..c4c3c7732e --- /dev/null +++ b/internal/v2/command/project_application_api_model.go @@ -0,0 +1,173 @@ +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" +) + +type APIApplicationWriteModel struct { + eventstore.WriteModel + + AppID string + AppName string + ClientID string + ClientSecret *crypto.CryptoValue + ClientSecretString string + AuthMethodType domain.APIAuthMethodType + State domain.AppState +} + +func NewAPIApplicationWriteModelWithAppID(projectID, appID, resourceOwner string) *APIApplicationWriteModel { + return &APIApplicationWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: projectID, + ResourceOwner: resourceOwner, + }, + AppID: appID, + } +} + +func NewAPIApplicationWriteModel(projectID, resourceOwner string) *APIApplicationWriteModel { + return &APIApplicationWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: projectID, + ResourceOwner: resourceOwner, + }, + } +} +func (wm *APIApplicationWriteModel) 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.APIConfigAddedEvent: + if e.AppID != wm.AppID { + continue + } + wm.WriteModel.AppendEvents(e) + case *project.APIConfigChangedEvent: + if e.AppID != wm.AppID { + continue + } + wm.WriteModel.AppendEvents(e) + case *project.APIConfigSecretChangedEvent: + if e.AppID != wm.AppID { + continue + } + wm.WriteModel.AppendEvents(e) + case *project.ProjectRemovedEvent: + wm.WriteModel.AppendEvents(e) + } + } +} + +func (wm *APIApplicationWriteModel) 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.APIConfigAddedEvent: + wm.appendAddAPIEvent(e) + case *project.APIConfigChangedEvent: + wm.appendChangeAPIEvent(e) + case *project.APIConfigSecretChangedEvent: + wm.ClientSecret = e.ClientSecret + case *project.ProjectRemovedEvent: + wm.State = domain.AppStateRemoved + } + } + return wm.WriteModel.Reduce() +} + +func (wm *APIApplicationWriteModel) appendAddAPIEvent(e *project.APIConfigAddedEvent) { + wm.ClientID = e.ClientID + wm.ClientSecret = e.ClientSecret + wm.AuthMethodType = e.AuthMethodType +} + +func (wm *APIApplicationWriteModel) appendChangeAPIEvent(e *project.APIConfigChangedEvent) { + if e.AuthMethodType != nil { + wm.AuthMethodType = *e.AuthMethodType + } +} + +func (wm *APIApplicationWriteModel) 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.APIConfigAddedType, + project.APIConfigChangedType, + project.APIConfigSecretChangedType, + project.ProjectRemovedType, + ) +} + +func (wm *APIApplicationWriteModel) NewChangedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + appID string, + authMethodType domain.APIAuthMethodType, +) (*project.APIConfigChangedEvent, bool, error) { + changes := make([]project.APIConfigChanges, 0) + var err error + + if wm.AuthMethodType != authMethodType { + changes = append(changes, project.ChangeAPIAuthMethodType(authMethodType)) + } + if len(changes) == 0 { + return nil, false, nil + } + changeEvent, err := project.NewAPIConfigChangedEvent(ctx, aggregate, appID, changes) + if err != nil { + return nil, false, err + } + return changeEvent, true, nil +} diff --git a/internal/v2/command/project_application_key.go b/internal/v2/command/project_application_key.go new file mode 100644 index 0000000000..4ba3cec35f --- /dev/null +++ b/internal/v2/command/project_application_key.go @@ -0,0 +1,77 @@ +package command + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +func (r *CommandSide) AddApplicationKey(ctx context.Context, key *domain.ApplicationKey, resourceOwner string) (_ *domain.ApplicationKey, err error) { + application, err := r.getApplicationWriteModel(ctx, key.AggregateID, key.ApplicationID, resourceOwner) + if err != nil { + return nil, err + } + if !application.State.Exists() { + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-sak25", "Errors.Application.NotFound") + } + key.KeyID, err = r.idGenerator.Next() + if err != nil { + return nil, err + } + keyWriteModel := NewApplicationKeyWriteModel(key.AggregateID, key.ApplicationID, key.KeyID, resourceOwner) + err = r.eventstore.FilterToQueryReducer(ctx, keyWriteModel) + if err != nil { + return nil, err + } + + if !keyWriteModel.KeysAllowed { + return nil, errors.ThrowPreconditionFailed(nil, "COMMAND-Dff54", "Errors.Project.App.AuthMethodNoPrivateKeyJWT") + } + + if err := domain.EnsureValidExpirationDate(key); err != nil { + return nil, err + } + + err = domain.SetNewAuthNKeyPair(key, r.applicationKeySize) + if err != nil { + return nil, err + } + key.ClientID = keyWriteModel.ClientID + + pushedEvents, err := r.eventstore.PushEvents(ctx, + project.NewApplicationKeyAddedEvent( + ctx, + ProjectAggregateFromWriteModel(&keyWriteModel.WriteModel), + key.ApplicationID, + key.ClientID, + key.KeyID, + key.Type, + key.ExpirationDate, + key.PublicKey), + ) + if err != nil { + return nil, err + } + err = AppendAndReduce(keyWriteModel, pushedEvents...) + if err != nil { + return nil, err + } + result := applicationKeyWriteModelToKey(keyWriteModel, key.PrivateKey) + return result, nil +} + +func (r *CommandSide) RemoveApplicationKey(ctx context.Context, projectID, applicationID, keyID, resourceOwner string) error { + keyWriteModel := NewApplicationKeyWriteModel(projectID, applicationID, keyID, resourceOwner) + err := r.eventstore.FilterToQueryReducer(ctx, keyWriteModel) + if err != nil { + return err + } + if !keyWriteModel.State.Exists() { + return errors.ThrowNotFound(nil, "COMMAND-4m77G", "Errors.Application.Key.NotFound") + } + + _, err = r.eventstore.PushEvents(ctx, project.NewApplicationKeyRemovedEvent(ctx, ProjectAggregateFromWriteModel(&keyWriteModel.WriteModel), keyID)) + return err +} diff --git a/internal/v2/command/project_application_key_model.go b/internal/v2/command/project_application_key_model.go new file mode 100644 index 0000000000..429150a93e --- /dev/null +++ b/internal/v2/command/project_application_key_model.go @@ -0,0 +1,141 @@ +package command + +import ( + "time" + + "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/v2/domain" + "github.com/caos/zitadel/internal/v2/repository/project" +) + +type ApplicationKeyWriteModel struct { + eventstore.WriteModel + + AppID string + ClientID string + KeyID string + KeyType domain.AuthNKeyType + ExpirationDate time.Time + + State domain.AppState + KeysAllowed bool +} + +func NewApplicationKeyWriteModel(projectID, appID, keyID, resourceOwner string) *ApplicationKeyWriteModel { + return &ApplicationKeyWriteModel{ + WriteModel: eventstore.WriteModel{ + AggregateID: projectID, + ResourceOwner: resourceOwner, + }, + AppID: appID, + KeyID: keyID, + } +} + +func (wm *ApplicationKeyWriteModel) AppendEvents(events ...eventstore.EventReader) { + for _, event := range events { + switch e := event.(type) { + 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.APIConfigAddedEvent: + if e.AppID != wm.AppID { + continue + } + wm.WriteModel.AppendEvents(e) + case *project.APIConfigChangedEvent: + if e.AppID != wm.AppID { + continue + } + wm.WriteModel.AppendEvents(e) + case *project.ApplicationKeyAddedEvent: + if e.AppID != wm.AppID || e.KeyID != wm.KeyID { + continue + } + wm.WriteModel.AppendEvents(e) + case *project.ApplicationKeyRemovedEvent: + if e.KeyID != wm.KeyID { + continue + } + wm.WriteModel.AppendEvents(e) + case *project.ProjectRemovedEvent: + wm.WriteModel.AppendEvents(e) + } + } +} + +func (wm *ApplicationKeyWriteModel) Reduce() error { + for _, event := range wm.Events { + switch e := event.(type) { + case *project.ApplicationRemovedEvent: + wm.State = domain.AppStateRemoved + case *project.OIDCConfigAddedEvent: + wm.appendAddOIDCEvent(e) + case *project.OIDCConfigChangedEvent: + wm.appendChangeOIDCEvent(e) + case *project.APIConfigAddedEvent: + wm.appendAddAPIEvent(e) + case *project.APIConfigChangedEvent: + wm.appendChangeAPIEvent(e) + case *project.ApplicationKeyAddedEvent: + wm.ClientID = e.ClientID + wm.ExpirationDate = e.ExpirationDate + wm.KeyType = e.KeyType + case *project.ApplicationKeyRemovedEvent: + wm.State = domain.AppStateRemoved + case *project.ProjectRemovedEvent: + wm.State = domain.AppStateRemoved + } + } + return wm.WriteModel.Reduce() +} + +func (wm *ApplicationKeyWriteModel) appendAddOIDCEvent(e *project.OIDCConfigAddedEvent) { + wm.ClientID = e.ClientID + wm.KeysAllowed = e.AuthMethodType == domain.OIDCAuthMethodTypePrivateKeyJWT +} + +func (wm *ApplicationKeyWriteModel) appendChangeOIDCEvent(e *project.OIDCConfigChangedEvent) { + if e.AuthMethodType != nil { + wm.KeysAllowed = *e.AuthMethodType == domain.OIDCAuthMethodTypePrivateKeyJWT + } +} + +func (wm *ApplicationKeyWriteModel) appendAddAPIEvent(e *project.APIConfigAddedEvent) { + wm.ClientID = e.ClientID + wm.KeysAllowed = e.AuthMethodType == domain.APIAuthMethodTypePrivateKeyJWT +} + +func (wm *ApplicationKeyWriteModel) appendChangeAPIEvent(e *project.APIConfigChangedEvent) { + if e.AuthMethodType != nil { + wm.KeysAllowed = *e.AuthMethodType == domain.APIAuthMethodTypePrivateKeyJWT + } +} + +func (wm *ApplicationKeyWriteModel) Query() *eventstore.SearchQueryBuilder { + return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent, project.AggregateType). + AggregateIDs(wm.AggregateID). + ResourceOwner(wm.ResourceOwner). + EventTypes( + project.ApplicationRemovedType, + project.OIDCConfigAddedType, + project.OIDCConfigChangedType, + project.APIConfigAddedType, + project.APIConfigChangedType, + project.ApplicationKeyAddedEventType, + project.ApplicationKeyRemovedEventType, + project.ProjectRemovedType, + ) +} diff --git a/internal/v2/command/project_application_oidc.go b/internal/v2/command/project_application_oidc.go index c63ba33665..87cdb22f2f 100644 --- a/internal/v2/command/project_application_oidc.go +++ b/internal/v2/command/project_application_oidc.go @@ -2,8 +2,13 @@ package command import ( "context" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" caos_errs "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/v2" + "github.com/caos/zitadel/internal/telemetry/tracing" "github.com/caos/zitadel/internal/v2/domain" "github.com/caos/zitadel/internal/v2/repository/project" ) @@ -48,11 +53,11 @@ func (r *CommandSide) addOIDCApplication(ctx context.Context, projectAgg *events } var stringPw string - err = oidcApp.GenerateNewClientID(r.idGenerator, proj) + err = domain.SetNewClientID(oidcApp, r.idGenerator, proj) if err != nil { return nil, "", err } - stringPw, err = oidcApp.GenerateClientSecretIfNeeded(r.applicationSecretGenerator) + stringPw, err = domain.SetNewClientSecretIfNeeded(oidcApp, r.applicationSecretGenerator) if err != nil { return nil, "", err } @@ -95,7 +100,6 @@ func (r *CommandSide) ChangeOIDCApplication(ctx context.Context, oidc *domain.OI ctx, projectAgg, oidc.AppID, - oidc.ClientID, oidc.RedirectUris, oidc.PostLogoutRedirectUris, oidc.ResponseTypes, @@ -162,8 +166,34 @@ func (r *CommandSide) ChangeOIDCApplicationSecret(ctx context.Context, projectID result.ClientSecretString = stringPW return result, err } + +func (r *CommandSide) VerifyOIDCClientSecret(ctx context.Context, projectID, appID, secret string) error { + app, err := r.getOIDCAppWriteModel(ctx, projectID, appID, "") + if err != nil { + return err + } + if !app.State.Exists() { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.NoExisting") + } + if app.ClientSecret == nil { + return caos_errs.ThrowPreconditionFailed(nil, "COMMAND-D6hba", "Errors.Project.App.OIDCConfigInvalid") + } + + projectAgg := ProjectAggregateFromWriteModel(&app.WriteModel) + ctx, spanPasswordComparison := tracing.NewNamedSpan(ctx, "crypto.CompareHash") + err = crypto.CompareHash(app.ClientSecret, []byte(secret), r.userPasswordAlg) + spanPasswordComparison.EndWithError(err) + if err == nil { + _, err = r.eventstore.PushEvents(ctx, project.NewOIDCConfigSecretCheckSucceededEvent(ctx, projectAgg, app.AppID)) + return err + } + _, err = r.eventstore.PushEvents(ctx, project.NewOIDCConfigSecretCheckFailedEvent(ctx, projectAgg, app.AppID)) + logging.Log("COMMAND-ADfhz").OnError(err).Error("could not push event OIDCClientSecretCheckFailed") + return caos_errs.ThrowInvalidArgument(nil, "COMMAND-Bz542", "Errors.Project.App.OIDCSecretInvalid") +} + func (r *CommandSide) getOIDCAppWriteModel(ctx context.Context, projectID, appID, resourceOwner string) (*OIDCApplicationWriteModel, error) { - appWriteModel := NewOIDCApplicationWriteModelWithAppIDC(projectID, appID, resourceOwner) + appWriteModel := NewOIDCApplicationWriteModelWithAppID(projectID, appID, resourceOwner) err := r.eventstore.FilterToQueryReducer(ctx, appWriteModel) if err != nil { return nil, err diff --git a/internal/v2/command/project_application_oidc_model.go b/internal/v2/command/project_application_oidc_model.go index 1393ab7efa..1334f6830a 100644 --- a/internal/v2/command/project_application_oidc_model.go +++ b/internal/v2/command/project_application_oidc_model.go @@ -35,7 +35,7 @@ type OIDCApplicationWriteModel struct { State domain.AppState } -func NewOIDCApplicationWriteModelWithAppIDC(projectID, appID, resourceOwner string) *OIDCApplicationWriteModel { +func NewOIDCApplicationWriteModelWithAppID(projectID, appID, resourceOwner string) *OIDCApplicationWriteModel { return &OIDCApplicationWriteModel{ WriteModel: eventstore.WriteModel{ AggregateID: projectID, @@ -154,9 +154,6 @@ func (wm *OIDCApplicationWriteModel) appendAddOIDCEvent(e *project.OIDCConfigAdd } func (wm *OIDCApplicationWriteModel) appendChangeOIDCEvent(e *project.OIDCConfigChangedEvent) { - if e.ClientID != nil { - wm.ClientID = *e.ClientID - } if e.RedirectUris != nil { wm.RedirectUris = *e.RedirectUris } @@ -218,8 +215,7 @@ func (wm *OIDCApplicationWriteModel) Query() *eventstore.SearchQueryBuilder { func (wm *OIDCApplicationWriteModel) NewChangedEvent( ctx context.Context, aggregate *eventstore.Aggregate, - appID, - clientID string, + appID string, redirectURIS, postLogoutRedirectURIs []string, responseTypes []domain.OIDCResponseType, @@ -237,9 +233,6 @@ func (wm *OIDCApplicationWriteModel) NewChangedEvent( 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)) } diff --git a/internal/v2/command/project_converter.go b/internal/v2/command/project_converter.go index 37f20204d5..ff2489af67 100644 --- a/internal/v2/command/project_converter.go +++ b/internal/v2/command/project_converter.go @@ -34,7 +34,7 @@ func applicationWriteModelToApplication(writeModel *ApplicationWriteModel) domai func oidcWriteModelToOIDCConfig(writeModel *OIDCApplicationWriteModel) *domain.OIDCApp { return &domain.OIDCApp{ ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel), - AppID: writeModel.AggregateID, + AppID: writeModel.AppID, AppName: writeModel.AppName, State: writeModel.State, ClientID: writeModel.ClientID, @@ -55,6 +55,18 @@ func oidcWriteModelToOIDCConfig(writeModel *OIDCApplicationWriteModel) *domain.O } } +func apiWriteModelToAPIConfig(writeModel *APIApplicationWriteModel) *domain.APIApp { + return &domain.APIApp{ + ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel), + AppID: writeModel.AppID, + AppName: writeModel.AppName, + State: writeModel.State, + ClientID: writeModel.ClientID, + ClientSecret: writeModel.ClientSecret, + AuthMethodType: writeModel.AuthMethodType, + } +} + func roleWriteModelToRole(writeModel *ProjectRoleWriteModel) *domain.ProjectRole { return &domain.ProjectRole{ ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel), @@ -72,3 +84,15 @@ func memberWriteModelToProjectGrantMember(writeModel *ProjectGrantMemberWriteMod UserID: writeModel.UserID, } } + +func applicationKeyWriteModelToKey(wm *ApplicationKeyWriteModel, privateKey []byte) *domain.ApplicationKey { + return &domain.ApplicationKey{ + ObjectRoot: writeModelToObjectRoot(wm.WriteModel), + ApplicationID: wm.AppID, + ClientID: wm.ClientID, + KeyID: wm.KeyID, + Type: wm.KeyType, + ExpirationDate: wm.ExpirationDate, + PrivateKey: privateKey, + } +} diff --git a/internal/v2/command/user_machine_key.go b/internal/v2/command/user_machine_key.go index 71e62ba0c2..acb056fd9b 100644 --- a/internal/v2/command/user_machine_key.go +++ b/internal/v2/command/user_machine_key.go @@ -2,7 +2,6 @@ package command import ( "context" - "time" "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/telemetry/tracing" @@ -10,11 +9,6 @@ import ( "github.com/caos/zitadel/internal/v2/repository/user" ) -var ( - //most of us won't survive until 12-31-9999 23:59:59, maybe ZITADEL does - defaultExpDate = time.Date(9999, time.December, 31, 23, 59, 59, 0, time.UTC) -) - func (r *CommandSide) AddUserMachineKey(ctx context.Context, machineKey *domain.MachineKey, resourceOwner string) (*domain.MachineKey, error) { err := r.checkUserExists(ctx, machineKey.AggregateID, resourceOwner) if err != nil { @@ -30,15 +24,11 @@ func (r *CommandSide) AddUserMachineKey(ctx context.Context, machineKey *domain. return nil, err } - if machineKey.ExpirationDate.IsZero() { - machineKey.ExpirationDate = defaultExpDate - } - if machineKey.ExpirationDate.Before(time.Now()) { - return nil, errors.ThrowInvalidArgument(nil, "COMMAND-38vns", "Errors.MachineKey.ExpireBeforeNow") + if err = domain.EnsureValidExpirationDate(machineKey); err != nil { + return nil, err } - err = machineKey.GenerateNewMachineKeyPair(r.machineKeySize) - if err != nil { + if err = domain.SetNewAuthNKeyPair(machineKey, r.machineKeySize); err != nil { return nil, err } diff --git a/internal/v2/command/user_machine_key_model.go b/internal/v2/command/user_machine_key_model.go index 475423b9e8..bcef6dd4bc 100644 --- a/internal/v2/command/user_machine_key_model.go +++ b/internal/v2/command/user_machine_key_model.go @@ -12,7 +12,7 @@ type MachineKeyWriteModel struct { eventstore.WriteModel KeyID string - KeyType domain.MachineKeyType + KeyType domain.AuthNKeyType ExpirationDate time.Time State domain.MachineKeyState diff --git a/internal/v2/domain/application.go b/internal/v2/domain/application.go index 3fb1e451ae..1f6125a62c 100644 --- a/internal/v2/domain/application.go +++ b/internal/v2/domain/application.go @@ -15,6 +15,10 @@ const ( AppStateRemoved ) +func (a AppState) Exists() bool { + return !(a == AppStateUnspecified || a == AppStateRemoved) +} + type ChangeApp struct { AppID string AppName string diff --git a/internal/v2/domain/application_api.go b/internal/v2/domain/application_api.go new file mode 100644 index 0000000000..76446d58d6 --- /dev/null +++ b/internal/v2/domain/application_api.go @@ -0,0 +1,61 @@ +package domain + +import ( + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/eventstore/models" +) + +type APIApp struct { + models.ObjectRoot + + AppID string + AppName string + ClientID string + ClientSecret *crypto.CryptoValue + ClientSecretString string + AuthMethodType APIAuthMethodType + + State AppState +} + +func (a *APIApp) GetApplicationName() string { + return a.AppName +} + +func (a *APIApp) GetState() AppState { + return a.State +} + +type APIAuthMethodType int32 + +const ( + APIAuthMethodTypeBasic APIAuthMethodType = iota + APIAuthMethodTypePrivateKeyJWT +) + +func (a *APIApp) IsValid() bool { + return true +} + +func (a *APIApp) setClientID(clientID string) { + a.ClientID = clientID +} + +func (a *APIApp) setClientSecret(clientSecret *crypto.CryptoValue) { + a.ClientSecret = clientSecret +} + +func (a *APIApp) requiresClientSecret() bool { + return a.AuthMethodType == APIAuthMethodTypeBasic +} + +func (a *APIApp) GenerateClientSecretIfNeeded(generator crypto.Generator) (secret string, err error) { + if a.AuthMethodType == APIAuthMethodTypePrivateKeyJWT { + return "", nil + } + a.ClientSecret, secret, err = NewClientSecret(generator) + if err != nil { + return "", err + } + return secret, nil +} diff --git a/internal/v2/domain/application_key.go b/internal/v2/domain/application_key.go new file mode 100644 index 0000000000..e199483a5e --- /dev/null +++ b/internal/v2/domain/application_key.go @@ -0,0 +1,60 @@ +package domain + +import ( + "encoding/json" + "time" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" +) + +type ApplicationKey struct { + models.ObjectRoot + + ApplicationID string + ClientID string + KeyID string + Type AuthNKeyType + ExpirationDate time.Time + PrivateKey []byte + PublicKey []byte +} + +func (k *ApplicationKey) setPublicKey(publicKey []byte) { + k.PublicKey = publicKey +} + +func (k *ApplicationKey) setPrivateKey(privateKey []byte) { + k.PrivateKey = privateKey +} + +func (k *ApplicationKey) expirationDate() time.Time { + return k.ExpirationDate +} + +func (k *ApplicationKey) setExpirationDate(expiration time.Time) { + k.ExpirationDate = expiration +} + +func (k *ApplicationKey) Detail() ([]byte, error) { + if k.Type == AuthNKeyTypeJSON { + return k.MarshalJSON() + } + return nil, errors.ThrowPreconditionFailed(nil, "KEY-dsg52", "Errors.Internal") +} + +func (k *ApplicationKey) MarshalJSON() ([]byte, error) { + return json.Marshal(struct { + Type string `json:"type"` + KeyID string `json:"keyId"` + Key string `json:"key"` + AppID string `json:"appId"` + ClientID string `json:"clientID"` + }{ + Type: "application", + KeyID: k.KeyID, + Key: string(k.PrivateKey), + AppID: k.ApplicationID, + ClientID: k.ClientID, + }) +} diff --git a/internal/v2/domain/application_oauth.go b/internal/v2/domain/application_oauth.go new file mode 100644 index 0000000000..c75b4e3658 --- /dev/null +++ b/internal/v2/domain/application_oauth.go @@ -0,0 +1,50 @@ +package domain + +import ( + "fmt" + "strings" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/id" +) + +type oAuthApplication interface { + setClientID(clientID string) + setClientSecret(secret *crypto.CryptoValue) + requiresClientSecret() bool +} + +//ClientID random_number@projectname (eg. 495894098234@zitadel) +func SetNewClientID(a oAuthApplication, idGenerator id.Generator, project *Project) error { + rndID, err := idGenerator.Next() + if err != nil { + return err + } + + a.setClientID(fmt.Sprintf("%v@%v", rndID, strings.ReplaceAll(strings.ToLower(project.Name), " ", "_"))) + return nil +} + +func SetNewClientSecretIfNeeded(a oAuthApplication, generator crypto.Generator) (string, error) { + if !a.requiresClientSecret() { + return "", nil + } + clientSecret, secretString, err := NewClientSecret(generator) + if err != nil { + return "", err + } + a.setClientSecret(clientSecret) + return secretString, 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 +} diff --git a/internal/v2/domain/application_oidc.go b/internal/v2/domain/application_oidc.go index b5c6cf54bb..ce5f4d3aca 100644 --- a/internal/v2/domain/application_oidc.go +++ b/internal/v2/domain/application_oidc.go @@ -1,16 +1,11 @@ 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 ( @@ -46,7 +41,7 @@ type OIDCApp struct { State AppState } -func (h OIDCApp) GetUsername() string { +func (h OIDCApp) GetApplicationName() string { return h.AppName } @@ -54,6 +49,18 @@ func (h OIDCApp) GetState() AppState { return h.State } +func (h OIDCApp) setClientID(clientID string) { + h.ClientID = clientID +} + +func (h OIDCApp) setClientSecret(clientSecret *crypto.CryptoValue) { + h.ClientSecret = clientSecret +} + +func (h OIDCApp) requiresClientSecret() bool { + return h.AuthMethodType == OIDCAuthMethodTypeBasic || h.AuthMethodType == OIDCAuthMethodTypePost +} + type OIDCVersion int32 const ( @@ -116,42 +123,6 @@ func (c *OIDCApp) IsValid() bool { 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 diff --git a/internal/v2/domain/authn_key.go b/internal/v2/domain/authn_key.go new file mode 100644 index 0000000000..9130dcc90a --- /dev/null +++ b/internal/v2/domain/authn_key.go @@ -0,0 +1,86 @@ +package domain + +import ( + "time" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" +) + +var ( + //most of us won't survive until 12-31-9999 23:59:59, maybe ZITADEL does + defaultExpDate = time.Date(9999, time.December, 31, 23, 59, 59, 0, time.UTC) +) + +type AuthNKey interface { +} + +type authNKey interface { + setPublicKey([]byte) + setPrivateKey([]byte) + expirationDate() time.Time + setExpirationDate(time.Time) +} + +type AuthNKeyType int32 + +const ( + AuthNKeyTypeNONE = iota + AuthNKeyTypeJSON + + keyCount +) + +func (k AuthNKeyType) Valid() bool { + return k >= 0 && k < keyCount +} + +func (key *MachineKey) GenerateNewMachineKeyPair(keySize int) error { + privateKey, publicKey, err := crypto.GenerateKeyPair(keySize) + if err != nil { + return err + } + key.PublicKey, err = crypto.PublicKeyToBytes(publicKey) + if err != nil { + return err + } + key.PrivateKey = crypto.PrivateKeyToBytes(privateKey) + return nil +} + +func EnsureValidExpirationDate(key authNKey) error { + if key.expirationDate().IsZero() { + key.setExpirationDate(defaultExpDate) + } + if key.expirationDate().Before(time.Now()) { + return errors.ThrowInvalidArgument(nil, "AUTHN-dv3t5", "Errors.AuthNKey.ExpireBeforeNow") + } + return nil +} + +func SetNewAuthNKeyPair(key authNKey, keySize int) error { + privateKey, publicKey, err := NewAuthNKeyPair(keySize) + if err != nil { + return err + } + key.setPrivateKey(privateKey) + key.setPublicKey(publicKey) + return nil +} + +func NewAuthNKeyPair(keySize int) (privateKey, publicKey []byte, err error) { + private, public, err := crypto.GenerateKeyPair(keySize) + if err != nil { + logging.Log("AUTHN-Ud51I").WithError(err).Error("unable to create authn key pair") + return nil, nil, errors.ThrowInternal(err, "AUTHN-gdg2l", "Errors.Project.CouldNotGenerateClientSecret") + } + publicKey, err = crypto.PublicKeyToBytes(public) + if err != nil { + logging.Log("AUTHN-Dbb35").WithError(err).Error("unable to convert public key") + return nil, nil, errors.ThrowInternal(err, "AUTHN-Bne3f", "Errors.Project.CouldNotGenerateClientSecret") + } + privateKey = crypto.PrivateKeyToBytes(private) + return privateKey, publicKey, nil +} diff --git a/internal/v2/domain/machine_key.go b/internal/v2/domain/machine_key.go index e6624ac00a..e29803aac3 100644 --- a/internal/v2/domain/machine_key.go +++ b/internal/v2/domain/machine_key.go @@ -1,29 +1,36 @@ package domain import ( - "github.com/caos/zitadel/internal/crypto" - "github.com/caos/zitadel/internal/eventstore/models" "time" + + "github.com/caos/zitadel/internal/eventstore/models" ) type MachineKey struct { models.ObjectRoot KeyID string - Type MachineKeyType + Type AuthNKeyType ExpirationDate time.Time PrivateKey []byte PublicKey []byte } -type MachineKeyType int32 +func (key *MachineKey) setPublicKey(publicKey []byte) { + key.PublicKey = publicKey +} -const ( - MachineKeyTypeNONE = iota - MachineKeyTypeJSON +func (key *MachineKey) setPrivateKey(privateKey []byte) { + key.PrivateKey = privateKey +} - keyCount -) +func (key *MachineKey) expirationDate() time.Time { + return key.ExpirationDate +} + +func (key *MachineKey) setExpirationDate(expiration time.Time) { + key.ExpirationDate = expiration +} type MachineKeyState int32 @@ -38,20 +45,3 @@ const ( func (f MachineKeyState) Valid() bool { return f >= 0 && f < machineKeyStateCount } - -func (f MachineKeyType) Valid() bool { - return f >= 0 && f < keyCount -} - -func (key *MachineKey) GenerateNewMachineKeyPair(keySize int) error { - privateKey, publicKey, err := crypto.GenerateKeyPair(keySize) - if err != nil { - return err - } - key.PublicKey, err = crypto.PublicKeyToBytes(publicKey) - if err != nil { - return err - } - key.PrivateKey = crypto.PrivateKeyToBytes(privateKey) - return nil -} diff --git a/internal/v2/repository/project/api_config.go b/internal/v2/repository/project/api_config.go new file mode 100644 index 0000000000..657799b3b3 --- /dev/null +++ b/internal/v2/repository/project/api_config.go @@ -0,0 +1,261 @@ +package project + +import ( + "context" + "encoding/json" + + "github.com/caos/zitadel/internal/crypto" + "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 ( + APIConfigAddedType = applicationEventTypePrefix + "config.api.added" + APIConfigChangedType = applicationEventTypePrefix + "config.api.changed" + APIConfigSecretChangedType = applicationEventTypePrefix + "config.api.secret.changed" + APIClientSecretCheckSucceededType = applicationEventTypePrefix + "api.secret.check.succeeded" + APIClientSecretCheckFailedType = applicationEventTypePrefix + "api.secret.check.failed" +) + +type APIConfigAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + AppID string `json:"appId"` + ClientID string `json:"clientId,omitempty"` + ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` + AuthMethodType domain.APIAuthMethodType `json:"authMethodType,omitempty"` +} + +func (e *APIConfigAddedEvent) Data() interface{} { + return e +} + +func (e *APIConfigAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewAPIConfigAddedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + appID, + clientID string, + clientSecret *crypto.CryptoValue, + authMethodType domain.APIAuthMethodType, +) *APIConfigAddedEvent { + return &APIConfigAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + APIConfigAddedType, + ), + AppID: appID, + ClientID: clientID, + ClientSecret: clientSecret, + AuthMethodType: authMethodType, + } +} + +func APIConfigAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &APIConfigAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "API-BFd15", "unable to unmarshal api config") + } + + return e, nil +} + +type APIConfigChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + AppID string `json:"appId"` + ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` + AuthMethodType *domain.APIAuthMethodType `json:"authMethodType,omitempty"` +} + +func (e *APIConfigChangedEvent) Data() interface{} { + return e +} + +func (e *APIConfigChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewAPIConfigChangedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + appID string, + changes []APIConfigChanges, +) (*APIConfigChangedEvent, error) { + if len(changes) == 0 { + return nil, errors.ThrowPreconditionFailed(nil, "API-i8idç", "Errors.NoChangesFound") + } + + changeEvent := &APIConfigChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + APIConfigChangedType, + ), + AppID: appID, + } + for _, change := range changes { + change(changeEvent) + } + return changeEvent, nil +} + +type APIConfigChanges func(event *APIConfigChangedEvent) + +func ChangeAPIAuthMethodType(authMethodType domain.APIAuthMethodType) func(event *APIConfigChangedEvent) { + return func(e *APIConfigChangedEvent) { + e.AuthMethodType = &authMethodType + } +} + +func APIConfigChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &APIConfigChangedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "API-BFd15", "unable to unmarshal api config") + } + + return e, nil +} + +type APIConfigSecretChangedEvent struct { + eventstore.BaseEvent `json:"-"` + + AppID string `json:"appId"` + ClientSecret *crypto.CryptoValue `json:"clientSecret,omitempty"` +} + +func (e *APIConfigSecretChangedEvent) Data() interface{} { + return e +} + +func (e *APIConfigSecretChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewAPIConfigSecretChangedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + appID string, + clientSecret *crypto.CryptoValue, +) *APIConfigSecretChangedEvent { + return &APIConfigSecretChangedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + APIConfigSecretChangedType, + ), + AppID: appID, + ClientSecret: clientSecret, + } +} + +func APIConfigSecretChangedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &APIConfigSecretChangedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "API-M893d", "unable to unmarshal api config") + } + + return e, nil +} + +type APIConfigSecretCheckSucceededEvent struct { + eventstore.BaseEvent `json:"-"` + + AppID string `json:"appId"` +} + +func (e *APIConfigSecretCheckSucceededEvent) Data() interface{} { + return e +} + +func (e *APIConfigSecretCheckSucceededEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewAPIConfigSecretCheckSucceededEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + appID string, +) *APIConfigSecretCheckSucceededEvent { + return &APIConfigSecretCheckSucceededEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + APIClientSecretCheckSucceededType, + ), + AppID: appID, + } +} + +func APIConfigSecretCheckSucceededEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &APIConfigSecretCheckSucceededEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "API-837gV", "unable to unmarshal api config") + } + + return e, nil +} + +type APIConfigSecretCheckFailedEvent struct { + eventstore.BaseEvent `json:"-"` + + AppID string `json:"appId"` +} + +func (e *APIConfigSecretCheckFailedEvent) Data() interface{} { + return e +} + +func (e *APIConfigSecretCheckFailedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewAPIConfigSecretCheckFailedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + appID string, +) *APIConfigSecretCheckFailedEvent { + return &APIConfigSecretCheckFailedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + APIClientSecretCheckFailedType, + ), + AppID: appID, + } +} + +func APIConfigSecretCheckFailedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &APIConfigSecretCheckFailedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "API-987g%", "unable to unmarshal api config") + } + + return e, nil +} diff --git a/internal/v2/repository/project/eventstore.go b/internal/v2/repository/project/eventstore.go index 9da51d47ec..faf6248272 100644 --- a/internal/v2/repository/project/eventstore.go +++ b/internal/v2/repository/project/eventstore.go @@ -34,5 +34,10 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(OIDCConfigChangedType, OIDCConfigChangedEventMapper). RegisterFilterEventMapper(OIDCConfigSecretChangedType, OIDCConfigSecretChangedEventMapper). RegisterFilterEventMapper(OIDCClientSecretCheckSucceededType, OIDCConfigSecretCheckSucceededEventMapper). - RegisterFilterEventMapper(OIDCClientSecretCheckFailedType, OIDCConfigSecretCheckFailedEventMapper) + RegisterFilterEventMapper(OIDCClientSecretCheckFailedType, OIDCConfigSecretCheckFailedEventMapper). + RegisterFilterEventMapper(APIConfigAddedType, APIConfigAddedEventMapper). + RegisterFilterEventMapper(APIConfigChangedType, APIConfigChangedEventMapper). + RegisterFilterEventMapper(APIConfigSecretChangedType, APIConfigSecretChangedEventMapper). + RegisterFilterEventMapper(ApplicationKeyAddedEventType, ApplicationKeyAddedEventMapper). + RegisterFilterEventMapper(ApplicationKeyRemovedEventType, ApplicationKeyRemovedEventMapper) } diff --git a/internal/v2/repository/project/key.go b/internal/v2/repository/project/key.go new file mode 100644 index 0000000000..f04b006c05 --- /dev/null +++ b/internal/v2/repository/project/key.go @@ -0,0 +1,116 @@ +package project + +import ( + "context" + "encoding/json" + "time" + + "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 ( + applicationKeyEventPrefix = applicationEventTypePrefix + "oidc.key." + ApplicationKeyAddedEventType = applicationKeyEventPrefix + "added" + ApplicationKeyRemovedEventType = applicationKeyEventPrefix + "removed" +) + +type ApplicationKeyAddedEvent struct { + eventstore.BaseEvent `json:"-"` + + AppID string `json:"applicationId"` + ClientID string `json:"clientId,omitempty"` + KeyID string `json:"keyId,omitempty"` + KeyType domain.AuthNKeyType `json:"type,omitempty"` + ExpirationDate time.Time `json:"expirationDate,omitempty"` + PublicKey []byte `json:"publicKey,omitempty"` +} + +func (e *ApplicationKeyAddedEvent) Data() interface{} { + return e +} + +func (e *ApplicationKeyAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewApplicationKeyAddedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + appID, + clientID, + keyID string, + keyType domain.AuthNKeyType, + expirationDate time.Time, + publicKey []byte, +) *ApplicationKeyAddedEvent { + return &ApplicationKeyAddedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + ApplicationKeyAddedEventType, + ), + AppID: appID, + ClientID: clientID, + KeyID: keyID, + KeyType: keyType, + ExpirationDate: expirationDate, + PublicKey: publicKey, + } +} + +func ApplicationKeyAddedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + e := &ApplicationKeyAddedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + + err := json.Unmarshal(event.Data, e) + if err != nil { + return nil, errors.ThrowInternal(err, "API-BFd15", "unable to unmarshal api config") + } + + return e, nil +} + +type ApplicationKeyRemovedEvent struct { + eventstore.BaseEvent `json:"-"` + + KeyID string `json:"keyId,omitempty"` +} + +func (e *ApplicationKeyRemovedEvent) Data() interface{} { + return e +} + +func (e *ApplicationKeyRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func NewApplicationKeyRemovedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, + keyID string, +) *ApplicationKeyRemovedEvent { + return &ApplicationKeyRemovedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + ApplicationKeyRemovedEventType, + ), + KeyID: keyID, + } +} + +func ApplicationKeyRemovedEventMapper(event *repository.Event) (eventstore.EventReader, error) { + applicationKeyRemoved := &ApplicationKeyRemovedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := json.Unmarshal(event.Data, applicationKeyRemoved) + if err != nil { + return nil, errors.ThrowInternal(err, "USER-5Gm9s", "unable to unmarshal application key removed") + } + + return applicationKeyRemoved, nil +} diff --git a/internal/v2/repository/project/oidc_config.go b/internal/v2/repository/project/oidc_config.go index 7bfdb77eef..ce4d4942fc 100644 --- a/internal/v2/repository/project/oidc_config.go +++ b/internal/v2/repository/project/oidc_config.go @@ -112,8 +112,6 @@ type OIDCConfigChangedEvent struct { 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"` @@ -168,12 +166,6 @@ func ChangeVersion(version domain.OIDCVersion) func(event *OIDCConfigChangedEven } } -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 diff --git a/internal/v2/repository/user/human_mfa_events.go b/internal/v2/repository/user/human_mfa_events.go index 6e782ed389..e158dc52cb 100644 --- a/internal/v2/repository/user/human_mfa_events.go +++ b/internal/v2/repository/user/human_mfa_events.go @@ -9,7 +9,7 @@ import ( const ( mfaEventPrefix = humanEventPrefix + "mfa." - HumanMFAInitSkippedType = mfaEventPrefix + "init.skiped" + HumanMFAInitSkippedType = mfaEventPrefix + "init.skipped" ) type HumanMFAInitSkippedEvent struct { diff --git a/internal/v2/repository/user/machine_key.go b/internal/v2/repository/user/machine_key.go index 795000dd8e..840c7848eb 100644 --- a/internal/v2/repository/user/machine_key.go +++ b/internal/v2/repository/user/machine_key.go @@ -20,10 +20,10 @@ const ( type MachineKeyAddedEvent struct { eventstore.BaseEvent `json:"-"` - KeyID string `json:"keyId,omitempty"` - KeyType domain.MachineKeyType `json:"type,omitempty"` - ExpirationDate time.Time `json:"expirationDate,omitempty"` - PublicKey []byte `json:"publicKey,omitempty"` + KeyID string `json:"keyId,omitempty"` + KeyType domain.AuthNKeyType `json:"type,omitempty"` + ExpirationDate time.Time `json:"expirationDate,omitempty"` + PublicKey []byte `json:"publicKey,omitempty"` } func (e *MachineKeyAddedEvent) Data() interface{} { @@ -38,7 +38,7 @@ func NewMachineKeyAddedEvent( ctx context.Context, aggregate *eventstore.Aggregate, keyID string, - keyType domain.MachineKeyType, + keyType domain.AuthNKeyType, expirationDate time.Time, publicKey []byte, ) *MachineKeyAddedEvent {