diff --git a/go.mod b/go.mod index dae92417fa..70c0b28593 100644 --- a/go.mod +++ b/go.mod @@ -59,7 +59,7 @@ require ( github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203 github.com/ttacon/libphonenumber v1.2.1 github.com/zitadel/logging v0.6.0 - github.com/zitadel/oidc/v3 v3.26.1 + github.com/zitadel/oidc/v3 v3.27.0 github.com/zitadel/passwap v0.6.0 github.com/zitadel/saml v0.1.3 github.com/zitadel/schema v1.3.0 diff --git a/go.sum b/go.sum index 16c1046d56..30eee5954c 100644 --- a/go.sum +++ b/go.sum @@ -723,8 +723,8 @@ github.com/zenazn/goji v1.0.1 h1:4lbD8Mx2h7IvloP7r2C0D6ltZP6Ufip8Hn0wmSK5LR8= github.com/zenazn/goji v1.0.1/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= github.com/zitadel/logging v0.6.0 h1:t5Nnt//r+m2ZhhoTmoPX+c96pbMarqJvW1Vq6xFTank= github.com/zitadel/logging v0.6.0/go.mod h1:Y4CyAXHpl3Mig6JOszcV5Rqqsojj+3n7y2F591Mp/ow= -github.com/zitadel/oidc/v3 v3.26.1 h1:/4wi2gxHByI9YYEjqcwEUx5GjsfDk8reudNP1Cp5Hgo= -github.com/zitadel/oidc/v3 v3.26.1/go.mod h1:ZwBEqSviCpJVZiYashzo53bEGRGXi7amE5Q8PpQg9IM= +github.com/zitadel/oidc/v3 v3.27.0 h1:zeYpyRH0UcgdCjVHUYzSsqf1jbSwVMPVxYKOnRXstgU= +github.com/zitadel/oidc/v3 v3.27.0/go.mod h1:ZwBEqSviCpJVZiYashzo53bEGRGXi7amE5Q8PpQg9IM= github.com/zitadel/passwap v0.6.0 h1:m9F3epFC0VkBXu25rihSLGyHvWiNlCzU5kk8RoI+SXQ= github.com/zitadel/passwap v0.6.0/go.mod h1:kqAiJ4I4eZvm3Y6oAk6hlEqlZZOkjMHraGXF90GG7LI= github.com/zitadel/saml v0.1.3 h1:LI4DOCVyyU1qKPkzs3vrGcA5J3H4pH3+CL9zr9ShkpM= diff --git a/internal/api/grpc/feature/v2/converter.go b/internal/api/grpc/feature/v2/converter.go index 3d35694bdd..533baaf534 100644 --- a/internal/api/grpc/feature/v2/converter.go +++ b/internal/api/grpc/feature/v2/converter.go @@ -43,6 +43,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm Actions: req.Actions, ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance), WebKey: req.WebKey, + DebugOIDCParentError: req.DebugOidcParentError, } } @@ -57,6 +58,7 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat Actions: featureSourceToFlagPb(&f.Actions), ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance), WebKey: featureSourceToFlagPb(&f.WebKey), + DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError), } } diff --git a/internal/api/grpc/feature/v2/converter_test.go b/internal/api/grpc/feature/v2/converter_test.go index e6335145b0..f88b96ea5a 100644 --- a/internal/api/grpc/feature/v2/converter_test.go +++ b/internal/api/grpc/feature/v2/converter_test.go @@ -217,6 +217,10 @@ func Test_instanceFeaturesToPb(t *testing.T) { Enabled: true, Source: feature_pb.Source_SOURCE_INSTANCE, }, + DebugOidcParentError: &feature_pb.FeatureFlag{ + Enabled: false, + Source: feature_pb.Source_SOURCE_UNSPECIFIED, + }, } got := instanceFeaturesToPb(arg) assert.Equal(t, want, got) diff --git a/internal/api/grpc/feature/v2beta/converter.go b/internal/api/grpc/feature/v2beta/converter.go index 16654d1e6b..63738672e6 100644 --- a/internal/api/grpc/feature/v2beta/converter.go +++ b/internal/api/grpc/feature/v2beta/converter.go @@ -43,6 +43,7 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm Actions: req.Actions, ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance), WebKey: req.WebKey, + DebugOIDCParentError: req.DebugOidcParentError, } } @@ -57,6 +58,7 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat Actions: featureSourceToFlagPb(&f.Actions), ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance), WebKey: featureSourceToFlagPb(&f.WebKey), + DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError), } } diff --git a/internal/api/grpc/feature/v2beta/converter_test.go b/internal/api/grpc/feature/v2beta/converter_test.go index b8a69f86a8..80be160077 100644 --- a/internal/api/grpc/feature/v2beta/converter_test.go +++ b/internal/api/grpc/feature/v2beta/converter_test.go @@ -217,6 +217,10 @@ func Test_instanceFeaturesToPb(t *testing.T) { Enabled: true, Source: feature_pb.Source_SOURCE_INSTANCE, }, + DebugOidcParentError: &feature_pb.FeatureFlag{ + Enabled: false, + Source: feature_pb.Source_SOURCE_UNSPECIFIED, + }, } got := instanceFeaturesToPb(arg) assert.Equal(t, want, got) diff --git a/internal/api/oidc/auth_request.go b/internal/api/oidc/auth_request.go index c99e4dd124..dd765a3045 100644 --- a/internal/api/oidc/auth_request.go +++ b/internal/api/oidc/auth_request.go @@ -277,7 +277,7 @@ func (o *OPStorage) RevokeToken(ctx context.Context, token, userID, clientID str if zerrors.IsPreconditionFailed(err) { return oidc.ErrInvalidClient().WithDescription("token was not issued for this client") } - return oidc.ErrServerError().WithParent(err) + return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } return o.revokeTokenV1(ctx, token, userID, clientID) @@ -293,14 +293,14 @@ func (o *OPStorage) revokeTokenV1(ctx context.Context, token, userID, clientID s if err == nil || zerrors.IsNotFound(err) { return nil } - return oidc.ErrServerError().WithParent(err) + return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } accessToken, err := o.repo.TokenByIDs(ctx, userID, token) if err != nil { if zerrors.IsNotFound(err) { return nil } - return oidc.ErrServerError().WithParent(err) + return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } if accessToken.ApplicationID != clientID { return oidc.ErrInvalidClient().WithDescription("token was not issued for this client") @@ -309,7 +309,7 @@ func (o *OPStorage) revokeTokenV1(ctx context.Context, token, userID, clientID s if err == nil || zerrors.IsNotFound(err) { return nil } - return oidc.ErrServerError().WithParent(err) + return oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } func (o *OPStorage) GetRefreshTokenInfo(ctx context.Context, clientID string, token string) (userID string, tokenID string, err error) { diff --git a/internal/api/oidc/client.go b/internal/api/oidc/client.go index 8dc7c58ad5..d0945cfa07 100644 --- a/internal/api/oidc/client.go +++ b/internal/api/oidc/client.go @@ -975,13 +975,13 @@ func (s *Server) VerifyClient(ctx context.Context, r *op.Request[op.ClientCreden return s.clientCredentialsAuth(ctx, r.Data.ClientID, r.Data.ClientSecret) } - clientID, assertion, err := clientIDFromCredentials(r.Data) + clientID, assertion, err := clientIDFromCredentials(ctx, r.Data) if err != nil { return nil, err } client, err := s.query.GetOIDCClientByID(ctx, clientID, assertion) if zerrors.IsNotFound(err) { - return nil, oidc.ErrInvalidClient().WithParent(err).WithDescription("client not found") + return nil, oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("client not found") } if err != nil { return nil, err // defaults to server error @@ -1019,7 +1019,7 @@ func (s *Server) verifyClientAssertion(ctx context.Context, client *query.OIDCCl } verifier := op.NewJWTProfileVerifierKeySet(keySetMap(client.PublicKeys), op.IssuerFromContext(ctx), time.Hour, client.ClockSkew) if _, err := op.VerifyJWTAssertion(ctx, assertion, verifier); err != nil { - return oidc.ErrInvalidClient().WithParent(err).WithDescription("invalid assertion") + return oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("invalid assertion") } return nil } @@ -1036,7 +1036,7 @@ func (s *Server) verifyClientSecret(ctx context.Context, client *query.OIDCClien spanPasswordComparison.EndWithError(err) if err != nil { s.command.OIDCSecretCheckFailed(ctx, client.AppID, client.ProjectID, client.Settings.ResourceOwner) - return oidc.ErrInvalidClient().WithParent(err).WithDescription("invalid secret") + return oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("invalid secret") } s.command.OIDCSecretCheckSucceeded(ctx, client.AppID, client.ProjectID, client.Settings.ResourceOwner, updated) return nil diff --git a/internal/api/oidc/client_converter.go b/internal/api/oidc/client_converter.go index 1a9d86afb6..c84049d2ad 100644 --- a/internal/api/oidc/client_converter.go +++ b/internal/api/oidc/client_converter.go @@ -1,6 +1,7 @@ package oidc import ( + "context" "slices" "strings" "time" @@ -8,6 +9,7 @@ import ( "github.com/zitadel/oidc/v3/pkg/oidc" "github.com/zitadel/oidc/v3/pkg/op" + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/query" @@ -218,11 +220,11 @@ func removeScopeWithPrefix(scopes []string, scopePrefix ...string) []string { return newScopeList } -func clientIDFromCredentials(cc *op.ClientCredentials) (clientID string, assertion bool, err error) { +func clientIDFromCredentials(ctx context.Context, cc *op.ClientCredentials) (clientID string, assertion bool, err error) { if cc.ClientAssertion != "" { claims := new(oidc.JWTTokenRequest) if _, err := oidc.ParseToken(cc.ClientAssertion, claims); err != nil { - return "", false, oidc.ErrInvalidClient().WithParent(err) + return "", false, oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } return claims.Issuer, true, nil } diff --git a/internal/api/oidc/client_credentials.go b/internal/api/oidc/client_credentials.go index b2821bcb70..b8c2a10a59 100644 --- a/internal/api/oidc/client_credentials.go +++ b/internal/api/oidc/client_credentials.go @@ -8,6 +8,7 @@ import ( "github.com/zitadel/oidc/v3/pkg/oidc" "github.com/zitadel/oidc/v3/pkg/op" + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/query" "github.com/zitadel/zitadel/internal/telemetry/tracing" "github.com/zitadel/zitadel/internal/zerrors" @@ -37,7 +38,7 @@ func (c *clientCredentialsRequest) GetScopes() []string { func (s *Server) clientCredentialsAuth(ctx context.Context, clientID, clientSecret string) (op.Client, error) { user, err := s.query.GetUserByLoginName(ctx, false, clientID) if zerrors.IsNotFound(err) { - return nil, oidc.ErrInvalidClient().WithParent(err).WithDescription("client not found") + return nil, oidc.ErrInvalidClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("client not found") } if err != nil { return nil, err // defaults to server error diff --git a/internal/api/oidc/introspect.go b/internal/api/oidc/introspect.go index 99602393c5..dc7ddcbe39 100644 --- a/internal/api/oidc/introspect.go +++ b/internal/api/oidc/introspect.go @@ -156,18 +156,18 @@ func (s *Server) introspectionClientAuth(ctx context.Context, cc *op.ClientCrede if cc.ClientAssertion != "" { verifier := op.NewJWTProfileVerifierKeySet(keySetMap(client.PublicKeys), op.IssuerFromContext(ctx), time.Hour, time.Second) if _, err := op.VerifyJWTAssertion(ctx, cc.ClientAssertion, verifier); err != nil { - return "", "", false, oidc.ErrUnauthorizedClient().WithParent(err) + return "", "", false, oidc.ErrUnauthorizedClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } return client.ClientID, client.ProjectID, client.ProjectRoleAssertion, nil } if client.HashedSecret != "" { if err := s.introspectionClientSecretAuth(ctx, client, cc.ClientSecret); err != nil { - return "", "", false, oidc.ErrUnauthorizedClient().WithParent(err) + return "", "", false, oidc.ErrUnauthorizedClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } return client.ClientID, client.ProjectID, client.ProjectRoleAssertion, nil } - return "", "", false, oidc.ErrUnauthorizedClient().WithParent(errNoClientSecret) + return "", "", false, oidc.ErrUnauthorizedClient().WithParent(errNoClientSecret).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) }() span.EndWithError(err) @@ -212,13 +212,13 @@ func (s *Server) introspectionClientSecretAuth(ctx context.Context, client *quer // clientFromCredentials parses the client ID early, // and makes a single query for the client for either auth methods. func (s *Server) clientFromCredentials(ctx context.Context, cc *op.ClientCredentials) (client *query.IntrospectionClient, err error) { - clientID, assertion, err := clientIDFromCredentials(cc) + clientID, assertion, err := clientIDFromCredentials(ctx, cc) if err != nil { return nil, err } client, err = s.query.GetIntrospectionClientByID(ctx, clientID, assertion) if errors.Is(err, sql.ErrNoRows) { - return nil, oidc.ErrUnauthorizedClient().WithParent(err) + return nil, oidc.ErrUnauthorizedClient().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } // any other error is regarded internal and should not be reported back to the client. return client, err diff --git a/internal/api/oidc/server.go b/internal/api/oidc/server.go index b0a062b74d..1152d81b48 100644 --- a/internal/api/oidc/server.go +++ b/internal/api/oidc/server.go @@ -10,6 +10,7 @@ import ( "github.com/zitadel/oidc/v3/pkg/oidc" "github.com/zitadel/oidc/v3/pkg/op" + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/auth/repository" "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/crypto" @@ -119,7 +120,7 @@ func (s *Server) Discovery(ctx context.Context, r *op.Request[struct{}]) (_ *op. }() restrictions, err := s.query.GetInstanceRestrictions(ctx) if err != nil { - return nil, op.NewStatusError(oidc.ErrServerError().WithParent(err).WithDescription("internal server error"), http.StatusInternalServerError) + return nil, op.NewStatusError(oidc.ErrServerError().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("internal server error"), http.StatusInternalServerError) } allowedLanguages := restrictions.AllowedLanguages if len(allowedLanguages) == 0 { diff --git a/internal/api/oidc/token_device.go b/internal/api/oidc/token_device.go index b574af1260..464e9e46ae 100644 --- a/internal/api/oidc/token_device.go +++ b/internal/api/oidc/token_device.go @@ -7,6 +7,7 @@ import ( "github.com/zitadel/oidc/v3/pkg/oidc" "github.com/zitadel/oidc/v3/pkg/op" + "github.com/zitadel/zitadel/internal/api/authz" "github.com/zitadel/zitadel/internal/command" "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/telemetry/tracing" @@ -29,7 +30,7 @@ func (s *Server) DeviceToken(ctx context.Context, r *op.ClientRequest[oidc.Devic return response(s.accessTokenResponseFromSession(ctx, client, session, "", client.client.ProjectID, client.client.ProjectRoleAssertion, client.client.AccessTokenRoleAssertion, client.client.IDTokenRoleAssertion, client.client.IDTokenUserinfoAssertion)) } if errors.Is(err, context.DeadlineExceeded) { - return nil, oidc.ErrSlowDown().WithParent(err) + return nil, oidc.ErrSlowDown().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } var target command.DeviceAuthStateError @@ -42,5 +43,5 @@ func (s *Server) DeviceToken(ctx context.Context, r *op.ClientRequest[oidc.Devic return nil, oidc.ErrExpiredDeviceCode() } } - return nil, oidc.ErrAccessDenied().WithParent(err) + return nil, oidc.ErrAccessDenied().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError) } diff --git a/internal/api/oidc/token_exchange.go b/internal/api/oidc/token_exchange.go index c29b7eb80b..c94621a4d2 100644 --- a/internal/api/oidc/token_exchange.go +++ b/internal/api/oidc/token_exchange.go @@ -55,7 +55,7 @@ func (s *Server) tokenExchange(ctx context.Context, r *op.ClientRequest[oidc.Tok subjectToken, err := s.verifyExchangeToken(ctx, client, r.Data.SubjectToken, r.Data.SubjectTokenType, oidc.AllTokenTypes...) if err != nil { - return nil, oidc.ErrInvalidRequest().WithParent(err).WithDescription("subject_token invalid") + return nil, oidc.ErrInvalidRequest().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("subject_token invalid") } actorToken := subjectToken // see [createExchangeTokens] comment. @@ -65,7 +65,7 @@ func (s *Server) tokenExchange(ctx context.Context, r *op.ClientRequest[oidc.Tok } actorToken, err = s.verifyExchangeToken(ctx, client, r.Data.ActorToken, r.Data.ActorTokenType, oidc.AccessTokenType, oidc.IDTokenType, oidc.RefreshTokenType) if err != nil { - return nil, oidc.ErrInvalidRequest().WithParent(err).WithDescription("actor_token invalid") + return nil, oidc.ErrInvalidRequest().WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError).WithDescription("actor_token invalid") } ctx = authz.SetCtxData(ctx, authz.CtxData{ UserID: actorToken.userID, diff --git a/internal/api/oidc/userinfo.go b/internal/api/oidc/userinfo.go index 93dffb623a..e023d7a63d 100644 --- a/internal/api/oidc/userinfo.go +++ b/internal/api/oidc/userinfo.go @@ -42,7 +42,7 @@ func (s *Server) UserInfo(ctx context.Context, r *op.Request[oidc.UserInfoReques token, err := s.verifyAccessToken(ctx, r.Data.AccessToken) if err != nil { - return nil, op.NewStatusError(oidc.ErrAccessDenied().WithDescription("access token invalid").WithParent(err), http.StatusUnauthorized) + return nil, op.NewStatusError(oidc.ErrAccessDenied().WithDescription("access token invalid").WithParent(err).WithReturnParentToClient(authz.GetFeatures(ctx).DebugOIDCParentError), http.StatusUnauthorized) } var ( diff --git a/internal/command/instance_features.go b/internal/command/instance_features.go index e6e448da9e..4fcf87b670 100644 --- a/internal/command/instance_features.go +++ b/internal/command/instance_features.go @@ -24,6 +24,7 @@ type InstanceFeatures struct { Actions *bool ImprovedPerformance []feature.ImprovedPerformanceType WebKey *bool + DebugOIDCParentError *bool } func (m *InstanceFeatures) isEmpty() bool { @@ -35,7 +36,8 @@ func (m *InstanceFeatures) isEmpty() bool { m.Actions == nil && // nil check to allow unset improvements m.ImprovedPerformance == nil && - m.WebKey == nil + m.WebKey == nil && + m.DebugOIDCParentError == nil } func (c *Commands) SetInstanceFeatures(ctx context.Context, f *InstanceFeatures) (*domain.ObjectDetails, error) { diff --git a/internal/command/instance_features_model.go b/internal/command/instance_features_model.go index bdb46d2e04..417b14dba7 100644 --- a/internal/command/instance_features_model.go +++ b/internal/command/instance_features_model.go @@ -68,6 +68,7 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder { feature_v2.InstanceActionsEventType, feature_v2.InstanceImprovedPerformanceEventType, feature_v2.InstanceWebKeyEventType, + feature_v2.InstanceDebugOIDCParentErrorEventType, ). Builder().ResourceOwner(m.ResourceOwner) } @@ -104,6 +105,9 @@ func reduceInstanceFeature(features *InstanceFeatures, key feature.Key, value an case feature.KeyWebKey: v := value.(bool) features.WebKey = &v + case feature.KeyDebugOIDCParentError: + v := value.(bool) + features.DebugOIDCParentError = &v } } @@ -118,5 +122,6 @@ func (wm *InstanceFeaturesWriteModel) setCommands(ctx context.Context, f *Instan cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.Actions, f.Actions, feature_v2.InstanceActionsEventType) cmds = appendFeatureSliceUpdate(ctx, cmds, aggregate, wm.ImprovedPerformance, f.ImprovedPerformance, feature_v2.InstanceImprovedPerformanceEventType) cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.WebKey, f.WebKey, feature_v2.InstanceWebKeyEventType) + cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.DebugOIDCParentError, f.DebugOIDCParentError, feature_v2.InstanceDebugOIDCParentErrorEventType) return cmds } diff --git a/internal/feature/feature.go b/internal/feature/feature.go index 34dd5d908a..b4b2c21d4c 100644 --- a/internal/feature/feature.go +++ b/internal/feature/feature.go @@ -15,6 +15,7 @@ const ( KeyActions KeyImprovedPerformance KeyWebKey + KeyDebugOIDCParentError ) //go:generate enumer -type Level -transform snake -trimprefix Level @@ -39,6 +40,7 @@ type Features struct { Actions bool `json:"actions,omitempty"` ImprovedPerformance []ImprovedPerformanceType `json:"improved_performance,omitempty"` WebKey bool `json:"web_key,omitempty"` + DebugOIDCParentError bool `json:"debug_oidc_parent_error,omitempty"` } type ImprovedPerformanceType int32 diff --git a/internal/feature/key_enumer.go b/internal/feature/key_enumer.go index 6452a258c3..c6d12fcb75 100644 --- a/internal/feature/key_enumer.go +++ b/internal/feature/key_enumer.go @@ -7,11 +7,11 @@ import ( "strings" ) -const _KeyName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactionsimproved_performanceweb_key" +const _KeyName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactionsimproved_performanceweb_keydebug_oidc_parent_error" -var _KeyIndex = [...]uint8{0, 11, 28, 61, 81, 92, 106, 113, 133, 140} +var _KeyIndex = [...]uint8{0, 11, 28, 61, 81, 92, 106, 113, 133, 140, 163} -const _KeyLowerName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactionsimproved_performanceweb_key" +const _KeyLowerName = "unspecifiedlogin_default_orgtrigger_introspection_projectionslegacy_introspectionuser_schematoken_exchangeactionsimproved_performanceweb_keydebug_oidc_parent_error" func (i Key) String() string { if i < 0 || i >= Key(len(_KeyIndex)-1) { @@ -33,9 +33,10 @@ func _KeyNoOp() { _ = x[KeyActions-(6)] _ = x[KeyImprovedPerformance-(7)] _ = x[KeyWebKey-(8)] + _ = x[KeyDebugOIDCParentError-(9)] } -var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActions, KeyImprovedPerformance, KeyWebKey} +var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyLegacyIntrospection, KeyUserSchema, KeyTokenExchange, KeyActions, KeyImprovedPerformance, KeyWebKey, KeyDebugOIDCParentError} var _KeyNameToValueMap = map[string]Key{ _KeyName[0:11]: KeyUnspecified, @@ -56,6 +57,8 @@ var _KeyNameToValueMap = map[string]Key{ _KeyLowerName[113:133]: KeyImprovedPerformance, _KeyName[133:140]: KeyWebKey, _KeyLowerName[133:140]: KeyWebKey, + _KeyName[140:163]: KeyDebugOIDCParentError, + _KeyLowerName[140:163]: KeyDebugOIDCParentError, } var _KeyNames = []string{ @@ -68,6 +71,7 @@ var _KeyNames = []string{ _KeyName[106:113], _KeyName[113:133], _KeyName[133:140], + _KeyName[140:163], } // KeyString retrieves an enum value from the enum constants string name. diff --git a/internal/query/instance_features.go b/internal/query/instance_features.go index f10039fa66..40bea9d8bf 100644 --- a/internal/query/instance_features.go +++ b/internal/query/instance_features.go @@ -17,6 +17,7 @@ type InstanceFeatures struct { Actions FeatureSource[bool] ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType] WebKey FeatureSource[bool] + DebugOIDCParentError FeatureSource[bool] } func (q *Queries) GetInstanceFeatures(ctx context.Context, cascade bool) (_ *InstanceFeatures, err error) { diff --git a/internal/query/instance_features_model.go b/internal/query/instance_features_model.go index a2ab09d263..134aafa67f 100644 --- a/internal/query/instance_features_model.go +++ b/internal/query/instance_features_model.go @@ -68,6 +68,7 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder { feature_v2.InstanceActionsEventType, feature_v2.InstanceImprovedPerformanceEventType, feature_v2.InstanceWebKeyEventType, + feature_v2.InstanceDebugOIDCParentErrorEventType, ). Builder().ResourceOwner(m.ResourceOwner) } @@ -118,6 +119,8 @@ func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_ features.ImprovedPerformance.set(level, event.Value) case feature.KeyWebKey: features.WebKey.set(level, event.Value) + case feature.KeyDebugOIDCParentError: + features.DebugOIDCParentError.set(level, event.Value) } return nil } diff --git a/internal/query/projection/instance_features.go b/internal/query/projection/instance_features.go index d24fe6d203..c0aaa8c3a7 100644 --- a/internal/query/projection/instance_features.go +++ b/internal/query/projection/instance_features.go @@ -92,6 +92,10 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer { Event: feature_v2.InstanceWebKeyEventType, Reduce: reduceInstanceSetFeature[bool], }, + { + Event: feature_v2.InstanceDebugOIDCParentErrorEventType, + Reduce: reduceInstanceSetFeature[bool], + }, { Event: instance.InstanceRemovedEventType, Reduce: reduceInstanceRemovedHelper(InstanceDomainInstanceIDCol), diff --git a/internal/repository/feature/feature_v2/eventstore.go b/internal/repository/feature/feature_v2/eventstore.go index 97b4e4ed3a..eebed8a3b8 100644 --- a/internal/repository/feature/feature_v2/eventstore.go +++ b/internal/repository/feature/feature_v2/eventstore.go @@ -24,4 +24,5 @@ func init() { eventstore.RegisterFilterEventMapper(AggregateType, InstanceActionsEventType, eventstore.GenericEventMapper[SetEvent[bool]]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceImprovedPerformanceEventType, eventstore.GenericEventMapper[SetEvent[[]feature.ImprovedPerformanceType]]) eventstore.RegisterFilterEventMapper(AggregateType, InstanceWebKeyEventType, eventstore.GenericEventMapper[SetEvent[bool]]) + eventstore.RegisterFilterEventMapper(AggregateType, InstanceDebugOIDCParentErrorEventType, eventstore.GenericEventMapper[SetEvent[bool]]) } diff --git a/internal/repository/feature/feature_v2/feature.go b/internal/repository/feature/feature_v2/feature.go index 27e1ed40fc..4c056c235f 100644 --- a/internal/repository/feature/feature_v2/feature.go +++ b/internal/repository/feature/feature_v2/feature.go @@ -29,6 +29,7 @@ var ( InstanceActionsEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyActions) InstanceImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyImprovedPerformance) InstanceWebKeyEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyWebKey) + InstanceDebugOIDCParentErrorEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyDebugOIDCParentError) ) const ( diff --git a/proto/zitadel/feature/v2/instance.proto b/proto/zitadel/feature/v2/instance.proto index 24c6df5db6..159c639908 100644 --- a/proto/zitadel/feature/v2/instance.proto +++ b/proto/zitadel/feature/v2/instance.proto @@ -65,6 +65,13 @@ message SetInstanceFeaturesRequest{ description: "Enable the webkey/v3alpha API. The first time this feature is enabled, web keys are generated and activated."; } ]; + + optional bool debug_oidc_parent_error = 9 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true"; + description: "Return parent errors to OIDC clients for debugging purposes. Parent errors may contain sensitive data or unwanted details about the system status of zitadel. Only enable if really needed."; + } + ]; } message SetInstanceFeaturesResponse { @@ -143,4 +150,11 @@ message GetInstanceFeaturesResponse { description: "Enable the webkey/v3alpha API. The first time this feature is enabled, web keys are generated and activated."; } ]; + + FeatureFlag debug_oidc_parent_error = 10 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true"; + description: "Return parent errors to OIDC clients for debugging purposes. Parent errors may contain sensitive data or unwanted details about the system status of zitadel. Only enable if really needed."; + } + ]; } diff --git a/proto/zitadel/feature/v2beta/instance.proto b/proto/zitadel/feature/v2beta/instance.proto index 33d00af3eb..2059abf17e 100644 --- a/proto/zitadel/feature/v2beta/instance.proto +++ b/proto/zitadel/feature/v2beta/instance.proto @@ -65,6 +65,13 @@ message SetInstanceFeaturesRequest{ description: "Enable the webkey/v3alpha API. The first time this feature is enabled, web keys are generated and activated."; } ]; + + optional bool debug_oidc_parent_error = 9 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true"; + description: "Return parent errors to OIDC clients for debugging purposes. Parent errors may contain sensitive data or unwanted details about the system status of zitadel. Only enable if really needed."; + } + ]; } message SetInstanceFeaturesResponse { @@ -143,4 +150,11 @@ message GetInstanceFeaturesResponse { description: "Enable the webkey/v3alpha API. The first time this feature is enabled, web keys are generated and activated."; } ]; + + FeatureFlag debug_oidc_parent_error = 10 [ + (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + example: "true"; + description: "Return parent errors to OIDC clients for debugging purposes. Parent errors may contain sensitive data or unwanted details about the system status of zitadel. Only enable if really needed."; + } + ]; }