feat: add apis and application keys (#1327)

* feat: add apis and application keys

* VerifyOIDCClientSecret

* Update internal/v2/repository/project/api_config.go

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* Update internal/v2/repository/project/key.go

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>

* fix append ApplicationKeyWriteModel

Co-authored-by: Fabi <38692350+fgerschwiler@users.noreply.github.com>
This commit is contained in:
Livio Amstutz
2021-02-22 12:27:47 +01:00
committed by GitHub
parent a7cc57822b
commit 2ba56595b1
35 changed files with 1421 additions and 527 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -12,7 +12,7 @@ type MachineKeyWriteModel struct {
eventstore.WriteModel
KeyID string
KeyType domain.MachineKeyType
KeyType domain.AuthNKeyType
ExpirationDate time.Time
State domain.MachineKeyState

View File

@@ -15,6 +15,10 @@ const (
AppStateRemoved
)
func (a AppState) Exists() bool {
return !(a == AppStateUnspecified || a == AppStateRemoved)
}
type ChangeApp struct {
AppID string
AppName string

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,7 @@ import (
const (
mfaEventPrefix = humanEventPrefix + "mfa."
HumanMFAInitSkippedType = mfaEventPrefix + "init.skiped"
HumanMFAInitSkippedType = mfaEventPrefix + "init.skipped"
)
type HumanMFAInitSkippedEvent struct {

View File

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