mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 21:27:42 +00:00
feat: App API v2 (#10077)
# Which Problems Are Solved This PR *partially* addresses #9450 . Specifically, it implements the resource based API for the apps. APIs for app keys ARE not part of this PR. # How the Problems Are Solved - `CreateApplication`, `PatchApplication` (update) and `RegenerateClientSecret` endpoints are now unique for all app types: API, SAML and OIDC apps. - All new endpoints have integration tests - All new endpoints are using permission checks V2 # Additional Changes - The `ListApplications` endpoint allows to do sorting (see protobuf for details) and filtering by app type (see protobuf). - SAML and OIDC update endpoint can now receive requests for partial updates # Additional Context Partially addresses #9450
This commit is contained in:
@@ -85,3 +85,11 @@ func (c *Commands) checkPermissionDeleteProjectGrant(ctx context.Context, resour
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionUpdateApplication(ctx context.Context, resourceOwner, appID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectAppWrite, project.AggregateType)(resourceOwner, appID)
|
||||
}
|
||||
|
||||
func (c *Commands) checkPermissionDeleteApp(ctx context.Context, resourceOwner, appID string) error {
|
||||
return c.newPermissionCheck(ctx, domain.PermissionProjectAppDelete, project.AggregateType)(resourceOwner, appID)
|
||||
}
|
||||
|
@@ -15,7 +15,7 @@ type AddApp struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeApplication(ctx context.Context, projectID string, appChange domain.Application, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
func (c *Commands) UpdateApplicationName(ctx context.Context, projectID string, appChange domain.Application, resourceOwner string) (*domain.ObjectDetails, error) {
|
||||
if projectID == "" || appChange.GetAppID() == "" || appChange.GetApplicationName() == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-4m9vS", "Errors.Project.App.Invalid")
|
||||
}
|
||||
@@ -30,6 +30,13 @@ func (c *Commands) ChangeApplication(ctx context.Context, projectID string, appC
|
||||
if existingApp.Name == appChange.GetApplicationName() {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-2m8vx", "Errors.NoChangesFound")
|
||||
}
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, existingApp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingApp.ResourceOwner, existingApp.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
pushedEvents, err := c.eventstore.Push(
|
||||
ctx,
|
||||
@@ -59,6 +66,13 @@ func (c *Commands) DeactivateApplication(ctx context.Context, projectID, appID,
|
||||
if existingApp.State != domain.AppStateActive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-dsh35", "Errors.Project.App.NotActive")
|
||||
}
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, existingApp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingApp.ResourceOwner, existingApp.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewApplicationDeactivatedEvent(ctx, projectAgg, appID))
|
||||
if err != nil {
|
||||
@@ -86,6 +100,11 @@ func (c *Commands) ReactivateApplication(ctx context.Context, projectID, appID,
|
||||
if existingApp.State != domain.AppStateInactive {
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-1n8cM", "Errors.Project.App.NotInactive")
|
||||
}
|
||||
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingApp.ResourceOwner, existingApp.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
|
||||
pushedEvents, err := c.eventstore.Push(ctx, project.NewApplicationReactivatedEvent(ctx, projectAgg, appID))
|
||||
@@ -111,6 +130,13 @@ func (c *Commands) RemoveApplication(ctx context.Context, projectID, appID, reso
|
||||
if existingApp.State == domain.AppStateUnspecified || existingApp.State == domain.AppStateRemoved {
|
||||
return nil, zerrors.ThrowNotFound(nil, "COMMAND-0po9s", "Errors.Project.App.NotExisting")
|
||||
}
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, existingApp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionDeleteApp(ctx, existingApp.ResourceOwner, existingApp.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingApp.WriteModel)
|
||||
|
||||
entityID := ""
|
||||
|
@@ -90,16 +90,24 @@ func (c *Commands) AddAPIApplication(ctx context.Context, apiApp *domain.APIApp,
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-5m9E", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
if _, err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner); err != nil {
|
||||
projectResOwner, err := c.checkProjectExists(ctx, apiApp.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resourceOwner == "" {
|
||||
resourceOwner = projectResOwner
|
||||
}
|
||||
|
||||
if !apiApp.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-Bff2g", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
appID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
appID := apiApp.AppID
|
||||
if appID == "" {
|
||||
appID, err = c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return c.addAPIApplicationWithID(ctx, apiApp, resourceOwner, appID)
|
||||
@@ -112,6 +120,13 @@ func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
||||
apiApp.AppID = appID
|
||||
|
||||
addedApplication := NewAPIApplicationWriteModel(apiApp.AggregateID, resourceOwner)
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, addedApplication); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionUpdateApplication(ctx, addedApplication.ResourceOwner, addedApplication.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
|
||||
|
||||
events := []eventstore.Command{
|
||||
@@ -150,7 +165,7 @@ func (c *Commands) addAPIApplicationWithID(ctx context.Context, apiApp *domain.A
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeAPIApplication(ctx context.Context, apiApp *domain.APIApp, resourceOwner string) (*domain.APIApp, error) {
|
||||
func (c *Commands) UpdateAPIApplication(ctx context.Context, apiApp *domain.APIApp, resourceOwner string) (*domain.APIApp, error) {
|
||||
if apiApp.AppID == "" || apiApp.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-1m900", "Errors.Project.App.APIConfigInvalid")
|
||||
}
|
||||
@@ -165,6 +180,13 @@ func (c *Commands) ChangeAPIApplication(ctx context.Context, apiApp *domain.APIA
|
||||
if !existingAPI.IsAPI() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Gnwt3", "Errors.Project.App.IsNotAPI")
|
||||
}
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, existingAPI); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingAPI.ResourceOwner, existingAPI.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingAPI.WriteModel)
|
||||
changedEvent, hasChanged, err := existingAPI.NewChangedEvent(
|
||||
ctx,
|
||||
@@ -205,6 +227,11 @@ func (c *Commands) ChangeAPIApplicationSecret(ctx context.Context, projectID, ap
|
||||
if !existingAPI.IsAPI() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-aeH4", "Errors.Project.App.IsNotAPI")
|
||||
}
|
||||
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingAPI.ResourceOwner, existingAPI.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encodedHash, plain, err := c.newHashedSecret(ctx, c.eventstore.Filter) //nolint:staticcheck
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -142,6 +142,7 @@ func TestAddAPIConfig(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
type fields struct {
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
@@ -238,6 +239,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -292,6 +294,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -346,6 +349,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -390,6 +394,8 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
@@ -397,6 +403,7 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
defaultSecretGenerators: &SecretGenerators{
|
||||
ClientSecret: emptyConfig,
|
||||
},
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.AddAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
@@ -413,6 +420,8 @@ func TestCommandSide_AddAPIApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
}
|
||||
@@ -516,6 +525,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
||||
domain.APIAuthMethodTypePrivateKeyJWT),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
@@ -555,6 +565,7 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
||||
domain.APIAuthMethodTypeBasic),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
newAPIAppChangedEvent(context.Background(),
|
||||
"app1",
|
||||
@@ -593,14 +604,17 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
newHashedSecret: mockHashedSecret("secret"),
|
||||
defaultSecretGenerators: &SecretGenerators{
|
||||
ClientSecret: emptyConfig,
|
||||
},
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.ChangeAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
|
||||
got, err := r.UpdateAPIApplication(tt.args.ctx, tt.args.apiApp, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -615,6 +629,8 @@ func TestCommandSide_ChangeAPIApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
@@ -734,12 +750,15 @@ func TestCommandSide_ChangeAPIApplicationSecret(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
newHashedSecret: mockHashedSecret("secret"),
|
||||
defaultSecretGenerators: &SecretGenerators{
|
||||
ClientSecret: emptyConfig,
|
||||
},
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.ChangeAPIApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
|
@@ -5,6 +5,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -120,6 +122,7 @@ func (c *Commands) AddOIDCAppCommand(app *addOIDCApp) preparation.Validation {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Combine with AddOIDCApplication and addOIDCApplicationWithID
|
||||
func (c *Commands) AddOIDCApplicationWithID(ctx context.Context, oidcApp *domain.OIDCApp, resourceOwner, appID string) (_ *domain.OIDCApp, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
@@ -142,9 +145,15 @@ func (c *Commands) AddOIDCApplication(ctx context.Context, oidcApp *domain.OIDCA
|
||||
if oidcApp == nil || oidcApp.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-34Fm0", "Errors.Project.App.Invalid")
|
||||
}
|
||||
if _, err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner); err != nil {
|
||||
|
||||
projectResOwner, err := c.checkProjectExists(ctx, oidcApp.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resourceOwner == "" {
|
||||
resourceOwner = projectResOwner
|
||||
}
|
||||
|
||||
if oidcApp.AppName == "" || !oidcApp.IsValid() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-1n8df", "Errors.Project.App.Invalid")
|
||||
}
|
||||
@@ -162,6 +171,13 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
addedApplication := NewOIDCApplicationWriteModel(oidcApp.AggregateID, resourceOwner)
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, addedApplication); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionUpdateApplication(ctx, addedApplication.ResourceOwner, addedApplication.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
|
||||
|
||||
oidcApp.AppID = appID
|
||||
@@ -183,27 +199,27 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
||||
}
|
||||
events = append(events, project_repo.NewOIDCConfigAddedEvent(ctx,
|
||||
projectAgg,
|
||||
oidcApp.OIDCVersion,
|
||||
gu.Value(oidcApp.OIDCVersion),
|
||||
oidcApp.AppID,
|
||||
oidcApp.ClientID,
|
||||
oidcApp.EncodedHash,
|
||||
trimStringSliceWhiteSpaces(oidcApp.RedirectUris),
|
||||
oidcApp.ResponseTypes,
|
||||
oidcApp.GrantTypes,
|
||||
oidcApp.ApplicationType,
|
||||
oidcApp.AuthMethodType,
|
||||
gu.Value(oidcApp.ApplicationType),
|
||||
gu.Value(oidcApp.AuthMethodType),
|
||||
trimStringSliceWhiteSpaces(oidcApp.PostLogoutRedirectUris),
|
||||
oidcApp.DevMode,
|
||||
oidcApp.AccessTokenType,
|
||||
oidcApp.AccessTokenRoleAssertion,
|
||||
oidcApp.IDTokenRoleAssertion,
|
||||
oidcApp.IDTokenUserinfoAssertion,
|
||||
oidcApp.ClockSkew,
|
||||
gu.Value(oidcApp.DevMode),
|
||||
gu.Value(oidcApp.AccessTokenType),
|
||||
gu.Value(oidcApp.AccessTokenRoleAssertion),
|
||||
gu.Value(oidcApp.IDTokenRoleAssertion),
|
||||
gu.Value(oidcApp.IDTokenUserinfoAssertion),
|
||||
gu.Value(oidcApp.ClockSkew),
|
||||
trimStringSliceWhiteSpaces(oidcApp.AdditionalOrigins),
|
||||
oidcApp.SkipNativeAppSuccessPage,
|
||||
strings.TrimSpace(oidcApp.BackChannelLogoutURI),
|
||||
oidcApp.LoginVersion,
|
||||
strings.TrimSpace(oidcApp.LoginBaseURI),
|
||||
gu.Value(oidcApp.SkipNativeAppSuccessPage),
|
||||
strings.TrimSpace(gu.Value(oidcApp.BackChannelLogoutURI)),
|
||||
gu.Value(oidcApp.LoginVersion),
|
||||
strings.TrimSpace(gu.Value(oidcApp.LoginBaseURI)),
|
||||
))
|
||||
|
||||
addedApplication.AppID = oidcApp.AppID
|
||||
@@ -226,7 +242,7 @@ func (c *Commands) addOIDCApplicationWithID(ctx context.Context, oidcApp *domain
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCApp, resourceOwner string) (*domain.OIDCApp, error) {
|
||||
func (c *Commands) UpdateOIDCApplication(ctx context.Context, oidc *domain.OIDCApp, resourceOwner string) (*domain.OIDCApp, error) {
|
||||
if !oidc.IsValid() || oidc.AppID == "" || oidc.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-5m9fs", "Errors.Project.App.OIDCConfigInvalid")
|
||||
}
|
||||
@@ -241,7 +257,23 @@ func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCA
|
||||
if !existingOIDC.IsOIDC() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-GBr34", "Errors.Project.App.IsNotOIDC")
|
||||
}
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, existingOIDC); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingOIDC.ResourceOwner, existingOIDC.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingOIDC.WriteModel)
|
||||
var backChannelLogout, loginBaseURI *string
|
||||
if oidc.BackChannelLogoutURI != nil {
|
||||
backChannelLogout = gu.Ptr(strings.TrimSpace(*oidc.BackChannelLogoutURI))
|
||||
}
|
||||
|
||||
if oidc.LoginBaseURI != nil {
|
||||
loginBaseURI = gu.Ptr(strings.TrimSpace(*oidc.LoginBaseURI))
|
||||
}
|
||||
|
||||
changedEvent, hasChanged, err := existingOIDC.NewChangedEvent(
|
||||
ctx,
|
||||
projectAgg,
|
||||
@@ -261,9 +293,9 @@ func (c *Commands) ChangeOIDCApplication(ctx context.Context, oidc *domain.OIDCA
|
||||
oidc.ClockSkew,
|
||||
trimStringSliceWhiteSpaces(oidc.AdditionalOrigins),
|
||||
oidc.SkipNativeAppSuccessPage,
|
||||
strings.TrimSpace(oidc.BackChannelLogoutURI),
|
||||
backChannelLogout,
|
||||
oidc.LoginVersion,
|
||||
strings.TrimSpace(oidc.LoginBaseURI),
|
||||
loginBaseURI,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -301,6 +333,11 @@ func (c *Commands) ChangeOIDCApplicationSecret(ctx context.Context, projectID, a
|
||||
if !existingOIDC.IsOIDC() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-Ghrh3", "Errors.Project.App.IsNotOIDC")
|
||||
}
|
||||
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingOIDC.ResourceOwner, existingOIDC.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encodedHash, plain, err := c.newHashedSecret(ctx, c.eventstore.Filter) //nolint:staticcheck
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -258,77 +258,77 @@ func (wm *OIDCApplicationWriteModel) NewChangedEvent(
|
||||
postLogoutRedirectURIs []string,
|
||||
responseTypes []domain.OIDCResponseType,
|
||||
grantTypes []domain.OIDCGrantType,
|
||||
appType domain.OIDCApplicationType,
|
||||
authMethodType domain.OIDCAuthMethodType,
|
||||
oidcVersion domain.OIDCVersion,
|
||||
accessTokenType domain.OIDCTokenType,
|
||||
appType *domain.OIDCApplicationType,
|
||||
authMethodType *domain.OIDCAuthMethodType,
|
||||
oidcVersion *domain.OIDCVersion,
|
||||
accessTokenType *domain.OIDCTokenType,
|
||||
devMode,
|
||||
accessTokenRoleAssertion,
|
||||
idTokenRoleAssertion,
|
||||
idTokenUserinfoAssertion bool,
|
||||
clockSkew time.Duration,
|
||||
idTokenUserinfoAssertion *bool,
|
||||
clockSkew *time.Duration,
|
||||
additionalOrigins []string,
|
||||
skipNativeAppSuccessPage bool,
|
||||
backChannelLogoutURI string,
|
||||
loginVersion domain.LoginVersion,
|
||||
loginBaseURI string,
|
||||
skipNativeAppSuccessPage *bool,
|
||||
backChannelLogoutURI *string,
|
||||
loginVersion *domain.LoginVersion,
|
||||
loginBaseURI *string,
|
||||
) (*project.OIDCConfigChangedEvent, bool, error) {
|
||||
changes := make([]project.OIDCConfigChanges, 0)
|
||||
var err error
|
||||
|
||||
if !slices.Equal(wm.RedirectUris, redirectURIS) {
|
||||
if redirectURIS != nil && !slices.Equal(wm.RedirectUris, redirectURIS) {
|
||||
changes = append(changes, project.ChangeRedirectURIs(redirectURIS))
|
||||
}
|
||||
if !slices.Equal(wm.ResponseTypes, responseTypes) {
|
||||
if responseTypes != nil && !slices.Equal(wm.ResponseTypes, responseTypes) {
|
||||
changes = append(changes, project.ChangeResponseTypes(responseTypes))
|
||||
}
|
||||
if !slices.Equal(wm.GrantTypes, grantTypes) {
|
||||
if grantTypes != nil && !slices.Equal(wm.GrantTypes, grantTypes) {
|
||||
changes = append(changes, project.ChangeGrantTypes(grantTypes))
|
||||
}
|
||||
if wm.ApplicationType != appType {
|
||||
changes = append(changes, project.ChangeApplicationType(appType))
|
||||
if appType != nil && wm.ApplicationType != *appType {
|
||||
changes = append(changes, project.ChangeApplicationType(*appType))
|
||||
}
|
||||
if wm.AuthMethodType != authMethodType {
|
||||
changes = append(changes, project.ChangeAuthMethodType(authMethodType))
|
||||
if authMethodType != nil && wm.AuthMethodType != *authMethodType {
|
||||
changes = append(changes, project.ChangeAuthMethodType(*authMethodType))
|
||||
}
|
||||
if !slices.Equal(wm.PostLogoutRedirectUris, postLogoutRedirectURIs) {
|
||||
if postLogoutRedirectURIs != nil && !slices.Equal(wm.PostLogoutRedirectUris, postLogoutRedirectURIs) {
|
||||
changes = append(changes, project.ChangePostLogoutRedirectURIs(postLogoutRedirectURIs))
|
||||
}
|
||||
if wm.OIDCVersion != oidcVersion {
|
||||
changes = append(changes, project.ChangeVersion(oidcVersion))
|
||||
if oidcVersion != nil && wm.OIDCVersion != *oidcVersion {
|
||||
changes = append(changes, project.ChangeVersion(*oidcVersion))
|
||||
}
|
||||
if wm.DevMode != devMode {
|
||||
changes = append(changes, project.ChangeDevMode(devMode))
|
||||
if devMode != nil && wm.DevMode != *devMode {
|
||||
changes = append(changes, project.ChangeDevMode(*devMode))
|
||||
}
|
||||
if wm.AccessTokenType != accessTokenType {
|
||||
changes = append(changes, project.ChangeAccessTokenType(accessTokenType))
|
||||
if accessTokenType != nil && wm.AccessTokenType != *accessTokenType {
|
||||
changes = append(changes, project.ChangeAccessTokenType(*accessTokenType))
|
||||
}
|
||||
if wm.AccessTokenRoleAssertion != accessTokenRoleAssertion {
|
||||
changes = append(changes, project.ChangeAccessTokenRoleAssertion(accessTokenRoleAssertion))
|
||||
if accessTokenRoleAssertion != nil && wm.AccessTokenRoleAssertion != *accessTokenRoleAssertion {
|
||||
changes = append(changes, project.ChangeAccessTokenRoleAssertion(*accessTokenRoleAssertion))
|
||||
}
|
||||
if wm.IDTokenRoleAssertion != idTokenRoleAssertion {
|
||||
changes = append(changes, project.ChangeIDTokenRoleAssertion(idTokenRoleAssertion))
|
||||
if idTokenRoleAssertion != nil && wm.IDTokenRoleAssertion != *idTokenRoleAssertion {
|
||||
changes = append(changes, project.ChangeIDTokenRoleAssertion(*idTokenRoleAssertion))
|
||||
}
|
||||
if wm.IDTokenUserinfoAssertion != idTokenUserinfoAssertion {
|
||||
changes = append(changes, project.ChangeIDTokenUserinfoAssertion(idTokenUserinfoAssertion))
|
||||
if idTokenUserinfoAssertion != nil && wm.IDTokenUserinfoAssertion != *idTokenUserinfoAssertion {
|
||||
changes = append(changes, project.ChangeIDTokenUserinfoAssertion(*idTokenUserinfoAssertion))
|
||||
}
|
||||
if wm.ClockSkew != clockSkew {
|
||||
changes = append(changes, project.ChangeClockSkew(clockSkew))
|
||||
if clockSkew != nil && wm.ClockSkew != *clockSkew {
|
||||
changes = append(changes, project.ChangeClockSkew(*clockSkew))
|
||||
}
|
||||
if !slices.Equal(wm.AdditionalOrigins, additionalOrigins) {
|
||||
if additionalOrigins != nil && !slices.Equal(wm.AdditionalOrigins, additionalOrigins) {
|
||||
changes = append(changes, project.ChangeAdditionalOrigins(additionalOrigins))
|
||||
}
|
||||
if wm.SkipNativeAppSuccessPage != skipNativeAppSuccessPage {
|
||||
changes = append(changes, project.ChangeSkipNativeAppSuccessPage(skipNativeAppSuccessPage))
|
||||
if skipNativeAppSuccessPage != nil && wm.SkipNativeAppSuccessPage != *skipNativeAppSuccessPage {
|
||||
changes = append(changes, project.ChangeSkipNativeAppSuccessPage(*skipNativeAppSuccessPage))
|
||||
}
|
||||
if wm.BackChannelLogoutURI != backChannelLogoutURI {
|
||||
changes = append(changes, project.ChangeBackChannelLogoutURI(backChannelLogoutURI))
|
||||
if backChannelLogoutURI != nil && wm.BackChannelLogoutURI != *backChannelLogoutURI {
|
||||
changes = append(changes, project.ChangeBackChannelLogoutURI(*backChannelLogoutURI))
|
||||
}
|
||||
if wm.LoginVersion != loginVersion {
|
||||
changes = append(changes, project.ChangeOIDCLoginVersion(loginVersion))
|
||||
if loginVersion != nil && wm.LoginVersion != *loginVersion {
|
||||
changes = append(changes, project.ChangeOIDCLoginVersion(*loginVersion))
|
||||
}
|
||||
if wm.LoginBaseURI != loginBaseURI {
|
||||
changes = append(changes, project.ChangeOIDCLoginBaseURI(loginBaseURI))
|
||||
if loginBaseURI != nil && wm.LoginBaseURI != *loginBaseURI {
|
||||
changes = append(changes, project.ChangeOIDCLoginBaseURI(*loginBaseURI))
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -401,6 +402,8 @@ func TestAddOIDCApp(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
@@ -497,6 +500,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -538,24 +542,24 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
},
|
||||
AppName: "app",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{" https://test.ch "},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{" https://test.ch/logout "},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: true,
|
||||
IDTokenRoleAssertion: true,
|
||||
IDTokenUserinfoAssertion: true,
|
||||
ClockSkew: time.Second * 1,
|
||||
DevMode: gu.Ptr(true),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{" https://sub.test.ch "},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: " https://test.ch/backchannel ",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: " https://login.test.ch ",
|
||||
SkipNativeAppSuccessPage: gu.Ptr(true),
|
||||
BackChannelLogoutURI: gu.Ptr(" https://test.ch/backchannel "),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr(" https://login.test.ch "),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -569,24 +573,24 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
ClientID: "client1",
|
||||
ClientSecretString: "secret",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{"https://test.ch"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{"https://test.ch/logout"},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: true,
|
||||
IDTokenRoleAssertion: true,
|
||||
IDTokenUserinfoAssertion: true,
|
||||
ClockSkew: time.Second * 1,
|
||||
DevMode: gu.Ptr(true),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{"https://sub.test.ch"},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: "https://test.ch/backchannel",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://login.test.ch",
|
||||
SkipNativeAppSuccessPage: gu.Ptr(true),
|
||||
BackChannelLogoutURI: gu.Ptr("https://test.ch/backchannel"),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://login.test.ch"),
|
||||
State: domain.AppStateActive,
|
||||
Compliance: &domain.Compliance{},
|
||||
},
|
||||
@@ -604,6 +608,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -645,24 +650,24 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
},
|
||||
AppName: "app",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{"https://test.ch"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{"https://test.ch/logout"},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: true,
|
||||
IDTokenRoleAssertion: true,
|
||||
IDTokenUserinfoAssertion: true,
|
||||
ClockSkew: time.Second * 1,
|
||||
DevMode: gu.Ptr(true),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{"https://sub.test.ch"},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: "https://test.ch/backchannel",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://login.test.ch",
|
||||
SkipNativeAppSuccessPage: gu.Ptr(true),
|
||||
BackChannelLogoutURI: gu.Ptr("https://test.ch/backchannel"),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://login.test.ch"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -676,24 +681,24 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
ClientID: "client1",
|
||||
ClientSecretString: "secret",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{"https://test.ch"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{"https://test.ch/logout"},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: true,
|
||||
IDTokenRoleAssertion: true,
|
||||
IDTokenUserinfoAssertion: true,
|
||||
ClockSkew: time.Second * 1,
|
||||
DevMode: gu.Ptr(true),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{"https://sub.test.ch"},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: "https://test.ch/backchannel",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://login.test.ch",
|
||||
SkipNativeAppSuccessPage: gu.Ptr(true),
|
||||
BackChannelLogoutURI: gu.Ptr("https://test.ch/backchannel"),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://login.test.ch"),
|
||||
State: domain.AppStateActive,
|
||||
Compliance: &domain.Compliance{},
|
||||
},
|
||||
@@ -702,6 +707,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
@@ -709,6 +715,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
defaultSecretGenerators: &SecretGenerators{
|
||||
ClientSecret: emptyConfig,
|
||||
},
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
c.setMilestonesCompletedForTest("instanceID")
|
||||
got, err := c.AddOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner)
|
||||
@@ -726,6 +733,7 @@ func TestCommandSide_AddOIDCApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
type fields struct {
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
@@ -775,7 +783,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
},
|
||||
AppID: "",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
},
|
||||
@@ -797,7 +805,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
AggregateID: "",
|
||||
},
|
||||
AppID: "appid",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
},
|
||||
@@ -821,7 +829,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
},
|
||||
AppID: "app1",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
},
|
||||
@@ -870,6 +878,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
@@ -880,24 +889,24 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{"https://test.ch"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{"https://test.ch/logout"},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: true,
|
||||
IDTokenRoleAssertion: true,
|
||||
IDTokenUserinfoAssertion: true,
|
||||
ClockSkew: time.Second * 1,
|
||||
DevMode: gu.Ptr(true),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{"https://sub.test.ch"},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: "https://test.ch/backchannel",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://login.test.ch",
|
||||
SkipNativeAppSuccessPage: gu.Ptr(true),
|
||||
BackChannelLogoutURI: gu.Ptr("https://test.ch/backchannel"),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://login.test.ch"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -944,6 +953,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
@@ -954,24 +964,24 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{"https://test.ch "},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{" https://test.ch/logout"},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: true,
|
||||
IDTokenRoleAssertion: true,
|
||||
IDTokenUserinfoAssertion: true,
|
||||
ClockSkew: time.Second * 1,
|
||||
DevMode: gu.Ptr(true),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{" https://sub.test.ch "},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: " https://test.ch/backchannel ",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: " https://login.test.ch ",
|
||||
SkipNativeAppSuccessPage: gu.Ptr(true),
|
||||
BackChannelLogoutURI: gu.Ptr(" https://test.ch/backchannel "),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr(" https://login.test.ch "),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -980,7 +990,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change oidc app, ok",
|
||||
name: "partial change oidc app, ok",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
@@ -1018,6 +1028,7 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
newOIDCAppChangedEvent(context.Background(),
|
||||
"app1",
|
||||
@@ -1032,26 +1043,11 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
RedirectUris: []string{" https://test-change.ch "},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
PostLogoutRedirectUris: []string{" https://test-change.ch/logout "},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeJWT,
|
||||
AccessTokenRoleAssertion: false,
|
||||
IDTokenRoleAssertion: false,
|
||||
IDTokenUserinfoAssertion: false,
|
||||
ClockSkew: time.Second * 2,
|
||||
AdditionalOrigins: []string{"https://sub.test.ch"},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: "https://test.ch/backchannel",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://login.test.ch",
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypeBasic),
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -1064,24 +1060,24 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
AppID: "app1",
|
||||
ClientID: "client1@project",
|
||||
AppName: "app",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
RedirectUris: []string{"https://test-change.ch"},
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypeBasic),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{"https://test.ch"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
PostLogoutRedirectUris: []string{"https://test-change.ch/logout"},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeJWT,
|
||||
AccessTokenRoleAssertion: false,
|
||||
IDTokenRoleAssertion: false,
|
||||
IDTokenUserinfoAssertion: false,
|
||||
ClockSkew: time.Second * 2,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{"https://test.ch/logout"},
|
||||
DevMode: gu.Ptr(false),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{"https://sub.test.ch"},
|
||||
SkipNativeAppSuccessPage: true,
|
||||
BackChannelLogoutURI: "https://test.ch/backchannel",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://login.test.ch",
|
||||
SkipNativeAppSuccessPage: gu.Ptr(true),
|
||||
BackChannelLogoutURI: gu.Ptr("https://test.ch/backchannel"),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion1),
|
||||
LoginBaseURI: gu.Ptr(""),
|
||||
Compliance: &domain.Compliance{},
|
||||
State: domain.AppStateActive,
|
||||
},
|
||||
@@ -1090,10 +1086,12 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// t.Parallel()
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.ChangeOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner)
|
||||
got, err := r.UpdateOIDCApplication(tt.args.ctx, tt.args.oidcApp, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -1108,6 +1106,8 @@ func TestCommandSide_ChangeOIDCApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
@@ -1237,36 +1237,40 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
||||
AppName: "app",
|
||||
ClientID: "client1@project",
|
||||
ClientSecretString: "secret",
|
||||
AuthMethodType: domain.OIDCAuthMethodTypePost,
|
||||
OIDCVersion: domain.OIDCVersionV1,
|
||||
AuthMethodType: gu.Ptr(domain.OIDCAuthMethodTypePost),
|
||||
OIDCVersion: gu.Ptr(domain.OIDCVersionV1),
|
||||
RedirectUris: []string{"https://test.ch"},
|
||||
ResponseTypes: []domain.OIDCResponseType{domain.OIDCResponseTypeCode},
|
||||
GrantTypes: []domain.OIDCGrantType{domain.OIDCGrantTypeAuthorizationCode},
|
||||
ApplicationType: domain.OIDCApplicationTypeWeb,
|
||||
ApplicationType: gu.Ptr(domain.OIDCApplicationTypeWeb),
|
||||
PostLogoutRedirectUris: []string{"https://test.ch/logout"},
|
||||
DevMode: true,
|
||||
AccessTokenType: domain.OIDCTokenTypeBearer,
|
||||
AccessTokenRoleAssertion: true,
|
||||
IDTokenRoleAssertion: true,
|
||||
IDTokenUserinfoAssertion: true,
|
||||
ClockSkew: time.Second * 1,
|
||||
DevMode: gu.Ptr(true),
|
||||
AccessTokenType: gu.Ptr(domain.OIDCTokenTypeBearer),
|
||||
AccessTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenRoleAssertion: gu.Ptr(true),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(true),
|
||||
ClockSkew: gu.Ptr(time.Second * 1),
|
||||
AdditionalOrigins: []string{"https://sub.test.ch"},
|
||||
SkipNativeAppSuccessPage: false,
|
||||
BackChannelLogoutURI: "",
|
||||
LoginVersion: domain.LoginVersionUnspecified,
|
||||
SkipNativeAppSuccessPage: gu.Ptr(false),
|
||||
BackChannelLogoutURI: gu.Ptr(""),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersionUnspecified),
|
||||
LoginBaseURI: gu.Ptr(""),
|
||||
State: domain.AppStateActive,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(*testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
newHashedSecret: mockHashedSecret("secret"),
|
||||
defaultSecretGenerators: &SecretGenerators{
|
||||
ClientSecret: emptyConfig,
|
||||
},
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.ChangeOIDCApplicationSecret(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
@@ -1284,16 +1288,7 @@ func TestCommandSide_ChangeOIDCApplicationSecret(t *testing.T) {
|
||||
|
||||
func newOIDCAppChangedEvent(ctx context.Context, appID, projectID, resourceOwner string) *project.OIDCConfigChangedEvent {
|
||||
changes := []project.OIDCConfigChanges{
|
||||
project.ChangeRedirectURIs([]string{"https://test-change.ch"}),
|
||||
project.ChangePostLogoutRedirectURIs([]string{"https://test-change.ch/logout"}),
|
||||
project.ChangeDevMode(true),
|
||||
project.ChangeAccessTokenType(domain.OIDCTokenTypeJWT),
|
||||
project.ChangeAccessTokenRoleAssertion(false),
|
||||
project.ChangeIDTokenRoleAssertion(false),
|
||||
project.ChangeIDTokenUserinfoAssertion(false),
|
||||
project.ChangeClockSkew(time.Second * 2),
|
||||
project.ChangeOIDCLoginVersion(domain.LoginVersion2),
|
||||
project.ChangeOIDCLoginBaseURI("https://login.test.ch"),
|
||||
project.ChangeAuthMethodType(domain.OIDCAuthMethodTypeBasic),
|
||||
}
|
||||
event, _ := project.NewOIDCConfigChangedEvent(ctx,
|
||||
&project.NewAggregate(projectID, resourceOwner).Aggregate,
|
||||
|
@@ -3,6 +3,7 @@ package command
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/zitadel/saml/pkg/provider/xml"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@@ -16,10 +17,22 @@ func (c *Commands) AddSAMLApplication(ctx context.Context, application *domain.S
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-35Fn0", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
if _, err := c.checkProjectExists(ctx, application.AggregateID, resourceOwner); err != nil {
|
||||
projectResOwner, err := c.checkProjectExists(ctx, application.AggregateID, resourceOwner)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resourceOwner == "" {
|
||||
resourceOwner = projectResOwner
|
||||
}
|
||||
|
||||
addedApplication := NewSAMLApplicationWriteModel(application.AggregateID, resourceOwner)
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, addedApplication); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.checkPermissionUpdateApplication(ctx, addedApplication.ResourceOwner, addedApplication.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&addedApplication.WriteModel)
|
||||
events, err := c.addSAMLApplication(ctx, projectAgg, application)
|
||||
if err != nil {
|
||||
@@ -49,12 +62,8 @@ func (c *Commands) addSAMLApplication(ctx context.Context, projectAgg *eventstor
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "PROJECT-1n9df", "Errors.Project.App.Invalid")
|
||||
}
|
||||
|
||||
if samlApp.Metadata == nil && samlApp.MetadataURL == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "SAML-podix9", "Errors.Project.App.SAMLMetadataMissing")
|
||||
}
|
||||
|
||||
if samlApp.MetadataURL != "" {
|
||||
data, err := xml.ReadMetadataFromURL(c.httpClient, samlApp.MetadataURL)
|
||||
if samlApp.MetadataURL != nil && *samlApp.MetadataURL != "" {
|
||||
data, err := xml.ReadMetadataFromURL(c.httpClient, *samlApp.MetadataURL)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "SAML-wmqlo1", "Errors.Project.App.SAMLMetadataMissing")
|
||||
}
|
||||
@@ -78,14 +87,14 @@ func (c *Commands) addSAMLApplication(ctx context.Context, projectAgg *eventstor
|
||||
samlApp.AppID,
|
||||
string(entity.EntityID),
|
||||
samlApp.Metadata,
|
||||
samlApp.MetadataURL,
|
||||
samlApp.LoginVersion,
|
||||
samlApp.LoginBaseURI,
|
||||
gu.Value(samlApp.MetadataURL),
|
||||
gu.Value(samlApp.LoginVersion),
|
||||
gu.Value(samlApp.LoginBaseURI),
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c *Commands) ChangeSAMLApplication(ctx context.Context, samlApp *domain.SAMLApp, resourceOwner string) (*domain.SAMLApp, error) {
|
||||
func (c *Commands) UpdateSAMLApplication(ctx context.Context, samlApp *domain.SAMLApp, resourceOwner string) (*domain.SAMLApp, error) {
|
||||
if !samlApp.IsValid() || samlApp.AppID == "" || samlApp.AggregateID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-5n9fs", "Errors.Project.App.SAMLConfigInvalid")
|
||||
}
|
||||
@@ -100,10 +109,15 @@ func (c *Commands) ChangeSAMLApplication(ctx context.Context, samlApp *domain.SA
|
||||
if !existingSAML.IsSAML() {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "COMMAND-GBr35", "Errors.Project.App.IsNotSAML")
|
||||
}
|
||||
|
||||
if err := c.checkPermissionUpdateApplication(ctx, existingSAML.ResourceOwner, existingSAML.AggregateID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
projectAgg := ProjectAggregateFromWriteModel(&existingSAML.WriteModel)
|
||||
|
||||
if samlApp.MetadataURL != "" {
|
||||
data, err := xml.ReadMetadataFromURL(c.httpClient, samlApp.MetadataURL)
|
||||
if samlApp.MetadataURL != nil && *samlApp.MetadataURL != "" {
|
||||
data, err := xml.ReadMetadataFromURL(c.httpClient, *samlApp.MetadataURL)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "SAML-J3kg3", "Errors.Project.App.SAMLMetadataMissing")
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -170,26 +170,26 @@ func (wm *SAMLApplicationWriteModel) NewChangedEvent(
|
||||
appID string,
|
||||
entityID string,
|
||||
metadata []byte,
|
||||
metadataURL string,
|
||||
loginVersion domain.LoginVersion,
|
||||
loginBaseURI string,
|
||||
metadataURL *string,
|
||||
loginVersion *domain.LoginVersion,
|
||||
loginBaseURI *string,
|
||||
) (*project.SAMLConfigChangedEvent, bool, error) {
|
||||
changes := make([]project.SAMLConfigChanges, 0)
|
||||
var err error
|
||||
if !reflect.DeepEqual(wm.Metadata, metadata) {
|
||||
if metadata != nil && !slices.Equal(wm.Metadata, metadata) {
|
||||
changes = append(changes, project.ChangeMetadata(metadata))
|
||||
}
|
||||
if wm.MetadataURL != metadataURL {
|
||||
changes = append(changes, project.ChangeMetadataURL(metadataURL))
|
||||
if metadataURL != nil && wm.MetadataURL != *metadataURL {
|
||||
changes = append(changes, project.ChangeMetadataURL(*metadataURL))
|
||||
}
|
||||
if wm.EntityID != entityID {
|
||||
changes = append(changes, project.ChangeEntityID(entityID))
|
||||
}
|
||||
if wm.LoginVersion != loginVersion {
|
||||
changes = append(changes, project.ChangeSAMLLoginVersion(loginVersion))
|
||||
if loginVersion != nil && wm.LoginVersion != *loginVersion {
|
||||
changes = append(changes, project.ChangeSAMLLoginVersion(*loginVersion))
|
||||
}
|
||||
if wm.LoginBaseURI != loginBaseURI {
|
||||
changes = append(changes, project.ChangeSAMLLoginBaseURI(loginBaseURI))
|
||||
if loginBaseURI != nil && wm.LoginBaseURI != *loginBaseURI {
|
||||
changes = append(changes, project.ChangeSAMLLoginBaseURI(*loginBaseURI))
|
||||
}
|
||||
|
||||
if len(changes) == 0 {
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -49,6 +50,8 @@ var testMetadataChangedEntityID = []byte(`<?xml version="1.0"?>
|
||||
`)
|
||||
|
||||
func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
idGenerator id.Generator
|
||||
@@ -117,6 +120,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
args: args{
|
||||
@@ -134,6 +138,37 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
err: zerrors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty metas, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(
|
||||
project.NewProjectAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"project", true, true, true,
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t),
|
||||
},
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instanceID"),
|
||||
samlApp: &domain.SAMLApp{
|
||||
ObjectRoot: models.ObjectRoot{
|
||||
AggregateID: "project1",
|
||||
},
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsErrorInvalidArgument,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create saml app, metadata not parsable",
|
||||
fields: fields{
|
||||
@@ -146,6 +181,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t),
|
||||
},
|
||||
@@ -158,7 +194,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: []byte("test metadata"),
|
||||
MetadataURL: "",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -178,6 +214,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -206,7 +243,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: "",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -216,12 +253,14 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: "",
|
||||
State: domain.AppStateActive,
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: gu.Ptr(""),
|
||||
State: domain.AppStateActive,
|
||||
LoginVersion: gu.Ptr(domain.LoginVersionUnspecified),
|
||||
LoginBaseURI: gu.Ptr(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -237,6 +276,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -265,9 +305,9 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: "",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://test.com/login",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://test.com/login"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -281,10 +321,10 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: "",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
State: domain.AppStateActive,
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://test.com/login",
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://test.com/login"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -300,6 +340,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -329,7 +370,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: nil,
|
||||
MetadataURL: "http://localhost:8080/saml/metadata",
|
||||
MetadataURL: gu.Ptr("http://localhost:8080/saml/metadata"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -339,12 +380,14 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: "http://localhost:8080/saml/metadata",
|
||||
State: domain.AppStateActive,
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: gu.Ptr("http://localhost:8080/saml/metadata"),
|
||||
State: domain.AppStateActive,
|
||||
LoginVersion: gu.Ptr(domain.LoginVersionUnspecified),
|
||||
LoginBaseURI: gu.Ptr(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -360,6 +403,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
domain.PrivateLabelingSettingUnspecified),
|
||||
),
|
||||
),
|
||||
expectFilter(),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t),
|
||||
httpClient: newTestClient(http.StatusNotFound, nil),
|
||||
@@ -373,7 +417,7 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: nil,
|
||||
MetadataURL: "http://localhost:8080/saml/metadata",
|
||||
MetadataURL: gu.Ptr("http://localhost:8080/saml/metadata"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -385,10 +429,13 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
c := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
httpClient: tt.fields.httpClient,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
idGenerator: tt.fields.idGenerator,
|
||||
httpClient: tt.fields.httpClient,
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
c.setMilestonesCompletedForTest("instanceID")
|
||||
got, err := c.AddSAMLApplication(tt.args.ctx, tt.args.samlApp, tt.args.resourceOwner)
|
||||
@@ -406,6 +453,8 @@ func TestCommandSide_AddSAMLApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore func(t *testing.T) *eventstore.Eventstore
|
||||
httpClient *http.Client
|
||||
@@ -544,7 +593,7 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AppID: "app1",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: nil,
|
||||
MetadataURL: "http://localhost:8080/saml/metadata",
|
||||
MetadataURL: gu.Ptr("http://localhost:8080/saml/metadata"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -590,7 +639,7 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AppID: "app1",
|
||||
EntityID: "https://test.com/saml/metadata",
|
||||
Metadata: testMetadata,
|
||||
MetadataURL: "",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -646,7 +695,7 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: nil,
|
||||
MetadataURL: "http://localhost:8080/saml/metadata",
|
||||
MetadataURL: gu.Ptr("http://localhost:8080/saml/metadata"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -656,17 +705,19 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: testMetadataChangedEntityID,
|
||||
MetadataURL: "http://localhost:8080/saml/metadata",
|
||||
State: domain.AppStateActive,
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: testMetadataChangedEntityID,
|
||||
MetadataURL: gu.Ptr("http://localhost:8080/saml/metadata"),
|
||||
State: domain.AppStateActive,
|
||||
LoginVersion: gu.Ptr(domain.LoginVersionUnspecified),
|
||||
LoginBaseURI: gu.Ptr(""),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "change saml app, ok, metadata",
|
||||
name: "partial change saml app, ok, metadata",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
@@ -713,7 +764,7 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: testMetadataChangedEntityID,
|
||||
MetadataURL: "",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -723,15 +774,18 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AggregateID: "project1",
|
||||
ResourceOwner: "org1",
|
||||
},
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: testMetadataChangedEntityID,
|
||||
MetadataURL: "",
|
||||
State: domain.AppStateActive,
|
||||
AppID: "app1",
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: testMetadataChangedEntityID,
|
||||
MetadataURL: gu.Ptr(""),
|
||||
State: domain.AppStateActive,
|
||||
LoginVersion: gu.Ptr(domain.LoginVersionUnspecified),
|
||||
LoginBaseURI: gu.Ptr(""),
|
||||
},
|
||||
},
|
||||
}, {
|
||||
},
|
||||
{
|
||||
name: "change saml app, ok, loginversion",
|
||||
fields: fields{
|
||||
eventstore: expectEventstore(
|
||||
@@ -781,9 +835,9 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: testMetadataChangedEntityID,
|
||||
MetadataURL: "",
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://test.com/login",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://test.com/login"),
|
||||
},
|
||||
resourceOwner: "org1",
|
||||
},
|
||||
@@ -797,10 +851,10 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
AppName: "app",
|
||||
EntityID: "https://test2.com/saml/metadata",
|
||||
Metadata: testMetadataChangedEntityID,
|
||||
MetadataURL: "",
|
||||
MetadataURL: gu.Ptr(""),
|
||||
State: domain.AppStateActive,
|
||||
LoginVersion: domain.LoginVersion2,
|
||||
LoginBaseURI: "https://test.com/login",
|
||||
LoginVersion: gu.Ptr(domain.LoginVersion2),
|
||||
LoginBaseURI: gu.Ptr("https://test.com/login"),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -808,11 +862,14 @@ func TestCommandSide_ChangeSAMLApplication(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
httpClient: tt.fields.httpClient,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
httpClient: tt.fields.httpClient,
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.ChangeSAMLApplication(tt.args.ctx, tt.args.samlApp, tt.args.resourceOwner)
|
||||
got, err := r.UpdateSAMLApplication(tt.args.ctx, tt.args.samlApp, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
@@ -8,13 +8,16 @@ import (
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository/mock"
|
||||
"github.com/zitadel/zitadel/internal/repository/project"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -35,9 +38,7 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
{
|
||||
name: "invalid app missing projectid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -55,9 +56,7 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
{
|
||||
name: "invalid app missing appid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -74,9 +73,7 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
{
|
||||
name: "invalid app missing name, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -94,10 +91,7 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
{
|
||||
name: "app not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
eventstore: expectEventstore(expectFilter()),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -115,8 +109,7 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
{
|
||||
name: "app name not changed, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -142,8 +135,14 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
{
|
||||
name: "app changed, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"app1",
|
||||
"app",
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -179,10 +178,13 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.ChangeApplication(tt.args.ctx, tt.args.projectID, tt.args.app, tt.args.resourceOwner)
|
||||
got, err := r.UpdateApplicationName(tt.args.ctx, tt.args.projectID, tt.args.app, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -197,8 +199,10 @@ func TestCommandSide_ChangeApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -219,9 +223,7 @@ func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "missing projectid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -236,9 +238,7 @@ func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "missing appid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -253,8 +253,7 @@ func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "app not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
},
|
||||
@@ -271,8 +270,7 @@ func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "app already inactive, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -299,8 +297,14 @@ func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "app deactivate, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
"app1",
|
||||
"app",
|
||||
)),
|
||||
),
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -331,8 +335,11 @@ func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.DeactivateApplication(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
@@ -349,8 +356,10 @@ func TestCommandSide_DeactivateApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -371,9 +380,7 @@ func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "missing projectid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -388,9 +395,7 @@ func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "missing appid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -405,10 +410,7 @@ func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "app not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
eventstore: expectEventstore(expectFilter()),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -423,8 +425,7 @@ func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "app already active, precondition error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -447,8 +448,7 @@ func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
{
|
||||
name: "app reactivate, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -483,8 +483,11 @@ func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.ReactivateApplication(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
@@ -501,8 +504,10 @@ func TestCommandSide_ReactivateApplication(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
type fields struct {
|
||||
eventstore *eventstore.Eventstore
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
}
|
||||
type args struct {
|
||||
ctx context.Context
|
||||
@@ -523,9 +528,7 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
{
|
||||
name: "missing projectid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -540,9 +543,7 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
{
|
||||
name: "missing appid, invalid argument error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
),
|
||||
eventstore: expectEventstore(func(mockRepository *mock.MockRepository) {}),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -557,10 +558,7 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
{
|
||||
name: "app not existing, not found error",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
expectFilter(),
|
||||
),
|
||||
eventstore: expectEventstore(expectFilter()),
|
||||
},
|
||||
args: args{
|
||||
ctx: context.Background(),
|
||||
@@ -575,8 +573,7 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
{
|
||||
name: "app remove, entityID, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -584,6 +581,7 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
"app",
|
||||
)),
|
||||
),
|
||||
expectFilter(),
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -625,8 +623,7 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
{
|
||||
name: "app remove, ok",
|
||||
fields: fields{
|
||||
eventstore: eventstoreExpect(
|
||||
t,
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(project.NewApplicationAddedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -636,6 +633,7 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
),
|
||||
// app is not saml, or no saml config available
|
||||
expectFilter(),
|
||||
expectFilter(),
|
||||
expectPush(
|
||||
project.NewApplicationRemovedEvent(context.Background(),
|
||||
&project.NewAggregate("project1", "org1").Aggregate,
|
||||
@@ -661,8 +659,11 @@ func TestCommandSide_RemoveApplication(t *testing.T) {
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r := &Commands{
|
||||
eventstore: tt.fields.eventstore,
|
||||
eventstore: tt.fields.eventstore(t),
|
||||
checkPermission: newMockPermissionCheckAllowed(),
|
||||
}
|
||||
got, err := r.RemoveApplication(tt.args.ctx, tt.args.projectID, tt.args.appID, tt.args.resourceOwner)
|
||||
if tt.res.err == nil {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"github.com/muhlemmer/gu"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
)
|
||||
|
||||
@@ -35,21 +37,21 @@ func oidcWriteModelToOIDCConfig(writeModel *OIDCApplicationWriteModel) *domain.O
|
||||
RedirectUris: writeModel.RedirectUris,
|
||||
ResponseTypes: writeModel.ResponseTypes,
|
||||
GrantTypes: writeModel.GrantTypes,
|
||||
ApplicationType: writeModel.ApplicationType,
|
||||
AuthMethodType: writeModel.AuthMethodType,
|
||||
ApplicationType: gu.Ptr(writeModel.ApplicationType),
|
||||
AuthMethodType: gu.Ptr(writeModel.AuthMethodType),
|
||||
PostLogoutRedirectUris: writeModel.PostLogoutRedirectUris,
|
||||
OIDCVersion: writeModel.OIDCVersion,
|
||||
DevMode: writeModel.DevMode,
|
||||
AccessTokenType: writeModel.AccessTokenType,
|
||||
AccessTokenRoleAssertion: writeModel.AccessTokenRoleAssertion,
|
||||
IDTokenRoleAssertion: writeModel.IDTokenRoleAssertion,
|
||||
IDTokenUserinfoAssertion: writeModel.IDTokenUserinfoAssertion,
|
||||
ClockSkew: writeModel.ClockSkew,
|
||||
OIDCVersion: gu.Ptr(writeModel.OIDCVersion),
|
||||
DevMode: gu.Ptr(writeModel.DevMode),
|
||||
AccessTokenType: gu.Ptr(writeModel.AccessTokenType),
|
||||
AccessTokenRoleAssertion: gu.Ptr(writeModel.AccessTokenRoleAssertion),
|
||||
IDTokenRoleAssertion: gu.Ptr(writeModel.IDTokenRoleAssertion),
|
||||
IDTokenUserinfoAssertion: gu.Ptr(writeModel.IDTokenUserinfoAssertion),
|
||||
ClockSkew: gu.Ptr(writeModel.ClockSkew),
|
||||
AdditionalOrigins: writeModel.AdditionalOrigins,
|
||||
SkipNativeAppSuccessPage: writeModel.SkipNativeAppSuccessPage,
|
||||
BackChannelLogoutURI: writeModel.BackChannelLogoutURI,
|
||||
LoginVersion: writeModel.LoginVersion,
|
||||
LoginBaseURI: writeModel.LoginBaseURI,
|
||||
SkipNativeAppSuccessPage: gu.Ptr(writeModel.SkipNativeAppSuccessPage),
|
||||
BackChannelLogoutURI: gu.Ptr(writeModel.BackChannelLogoutURI),
|
||||
LoginVersion: gu.Ptr(writeModel.LoginVersion),
|
||||
LoginBaseURI: gu.Ptr(writeModel.LoginBaseURI),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,10 +62,10 @@ func samlWriteModelToSAMLConfig(writeModel *SAMLApplicationWriteModel) *domain.S
|
||||
AppName: writeModel.AppName,
|
||||
State: writeModel.State,
|
||||
Metadata: writeModel.Metadata,
|
||||
MetadataURL: writeModel.MetadataURL,
|
||||
MetadataURL: gu.Ptr(writeModel.MetadataURL),
|
||||
EntityID: writeModel.EntityID,
|
||||
LoginVersion: writeModel.LoginVersion,
|
||||
LoginBaseURI: writeModel.LoginBaseURI,
|
||||
LoginVersion: gu.Ptr(writeModel.LoginVersion),
|
||||
LoginBaseURI: gu.Ptr(writeModel.LoginBaseURI),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,15 +80,6 @@ func apiWriteModelToAPIConfig(writeModel *APIApplicationWriteModel) *domain.APIA
|
||||
}
|
||||
}
|
||||
|
||||
func roleWriteModelToRole(writeModel *ProjectRoleWriteModel) *domain.ProjectRole {
|
||||
return &domain.ProjectRole{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
Key: writeModel.Key,
|
||||
DisplayName: writeModel.DisplayName,
|
||||
Group: writeModel.Group,
|
||||
}
|
||||
}
|
||||
|
||||
func memberWriteModelToProjectGrantMember(writeModel *ProjectGrantMemberWriteModel) *domain.ProjectGrantMember {
|
||||
return &domain.ProjectGrantMember{
|
||||
ObjectRoot: writeModelToObjectRoot(writeModel.WriteModel),
|
||||
|
@@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@@ -120,7 +121,7 @@ func (wm *ProjectWriteModel) NewChangedEvent(
|
||||
}
|
||||
|
||||
func isProjectStateExists(state domain.ProjectState) bool {
|
||||
return !hasProjectState(state, domain.ProjectStateRemoved, domain.ProjectStateUnspecified)
|
||||
return !slices.Contains([]domain.ProjectState{domain.ProjectStateRemoved, domain.ProjectStateUnspecified}, state)
|
||||
}
|
||||
|
||||
func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggregate {
|
||||
@@ -130,12 +131,3 @@ func ProjectAggregateFromWriteModel(wm *eventstore.WriteModel) *eventstore.Aggre
|
||||
func ProjectAggregateFromWriteModelWithCTX(ctx context.Context, wm *eventstore.WriteModel) *eventstore.Aggregate {
|
||||
return project.AggregateFromWriteModel(ctx, wm)
|
||||
}
|
||||
|
||||
func hasProjectState(check domain.ProjectState, states ...domain.ProjectState) bool {
|
||||
for _, state := range states {
|
||||
if check == state {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
Reference in New Issue
Block a user