mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 14:47:33 +00:00
chore(oidc): graduate webkey to stable (#10122)
# Which Problems Are Solved Stabilize the usage of webkeys. # How the Problems Are Solved - Remove all legacy signing key code from the OIDC API - Remove the webkey feature flag from proto - Remove the webkey feature flag from console - Cleanup documentation # Additional Changes - Resolved some canonical header linter errors in OIDC - Use the constant for `projections.lock` in the saml package. # Additional Context - Closes #10029 - After #10105 - After #10061
This commit is contained in:
@@ -58,7 +58,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) (*com
|
||||
UserSchema: req.UserSchema,
|
||||
TokenExchange: req.OidcTokenExchange,
|
||||
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
|
||||
WebKey: req.WebKey,
|
||||
DebugOIDCParentError: req.DebugOidcParentError,
|
||||
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
|
||||
DisableUserTokenEvent: req.DisableUserTokenEvent,
|
||||
@@ -77,7 +76,6 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
|
||||
UserSchema: featureSourceToFlagPb(&f.UserSchema),
|
||||
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
|
||||
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
|
||||
WebKey: featureSourceToFlagPb(&f.WebKey),
|
||||
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),
|
||||
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
|
||||
DisableUserTokenEvent: featureSourceToFlagPb(&f.DisableUserTokenEvent),
|
||||
|
@@ -153,7 +153,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
|
||||
UserSchema: gu.Ptr(true),
|
||||
OidcTokenExchange: gu.Ptr(true),
|
||||
ImprovedPerformance: nil,
|
||||
WebKey: gu.Ptr(true),
|
||||
DebugOidcParentError: gu.Ptr(true),
|
||||
OidcSingleV1SessionTermination: gu.Ptr(true),
|
||||
EnableBackChannelLogout: gu.Ptr(true),
|
||||
@@ -169,7 +168,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
|
||||
UserSchema: gu.Ptr(true),
|
||||
TokenExchange: gu.Ptr(true),
|
||||
ImprovedPerformance: nil,
|
||||
WebKey: gu.Ptr(true),
|
||||
DebugOIDCParentError: gu.Ptr(true),
|
||||
OIDCSingleV1SessionTermination: gu.Ptr(true),
|
||||
EnableBackChannelLogout: gu.Ptr(true),
|
||||
@@ -211,10 +209,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
Level: feature.LevelSystem,
|
||||
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgByID},
|
||||
},
|
||||
WebKey: query.FeatureSource[bool]{
|
||||
Level: feature.LevelInstance,
|
||||
Value: true,
|
||||
},
|
||||
OIDCSingleV1SessionTermination: query.FeatureSource[bool]{
|
||||
Level: feature.LevelInstance,
|
||||
Value: true,
|
||||
@@ -265,10 +259,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
ExecutionPaths: []feature_pb.ImprovedPerformance{feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID},
|
||||
Source: feature_pb.Source_SOURCE_SYSTEM,
|
||||
},
|
||||
WebKey: &feature_pb.FeatureFlag{
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
DebugOidcParentError: &feature_pb.FeatureFlag{
|
||||
Enabled: false,
|
||||
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
|
||||
|
@@ -38,7 +38,6 @@ func instanceFeaturesToCommand(req *feature_pb.SetInstanceFeaturesRequest) *comm
|
||||
UserSchema: req.UserSchema,
|
||||
TokenExchange: req.OidcTokenExchange,
|
||||
ImprovedPerformance: improvedPerformanceListToDomain(req.ImprovedPerformance),
|
||||
WebKey: req.WebKey,
|
||||
DebugOIDCParentError: req.DebugOidcParentError,
|
||||
OIDCSingleV1SessionTermination: req.OidcSingleV1SessionTermination,
|
||||
}
|
||||
@@ -52,7 +51,6 @@ func instanceFeaturesToPb(f *query.InstanceFeatures) *feature_pb.GetInstanceFeat
|
||||
UserSchema: featureSourceToFlagPb(&f.UserSchema),
|
||||
OidcTokenExchange: featureSourceToFlagPb(&f.TokenExchange),
|
||||
ImprovedPerformance: featureSourceToImprovedPerformanceFlagPb(&f.ImprovedPerformance),
|
||||
WebKey: featureSourceToFlagPb(&f.WebKey),
|
||||
DebugOidcParentError: featureSourceToFlagPb(&f.DebugOIDCParentError),
|
||||
OidcSingleV1SessionTermination: featureSourceToFlagPb(&f.OIDCSingleV1SessionTermination),
|
||||
}
|
||||
|
@@ -111,7 +111,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
|
||||
UserSchema: gu.Ptr(true),
|
||||
OidcTokenExchange: gu.Ptr(true),
|
||||
ImprovedPerformance: nil,
|
||||
WebKey: gu.Ptr(true),
|
||||
OidcSingleV1SessionTermination: gu.Ptr(true),
|
||||
}
|
||||
want := &command.InstanceFeatures{
|
||||
@@ -120,7 +119,6 @@ func Test_instanceFeaturesToCommand(t *testing.T) {
|
||||
UserSchema: gu.Ptr(true),
|
||||
TokenExchange: gu.Ptr(true),
|
||||
ImprovedPerformance: nil,
|
||||
WebKey: gu.Ptr(true),
|
||||
OIDCSingleV1SessionTermination: gu.Ptr(true),
|
||||
}
|
||||
got := instanceFeaturesToCommand(arg)
|
||||
@@ -154,10 +152,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
Level: feature.LevelSystem,
|
||||
Value: []feature.ImprovedPerformanceType{feature.ImprovedPerformanceTypeOrgByID},
|
||||
},
|
||||
WebKey: query.FeatureSource[bool]{
|
||||
Level: feature.LevelInstance,
|
||||
Value: true,
|
||||
},
|
||||
OIDCSingleV1SessionTermination: query.FeatureSource[bool]{
|
||||
Level: feature.LevelInstance,
|
||||
Value: true,
|
||||
@@ -189,10 +183,6 @@ func Test_instanceFeaturesToPb(t *testing.T) {
|
||||
ExecutionPaths: []feature_pb.ImprovedPerformance{feature_pb.ImprovedPerformance_IMPROVED_PERFORMANCE_ORG_BY_ID},
|
||||
Source: feature_pb.Source_SOURCE_SYSTEM,
|
||||
},
|
||||
WebKey: &feature_pb.FeatureFlag{
|
||||
Enabled: true,
|
||||
Source: feature_pb.Source_SOURCE_INSTANCE,
|
||||
},
|
||||
DebugOidcParentError: &feature_pb.FeatureFlag{
|
||||
Enabled: false,
|
||||
Source: feature_pb.Source_SOURCE_UNSPECIFIED,
|
||||
|
@@ -12,11 +12,9 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
|
||||
webkey "github.com/zitadel/zitadel/pkg/grpc/webkey/v2beta"
|
||||
)
|
||||
|
||||
@@ -33,34 +31,8 @@ func TestMain(m *testing.M) {
|
||||
}())
|
||||
}
|
||||
|
||||
func TestServer_Feature_Disabled(t *testing.T) {
|
||||
instance, iamCtx, _ := createInstance(t, false)
|
||||
client := instance.Client.WebKeyV2Beta
|
||||
|
||||
t.Run("CreateWebKey", func(t *testing.T) {
|
||||
_, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{})
|
||||
assertFeatureDisabledError(t, err)
|
||||
})
|
||||
t.Run("ActivateWebKey", func(t *testing.T) {
|
||||
_, err := client.ActivateWebKey(iamCtx, &webkey.ActivateWebKeyRequest{
|
||||
Id: "1",
|
||||
})
|
||||
assertFeatureDisabledError(t, err)
|
||||
})
|
||||
t.Run("DeleteWebKey", func(t *testing.T) {
|
||||
_, err := client.DeleteWebKey(iamCtx, &webkey.DeleteWebKeyRequest{
|
||||
Id: "1",
|
||||
})
|
||||
assertFeatureDisabledError(t, err)
|
||||
})
|
||||
t.Run("ListWebKeys", func(t *testing.T) {
|
||||
_, err := client.ListWebKeys(iamCtx, &webkey.ListWebKeysRequest{})
|
||||
assertFeatureDisabledError(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestServer_ListWebKeys(t *testing.T) {
|
||||
instance, iamCtx, creationDate := createInstance(t, true)
|
||||
instance, iamCtx, creationDate := createInstance(t)
|
||||
// After the feature is first enabled, we can expect 2 generated keys with the default config.
|
||||
checkWebKeyListState(iamCtx, t, instance, 2, "", &webkey.WebKey_Rsa{
|
||||
Rsa: &webkey.RSA{
|
||||
@@ -71,7 +43,7 @@ func TestServer_ListWebKeys(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_CreateWebKey(t *testing.T) {
|
||||
instance, iamCtx, creationDate := createInstance(t, true)
|
||||
instance, iamCtx, creationDate := createInstance(t)
|
||||
client := instance.Client.WebKeyV2Beta
|
||||
|
||||
_, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
|
||||
@@ -93,7 +65,7 @@ func TestServer_CreateWebKey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_ActivateWebKey(t *testing.T) {
|
||||
instance, iamCtx, creationDate := createInstance(t, true)
|
||||
instance, iamCtx, creationDate := createInstance(t)
|
||||
client := instance.Client.WebKeyV2Beta
|
||||
|
||||
resp, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
|
||||
@@ -120,7 +92,7 @@ func TestServer_ActivateWebKey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestServer_DeleteWebKey(t *testing.T) {
|
||||
instance, iamCtx, creationDate := createInstance(t, true)
|
||||
instance, iamCtx, creationDate := createInstance(t)
|
||||
client := instance.Client.WebKeyV2Beta
|
||||
|
||||
keyIDs := make([]string, 2)
|
||||
@@ -197,40 +169,22 @@ func TestServer_DeleteWebKey(t *testing.T) {
|
||||
}, creationDate)
|
||||
}
|
||||
|
||||
func createInstance(t *testing.T, enableFeature bool) (*integration.Instance, context.Context, *timestamppb.Timestamp) {
|
||||
func createInstance(t *testing.T) (*integration.Instance, context.Context, *timestamppb.Timestamp) {
|
||||
instance := integration.NewInstance(CTX)
|
||||
creationDate := timestamppb.Now()
|
||||
iamCTX := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
|
||||
if enableFeature {
|
||||
_, err := instance.Client.FeatureV2.SetInstanceFeatures(iamCTX, &feature.SetInstanceFeaturesRequest{
|
||||
WebKey: proto.Bool(true),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(iamCTX, time.Minute)
|
||||
assert.EventuallyWithT(t, func(collect *assert.CollectT) {
|
||||
resp, err := instance.Client.WebKeyV2Beta.ListWebKeys(iamCTX, &webkey.ListWebKeysRequest{})
|
||||
if enableFeature {
|
||||
assert.NoError(collect, err)
|
||||
assert.Len(collect, resp.GetWebKeys(), 2)
|
||||
} else {
|
||||
assert.Error(collect, err)
|
||||
}
|
||||
assert.NoError(collect, err)
|
||||
assert.Len(collect, resp.GetWebKeys(), 2)
|
||||
|
||||
}, retryDuration, tick)
|
||||
|
||||
return instance, iamCTX, creationDate
|
||||
}
|
||||
|
||||
func assertFeatureDisabledError(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
require.Error(t, err)
|
||||
s := status.Convert(err)
|
||||
assert.Equal(t, codes.FailedPrecondition, s.Code())
|
||||
assert.Contains(t, s.Message(), "WEBKEY-Ohx6E")
|
||||
}
|
||||
|
||||
func checkWebKeyListState(ctx context.Context, t *testing.T, instance *integration.Instance, nKeys int, expectActiveKeyID string, config any, creationDate *timestamppb.Timestamp) {
|
||||
t.Helper()
|
||||
|
||||
|
@@ -5,9 +5,7 @@ import (
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
webkey "github.com/zitadel/zitadel/pkg/grpc/webkey/v2beta"
|
||||
)
|
||||
|
||||
@@ -15,9 +13,6 @@ func (s *Server) CreateWebKey(ctx context.Context, req *webkey.CreateWebKeyReque
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err = checkWebKeyFeature(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
webKey, err := s.command.CreateWebKey(ctx, createWebKeyRequestToConfig(req))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -33,9 +28,6 @@ func (s *Server) ActivateWebKey(ctx context.Context, req *webkey.ActivateWebKeyR
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err = checkWebKeyFeature(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
details, err := s.command.ActivateWebKey(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -50,9 +42,6 @@ func (s *Server) DeleteWebKey(ctx context.Context, req *webkey.DeleteWebKeyReque
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err = checkWebKeyFeature(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
deletedAt, err := s.command.DeleteWebKey(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -71,9 +60,6 @@ func (s *Server) ListWebKeys(ctx context.Context, _ *webkey.ListWebKeysRequest)
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if err = checkWebKeyFeature(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
list, err := s.query.ListWebKeys(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -83,10 +69,3 @@ func (s *Server) ListWebKeys(ctx context.Context, _ *webkey.ListWebKeysRequest)
|
||||
WebKeys: webKeyDetailsListToPb(list),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func checkWebKeyFeature(ctx context.Context) error {
|
||||
if !authz.GetFeatures(ctx).WebKey {
|
||||
return zerrors.ThrowPreconditionFailed(nil, "WEBKEY-Ohx6E", "Errors.WebKey.FeatureDisabled")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ func (s *Server) verifyAccessToken(ctx context.Context, tkn string) (_ *accessTo
|
||||
tokenID, subject = split[0], split[1]
|
||||
} else {
|
||||
verifier := op.NewAccessTokenVerifier(op.IssuerFromContext(ctx), s.accessTokenKeySet,
|
||||
op.WithSupportedAccessTokenSigningAlgorithms(supportedSigningAlgs(ctx)...),
|
||||
op.WithSupportedAccessTokenSigningAlgorithms(supportedSigningAlgs()...),
|
||||
)
|
||||
claims, err := op.VerifyAccessToken[*oidc.AccessTokenClaims](ctx, tkn, verifier)
|
||||
if err != nil {
|
||||
|
@@ -140,13 +140,8 @@ func HttpHeadersFromContext(ctx context.Context) (userAgent, acceptLang string)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if agents, ok := ctxHeaders[http_utils.UserAgentHeader]; ok {
|
||||
userAgent = agents[0]
|
||||
}
|
||||
if langs, ok := ctxHeaders[http_utils.AcceptLanguage]; ok {
|
||||
acceptLang = langs[0]
|
||||
}
|
||||
return userAgent, acceptLang
|
||||
return ctxHeaders.Get(http_utils.UserAgentHeader),
|
||||
ctxHeaders.Get(http_utils.AcceptLanguage)
|
||||
}
|
||||
|
||||
func IpFromContext(ctx context.Context) net.IP {
|
||||
|
@@ -14,12 +14,10 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/zitadel/oidc/v3/pkg/client"
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"google.golang.org/protobuf/proto"
|
||||
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/feature/v2"
|
||||
oidc_pb "github.com/zitadel/zitadel/pkg/grpc/oidc/v2"
|
||||
)
|
||||
|
||||
@@ -53,25 +51,16 @@ func TestServer_Keys(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
webKeyFeature bool
|
||||
wantLen int
|
||||
name string
|
||||
wantLen int
|
||||
}{
|
||||
{
|
||||
name: "legacy only",
|
||||
webKeyFeature: false,
|
||||
wantLen: 1,
|
||||
},
|
||||
{
|
||||
name: "webkeys with legacy",
|
||||
webKeyFeature: true,
|
||||
wantLen: 3, // 1 legacy + 2 created by enabling feature flag
|
||||
name: "webkeys",
|
||||
wantLen: 2, // 2 from instance creation.
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ensureWebKeyFeature(t, instance, tt.webKeyFeature)
|
||||
|
||||
assert.EventuallyWithT(t, func(ttt *assert.CollectT) {
|
||||
resp, err := http.Get(discovery.JwksURI)
|
||||
require.NoError(ttt, err)
|
||||
@@ -92,30 +81,10 @@ func TestServer_Keys(t *testing.T) {
|
||||
}
|
||||
|
||||
cacheControl := resp.Header.Get("cache-control")
|
||||
if tt.webKeyFeature {
|
||||
require.Equal(ttt, "max-age=300, must-revalidate", cacheControl)
|
||||
return
|
||||
}
|
||||
require.Equal(ttt, "no-store", cacheControl)
|
||||
require.Equal(ttt, "max-age=300, must-revalidate", cacheControl)
|
||||
|
||||
}, time.Minute, time.Second/10)
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func ensureWebKeyFeature(t *testing.T, instance *integration.Instance, set bool) {
|
||||
ctxIam := instance.WithAuthorization(CTX, integration.UserTypeIAMOwner)
|
||||
|
||||
_, err := instance.Client.FeatureV2.SetInstanceFeatures(ctxIam, &feature.SetInstanceFeaturesRequest{
|
||||
WebKey: proto.Bool(set),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Cleanup(func() {
|
||||
_, err := instance.Client.FeatureV2.SetInstanceFeatures(ctxIam, &feature.SetInstanceFeaturesRequest{
|
||||
WebKey: proto.Bool(false),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
|
@@ -35,21 +35,14 @@ func TestServer_UserInfo(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
trigger bool
|
||||
webKey bool
|
||||
}{
|
||||
{
|
||||
name: "trigger enabled",
|
||||
trigger: true,
|
||||
},
|
||||
|
||||
// This is the only functional test we need to cover web keys.
|
||||
// - By creating tokens the signer is tested
|
||||
// - When obtaining the tokens, the RP verifies the ID Token using the key set from the jwks endpoint.
|
||||
// - By calling userinfo with the access token as JWT, the Token Verifier with the public key cache is tested.
|
||||
{
|
||||
name: "web keys",
|
||||
name: "trigger disabled",
|
||||
trigger: false,
|
||||
webKey: true,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -57,7 +50,6 @@ func TestServer_UserInfo(t *testing.T) {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := Instance.Client.FeatureV2.SetInstanceFeatures(iamOwnerCTX, &feature.SetInstanceFeaturesRequest{
|
||||
OidcTriggerIntrospectionProjections: &tt.trigger,
|
||||
WebKey: &tt.webKey,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
testServer_UserInfo(t)
|
||||
|
@@ -10,18 +10,12 @@ import (
|
||||
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/jonboulle/clockwork"
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/shopspring/decimal"
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_util "github.com/zitadel/zitadel/internal/api/http"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/keypair"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -36,11 +30,8 @@ var supportedWebKeyAlgs = []string{
|
||||
string(jose.ES512),
|
||||
}
|
||||
|
||||
func supportedSigningAlgs(ctx context.Context) []string {
|
||||
if authz.GetFeatures(ctx).WebKey {
|
||||
return supportedWebKeyAlgs
|
||||
}
|
||||
return []string{string(jose.RS256)}
|
||||
func supportedSigningAlgs() []string {
|
||||
return supportedWebKeyAlgs
|
||||
}
|
||||
|
||||
type cachedPublicKey struct {
|
||||
@@ -211,15 +202,6 @@ func withKeyExpiryCheck(check bool) keySetOption {
|
||||
}
|
||||
}
|
||||
|
||||
func jsonWebkey(key query.PublicKey) *jose.JSONWebKey {
|
||||
return &jose.JSONWebKey{
|
||||
KeyID: key.ID(),
|
||||
Algorithm: key.Algorithm(),
|
||||
Use: key.Use().String(),
|
||||
Key: key.Key(),
|
||||
}
|
||||
}
|
||||
|
||||
// keySetMap is a mapping of key IDs to public key data.
|
||||
type keySetMap map[string][]byte
|
||||
|
||||
@@ -250,7 +232,6 @@ func (k keySetMap) VerifySignature(ctx context.Context, jws *jose.JSONWebSignatu
|
||||
}
|
||||
|
||||
const (
|
||||
locksTable = "projections.locks"
|
||||
signingKey = "signing_key"
|
||||
oidcUser = "OIDC"
|
||||
|
||||
@@ -279,203 +260,36 @@ func (s *SigningKey) ID() string {
|
||||
return s.id
|
||||
}
|
||||
|
||||
// PublicKey wraps the query.PublicKey to implement the op.Key interface
|
||||
type PublicKey struct {
|
||||
key query.PublicKey
|
||||
}
|
||||
|
||||
func (s *PublicKey) Algorithm() jose.SignatureAlgorithm {
|
||||
return jose.SignatureAlgorithm(s.key.Algorithm())
|
||||
}
|
||||
|
||||
func (s *PublicKey) Use() string {
|
||||
return s.key.Use().String()
|
||||
}
|
||||
|
||||
func (s *PublicKey) Key() interface{} {
|
||||
return s.key.Key()
|
||||
}
|
||||
|
||||
func (s *PublicKey) ID() string {
|
||||
return s.key.ID()
|
||||
}
|
||||
|
||||
// KeySet implements the op.Storage interface
|
||||
func (o *OPStorage) KeySet(ctx context.Context) (keys []op.Key, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
err = retry(func() error {
|
||||
publicKeys, err := o.query.ActivePublicKeys(ctx, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keys = make([]op.Key, len(publicKeys.Keys))
|
||||
for i, key := range publicKeys.Keys {
|
||||
keys[i] = &PublicKey{key}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return keys, err
|
||||
panic(o.panicErr("KeySet"))
|
||||
}
|
||||
|
||||
// SignatureAlgorithms implements the op.Storage interface
|
||||
func (o *OPStorage) SignatureAlgorithms(ctx context.Context) ([]jose.SignatureAlgorithm, error) {
|
||||
key, err := o.SigningKey(ctx)
|
||||
if err != nil {
|
||||
logging.WithError(err).Warn("unable to fetch signing key")
|
||||
return nil, err
|
||||
}
|
||||
return []jose.SignatureAlgorithm{key.SignatureAlgorithm()}, nil
|
||||
panic(o.panicErr("SignatureAlgorithms"))
|
||||
}
|
||||
|
||||
// SigningKey implements the op.Storage interface
|
||||
func (o *OPStorage) SigningKey(ctx context.Context) (key op.SigningKey, err error) {
|
||||
err = retry(func() error {
|
||||
key, err = o.getSigningKey(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if key == nil {
|
||||
return zerrors.ThrowNotFound(nil, "OIDC-ve4Qu", "Errors.Internal")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return key, err
|
||||
}
|
||||
|
||||
func (o *OPStorage) getSigningKey(ctx context.Context) (op.SigningKey, error) {
|
||||
keys, err := o.query.ActivePrivateSigningKey(ctx, time.Now().Add(gracefulPeriod))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(keys.Keys) > 0 {
|
||||
return PrivateKeyToSigningKey(SelectSigningKey(keys.Keys), o.encAlg)
|
||||
}
|
||||
var position decimal.Decimal
|
||||
if keys.State != nil {
|
||||
position = keys.State.Position
|
||||
}
|
||||
return nil, o.refreshSigningKey(ctx, position)
|
||||
}
|
||||
|
||||
func (o *OPStorage) refreshSigningKey(ctx context.Context, position decimal.Decimal) error {
|
||||
ok, err := o.ensureIsLatestKey(ctx, position)
|
||||
if err != nil || !ok {
|
||||
return zerrors.ThrowInternal(err, "OIDC-ASfh3", "cannot ensure that projection is up to date")
|
||||
}
|
||||
err = o.lockAndGenerateSigningKeyPair(ctx)
|
||||
if err != nil {
|
||||
return zerrors.ThrowInternal(err, "OIDC-ADh31", "could not create signing key")
|
||||
}
|
||||
return zerrors.ThrowInternal(nil, "OIDC-Df1bh", "")
|
||||
}
|
||||
|
||||
func (o *OPStorage) ensureIsLatestKey(ctx context.Context, position decimal.Decimal) (bool, error) {
|
||||
maxSequence, err := o.getMaxKeyPosition(ctx)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("error retrieving new events: %w", err)
|
||||
}
|
||||
return position.GreaterThanOrEqual(maxSequence), nil
|
||||
}
|
||||
|
||||
func PrivateKeyToSigningKey(key query.PrivateKey, algorithm crypto.EncryptionAlgorithm) (_ op.SigningKey, err error) {
|
||||
keyData, err := crypto.Decrypt(key.Key(), algorithm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
privateKey, err := crypto.BytesToPrivateKey(keyData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &SigningKey{
|
||||
algorithm: jose.SignatureAlgorithm(key.Algorithm()),
|
||||
key: privateKey,
|
||||
id: key.ID(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *OPStorage) lockAndGenerateSigningKeyPair(ctx context.Context) error {
|
||||
logging.Info("lock and generate signing key pair")
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
errs := o.locker.Lock(ctx, lockDuration, authz.GetInstance(ctx).InstanceID())
|
||||
err, ok := <-errs
|
||||
if err != nil || !ok {
|
||||
if zerrors.IsErrorAlreadyExists(err) {
|
||||
return nil
|
||||
}
|
||||
logging.OnError(err).Debug("initial lock failed")
|
||||
return err
|
||||
}
|
||||
|
||||
return o.command.GenerateSigningKeyPair(setOIDCCtx(ctx), "RS256")
|
||||
}
|
||||
|
||||
func (o *OPStorage) getMaxKeyPosition(ctx context.Context) (decimal.Decimal, error) {
|
||||
return o.eventstore.LatestPosition(ctx,
|
||||
eventstore.NewSearchQueryBuilder(eventstore.ColumnsMaxPosition).
|
||||
ResourceOwner(authz.GetInstance(ctx).InstanceID()).
|
||||
AwaitOpenTransactions().
|
||||
AddQuery().
|
||||
AggregateTypes(
|
||||
keypair.AggregateType,
|
||||
instance.AggregateType,
|
||||
).
|
||||
EventTypes(
|
||||
keypair.AddedEventType,
|
||||
instance.InstanceRemovedEventType,
|
||||
).
|
||||
Builder(),
|
||||
)
|
||||
}
|
||||
|
||||
func SelectSigningKey(keys []query.PrivateKey) query.PrivateKey {
|
||||
return keys[len(keys)-1]
|
||||
}
|
||||
|
||||
func setOIDCCtx(ctx context.Context) context.Context {
|
||||
return authz.SetCtxData(ctx, authz.CtxData{UserID: oidcUser, OrgID: authz.GetInstance(ctx).InstanceID()})
|
||||
}
|
||||
|
||||
func retry(retryable func() error) (err error) {
|
||||
for i := 0; i < retryCount; i++ {
|
||||
err = retryable()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
time.Sleep(retryBackoff)
|
||||
}
|
||||
return err
|
||||
panic(o.panicErr("SigningKey"))
|
||||
}
|
||||
|
||||
func (s *Server) Keys(ctx context.Context, r *op.Request[struct{}]) (_ *op.Response, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if !authz.GetFeatures(ctx).WebKey {
|
||||
return s.LegacyServer.Keys(ctx, r)
|
||||
}
|
||||
|
||||
keyset, err := s.query.GetWebKeySet(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return legacy keys, so we do not invalidate all tokens
|
||||
// once the feature flag is enabled.
|
||||
legacyKeys, err := s.query.ActivePublicKeys(ctx, time.Now())
|
||||
logging.OnError(err).Error("oidc server: active public keys (legacy)")
|
||||
appendPublicKeysToWebKeySet(keyset, legacyKeys)
|
||||
|
||||
resp := op.NewResponse(keyset)
|
||||
if s.jwksCacheControlMaxAge != 0 {
|
||||
resp.Header.Set(http_util.CacheControl,
|
||||
fmt.Sprintf("max-age=%d, must-revalidate", int(s.jwksCacheControlMaxAge/time.Second)),
|
||||
)
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
@@ -497,20 +311,10 @@ func appendPublicKeysToWebKeySet(keyset *jose.JSONWebKeySet, pubkeys *query.Publ
|
||||
|
||||
func queryKeyFunc(q *query.Queries) func(ctx context.Context, keyID string) (*jose.JSONWebKey, *time.Time, error) {
|
||||
return func(ctx context.Context, keyID string) (*jose.JSONWebKey, *time.Time, error) {
|
||||
if authz.GetFeatures(ctx).WebKey {
|
||||
webKey, err := q.GetPublicWebKeyByID(ctx, keyID)
|
||||
if err == nil {
|
||||
return webKey, nil, nil
|
||||
}
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
pubKey, err := q.GetPublicKeyByID(ctx, keyID)
|
||||
webKey, err := q.GetPublicWebKeyByID(ctx, keyID)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return jsonWebkey(pubKey), gu.Ptr(pubKey.Expiry()), nil
|
||||
return webKey, nil, nil
|
||||
}
|
||||
}
|
||||
|
@@ -18,10 +18,8 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/cache"
|
||||
"github.com/zitadel/zitadel/internal/command"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain/federatedlogout"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/handler/crdb"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/metrics"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
@@ -75,7 +73,6 @@ type OPStorage struct {
|
||||
defaultRefreshTokenIdleExpiration time.Duration
|
||||
defaultRefreshTokenExpiration time.Duration
|
||||
encAlg crypto.EncryptionAlgorithm
|
||||
locker crdb.Locker
|
||||
assetAPIPrefix func(ctx context.Context) string
|
||||
contextToIssuer func(context.Context) string
|
||||
federateLogoutCache cache.Cache[federatedlogout.Index, string, *federatedlogout.FederatedLogout]
|
||||
@@ -91,14 +88,14 @@ type Provider struct {
|
||||
// IDTokenHintVerifier configures a Verifier and supported signing algorithms based on the Web Key feature in the context.
|
||||
func (o *Provider) IDTokenHintVerifier(ctx context.Context) *op.IDTokenHintVerifier {
|
||||
return op.NewIDTokenHintVerifier(op.IssuerFromContext(ctx), o.idTokenHintKeySet, op.WithSupportedIDTokenHintSigningAlgorithms(
|
||||
supportedSigningAlgs(ctx)...,
|
||||
supportedSigningAlgs()...,
|
||||
))
|
||||
}
|
||||
|
||||
// AccessTokenVerifier configures a Verifier and supported signing algorithms based on the Web Key feature in the context.
|
||||
func (o *Provider) AccessTokenVerifier(ctx context.Context) *op.AccessTokenVerifier {
|
||||
return op.NewAccessTokenVerifier(op.IssuerFromContext(ctx), o.accessTokenKeySet, op.WithSupportedAccessTokenSigningAlgorithms(
|
||||
supportedSigningAlgs(ctx)...,
|
||||
supportedSigningAlgs()...,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -113,7 +110,6 @@ func NewServer(
|
||||
encryptionAlg crypto.EncryptionAlgorithm,
|
||||
cryptoKey []byte,
|
||||
es *eventstore.Eventstore,
|
||||
projections *database.DB,
|
||||
userAgentCookie, instanceHandler func(http.Handler) http.Handler,
|
||||
accessHandler *middleware.AccessInterceptor,
|
||||
fallbackLogger *slog.Logger,
|
||||
@@ -124,7 +120,7 @@ func NewServer(
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "OIDC-EGrqd", "cannot create op config: %w")
|
||||
}
|
||||
storage := newStorage(config, command, query, repo, encryptionAlg, es, projections, ContextToIssuer, federatedLogoutCache)
|
||||
storage := newStorage(config, command, query, repo, encryptionAlg, es, ContextToIssuer, federatedLogoutCache)
|
||||
keyCache := newPublicKeyCache(ctx, config.PublicKeyCacheMaxAge, queryKeyFunc(query))
|
||||
accessTokenKeySet := newOidcKeySet(keyCache, withKeyExpiryCheck(true))
|
||||
idTokenHintKeySet := newOidcKeySet(keyCache)
|
||||
@@ -236,7 +232,6 @@ func newStorage(
|
||||
repo repository.Repository,
|
||||
encAlg crypto.EncryptionAlgorithm,
|
||||
es *eventstore.Eventstore,
|
||||
db *database.DB,
|
||||
contextToIssuer func(context.Context) string,
|
||||
federateLogoutCache cache.Cache[federatedlogout.Index, string, *federatedlogout.FederatedLogout],
|
||||
) *OPStorage {
|
||||
@@ -253,7 +248,6 @@ func newStorage(
|
||||
defaultRefreshTokenIdleExpiration: config.DefaultRefreshTokenIdleExpiration,
|
||||
defaultRefreshTokenExpiration: config.DefaultRefreshTokenExpiration,
|
||||
encAlg: encAlg,
|
||||
locker: crdb.NewLocker(db.DB, locksTable, signingKey),
|
||||
assetAPIPrefix: assets.AssetAPI(),
|
||||
contextToIssuer: contextToIssuer,
|
||||
federateLogoutCache: federateLogoutCache,
|
||||
|
@@ -188,7 +188,7 @@ func (s *Server) createDiscoveryConfig(ctx context.Context, supportedUILocales o
|
||||
},
|
||||
GrantTypesSupported: op.GrantTypes(s.Provider()),
|
||||
SubjectTypesSupported: op.SubjectTypes(s.Provider()),
|
||||
IDTokenSigningAlgValuesSupported: supportedSigningAlgs(ctx),
|
||||
IDTokenSigningAlgValuesSupported: supportedSigningAlgs(),
|
||||
RequestObjectSigningAlgValuesSupported: op.RequestObjectSigAlgorithms(s.Provider()),
|
||||
TokenEndpointAuthMethodsSupported: op.AuthMethodsTokenEndpoint(s.Provider()),
|
||||
TokenEndpointAuthSigningAlgValuesSupported: op.TokenSigAlgorithms(s.Provider()),
|
||||
|
@@ -8,9 +8,6 @@ import (
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
)
|
||||
|
||||
func TestServer_createDiscoveryConfig(t *testing.T) {
|
||||
@@ -63,92 +60,6 @@ func TestServer_createDiscoveryConfig(t *testing.T) {
|
||||
ctx: op.ContextWithIssuer(context.Background(), "https://issuer.com"),
|
||||
supportedUILocales: []language.Tag{language.English, language.German},
|
||||
},
|
||||
&oidc.DiscoveryConfiguration{
|
||||
Issuer: "https://issuer.com",
|
||||
AuthorizationEndpoint: "https://issuer.com/auth",
|
||||
TokenEndpoint: "https://issuer.com/token",
|
||||
IntrospectionEndpoint: "https://issuer.com/introspect",
|
||||
UserinfoEndpoint: "https://issuer.com/userinfo",
|
||||
RevocationEndpoint: "https://issuer.com/revoke",
|
||||
EndSessionEndpoint: "https://issuer.com/logout",
|
||||
DeviceAuthorizationEndpoint: "https://issuer.com/device",
|
||||
CheckSessionIframe: "",
|
||||
JwksURI: "https://issuer.com/keys",
|
||||
RegistrationEndpoint: "",
|
||||
ScopesSupported: []string{oidc.ScopeOpenID, oidc.ScopeProfile, oidc.ScopeEmail, oidc.ScopePhone, oidc.ScopeAddress, oidc.ScopeOfflineAccess},
|
||||
ResponseTypesSupported: []string{string(oidc.ResponseTypeCode), string(oidc.ResponseTypeIDTokenOnly), string(oidc.ResponseTypeIDToken)},
|
||||
ResponseModesSupported: []string{string(oidc.ResponseModeQuery), string(oidc.ResponseModeFragment), string(oidc.ResponseModeFormPost)},
|
||||
GrantTypesSupported: []oidc.GrantType{oidc.GrantTypeCode, oidc.GrantTypeImplicit, oidc.GrantTypeRefreshToken, oidc.GrantTypeBearer},
|
||||
ACRValuesSupported: nil,
|
||||
SubjectTypesSupported: []string{"public"},
|
||||
IDTokenSigningAlgValuesSupported: []string{"RS256"},
|
||||
IDTokenEncryptionAlgValuesSupported: nil,
|
||||
IDTokenEncryptionEncValuesSupported: nil,
|
||||
UserinfoSigningAlgValuesSupported: nil,
|
||||
UserinfoEncryptionAlgValuesSupported: nil,
|
||||
UserinfoEncryptionEncValuesSupported: nil,
|
||||
RequestObjectSigningAlgValuesSupported: []string{"RS256"},
|
||||
RequestObjectEncryptionAlgValuesSupported: nil,
|
||||
RequestObjectEncryptionEncValuesSupported: nil,
|
||||
TokenEndpointAuthMethodsSupported: []oidc.AuthMethod{oidc.AuthMethodNone, oidc.AuthMethodBasic, oidc.AuthMethodPost, oidc.AuthMethodPrivateKeyJWT},
|
||||
TokenEndpointAuthSigningAlgValuesSupported: []string{"RS256"},
|
||||
RevocationEndpointAuthMethodsSupported: []oidc.AuthMethod{oidc.AuthMethodNone, oidc.AuthMethodBasic, oidc.AuthMethodPost, oidc.AuthMethodPrivateKeyJWT},
|
||||
RevocationEndpointAuthSigningAlgValuesSupported: []string{"RS256"},
|
||||
IntrospectionEndpointAuthMethodsSupported: []oidc.AuthMethod{oidc.AuthMethodBasic, oidc.AuthMethodPrivateKeyJWT},
|
||||
IntrospectionEndpointAuthSigningAlgValuesSupported: []string{"RS256"},
|
||||
DisplayValuesSupported: nil,
|
||||
ClaimTypesSupported: nil,
|
||||
ClaimsSupported: []string{"sub", "aud", "exp", "iat", "iss", "auth_time", "nonce", "acr", "amr", "c_hash", "at_hash", "act", "scopes", "client_id", "azp", "preferred_username", "name", "family_name", "given_name", "locale", "email", "email_verified", "phone_number", "phone_number_verified"},
|
||||
ClaimsParameterSupported: false,
|
||||
CodeChallengeMethodsSupported: []oidc.CodeChallengeMethod{"S256"},
|
||||
ServiceDocumentation: "",
|
||||
ClaimsLocalesSupported: nil,
|
||||
UILocalesSupported: []language.Tag{language.English, language.German},
|
||||
RequestParameterSupported: true,
|
||||
RequestURIParameterSupported: false,
|
||||
RequireRequestURIRegistration: false,
|
||||
OPPolicyURI: "",
|
||||
OPTermsOfServiceURI: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
"web keys feature enabled",
|
||||
fields{
|
||||
LegacyServer: op.NewLegacyServer(
|
||||
func() *op.Provider {
|
||||
//nolint:staticcheck
|
||||
provider, _ := op.NewForwardedOpenIDProvider("path",
|
||||
&op.Config{
|
||||
CodeMethodS256: true,
|
||||
AuthMethodPost: true,
|
||||
AuthMethodPrivateKeyJWT: true,
|
||||
GrantTypeRefreshToken: true,
|
||||
RequestObjectSupported: true,
|
||||
},
|
||||
nil,
|
||||
)
|
||||
return provider
|
||||
}(),
|
||||
op.Endpoints{
|
||||
Authorization: op.NewEndpoint("auth"),
|
||||
Token: op.NewEndpoint("token"),
|
||||
Introspection: op.NewEndpoint("introspect"),
|
||||
Userinfo: op.NewEndpoint("userinfo"),
|
||||
Revocation: op.NewEndpoint("revoke"),
|
||||
EndSession: op.NewEndpoint("logout"),
|
||||
JwksURI: op.NewEndpoint("keys"),
|
||||
DeviceAuthorization: op.NewEndpoint("device"),
|
||||
},
|
||||
),
|
||||
signingKeyAlgorithm: "RS256",
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithFeatures(
|
||||
op.ContextWithIssuer(context.Background(), "https://issuer.com"),
|
||||
feature.Features{WebKey: true},
|
||||
),
|
||||
supportedUILocales: []language.Tag{language.English, language.German},
|
||||
},
|
||||
&oidc.DiscoveryConfiguration{
|
||||
Issuer: "https://issuer.com",
|
||||
AuthorizationEndpoint: "https://issuer.com/auth",
|
||||
|
@@ -12,7 +12,6 @@ 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"
|
||||
@@ -64,14 +63,13 @@ func (s *Server) accessTokenResponseFromSession(ctx context.Context, client op.C
|
||||
type SignerFunc func(ctx context.Context) (jose.Signer, jose.SignatureAlgorithm, error)
|
||||
|
||||
func (s *Server) getSignerOnce() SignerFunc {
|
||||
return GetSignerOnce(s.query.GetActiveSigningWebKey, s.Provider().Storage().SigningKey)
|
||||
return GetSignerOnce(s.query.GetActiveSigningWebKey)
|
||||
}
|
||||
|
||||
// GetSignerOnce returns a function which retrieves the instance's signer from the database once.
|
||||
// Repeated calls of the returned function return the same results.
|
||||
func GetSignerOnce(
|
||||
getActiveSigningWebKey func(ctx context.Context) (*jose.JSONWebKey, error),
|
||||
getSigningKey func(ctx context.Context) (op.SigningKey, error),
|
||||
) SignerFunc {
|
||||
var (
|
||||
once sync.Once
|
||||
@@ -84,23 +82,12 @@ func GetSignerOnce(
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
if authz.GetFeatures(ctx).WebKey {
|
||||
var webKey *jose.JSONWebKey
|
||||
webKey, err = getActiveSigningWebKey(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signer, signAlg, err = signerFromWebKey(webKey)
|
||||
return
|
||||
}
|
||||
|
||||
var signingKey op.SigningKey
|
||||
signingKey, err = getSigningKey(ctx)
|
||||
var webKey *jose.JSONWebKey
|
||||
webKey, err = getActiveSigningWebKey(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
signAlg = signingKey.SignatureAlgorithm()
|
||||
signer, err = op.SignerFromKey(signingKey)
|
||||
signer, signAlg, err = signerFromWebKey(webKey)
|
||||
})
|
||||
return signer, signAlg, err
|
||||
}
|
||||
|
@@ -14,13 +14,14 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/repository/keypair"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
const (
|
||||
locksTable = "projections.locks"
|
||||
locksTable = projection.LocksTable
|
||||
signingKey = "signing_key"
|
||||
samlUser = "SAML"
|
||||
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -329,18 +328,10 @@ type openIDKeySet struct {
|
||||
// VerifySignature implements the oidc.KeySet interface
|
||||
// providing an implementation for the keys retrieved directly from Queries
|
||||
func (o *openIDKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSignature) (payload []byte, err error) {
|
||||
keySet := new(jose.JSONWebKeySet)
|
||||
if authz.GetFeatures(ctx).WebKey {
|
||||
keySet, err = o.Queries.GetWebKeySet(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
legacyKeySet, err := o.Queries.ActivePublicKeys(ctx, time.Now())
|
||||
keySet, err := o.Queries.GetWebKeySet(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error fetching keys: %w", err)
|
||||
return nil, err
|
||||
}
|
||||
appendPublicKeysToWebKeySet(keySet, legacyKeySet)
|
||||
keyID, alg := oidc.GetKeyIDAndAlg(jws)
|
||||
key, err := oidc.FindMatchingKey(keyID, oidc.KeyUseSignature, alg, keySet.Keys...)
|
||||
if err != nil {
|
||||
@@ -348,19 +339,3 @@ func (o *openIDKeySet) VerifySignature(ctx context.Context, jws *jose.JSONWebSig
|
||||
}
|
||||
return jws.Verify(&key)
|
||||
}
|
||||
|
||||
func appendPublicKeysToWebKeySet(keyset *jose.JSONWebKeySet, pubkeys *query.PublicKeys) {
|
||||
if pubkeys == nil || len(pubkeys.Keys) == 0 {
|
||||
return
|
||||
}
|
||||
keyset.Keys = slices.Grow(keyset.Keys, len(pubkeys.Keys))
|
||||
|
||||
for _, key := range pubkeys.Keys {
|
||||
keyset.Keys = append(keyset.Keys, jose.JSONWebKey{
|
||||
Key: key.Key(),
|
||||
KeyID: key.ID(),
|
||||
Algorithm: key.Algorithm(),
|
||||
Use: key.Use().String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -3,11 +3,8 @@ package command
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/feature"
|
||||
@@ -21,7 +18,6 @@ type InstanceFeatures struct {
|
||||
UserSchema *bool
|
||||
TokenExchange *bool
|
||||
ImprovedPerformance []feature.ImprovedPerformanceType
|
||||
WebKey *bool
|
||||
DebugOIDCParentError *bool
|
||||
OIDCSingleV1SessionTermination *bool
|
||||
DisableUserTokenEvent *bool
|
||||
@@ -38,7 +34,6 @@ func (m *InstanceFeatures) isEmpty() bool {
|
||||
m.TokenExchange == nil &&
|
||||
// nil check to allow unset improvements
|
||||
m.ImprovedPerformance == nil &&
|
||||
m.WebKey == nil &&
|
||||
m.DebugOIDCParentError == nil &&
|
||||
m.OIDCSingleV1SessionTermination == nil &&
|
||||
m.DisableUserTokenEvent == nil &&
|
||||
@@ -55,9 +50,6 @@ func (c *Commands) SetInstanceFeatures(ctx context.Context, f *InstanceFeatures)
|
||||
if err := c.eventstore.FilterToQueryReducer(ctx, wm); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := c.setupWebKeyFeature(ctx, wm, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commands := wm.setCommands(ctx, f)
|
||||
if len(commands) == 0 {
|
||||
return writeModelToObjectDetails(wm.WriteModel), nil
|
||||
@@ -78,21 +70,6 @@ func prepareSetFeatures(instanceID string, f *InstanceFeatures) preparation.Vali
|
||||
}
|
||||
}
|
||||
|
||||
// setupWebKeyFeature generates the initial web keys for the instance,
|
||||
// if the feature is enabled in the request and the feature wasn't enabled already in the writeModel.
|
||||
// [Commands.GenerateInitialWebKeys] checks if keys already exist and does nothing if that's the case.
|
||||
// The default config of a RSA key with 2048 and the SHA256 hasher is assumed.
|
||||
// Users can customize this after using the webkey/v3 API.
|
||||
func (c *Commands) setupWebKeyFeature(ctx context.Context, wm *InstanceFeaturesWriteModel, f *InstanceFeatures) error {
|
||||
if !gu.Value(f.WebKey) || gu.Value(wm.WebKey) {
|
||||
return nil
|
||||
}
|
||||
return c.GenerateInitialWebKeys(ctx, &crypto.WebKeyRSAConfig{
|
||||
Bits: crypto.RSABits2048,
|
||||
Hasher: crypto.RSAHasherSHA256,
|
||||
})
|
||||
}
|
||||
|
||||
func (c *Commands) ResetInstanceFeatures(ctx context.Context) (*domain.ObjectDetails, error) {
|
||||
instanceID := authz.GetInstance(ctx).InstanceID()
|
||||
wm := NewInstanceFeaturesWriteModel(instanceID)
|
||||
|
@@ -71,7 +71,6 @@ func (m *InstanceFeaturesWriteModel) Query() *eventstore.SearchQueryBuilder {
|
||||
feature_v2.InstanceUserSchemaEventType,
|
||||
feature_v2.InstanceTokenExchangeEventType,
|
||||
feature_v2.InstanceImprovedPerformanceEventType,
|
||||
feature_v2.InstanceWebKeyEventType,
|
||||
feature_v2.InstanceDebugOIDCParentErrorEventType,
|
||||
feature_v2.InstanceOIDCSingleV1SessionTerminationEventType,
|
||||
feature_v2.InstanceDisableUserTokenEvent,
|
||||
@@ -106,9 +105,6 @@ func reduceInstanceFeature(features *InstanceFeatures, key feature.Key, value an
|
||||
case feature.KeyImprovedPerformance:
|
||||
v := value.([]feature.ImprovedPerformanceType)
|
||||
features.ImprovedPerformance = v
|
||||
case feature.KeyWebKey:
|
||||
v := value.(bool)
|
||||
features.WebKey = &v
|
||||
case feature.KeyDebugOIDCParentError:
|
||||
v := value.(bool)
|
||||
features.DebugOIDCParentError = &v
|
||||
@@ -140,7 +136,6 @@ func (wm *InstanceFeaturesWriteModel) setCommands(ctx context.Context, f *Instan
|
||||
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.TokenExchange, f.TokenExchange, feature_v2.InstanceTokenExchangeEventType)
|
||||
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.UserSchema, f.UserSchema, feature_v2.InstanceUserSchemaEventType)
|
||||
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)
|
||||
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.OIDCSingleV1SessionTermination, f.OIDCSingleV1SessionTermination, feature_v2.InstanceOIDCSingleV1SessionTerminationEventType)
|
||||
cmds = appendFeatureUpdate(ctx, cmds, aggregate, wm.DisableUserTokenEvent, f.DisableUserTokenEvent, feature_v2.InstanceDisableUserTokenEvent)
|
||||
|
@@ -13,31 +13,6 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/repository/keypair"
|
||||
)
|
||||
|
||||
func (c *Commands) GenerateSigningKeyPair(ctx context.Context, algorithm string) error {
|
||||
privateCrypto, publicCrypto, err := crypto.GenerateEncryptedKeyPair(c.keySize, c.keyAlgorithm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
keyID, err := c.idGenerator.Next()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
privateKeyExp := time.Now().UTC().Add(c.privateKeyLifetime)
|
||||
publicKeyExp := time.Now().UTC().Add(c.publicKeyLifetime)
|
||||
|
||||
keyPairWriteModel := NewKeyPairWriteModel(keyID, authz.GetInstance(ctx).InstanceID())
|
||||
keyAgg := KeyPairAggregateFromWriteModel(&keyPairWriteModel.WriteModel)
|
||||
_, err = c.eventstore.Push(ctx, keypair.NewAddedEvent(
|
||||
ctx,
|
||||
keyAgg,
|
||||
crypto.KeyUsageSigning,
|
||||
algorithm,
|
||||
privateCrypto, publicCrypto,
|
||||
privateKeyExp, publicKeyExp))
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *Commands) GenerateSAMLCACertificate(ctx context.Context, algorithm string) error {
|
||||
now := time.Now().UTC()
|
||||
after := now.Add(c.certificateLifetime)
|
||||
|
@@ -21,14 +21,6 @@ func GenerateKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
return privkey, &privkey.PublicKey, nil
|
||||
}
|
||||
|
||||
func GenerateEncryptedKeyPair(bits int, alg EncryptionAlgorithm) (*CryptoValue, *CryptoValue, error) {
|
||||
privateKey, publicKey, err := GenerateKeyPair(bits)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return EncryptKeys(privateKey, publicKey, alg)
|
||||
}
|
||||
|
||||
type CertificateInformations struct {
|
||||
SerialNumber *big.Int
|
||||
Organisation []string
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
type Key int
|
||||
|
||||
const (
|
||||
// Reserved: 3, 6
|
||||
// Reserved: 3, 6, 8
|
||||
|
||||
KeyUnspecified Key = 0
|
||||
KeyLoginDefaultOrg Key = 1
|
||||
@@ -17,7 +17,6 @@ const (
|
||||
KeyUserSchema Key = 4
|
||||
KeyTokenExchange Key = 5
|
||||
KeyImprovedPerformance Key = 7
|
||||
KeyWebKey Key = 8
|
||||
KeyDebugOIDCParentError Key = 9
|
||||
KeyOIDCSingleV1SessionTermination Key = 10
|
||||
KeyDisableUserTokenEvent Key = 11
|
||||
@@ -46,7 +45,6 @@ type Features struct {
|
||||
UserSchema bool `json:"user_schema,omitempty"`
|
||||
TokenExchange bool `json:"token_exchange,omitempty"`
|
||||
ImprovedPerformance []ImprovedPerformanceType `json:"improved_performance,omitempty"`
|
||||
WebKey bool `json:"web_key,omitempty"`
|
||||
DebugOIDCParentError bool `json:"debug_oidc_parent_error,omitempty"`
|
||||
OIDCSingleV1SessionTermination bool `json:"oidc_single_v1_session_termination,omitempty"`
|
||||
DisableUserTokenEvent bool `json:"disable_user_token_event,omitempty"`
|
||||
|
@@ -12,14 +12,17 @@ const (
|
||||
_KeyLowerName_0 = "unspecifiedlogin_default_orgtrigger_introspection_projections"
|
||||
_KeyName_1 = "user_schematoken_exchange"
|
||||
_KeyLowerName_1 = "user_schematoken_exchange"
|
||||
_KeyName_2 = "improved_performanceweb_keydebug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
|
||||
_KeyLowerName_2 = "improved_performanceweb_keydebug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
|
||||
_KeyName_2 = "improved_performance"
|
||||
_KeyLowerName_2 = "improved_performance"
|
||||
_KeyName_3 = "debug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
|
||||
_KeyLowerName_3 = "debug_oidc_parent_erroroidc_single_v1_session_terminationdisable_user_token_eventenable_back_channel_logoutlogin_v2permission_check_v2console_use_v2_user_api"
|
||||
)
|
||||
|
||||
var (
|
||||
_KeyIndex_0 = [...]uint8{0, 11, 28, 61}
|
||||
_KeyIndex_1 = [...]uint8{0, 11, 25}
|
||||
_KeyIndex_2 = [...]uint8{0, 20, 27, 50, 84, 108, 134, 142, 161, 184}
|
||||
_KeyIndex_2 = [...]uint8{0, 20}
|
||||
_KeyIndex_3 = [...]uint8{0, 23, 57, 81, 107, 115, 134, 157}
|
||||
)
|
||||
|
||||
func (i Key) String() string {
|
||||
@@ -29,9 +32,11 @@ func (i Key) String() string {
|
||||
case 4 <= i && i <= 5:
|
||||
i -= 4
|
||||
return _KeyName_1[_KeyIndex_1[i]:_KeyIndex_1[i+1]]
|
||||
case 7 <= i && i <= 15:
|
||||
i -= 7
|
||||
return _KeyName_2[_KeyIndex_2[i]:_KeyIndex_2[i+1]]
|
||||
case i == 7:
|
||||
return _KeyName_2
|
||||
case 9 <= i && i <= 15:
|
||||
i -= 9
|
||||
return _KeyName_3[_KeyIndex_3[i]:_KeyIndex_3[i+1]]
|
||||
default:
|
||||
return fmt.Sprintf("Key(%d)", i)
|
||||
}
|
||||
@@ -47,7 +52,6 @@ func _KeyNoOp() {
|
||||
_ = x[KeyUserSchema-(4)]
|
||||
_ = x[KeyTokenExchange-(5)]
|
||||
_ = x[KeyImprovedPerformance-(7)]
|
||||
_ = x[KeyWebKey-(8)]
|
||||
_ = x[KeyDebugOIDCParentError-(9)]
|
||||
_ = x[KeyOIDCSingleV1SessionTermination-(10)]
|
||||
_ = x[KeyDisableUserTokenEvent-(11)]
|
||||
@@ -57,7 +61,7 @@ func _KeyNoOp() {
|
||||
_ = x[KeyConsoleUseV2UserApi-(15)]
|
||||
}
|
||||
|
||||
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyUserSchema, KeyTokenExchange, KeyImprovedPerformance, KeyWebKey, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyDisableUserTokenEvent, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyConsoleUseV2UserApi}
|
||||
var _KeyValues = []Key{KeyUnspecified, KeyLoginDefaultOrg, KeyTriggerIntrospectionProjections, KeyUserSchema, KeyTokenExchange, KeyImprovedPerformance, KeyDebugOIDCParentError, KeyOIDCSingleV1SessionTermination, KeyDisableUserTokenEvent, KeyEnableBackChannelLogout, KeyLoginV2, KeyPermissionCheckV2, KeyConsoleUseV2UserApi}
|
||||
|
||||
var _KeyNameToValueMap = map[string]Key{
|
||||
_KeyName_0[0:11]: KeyUnspecified,
|
||||
@@ -72,22 +76,20 @@ var _KeyNameToValueMap = map[string]Key{
|
||||
_KeyLowerName_1[11:25]: KeyTokenExchange,
|
||||
_KeyName_2[0:20]: KeyImprovedPerformance,
|
||||
_KeyLowerName_2[0:20]: KeyImprovedPerformance,
|
||||
_KeyName_2[20:27]: KeyWebKey,
|
||||
_KeyLowerName_2[20:27]: KeyWebKey,
|
||||
_KeyName_2[27:50]: KeyDebugOIDCParentError,
|
||||
_KeyLowerName_2[27:50]: KeyDebugOIDCParentError,
|
||||
_KeyName_2[50:84]: KeyOIDCSingleV1SessionTermination,
|
||||
_KeyLowerName_2[50:84]: KeyOIDCSingleV1SessionTermination,
|
||||
_KeyName_2[84:108]: KeyDisableUserTokenEvent,
|
||||
_KeyLowerName_2[84:108]: KeyDisableUserTokenEvent,
|
||||
_KeyName_2[108:134]: KeyEnableBackChannelLogout,
|
||||
_KeyLowerName_2[108:134]: KeyEnableBackChannelLogout,
|
||||
_KeyName_2[134:142]: KeyLoginV2,
|
||||
_KeyLowerName_2[134:142]: KeyLoginV2,
|
||||
_KeyName_2[142:161]: KeyPermissionCheckV2,
|
||||
_KeyLowerName_2[142:161]: KeyPermissionCheckV2,
|
||||
_KeyName_2[161:184]: KeyConsoleUseV2UserApi,
|
||||
_KeyLowerName_2[161:184]: KeyConsoleUseV2UserApi,
|
||||
_KeyName_3[0:23]: KeyDebugOIDCParentError,
|
||||
_KeyLowerName_3[0:23]: KeyDebugOIDCParentError,
|
||||
_KeyName_3[23:57]: KeyOIDCSingleV1SessionTermination,
|
||||
_KeyLowerName_3[23:57]: KeyOIDCSingleV1SessionTermination,
|
||||
_KeyName_3[57:81]: KeyDisableUserTokenEvent,
|
||||
_KeyLowerName_3[57:81]: KeyDisableUserTokenEvent,
|
||||
_KeyName_3[81:107]: KeyEnableBackChannelLogout,
|
||||
_KeyLowerName_3[81:107]: KeyEnableBackChannelLogout,
|
||||
_KeyName_3[107:115]: KeyLoginV2,
|
||||
_KeyLowerName_3[107:115]: KeyLoginV2,
|
||||
_KeyName_3[115:134]: KeyPermissionCheckV2,
|
||||
_KeyLowerName_3[115:134]: KeyPermissionCheckV2,
|
||||
_KeyName_3[134:157]: KeyConsoleUseV2UserApi,
|
||||
_KeyLowerName_3[134:157]: KeyConsoleUseV2UserApi,
|
||||
}
|
||||
|
||||
var _KeyNames = []string{
|
||||
@@ -97,14 +99,13 @@ var _KeyNames = []string{
|
||||
_KeyName_1[0:11],
|
||||
_KeyName_1[11:25],
|
||||
_KeyName_2[0:20],
|
||||
_KeyName_2[20:27],
|
||||
_KeyName_2[27:50],
|
||||
_KeyName_2[50:84],
|
||||
_KeyName_2[84:108],
|
||||
_KeyName_2[108:134],
|
||||
_KeyName_2[134:142],
|
||||
_KeyName_2[142:161],
|
||||
_KeyName_2[161:184],
|
||||
_KeyName_3[0:23],
|
||||
_KeyName_3[23:57],
|
||||
_KeyName_3[57:81],
|
||||
_KeyName_3[81:107],
|
||||
_KeyName_3[107:115],
|
||||
_KeyName_3[115:134],
|
||||
_KeyName_3[134:157],
|
||||
}
|
||||
|
||||
// KeyString retrieves an enum value from the enum constants string name.
|
||||
|
@@ -7,10 +7,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
"github.com/zitadel/oidc/v3/pkg/crypto"
|
||||
"github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
"github.com/zitadel/oidc/v3/pkg/op"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
http_utils "github.com/zitadel/zitadel/internal/api/http"
|
||||
@@ -149,7 +147,7 @@ func (u *backChannelLogoutNotifier) terminateSession(ctx context.Context, id str
|
||||
return err
|
||||
}
|
||||
|
||||
getSigner := zoidc.GetSignerOnce(u.queries.GetActiveSigningWebKey, u.signingKey)
|
||||
getSigner := zoidc.GetSignerOnce(u.queries.GetActiveSigningWebKey)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(len(sessions.sessions))
|
||||
@@ -172,20 +170,6 @@ func (u *backChannelLogoutNotifier) terminateSession(ctx context.Context, id str
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
|
||||
func (u *backChannelLogoutNotifier) signingKey(ctx context.Context) (op.SigningKey, error) {
|
||||
keys, err := u.queries.ActivePrivateSigningKey(ctx, time.Now())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(keys.Keys) == 0 {
|
||||
logging.WithFields("instanceID", authz.GetInstance(ctx).InstanceID()).
|
||||
Info("There's no active signing key and automatic rotation is not supported for back channel logout." +
|
||||
"Please enable the webkey management feature on your instance")
|
||||
return nil, zerrors.ThrowPreconditionFailed(nil, "HANDL-DF3nf", "no active signing key")
|
||||
}
|
||||
return zoidc.PrivateKeyToSigningKey(zoidc.SelectSigningKey(keys.Keys), u.keyEncryptionAlg)
|
||||
}
|
||||
|
||||
func (u *backChannelLogoutNotifier) sendLogoutToken(ctx context.Context, oidcSession *backChannelLogoutOIDCSessions, e eventstore.Event, getSigner zoidc.SignerFunc) error {
|
||||
token, err := u.logoutToken(ctx, oidcSession, getSigner)
|
||||
if err != nil {
|
||||
|
@@ -23,6 +23,7 @@ import (
|
||||
type MockCommands struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockCommandsMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockCommandsMockRecorder is the mock recorder for MockCommands.
|
||||
@@ -43,197 +44,197 @@ func (m *MockCommands) EXPECT() *MockCommandsMockRecorder {
|
||||
}
|
||||
|
||||
// HumanEmailVerificationCodeSent mocks base method.
|
||||
func (m *MockCommands) HumanEmailVerificationCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
func (m *MockCommands) HumanEmailVerificationCodeSent(ctx context.Context, orgID, userID string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanEmailVerificationCodeSent", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "HumanEmailVerificationCodeSent", ctx, orgID, userID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanEmailVerificationCodeSent indicates an expected call of HumanEmailVerificationCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanEmailVerificationCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) HumanEmailVerificationCodeSent(ctx, orgID, userID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanEmailVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanEmailVerificationCodeSent), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanEmailVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanEmailVerificationCodeSent), ctx, orgID, userID)
|
||||
}
|
||||
|
||||
// HumanInitCodeSent mocks base method.
|
||||
func (m *MockCommands) HumanInitCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
func (m *MockCommands) HumanInitCodeSent(ctx context.Context, orgID, userID string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanInitCodeSent", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "HumanInitCodeSent", ctx, orgID, userID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanInitCodeSent indicates an expected call of HumanInitCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanInitCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) HumanInitCodeSent(ctx, orgID, userID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanInitCodeSent), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanInitCodeSent), ctx, orgID, userID)
|
||||
}
|
||||
|
||||
// HumanOTPEmailCodeSent mocks base method.
|
||||
func (m *MockCommands) HumanOTPEmailCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
func (m *MockCommands) HumanOTPEmailCodeSent(ctx context.Context, userID, resourceOwner string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanOTPEmailCodeSent", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "HumanOTPEmailCodeSent", ctx, userID, resourceOwner)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanOTPEmailCodeSent indicates an expected call of HumanOTPEmailCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPEmailCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPEmailCodeSent(ctx, userID, resourceOwner any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPEmailCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPEmailCodeSent), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPEmailCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPEmailCodeSent), ctx, userID, resourceOwner)
|
||||
}
|
||||
|
||||
// HumanOTPSMSCodeSent mocks base method.
|
||||
func (m *MockCommands) HumanOTPSMSCodeSent(arg0 context.Context, arg1, arg2 string, arg3 *senders.CodeGeneratorInfo) error {
|
||||
func (m *MockCommands) HumanOTPSMSCodeSent(ctx context.Context, userID, resourceOwner string, generatorInfo *senders.CodeGeneratorInfo) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanOTPSMSCodeSent", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "HumanOTPSMSCodeSent", ctx, userID, resourceOwner, generatorInfo)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanOTPSMSCodeSent indicates an expected call of HumanOTPSMSCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPSMSCodeSent(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) HumanOTPSMSCodeSent(ctx, userID, resourceOwner, generatorInfo any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPSMSCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPSMSCodeSent), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanOTPSMSCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanOTPSMSCodeSent), ctx, userID, resourceOwner, generatorInfo)
|
||||
}
|
||||
|
||||
// HumanPasswordlessInitCodeSent mocks base method.
|
||||
func (m *MockCommands) HumanPasswordlessInitCodeSent(arg0 context.Context, arg1, arg2, arg3 string) error {
|
||||
func (m *MockCommands) HumanPasswordlessInitCodeSent(ctx context.Context, userID, resourceOwner, codeID string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanPasswordlessInitCodeSent", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "HumanPasswordlessInitCodeSent", ctx, userID, resourceOwner, codeID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanPasswordlessInitCodeSent indicates an expected call of HumanPasswordlessInitCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanPasswordlessInitCodeSent(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) HumanPasswordlessInitCodeSent(ctx, userID, resourceOwner, codeID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPasswordlessInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPasswordlessInitCodeSent), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPasswordlessInitCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPasswordlessInitCodeSent), ctx, userID, resourceOwner, codeID)
|
||||
}
|
||||
|
||||
// HumanPhoneVerificationCodeSent mocks base method.
|
||||
func (m *MockCommands) HumanPhoneVerificationCodeSent(arg0 context.Context, arg1, arg2 string, arg3 *senders.CodeGeneratorInfo) error {
|
||||
func (m *MockCommands) HumanPhoneVerificationCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "HumanPhoneVerificationCodeSent", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "HumanPhoneVerificationCodeSent", ctx, orgID, userID, generatorInfo)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// HumanPhoneVerificationCodeSent indicates an expected call of HumanPhoneVerificationCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) HumanPhoneVerificationCodeSent(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) HumanPhoneVerificationCodeSent(ctx, orgID, userID, generatorInfo any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPhoneVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPhoneVerificationCodeSent), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HumanPhoneVerificationCodeSent", reflect.TypeOf((*MockCommands)(nil).HumanPhoneVerificationCodeSent), ctx, orgID, userID, generatorInfo)
|
||||
}
|
||||
|
||||
// InviteCodeSent mocks base method.
|
||||
func (m *MockCommands) InviteCodeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
func (m *MockCommands) InviteCodeSent(ctx context.Context, orgID, userID string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InviteCodeSent", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "InviteCodeSent", ctx, orgID, userID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InviteCodeSent indicates an expected call of InviteCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) InviteCodeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) InviteCodeSent(ctx, orgID, userID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InviteCodeSent", reflect.TypeOf((*MockCommands)(nil).InviteCodeSent), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InviteCodeSent", reflect.TypeOf((*MockCommands)(nil).InviteCodeSent), ctx, orgID, userID)
|
||||
}
|
||||
|
||||
// MilestonePushed mocks base method.
|
||||
func (m *MockCommands) MilestonePushed(arg0 context.Context, arg1 string, arg2 milestone.Type, arg3 []string) error {
|
||||
func (m *MockCommands) MilestonePushed(ctx context.Context, instanceID string, msType milestone.Type, endpoints []string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MilestonePushed", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "MilestonePushed", ctx, instanceID, msType, endpoints)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// MilestonePushed indicates an expected call of MilestonePushed.
|
||||
func (mr *MockCommandsMockRecorder) MilestonePushed(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) MilestonePushed(ctx, instanceID, msType, endpoints any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MilestonePushed", reflect.TypeOf((*MockCommands)(nil).MilestonePushed), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MilestonePushed", reflect.TypeOf((*MockCommands)(nil).MilestonePushed), ctx, instanceID, msType, endpoints)
|
||||
}
|
||||
|
||||
// OTPEmailSent mocks base method.
|
||||
func (m *MockCommands) OTPEmailSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
func (m *MockCommands) OTPEmailSent(ctx context.Context, sessionID, resourceOwner string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "OTPEmailSent", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "OTPEmailSent", ctx, sessionID, resourceOwner)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// OTPEmailSent indicates an expected call of OTPEmailSent.
|
||||
func (mr *MockCommandsMockRecorder) OTPEmailSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) OTPEmailSent(ctx, sessionID, resourceOwner any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPEmailSent", reflect.TypeOf((*MockCommands)(nil).OTPEmailSent), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPEmailSent", reflect.TypeOf((*MockCommands)(nil).OTPEmailSent), ctx, sessionID, resourceOwner)
|
||||
}
|
||||
|
||||
// OTPSMSSent mocks base method.
|
||||
func (m *MockCommands) OTPSMSSent(arg0 context.Context, arg1, arg2 string, arg3 *senders.CodeGeneratorInfo) error {
|
||||
func (m *MockCommands) OTPSMSSent(ctx context.Context, sessionID, resourceOwner string, generatorInfo *senders.CodeGeneratorInfo) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "OTPSMSSent", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "OTPSMSSent", ctx, sessionID, resourceOwner, generatorInfo)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// OTPSMSSent indicates an expected call of OTPSMSSent.
|
||||
func (mr *MockCommandsMockRecorder) OTPSMSSent(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) OTPSMSSent(ctx, sessionID, resourceOwner, generatorInfo any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPSMSSent", reflect.TypeOf((*MockCommands)(nil).OTPSMSSent), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OTPSMSSent", reflect.TypeOf((*MockCommands)(nil).OTPSMSSent), ctx, sessionID, resourceOwner, generatorInfo)
|
||||
}
|
||||
|
||||
// PasswordChangeSent mocks base method.
|
||||
func (m *MockCommands) PasswordChangeSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
func (m *MockCommands) PasswordChangeSent(ctx context.Context, orgID, userID string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PasswordChangeSent", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "PasswordChangeSent", ctx, orgID, userID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PasswordChangeSent indicates an expected call of PasswordChangeSent.
|
||||
func (mr *MockCommandsMockRecorder) PasswordChangeSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) PasswordChangeSent(ctx, orgID, userID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordChangeSent", reflect.TypeOf((*MockCommands)(nil).PasswordChangeSent), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordChangeSent", reflect.TypeOf((*MockCommands)(nil).PasswordChangeSent), ctx, orgID, userID)
|
||||
}
|
||||
|
||||
// PasswordCodeSent mocks base method.
|
||||
func (m *MockCommands) PasswordCodeSent(arg0 context.Context, arg1, arg2 string, arg3 *senders.CodeGeneratorInfo) error {
|
||||
func (m *MockCommands) PasswordCodeSent(ctx context.Context, orgID, userID string, generatorInfo *senders.CodeGeneratorInfo) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PasswordCodeSent", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "PasswordCodeSent", ctx, orgID, userID, generatorInfo)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// PasswordCodeSent indicates an expected call of PasswordCodeSent.
|
||||
func (mr *MockCommandsMockRecorder) PasswordCodeSent(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) PasswordCodeSent(ctx, orgID, userID, generatorInfo any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordCodeSent", reflect.TypeOf((*MockCommands)(nil).PasswordCodeSent), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PasswordCodeSent", reflect.TypeOf((*MockCommands)(nil).PasswordCodeSent), ctx, orgID, userID, generatorInfo)
|
||||
}
|
||||
|
||||
// UsageNotificationSent mocks base method.
|
||||
func (m *MockCommands) UsageNotificationSent(arg0 context.Context, arg1 *quota.NotificationDueEvent) error {
|
||||
func (m *MockCommands) UsageNotificationSent(ctx context.Context, dueEvent *quota.NotificationDueEvent) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UsageNotificationSent", arg0, arg1)
|
||||
ret := m.ctrl.Call(m, "UsageNotificationSent", ctx, dueEvent)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UsageNotificationSent indicates an expected call of UsageNotificationSent.
|
||||
func (mr *MockCommandsMockRecorder) UsageNotificationSent(arg0, arg1 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) UsageNotificationSent(ctx, dueEvent any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UsageNotificationSent", reflect.TypeOf((*MockCommands)(nil).UsageNotificationSent), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UsageNotificationSent", reflect.TypeOf((*MockCommands)(nil).UsageNotificationSent), ctx, dueEvent)
|
||||
}
|
||||
|
||||
// UserDomainClaimedSent mocks base method.
|
||||
func (m *MockCommands) UserDomainClaimedSent(arg0 context.Context, arg1, arg2 string) error {
|
||||
func (m *MockCommands) UserDomainClaimedSent(ctx context.Context, orgID, userID string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UserDomainClaimedSent", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "UserDomainClaimedSent", ctx, orgID, userID)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UserDomainClaimedSent indicates an expected call of UserDomainClaimedSent.
|
||||
func (mr *MockCommandsMockRecorder) UserDomainClaimedSent(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockCommandsMockRecorder) UserDomainClaimedSent(ctx, orgID, userID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserDomainClaimedSent", reflect.TypeOf((*MockCommands)(nil).UserDomainClaimedSent), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UserDomainClaimedSent", reflect.TypeOf((*MockCommands)(nil).UserDomainClaimedSent), ctx, orgID, userID)
|
||||
}
|
||||
|
@@ -12,7 +12,6 @@ package mock
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
time "time"
|
||||
|
||||
jose "github.com/go-jose/go-jose/v4"
|
||||
authz "github.com/zitadel/zitadel/internal/api/authz"
|
||||
@@ -26,6 +25,7 @@ import (
|
||||
type MockQueries struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockQueriesMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockQueriesMockRecorder is the mock recorder for MockQueries.
|
||||
@@ -60,240 +60,225 @@ func (mr *MockQueriesMockRecorder) ActiveInstances() *gomock.Call {
|
||||
}
|
||||
|
||||
// ActiveLabelPolicyByOrg mocks base method.
|
||||
func (m *MockQueries) ActiveLabelPolicyByOrg(arg0 context.Context, arg1 string, arg2 bool) (*query.LabelPolicy, error) {
|
||||
func (m *MockQueries) ActiveLabelPolicyByOrg(ctx context.Context, orgID string, withOwnerRemoved bool) (*query.LabelPolicy, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ActiveLabelPolicyByOrg", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "ActiveLabelPolicyByOrg", ctx, orgID, withOwnerRemoved)
|
||||
ret0, _ := ret[0].(*query.LabelPolicy)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ActiveLabelPolicyByOrg indicates an expected call of ActiveLabelPolicyByOrg.
|
||||
func (mr *MockQueriesMockRecorder) ActiveLabelPolicyByOrg(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) ActiveLabelPolicyByOrg(ctx, orgID, withOwnerRemoved any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActiveLabelPolicyByOrg", reflect.TypeOf((*MockQueries)(nil).ActiveLabelPolicyByOrg), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ActivePrivateSigningKey mocks base method.
|
||||
func (m *MockQueries) ActivePrivateSigningKey(arg0 context.Context, arg1 time.Time) (*query.PrivateKeys, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ActivePrivateSigningKey", arg0, arg1)
|
||||
ret0, _ := ret[0].(*query.PrivateKeys)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ActivePrivateSigningKey indicates an expected call of ActivePrivateSigningKey.
|
||||
func (mr *MockQueriesMockRecorder) ActivePrivateSigningKey(arg0, arg1 any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivePrivateSigningKey", reflect.TypeOf((*MockQueries)(nil).ActivePrivateSigningKey), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActiveLabelPolicyByOrg", reflect.TypeOf((*MockQueries)(nil).ActiveLabelPolicyByOrg), ctx, orgID, withOwnerRemoved)
|
||||
}
|
||||
|
||||
// CustomTextListByTemplate mocks base method.
|
||||
func (m *MockQueries) CustomTextListByTemplate(arg0 context.Context, arg1, arg2 string, arg3 bool) (*query.CustomTexts, error) {
|
||||
func (m *MockQueries) CustomTextListByTemplate(ctx context.Context, aggregateID, template string, withOwnerRemoved bool) (*query.CustomTexts, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CustomTextListByTemplate", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "CustomTextListByTemplate", ctx, aggregateID, template, withOwnerRemoved)
|
||||
ret0, _ := ret[0].(*query.CustomTexts)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CustomTextListByTemplate indicates an expected call of CustomTextListByTemplate.
|
||||
func (mr *MockQueriesMockRecorder) CustomTextListByTemplate(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) CustomTextListByTemplate(ctx, aggregateID, template, withOwnerRemoved any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CustomTextListByTemplate", reflect.TypeOf((*MockQueries)(nil).CustomTextListByTemplate), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CustomTextListByTemplate", reflect.TypeOf((*MockQueries)(nil).CustomTextListByTemplate), ctx, aggregateID, template, withOwnerRemoved)
|
||||
}
|
||||
|
||||
// GetActiveSigningWebKey mocks base method.
|
||||
func (m *MockQueries) GetActiveSigningWebKey(arg0 context.Context) (*jose.JSONWebKey, error) {
|
||||
func (m *MockQueries) GetActiveSigningWebKey(ctx context.Context) (*jose.JSONWebKey, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetActiveSigningWebKey", arg0)
|
||||
ret := m.ctrl.Call(m, "GetActiveSigningWebKey", ctx)
|
||||
ret0, _ := ret[0].(*jose.JSONWebKey)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetActiveSigningWebKey indicates an expected call of GetActiveSigningWebKey.
|
||||
func (mr *MockQueriesMockRecorder) GetActiveSigningWebKey(arg0 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) GetActiveSigningWebKey(ctx any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveSigningWebKey", reflect.TypeOf((*MockQueries)(nil).GetActiveSigningWebKey), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetActiveSigningWebKey", reflect.TypeOf((*MockQueries)(nil).GetActiveSigningWebKey), ctx)
|
||||
}
|
||||
|
||||
// GetDefaultLanguage mocks base method.
|
||||
func (m *MockQueries) GetDefaultLanguage(arg0 context.Context) language.Tag {
|
||||
func (m *MockQueries) GetDefaultLanguage(ctx context.Context) language.Tag {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetDefaultLanguage", arg0)
|
||||
ret := m.ctrl.Call(m, "GetDefaultLanguage", ctx)
|
||||
ret0, _ := ret[0].(language.Tag)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// GetDefaultLanguage indicates an expected call of GetDefaultLanguage.
|
||||
func (mr *MockQueriesMockRecorder) GetDefaultLanguage(arg0 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) GetDefaultLanguage(ctx any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultLanguage", reflect.TypeOf((*MockQueries)(nil).GetDefaultLanguage), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDefaultLanguage", reflect.TypeOf((*MockQueries)(nil).GetDefaultLanguage), ctx)
|
||||
}
|
||||
|
||||
// GetInstanceRestrictions mocks base method.
|
||||
func (m *MockQueries) GetInstanceRestrictions(arg0 context.Context) (query.Restrictions, error) {
|
||||
func (m *MockQueries) GetInstanceRestrictions(ctx context.Context) (query.Restrictions, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetInstanceRestrictions", arg0)
|
||||
ret := m.ctrl.Call(m, "GetInstanceRestrictions", ctx)
|
||||
ret0, _ := ret[0].(query.Restrictions)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetInstanceRestrictions indicates an expected call of GetInstanceRestrictions.
|
||||
func (mr *MockQueriesMockRecorder) GetInstanceRestrictions(arg0 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) GetInstanceRestrictions(ctx any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceRestrictions", reflect.TypeOf((*MockQueries)(nil).GetInstanceRestrictions), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInstanceRestrictions", reflect.TypeOf((*MockQueries)(nil).GetInstanceRestrictions), ctx)
|
||||
}
|
||||
|
||||
// GetNotifyUserByID mocks base method.
|
||||
func (m *MockQueries) GetNotifyUserByID(arg0 context.Context, arg1 bool, arg2 string) (*query.NotifyUser, error) {
|
||||
func (m *MockQueries) GetNotifyUserByID(ctx context.Context, shouldTriggered bool, userID string) (*query.NotifyUser, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetNotifyUserByID", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "GetNotifyUserByID", ctx, shouldTriggered, userID)
|
||||
ret0, _ := ret[0].(*query.NotifyUser)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetNotifyUserByID indicates an expected call of GetNotifyUserByID.
|
||||
func (mr *MockQueriesMockRecorder) GetNotifyUserByID(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) GetNotifyUserByID(ctx, shouldTriggered, userID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNotifyUserByID", reflect.TypeOf((*MockQueries)(nil).GetNotifyUserByID), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNotifyUserByID", reflect.TypeOf((*MockQueries)(nil).GetNotifyUserByID), ctx, shouldTriggered, userID)
|
||||
}
|
||||
|
||||
// InstanceByID mocks base method.
|
||||
func (m *MockQueries) InstanceByID(arg0 context.Context, arg1 string) (authz.Instance, error) {
|
||||
func (m *MockQueries) InstanceByID(ctx context.Context, id string) (authz.Instance, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InstanceByID", arg0, arg1)
|
||||
ret := m.ctrl.Call(m, "InstanceByID", ctx, id)
|
||||
ret0, _ := ret[0].(authz.Instance)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// InstanceByID indicates an expected call of InstanceByID.
|
||||
func (mr *MockQueriesMockRecorder) InstanceByID(arg0, arg1 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) InstanceByID(ctx, id any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceByID", reflect.TypeOf((*MockQueries)(nil).InstanceByID), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceByID", reflect.TypeOf((*MockQueries)(nil).InstanceByID), ctx, id)
|
||||
}
|
||||
|
||||
// MailTemplateByOrg mocks base method.
|
||||
func (m *MockQueries) MailTemplateByOrg(arg0 context.Context, arg1 string, arg2 bool) (*query.MailTemplate, error) {
|
||||
func (m *MockQueries) MailTemplateByOrg(ctx context.Context, orgID string, withOwnerRemoved bool) (*query.MailTemplate, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "MailTemplateByOrg", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "MailTemplateByOrg", ctx, orgID, withOwnerRemoved)
|
||||
ret0, _ := ret[0].(*query.MailTemplate)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// MailTemplateByOrg indicates an expected call of MailTemplateByOrg.
|
||||
func (mr *MockQueriesMockRecorder) MailTemplateByOrg(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) MailTemplateByOrg(ctx, orgID, withOwnerRemoved any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MailTemplateByOrg", reflect.TypeOf((*MockQueries)(nil).MailTemplateByOrg), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MailTemplateByOrg", reflect.TypeOf((*MockQueries)(nil).MailTemplateByOrg), ctx, orgID, withOwnerRemoved)
|
||||
}
|
||||
|
||||
// NotificationPolicyByOrg mocks base method.
|
||||
func (m *MockQueries) NotificationPolicyByOrg(arg0 context.Context, arg1 bool, arg2 string, arg3 bool) (*query.NotificationPolicy, error) {
|
||||
func (m *MockQueries) NotificationPolicyByOrg(ctx context.Context, shouldTriggerBulk bool, orgID string, withOwnerRemoved bool) (*query.NotificationPolicy, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NotificationPolicyByOrg", arg0, arg1, arg2, arg3)
|
||||
ret := m.ctrl.Call(m, "NotificationPolicyByOrg", ctx, shouldTriggerBulk, orgID, withOwnerRemoved)
|
||||
ret0, _ := ret[0].(*query.NotificationPolicy)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NotificationPolicyByOrg indicates an expected call of NotificationPolicyByOrg.
|
||||
func (mr *MockQueriesMockRecorder) NotificationPolicyByOrg(arg0, arg1, arg2, arg3 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) NotificationPolicyByOrg(ctx, shouldTriggerBulk, orgID, withOwnerRemoved any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotificationPolicyByOrg", reflect.TypeOf((*MockQueries)(nil).NotificationPolicyByOrg), arg0, arg1, arg2, arg3)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotificationPolicyByOrg", reflect.TypeOf((*MockQueries)(nil).NotificationPolicyByOrg), ctx, shouldTriggerBulk, orgID, withOwnerRemoved)
|
||||
}
|
||||
|
||||
// NotificationProviderByIDAndType mocks base method.
|
||||
func (m *MockQueries) NotificationProviderByIDAndType(arg0 context.Context, arg1 string, arg2 domain.NotificationProviderType) (*query.DebugNotificationProvider, error) {
|
||||
func (m *MockQueries) NotificationProviderByIDAndType(ctx context.Context, aggID string, providerType domain.NotificationProviderType) (*query.DebugNotificationProvider, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NotificationProviderByIDAndType", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "NotificationProviderByIDAndType", ctx, aggID, providerType)
|
||||
ret0, _ := ret[0].(*query.DebugNotificationProvider)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NotificationProviderByIDAndType indicates an expected call of NotificationProviderByIDAndType.
|
||||
func (mr *MockQueriesMockRecorder) NotificationProviderByIDAndType(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) NotificationProviderByIDAndType(ctx, aggID, providerType any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotificationProviderByIDAndType", reflect.TypeOf((*MockQueries)(nil).NotificationProviderByIDAndType), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NotificationProviderByIDAndType", reflect.TypeOf((*MockQueries)(nil).NotificationProviderByIDAndType), ctx, aggID, providerType)
|
||||
}
|
||||
|
||||
// SMSProviderConfigActive mocks base method.
|
||||
func (m *MockQueries) SMSProviderConfigActive(arg0 context.Context, arg1 string) (*query.SMSConfig, error) {
|
||||
func (m *MockQueries) SMSProviderConfigActive(ctx context.Context, resourceOwner string) (*query.SMSConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SMSProviderConfigActive", arg0, arg1)
|
||||
ret := m.ctrl.Call(m, "SMSProviderConfigActive", ctx, resourceOwner)
|
||||
ret0, _ := ret[0].(*query.SMSConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SMSProviderConfigActive indicates an expected call of SMSProviderConfigActive.
|
||||
func (mr *MockQueriesMockRecorder) SMSProviderConfigActive(arg0, arg1 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) SMSProviderConfigActive(ctx, resourceOwner any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMSProviderConfigActive", reflect.TypeOf((*MockQueries)(nil).SMSProviderConfigActive), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMSProviderConfigActive", reflect.TypeOf((*MockQueries)(nil).SMSProviderConfigActive), ctx, resourceOwner)
|
||||
}
|
||||
|
||||
// SMTPConfigActive mocks base method.
|
||||
func (m *MockQueries) SMTPConfigActive(arg0 context.Context, arg1 string) (*query.SMTPConfig, error) {
|
||||
func (m *MockQueries) SMTPConfigActive(ctx context.Context, resourceOwner string) (*query.SMTPConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SMTPConfigActive", arg0, arg1)
|
||||
ret := m.ctrl.Call(m, "SMTPConfigActive", ctx, resourceOwner)
|
||||
ret0, _ := ret[0].(*query.SMTPConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SMTPConfigActive indicates an expected call of SMTPConfigActive.
|
||||
func (mr *MockQueriesMockRecorder) SMTPConfigActive(arg0, arg1 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) SMTPConfigActive(ctx, resourceOwner any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMTPConfigActive", reflect.TypeOf((*MockQueries)(nil).SMTPConfigActive), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SMTPConfigActive", reflect.TypeOf((*MockQueries)(nil).SMTPConfigActive), ctx, resourceOwner)
|
||||
}
|
||||
|
||||
// SearchInstanceDomains mocks base method.
|
||||
func (m *MockQueries) SearchInstanceDomains(arg0 context.Context, arg1 *query.InstanceDomainSearchQueries) (*query.InstanceDomains, error) {
|
||||
func (m *MockQueries) SearchInstanceDomains(ctx context.Context, queries *query.InstanceDomainSearchQueries) (*query.InstanceDomains, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SearchInstanceDomains", arg0, arg1)
|
||||
ret := m.ctrl.Call(m, "SearchInstanceDomains", ctx, queries)
|
||||
ret0, _ := ret[0].(*query.InstanceDomains)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SearchInstanceDomains indicates an expected call of SearchInstanceDomains.
|
||||
func (mr *MockQueriesMockRecorder) SearchInstanceDomains(arg0, arg1 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) SearchInstanceDomains(ctx, queries any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchInstanceDomains", reflect.TypeOf((*MockQueries)(nil).SearchInstanceDomains), arg0, arg1)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchInstanceDomains", reflect.TypeOf((*MockQueries)(nil).SearchInstanceDomains), ctx, queries)
|
||||
}
|
||||
|
||||
// SearchMilestones mocks base method.
|
||||
func (m *MockQueries) SearchMilestones(arg0 context.Context, arg1 []string, arg2 *query.MilestonesSearchQueries) (*query.Milestones, error) {
|
||||
func (m *MockQueries) SearchMilestones(ctx context.Context, instanceIDs []string, queries *query.MilestonesSearchQueries) (*query.Milestones, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SearchMilestones", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "SearchMilestones", ctx, instanceIDs, queries)
|
||||
ret0, _ := ret[0].(*query.Milestones)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SearchMilestones indicates an expected call of SearchMilestones.
|
||||
func (mr *MockQueriesMockRecorder) SearchMilestones(arg0, arg1, arg2 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) SearchMilestones(ctx, instanceIDs, queries any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchMilestones", reflect.TypeOf((*MockQueries)(nil).SearchMilestones), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchMilestones", reflect.TypeOf((*MockQueries)(nil).SearchMilestones), ctx, instanceIDs, queries)
|
||||
}
|
||||
|
||||
// SessionByID mocks base method.
|
||||
func (m *MockQueries) SessionByID(arg0 context.Context, arg1 bool, arg2, arg3 string, arg4 domain.PermissionCheck) (*query.Session, error) {
|
||||
func (m *MockQueries) SessionByID(ctx context.Context, shouldTriggerBulk bool, id, sessionToken string, check domain.PermissionCheck) (*query.Session, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SessionByID", arg0, arg1, arg2, arg3, arg4)
|
||||
ret := m.ctrl.Call(m, "SessionByID", ctx, shouldTriggerBulk, id, sessionToken, check)
|
||||
ret0, _ := ret[0].(*query.Session)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SessionByID indicates an expected call of SessionByID.
|
||||
func (mr *MockQueriesMockRecorder) SessionByID(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call {
|
||||
func (mr *MockQueriesMockRecorder) SessionByID(ctx, shouldTriggerBulk, id, sessionToken, check any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SessionByID", reflect.TypeOf((*MockQueries)(nil).SessionByID), arg0, arg1, arg2, arg3, arg4)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SessionByID", reflect.TypeOf((*MockQueries)(nil).SessionByID), ctx, shouldTriggerBulk, id, sessionToken, check)
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import (
|
||||
type MockQueue struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockQueueMockRecorder
|
||||
isgomock struct{}
|
||||
}
|
||||
|
||||
// MockQueueMockRecorder is the mock recorder for MockQueue.
|
||||
@@ -42,10 +43,10 @@ func (m *MockQueue) EXPECT() *MockQueueMockRecorder {
|
||||
}
|
||||
|
||||
// Insert mocks base method.
|
||||
func (m *MockQueue) Insert(arg0 context.Context, arg1 river.JobArgs, arg2 ...queue.InsertOpt) error {
|
||||
func (m *MockQueue) Insert(ctx context.Context, args river.JobArgs, opts ...queue.InsertOpt) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []any{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs := []any{ctx, args}
|
||||
for _, a := range opts {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "Insert", varargs...)
|
||||
@@ -54,8 +55,8 @@ func (m *MockQueue) Insert(arg0 context.Context, arg1 river.JobArgs, arg2 ...que
|
||||
}
|
||||
|
||||
// Insert indicates an expected call of Insert.
|
||||
func (mr *MockQueueMockRecorder) Insert(arg0, arg1 any, arg2 ...any) *gomock.Call {
|
||||
func (mr *MockQueueMockRecorder) Insert(ctx, args any, opts ...any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]any{arg0, arg1}, arg2...)
|
||||
varargs := append([]any{ctx, args}, opts...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockQueue)(nil).Insert), varargs...)
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package handlers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"golang.org/x/text/language"
|
||||
@@ -30,7 +29,6 @@ type Queries interface {
|
||||
GetInstanceRestrictions(ctx context.Context) (restrictions query.Restrictions, err error)
|
||||
InstanceByID(ctx context.Context, id string) (instance authz.Instance, err error)
|
||||
GetActiveSigningWebKey(ctx context.Context) (*jose.JSONWebKey, error)
|
||||
ActivePrivateSigningKey(ctx context.Context, t time.Time) (keys *query.PrivateKeys, err error)
|
||||
|
||||
ActiveInstances() []string
|
||||
}
|
||||
|
@@ -14,7 +14,6 @@ type InstanceFeatures struct {
|
||||
UserSchema FeatureSource[bool]
|
||||
TokenExchange FeatureSource[bool]
|
||||
ImprovedPerformance FeatureSource[[]feature.ImprovedPerformanceType]
|
||||
WebKey FeatureSource[bool]
|
||||
DebugOIDCParentError FeatureSource[bool]
|
||||
OIDCSingleV1SessionTermination FeatureSource[bool]
|
||||
DisableUserTokenEvent FeatureSource[bool]
|
||||
|
@@ -67,7 +67,6 @@ func (m *InstanceFeaturesReadModel) Query() *eventstore.SearchQueryBuilder {
|
||||
feature_v2.InstanceUserSchemaEventType,
|
||||
feature_v2.InstanceTokenExchangeEventType,
|
||||
feature_v2.InstanceImprovedPerformanceEventType,
|
||||
feature_v2.InstanceWebKeyEventType,
|
||||
feature_v2.InstanceDebugOIDCParentErrorEventType,
|
||||
feature_v2.InstanceOIDCSingleV1SessionTerminationEventType,
|
||||
feature_v2.InstanceDisableUserTokenEvent,
|
||||
@@ -121,8 +120,6 @@ func reduceInstanceFeatureSet[T any](features *InstanceFeatures, event *feature_
|
||||
features.TokenExchange.set(level, event.Value)
|
||||
case feature.KeyImprovedPerformance:
|
||||
features.ImprovedPerformance.set(level, event.Value)
|
||||
case feature.KeyWebKey:
|
||||
features.WebKey.set(level, event.Value)
|
||||
case feature.KeyDebugOIDCParentError:
|
||||
features.DebugOIDCParentError.set(level, event.Value)
|
||||
case feature.KeyOIDCSingleV1SessionTermination:
|
||||
|
@@ -1,20 +1,10 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
sq "github.com/Masterminds/squirrel"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/query/projection"
|
||||
"github.com/zitadel/zitadel/internal/repository/keypair"
|
||||
"github.com/zitadel/zitadel/internal/telemetry/tracing"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
type Key interface {
|
||||
@@ -36,11 +26,6 @@ type PublicKey interface {
|
||||
Key() interface{}
|
||||
}
|
||||
|
||||
type PrivateKeys struct {
|
||||
SearchResponse
|
||||
Keys []PrivateKey
|
||||
}
|
||||
|
||||
type PublicKeys struct {
|
||||
SearchResponse
|
||||
Keys []PublicKey
|
||||
@@ -72,34 +57,6 @@ func (k *key) Sequence() uint64 {
|
||||
return k.sequence
|
||||
}
|
||||
|
||||
type privateKey struct {
|
||||
key
|
||||
expiry time.Time
|
||||
privateKey *crypto.CryptoValue
|
||||
}
|
||||
|
||||
func (k *privateKey) Expiry() time.Time {
|
||||
return k.expiry
|
||||
}
|
||||
|
||||
func (k *privateKey) Key() *crypto.CryptoValue {
|
||||
return k.privateKey
|
||||
}
|
||||
|
||||
type rsaPublicKey struct {
|
||||
key
|
||||
expiry time.Time
|
||||
publicKey *rsa.PublicKey
|
||||
}
|
||||
|
||||
func (r *rsaPublicKey) Expiry() time.Time {
|
||||
return r.expiry
|
||||
}
|
||||
|
||||
func (r *rsaPublicKey) Key() interface{} {
|
||||
return r.publicKey
|
||||
}
|
||||
|
||||
var (
|
||||
keyTable = table{
|
||||
name: projection.KeyProjectionTable,
|
||||
@@ -157,277 +114,3 @@ var (
|
||||
table: keyPrivateTable,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
keyPublicTable = table{
|
||||
name: projection.KeyPublicTable,
|
||||
instanceIDCol: projection.KeyPrivateColumnInstanceID,
|
||||
}
|
||||
KeyPublicColID = Column{
|
||||
name: projection.KeyPublicColumnID,
|
||||
table: keyPublicTable,
|
||||
}
|
||||
KeyPublicColExpiry = Column{
|
||||
name: projection.KeyPublicColumnExpiry,
|
||||
table: keyPublicTable,
|
||||
}
|
||||
KeyPublicColKey = Column{
|
||||
name: projection.KeyPublicColumnKey,
|
||||
table: keyPublicTable,
|
||||
}
|
||||
)
|
||||
|
||||
func (q *Queries) ActivePublicKeys(ctx context.Context, t time.Time) (keys *PublicKeys, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
query, scan := preparePublicKeysQuery()
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
}
|
||||
stmt, args, err := query.Where(
|
||||
sq.And{
|
||||
sq.Eq{KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID()},
|
||||
sq.Gt{KeyPublicColExpiry.identifier(): t},
|
||||
}).ToSql()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-SDFfg", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
err = q.client.QueryContext(ctx, func(rows *sql.Rows) error {
|
||||
keys, err = scan(rows)
|
||||
return err
|
||||
}, stmt, args...)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-Sghn4", "Errors.Internal")
|
||||
}
|
||||
|
||||
keys.State, err = q.latestState(ctx, keyTable)
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return keys, err
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (q *Queries) ActivePrivateSigningKey(ctx context.Context, t time.Time) (keys *PrivateKeys, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
stmt, scan := preparePrivateKeysQuery()
|
||||
if t.IsZero() {
|
||||
t = time.Now()
|
||||
}
|
||||
query, args, err := stmt.Where(
|
||||
sq.And{
|
||||
sq.Eq{
|
||||
KeyColUse.identifier(): crypto.KeyUsageSigning,
|
||||
KeyColInstanceID.identifier(): authz.GetInstance(ctx).InstanceID(),
|
||||
},
|
||||
sq.Gt{KeyPrivateColExpiry.identifier(): t},
|
||||
}).OrderBy(KeyPrivateColExpiry.identifier()).ToSql()
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-SDff2", "Errors.Query.SQLStatement")
|
||||
}
|
||||
|
||||
err = q.client.QueryContext(ctx, func(rows *sql.Rows) error {
|
||||
keys, err = scan(rows)
|
||||
return err
|
||||
}, query, args...)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-WRFG4", "Errors.Internal")
|
||||
}
|
||||
keys.State, err = q.latestState(ctx, keyTable)
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return keys, err
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func preparePublicKeysQuery() (sq.SelectBuilder, func(*sql.Rows) (*PublicKeys, error)) {
|
||||
return sq.Select(
|
||||
KeyColID.identifier(),
|
||||
KeyColCreationDate.identifier(),
|
||||
KeyColChangeDate.identifier(),
|
||||
KeyColSequence.identifier(),
|
||||
KeyColResourceOwner.identifier(),
|
||||
KeyColAlgorithm.identifier(),
|
||||
KeyColUse.identifier(),
|
||||
KeyPublicColExpiry.identifier(),
|
||||
KeyPublicColKey.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(keyTable.identifier()).
|
||||
LeftJoin(join(KeyPublicColID, KeyColID)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*PublicKeys, error) {
|
||||
keys := make([]PublicKey, 0)
|
||||
var count uint64
|
||||
for rows.Next() {
|
||||
k := new(rsaPublicKey)
|
||||
var keyValue []byte
|
||||
err := rows.Scan(
|
||||
&k.id,
|
||||
&k.creationDate,
|
||||
&k.changeDate,
|
||||
&k.sequence,
|
||||
&k.resourceOwner,
|
||||
&k.algorithm,
|
||||
&k.use,
|
||||
&k.expiry,
|
||||
&keyValue,
|
||||
&count,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
k.publicKey, err = crypto.BytesToPublicKey(keyValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-rKd6k", "Errors.Query.CloseRows")
|
||||
}
|
||||
|
||||
return &PublicKeys{
|
||||
Keys: keys,
|
||||
SearchResponse: SearchResponse{
|
||||
Count: count,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func preparePrivateKeysQuery() (sq.SelectBuilder, func(*sql.Rows) (*PrivateKeys, error)) {
|
||||
return sq.Select(
|
||||
KeyColID.identifier(),
|
||||
KeyColCreationDate.identifier(),
|
||||
KeyColChangeDate.identifier(),
|
||||
KeyColSequence.identifier(),
|
||||
KeyColResourceOwner.identifier(),
|
||||
KeyColAlgorithm.identifier(),
|
||||
KeyColUse.identifier(),
|
||||
KeyPrivateColExpiry.identifier(),
|
||||
KeyPrivateColKey.identifier(),
|
||||
countColumn.identifier(),
|
||||
).From(keyTable.identifier()).
|
||||
LeftJoin(join(KeyPrivateColID, KeyColID)).
|
||||
PlaceholderFormat(sq.Dollar),
|
||||
func(rows *sql.Rows) (*PrivateKeys, error) {
|
||||
keys := make([]PrivateKey, 0)
|
||||
var count uint64
|
||||
for rows.Next() {
|
||||
k := new(privateKey)
|
||||
err := rows.Scan(
|
||||
&k.id,
|
||||
&k.creationDate,
|
||||
&k.changeDate,
|
||||
&k.sequence,
|
||||
&k.resourceOwner,
|
||||
&k.algorithm,
|
||||
&k.use,
|
||||
&k.expiry,
|
||||
&k.privateKey,
|
||||
&count,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
keys = append(keys, k)
|
||||
}
|
||||
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-rKd6k", "Errors.Query.CloseRows")
|
||||
}
|
||||
|
||||
return &PrivateKeys{
|
||||
Keys: keys,
|
||||
SearchResponse: SearchResponse{
|
||||
Count: count,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type PublicKeyReadModel struct {
|
||||
eventstore.ReadModel
|
||||
|
||||
Algorithm string
|
||||
Key *crypto.CryptoValue
|
||||
Expiry time.Time
|
||||
Usage crypto.KeyUsage
|
||||
}
|
||||
|
||||
func NewPublicKeyReadModel(keyID, resourceOwner string) *PublicKeyReadModel {
|
||||
return &PublicKeyReadModel{
|
||||
ReadModel: eventstore.ReadModel{
|
||||
AggregateID: keyID,
|
||||
ResourceOwner: resourceOwner,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (wm *PublicKeyReadModel) AppendEvents(events ...eventstore.Event) {
|
||||
wm.ReadModel.AppendEvents(events...)
|
||||
}
|
||||
|
||||
func (wm *PublicKeyReadModel) Reduce() error {
|
||||
for _, event := range wm.Events {
|
||||
switch e := event.(type) {
|
||||
case *keypair.AddedEvent:
|
||||
wm.Algorithm = e.Algorithm
|
||||
wm.Key = e.PublicKey.Key
|
||||
wm.Expiry = e.PublicKey.Expiry
|
||||
wm.Usage = e.Usage
|
||||
default:
|
||||
}
|
||||
}
|
||||
return wm.ReadModel.Reduce()
|
||||
}
|
||||
|
||||
func (wm *PublicKeyReadModel) Query() *eventstore.SearchQueryBuilder {
|
||||
return eventstore.NewSearchQueryBuilder(eventstore.ColumnsEvent).
|
||||
AwaitOpenTransactions().
|
||||
ResourceOwner(wm.ResourceOwner).
|
||||
AddQuery().
|
||||
AggregateTypes(keypair.AggregateType).
|
||||
AggregateIDs(wm.AggregateID).
|
||||
EventTypes(keypair.AddedEventType).
|
||||
Builder()
|
||||
}
|
||||
|
||||
func (q *Queries) GetPublicKeyByID(ctx context.Context, keyID string) (_ PublicKey, err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
||||
model := NewPublicKeyReadModel(keyID, authz.GetInstance(ctx).InstanceID())
|
||||
if err := q.eventstore.FilterToQueryReducer(ctx, model); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if model.Algorithm == "" || model.Key == nil {
|
||||
return nil, zerrors.ThrowNotFound(err, "QUERY-Ahf7x", "Errors.Key.NotFound")
|
||||
}
|
||||
keyValue, err := crypto.Decrypt(model.Key, q.keyEncryptionAlgorithm)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-Ie4oh", "Errors.Internal")
|
||||
}
|
||||
publicKey, err := crypto.BytesToPublicKey(keyValue)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "QUERY-Kai2Z", "Errors.Internal")
|
||||
}
|
||||
|
||||
return &rsaPublicKey{
|
||||
key: key{
|
||||
id: model.AggregateID,
|
||||
creationDate: model.CreationDate,
|
||||
changeDate: model.ChangeDate,
|
||||
sequence: model.ProcessedSequence,
|
||||
resourceOwner: model.ResourceOwner,
|
||||
algorithm: model.Algorithm,
|
||||
use: model.Usage,
|
||||
},
|
||||
expiry: model.Expiry,
|
||||
publicKey: publicKey,
|
||||
}, nil
|
||||
}
|
||||
|
@@ -1,453 +0,0 @@
|
||||
package query
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rsa"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/mock/gomock"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
key_repo "github.com/zitadel/zitadel/internal/repository/keypair"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
var (
|
||||
preparePublicKeysStmt = `SELECT projections.keys4.id,` +
|
||||
` projections.keys4.creation_date,` +
|
||||
` projections.keys4.change_date,` +
|
||||
` projections.keys4.sequence,` +
|
||||
` projections.keys4.resource_owner,` +
|
||||
` projections.keys4.algorithm,` +
|
||||
` projections.keys4.use,` +
|
||||
` projections.keys4_public.expiry,` +
|
||||
` projections.keys4_public.key,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.keys4` +
|
||||
` LEFT JOIN projections.keys4_public ON projections.keys4.id = projections.keys4_public.id AND projections.keys4.instance_id = projections.keys4_public.instance_id`
|
||||
preparePublicKeysCols = []string{
|
||||
"id",
|
||||
"creation_date",
|
||||
"change_date",
|
||||
"sequence",
|
||||
"resource_owner",
|
||||
"algorithm",
|
||||
"use",
|
||||
"expiry",
|
||||
"key",
|
||||
"count",
|
||||
}
|
||||
|
||||
preparePrivateKeysStmt = `SELECT projections.keys4.id,` +
|
||||
` projections.keys4.creation_date,` +
|
||||
` projections.keys4.change_date,` +
|
||||
` projections.keys4.sequence,` +
|
||||
` projections.keys4.resource_owner,` +
|
||||
` projections.keys4.algorithm,` +
|
||||
` projections.keys4.use,` +
|
||||
` projections.keys4_private.expiry,` +
|
||||
` projections.keys4_private.key,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.keys4` +
|
||||
` LEFT JOIN projections.keys4_private ON projections.keys4.id = projections.keys4_private.id AND projections.keys4.instance_id = projections.keys4_private.instance_id`
|
||||
)
|
||||
|
||||
func Test_KeyPrepares(t *testing.T) {
|
||||
type want struct {
|
||||
sqlExpectations sqlExpectation
|
||||
err checkErr
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
prepare interface{}
|
||||
want want
|
||||
object interface{}
|
||||
}{
|
||||
{
|
||||
name: "preparePublicKeysQuery no result",
|
||||
prepare: preparePublicKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(preparePublicKeysStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: &PublicKeys{Keys: []PublicKey{}},
|
||||
},
|
||||
{
|
||||
name: "preparePublicKeysQuery found",
|
||||
prepare: preparePublicKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(preparePublicKeysStmt),
|
||||
preparePublicKeysCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"key-id",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
"ro",
|
||||
"RS256",
|
||||
0,
|
||||
testNow,
|
||||
[]byte("-----BEGIN RSA PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsvX9P58JFxEs5C+L+H7W\nduFSWL5EPzber7C2m94klrSV6q0bAcrYQnGwFOlveThsY200hRbadKaKjHD7qIKH\nDEe0IY2PSRht33Jye52AwhkRw+M3xuQH/7R8LydnsNFk2KHpr5X2SBv42e37LjkE\nslKSaMRgJW+v0KZ30piY8QsdFRKKaVg5/Ajt1YToM1YVsdHXJ3vmXFMtypLdxwUD\ndIaLEX6pFUkU75KSuEQ/E2luT61Q3ta9kOWm9+0zvi7OMcbdekJT7mzcVnh93R1c\n13ZhQCLbh9A7si8jKFtaMWevjayrvqQABEcTN9N4Hoxcyg6l4neZtRDk75OMYcqm\nDQIDAQAB\n-----END RSA PUBLIC KEY-----\n"),
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &PublicKeys{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 1,
|
||||
},
|
||||
Keys: []PublicKey{
|
||||
&rsaPublicKey{
|
||||
key: key{
|
||||
id: "key-id",
|
||||
creationDate: testNow,
|
||||
changeDate: testNow,
|
||||
sequence: 20211109,
|
||||
resourceOwner: "ro",
|
||||
algorithm: "RS256",
|
||||
use: crypto.KeyUsageSigning,
|
||||
},
|
||||
expiry: testNow,
|
||||
publicKey: &rsa.PublicKey{
|
||||
E: 65537,
|
||||
N: fromBase16("b2f5fd3f9f0917112ce42f8bf87ed676e15258be443f36deafb0b69bde2496b495eaad1b01cad84271b014e96f79386c636d348516da74a68a8c70fba882870c47b4218d8f49186ddf72727b9d80c21911c3e337c6e407ffb47c2f2767b0d164d8a1e9af95f6481bf8d9edfb2e3904b2529268c460256fafd0a677d29898f10b1d15128a695839fc08edd584e8335615b1d1d7277be65c532dca92ddc7050374868b117ea9154914ef9292b8443f13696e4fad50ded6bd90e5a6f7ed33be2ece31c6dd7a4253ee6cdc56787ddd1d5cd776614022db87d03bb22f23285b5a3167af8dacabbea40004471337d3781e8c5cca0ea5e27799b510e4ef938c61caa60d"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "preparePublicKeysQuery sql err",
|
||||
prepare: preparePublicKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(preparePublicKeysStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errors.Is(err, sql.ErrConnDone) {
|
||||
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: (*PublicKeys)(nil),
|
||||
},
|
||||
{
|
||||
name: "preparePrivateKeysQuery no result",
|
||||
prepare: preparePrivateKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(preparePrivateKeysStmt),
|
||||
nil,
|
||||
nil,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !zerrors.IsNotFound(err) {
|
||||
return fmt.Errorf("err should be zitadel.NotFoundError got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: &PrivateKeys{Keys: []PrivateKey{}},
|
||||
},
|
||||
{
|
||||
name: "preparePrivateKeysQuery found",
|
||||
prepare: preparePrivateKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueries(
|
||||
regexp.QuoteMeta(preparePrivateKeysStmt),
|
||||
preparePublicKeysCols,
|
||||
[][]driver.Value{
|
||||
{
|
||||
"key-id",
|
||||
testNow,
|
||||
testNow,
|
||||
uint64(20211109),
|
||||
"ro",
|
||||
"RS256",
|
||||
0,
|
||||
testNow,
|
||||
[]byte(`{"Algorithm": "enc", "Crypted": "cHJpdmF0ZUtleQ==", "CryptoType": 0, "KeyID": "id"}`),
|
||||
},
|
||||
},
|
||||
),
|
||||
},
|
||||
object: &PrivateKeys{
|
||||
SearchResponse: SearchResponse{
|
||||
Count: 1,
|
||||
},
|
||||
Keys: []PrivateKey{
|
||||
&privateKey{
|
||||
key: key{
|
||||
id: "key-id",
|
||||
creationDate: testNow,
|
||||
changeDate: testNow,
|
||||
sequence: 20211109,
|
||||
resourceOwner: "ro",
|
||||
algorithm: "RS256",
|
||||
use: crypto.KeyUsageSigning,
|
||||
},
|
||||
expiry: testNow,
|
||||
privateKey: &crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("privateKey"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "preparePrivateKeysQuery sql err",
|
||||
prepare: preparePrivateKeysQuery,
|
||||
want: want{
|
||||
sqlExpectations: mockQueryErr(
|
||||
regexp.QuoteMeta(preparePrivateKeysStmt),
|
||||
sql.ErrConnDone,
|
||||
),
|
||||
err: func(err error) (error, bool) {
|
||||
if !errors.Is(err, sql.ErrConnDone) {
|
||||
return fmt.Errorf("err should be sql.ErrConnDone got: %w", err), false
|
||||
}
|
||||
return nil, true
|
||||
},
|
||||
},
|
||||
object: (*PrivateKeys)(nil),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
assertPrepare(t, tt.prepare, tt.object, tt.want.sqlExpectations, tt.want.err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fromBase16(base16 string) *big.Int {
|
||||
i, ok := new(big.Int).SetString(base16, 16)
|
||||
if !ok {
|
||||
panic("bad number: " + base16)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
const pubKey = `-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs38btwb3c7r0tMaQpGvB
|
||||
mY+mPwMU/LpfuPoC0k2t4RsKp0fv40SMl50CRrHgk395wch8PMPYbl3+8TtYAJuy
|
||||
rFALIj3Ff1UcKIk0hOH5DDsfh7/q2wFuncTmS6bifYo8CfSq2vDGnM7nZnEvxY/M
|
||||
fSydZdcmIqlkUpfQmtzExw9+tSe5Dxq6gn5JtlGgLgZGt69r5iMMrTEGhhVAXzNu
|
||||
MZbmlCoBru+rC8ITlTX/0V1ZcsSbL8tYWhthyu9x6yjo1bH85wiVI4gs0MhU8f2a
|
||||
+kjL/KGZbR14Ua2eo6tonBZLC5DHWM2TkYXgRCDPufjcgmzN0Lm91E4P8KvBcvly
|
||||
6QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
`
|
||||
|
||||
func TestQueries_GetPublicKeyByID(t *testing.T) {
|
||||
now := time.Now()
|
||||
future := now.Add(time.Hour)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
encryption func(*testing.T) *crypto.MockEncryptionAlgorithm
|
||||
want *rsaPublicKey
|
||||
wantErr error
|
||||
}{
|
||||
{
|
||||
name: "filter error",
|
||||
eventstore: expectEventstore(
|
||||
expectFilterError(io.ErrClosedPipe),
|
||||
),
|
||||
wantErr: io.ErrClosedPipe,
|
||||
},
|
||||
{
|
||||
name: "not found error",
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(),
|
||||
),
|
||||
wantErr: zerrors.ThrowNotFound(nil, "QUERY-Ahf7x", "Errors.Key.NotFound"),
|
||||
},
|
||||
{
|
||||
name: "decrypt error",
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(key_repo.NewAddedEvent(context.Background(),
|
||||
&eventstore.Aggregate{
|
||||
ID: "keyID",
|
||||
Type: key_repo.AggregateType,
|
||||
ResourceOwner: "instanceID",
|
||||
InstanceID: "instanceID",
|
||||
Version: key_repo.AggregateVersion,
|
||||
},
|
||||
crypto.KeyUsageSigning, "alg",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "alg",
|
||||
KeyID: "keyID",
|
||||
Crypted: []byte("private"),
|
||||
},
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "alg",
|
||||
KeyID: "keyID",
|
||||
Crypted: []byte("public"),
|
||||
},
|
||||
future,
|
||||
future,
|
||||
)),
|
||||
),
|
||||
),
|
||||
encryption: func(t *testing.T) *crypto.MockEncryptionAlgorithm {
|
||||
encryption := crypto.NewMockEncryptionAlgorithm(gomock.NewController(t))
|
||||
expect := encryption.EXPECT()
|
||||
expect.Algorithm().Return("alg")
|
||||
expect.DecryptionKeyIDs().Return([]string{})
|
||||
return encryption
|
||||
},
|
||||
wantErr: zerrors.ThrowInternal(nil, "QUERY-Ie4oh", "Errors.Internal"),
|
||||
},
|
||||
{
|
||||
name: "parse error",
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(key_repo.NewAddedEvent(context.Background(),
|
||||
&eventstore.Aggregate{
|
||||
ID: "keyID",
|
||||
Type: key_repo.AggregateType,
|
||||
ResourceOwner: "instanceID",
|
||||
InstanceID: "instanceID",
|
||||
Version: key_repo.AggregateVersion,
|
||||
},
|
||||
crypto.KeyUsageSigning, "alg",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "alg",
|
||||
KeyID: "keyID",
|
||||
Crypted: []byte("private"),
|
||||
},
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "alg",
|
||||
KeyID: "keyID",
|
||||
Crypted: []byte("public"),
|
||||
},
|
||||
future,
|
||||
future,
|
||||
)),
|
||||
),
|
||||
),
|
||||
encryption: func(t *testing.T) *crypto.MockEncryptionAlgorithm {
|
||||
encryption := crypto.NewMockEncryptionAlgorithm(gomock.NewController(t))
|
||||
expect := encryption.EXPECT()
|
||||
expect.Algorithm().Return("alg")
|
||||
expect.DecryptionKeyIDs().Return([]string{"keyID"})
|
||||
expect.Decrypt([]byte("public"), "keyID").Return([]byte("foo"), nil)
|
||||
return encryption
|
||||
},
|
||||
wantErr: zerrors.ThrowInternal(nil, "QUERY-Kai2Z", "Errors.Internal"),
|
||||
},
|
||||
{
|
||||
name: "success",
|
||||
eventstore: expectEventstore(
|
||||
expectFilter(
|
||||
eventFromEventPusher(key_repo.NewAddedEvent(context.Background(),
|
||||
&eventstore.Aggregate{
|
||||
ID: "keyID",
|
||||
Type: key_repo.AggregateType,
|
||||
ResourceOwner: "instanceID",
|
||||
InstanceID: "instanceID",
|
||||
Version: key_repo.AggregateVersion,
|
||||
},
|
||||
crypto.KeyUsageSigning, "alg",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "alg",
|
||||
KeyID: "keyID",
|
||||
Crypted: []byte("private"),
|
||||
},
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "alg",
|
||||
KeyID: "keyID",
|
||||
Crypted: []byte("public"),
|
||||
},
|
||||
future,
|
||||
future,
|
||||
)),
|
||||
),
|
||||
),
|
||||
encryption: func(t *testing.T) *crypto.MockEncryptionAlgorithm {
|
||||
encryption := crypto.NewMockEncryptionAlgorithm(gomock.NewController(t))
|
||||
expect := encryption.EXPECT()
|
||||
expect.Algorithm().Return("alg")
|
||||
expect.DecryptionKeyIDs().Return([]string{"keyID"})
|
||||
expect.Decrypt([]byte("public"), "keyID").Return([]byte(pubKey), nil)
|
||||
return encryption
|
||||
},
|
||||
want: &rsaPublicKey{
|
||||
key: key{
|
||||
id: "keyID",
|
||||
resourceOwner: "instanceID",
|
||||
algorithm: "alg",
|
||||
use: crypto.KeyUsageSigning,
|
||||
},
|
||||
expiry: future,
|
||||
publicKey: func() *rsa.PublicKey {
|
||||
publicKey, err := crypto.BytesToPublicKey([]byte(pubKey))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return publicKey
|
||||
}(),
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
q := &Queries{
|
||||
eventstore: tt.eventstore(t),
|
||||
}
|
||||
if tt.encryption != nil {
|
||||
q.keyEncryptionAlgorithm = tt.encryption(t)
|
||||
}
|
||||
ctx := authz.NewMockContext("instanceID", "orgID", "loginClient")
|
||||
key, err := q.GetPublicKeyByID(ctx, "keyID")
|
||||
if tt.wantErr != nil {
|
||||
require.ErrorIs(t, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, key)
|
||||
|
||||
got := key.(*rsaPublicKey)
|
||||
assert.WithinDuration(t, tt.want.expiry, got.expiry, time.Second)
|
||||
tt.want.expiry = time.Time{}
|
||||
got.expiry = time.Time{}
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
@@ -80,10 +80,6 @@ func (*instanceFeatureProjection) Reducers() []handler.AggregateReducer {
|
||||
Event: feature_v2.InstanceImprovedPerformanceEventType,
|
||||
Reduce: reduceInstanceSetFeature[[]feature.ImprovedPerformanceType],
|
||||
},
|
||||
{
|
||||
Event: feature_v2.InstanceWebKeyEventType,
|
||||
Reduce: reduceInstanceSetFeature[bool],
|
||||
},
|
||||
{
|
||||
Event: feature_v2.InstanceDebugOIDCParentErrorEventType,
|
||||
Reduce: reduceInstanceSetFeature[bool],
|
||||
|
@@ -24,7 +24,6 @@ func init() {
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, InstanceUserSchemaEventType, eventstore.GenericEventMapper[SetEvent[bool]])
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, InstanceTokenExchangeEventType, 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]])
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, InstanceOIDCSingleV1SessionTerminationEventType, eventstore.GenericEventMapper[SetEvent[bool]])
|
||||
eventstore.RegisterFilterEventMapper(AggregateType, InstanceDisableUserTokenEvent, eventstore.GenericEventMapper[SetEvent[bool]])
|
||||
|
@@ -29,7 +29,6 @@ var (
|
||||
InstanceUserSchemaEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyUserSchema)
|
||||
InstanceTokenExchangeEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyTokenExchange)
|
||||
InstanceImprovedPerformanceEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyImprovedPerformance)
|
||||
InstanceWebKeyEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyWebKey)
|
||||
InstanceDebugOIDCParentErrorEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyDebugOIDCParentError)
|
||||
InstanceOIDCSingleV1SessionTerminationEventType = setEventTypeFromFeature(feature.LevelInstance, feature.KeyOIDCSingleV1SessionTermination)
|
||||
InstanceDisableUserTokenEvent = setEventTypeFromFeature(feature.LevelInstance, feature.KeyDisableUserTokenEvent)
|
||||
|
Reference in New Issue
Block a user