chore!: Introduce ZITADEL v3 (#9645)

This PR summarizes multiple changes specifically only available with
ZITADEL v3:

- feat: Web Keys management
(https://github.com/zitadel/zitadel/pull/9526)
- fix(cmd): ensure proper working of mirror
(https://github.com/zitadel/zitadel/pull/9509)
- feat(Authz): system user support for permission check v2
(https://github.com/zitadel/zitadel/pull/9640)
- chore(license): change from Apache to AGPL
(https://github.com/zitadel/zitadel/pull/9597)
- feat(console): list v2 sessions
(https://github.com/zitadel/zitadel/pull/9539)
- fix(console): add loginV2 feature flag
(https://github.com/zitadel/zitadel/pull/9682)
- fix(feature flags): allow reading "own" flags
(https://github.com/zitadel/zitadel/pull/9649)
- feat(console): add Actions V2 UI
(https://github.com/zitadel/zitadel/pull/9591)

BREAKING CHANGE
- feat(webkey): migrate to v2beta API
(https://github.com/zitadel/zitadel/pull/9445)
- chore!: remove CockroachDB Support
(https://github.com/zitadel/zitadel/pull/9444)
- feat(actions): migrate to v2beta API
(https://github.com/zitadel/zitadel/pull/9489)

---------

Co-authored-by: Livio Spring <livio.a@gmail.com>
Co-authored-by: Stefan Benz <46600784+stebenz@users.noreply.github.com>
Co-authored-by: Silvan <27845747+adlerhurst@users.noreply.github.com>
Co-authored-by: Ramon <mail@conblem.me>
Co-authored-by: Elio Bischof <elio@zitadel.com>
Co-authored-by: Kenta Yamaguchi <56732734+KEY60228@users.noreply.github.com>
Co-authored-by: Harsha Reddy <harsha.reddy@klaviyo.com>
Co-authored-by: Livio Spring <livio@zitadel.com>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: Iraq <66622793+kkrime@users.noreply.github.com>
Co-authored-by: Florian Forster <florian@zitadel.com>
Co-authored-by: Tim Möhlmann <tim+github@zitadel.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Max Peintner <peintnerm@gmail.com>
This commit is contained in:
Fabienne Bühler
2025-04-02 16:53:06 +02:00
committed by GitHub
parent d14a23ae7e
commit 07ce3b6905
559 changed files with 14578 additions and 7622 deletions

View File

@@ -0,0 +1,262 @@
//go:build integration
package webkey_test
import (
"context"
"os"
"testing"
"time"
"github.com/stretchr/testify/assert"
"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"
)
var (
CTX context.Context
)
func TestMain(m *testing.M) {
os.Exit(func() int {
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)
defer cancel()
CTX = ctx
return m.Run()
}())
}
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)
// 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{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
}, creationDate)
}
func TestServer_CreateWebKey(t *testing.T) {
instance, iamCtx, creationDate := createInstance(t, true)
client := instance.Client.WebKeyV2Beta
_, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
Key: &webkey.CreateWebKeyRequest_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
},
})
require.NoError(t, err)
checkWebKeyListState(iamCtx, t, instance, 3, "", &webkey.WebKey_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
}, creationDate)
}
func TestServer_ActivateWebKey(t *testing.T) {
instance, iamCtx, creationDate := createInstance(t, true)
client := instance.Client.WebKeyV2Beta
resp, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
Key: &webkey.CreateWebKeyRequest_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
},
})
require.NoError(t, err)
_, err = client.ActivateWebKey(iamCtx, &webkey.ActivateWebKeyRequest{
Id: resp.GetId(),
})
require.NoError(t, err)
checkWebKeyListState(iamCtx, t, instance, 3, resp.GetId(), &webkey.WebKey_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
}, creationDate)
}
func TestServer_DeleteWebKey(t *testing.T) {
instance, iamCtx, creationDate := createInstance(t, true)
client := instance.Client.WebKeyV2Beta
keyIDs := make([]string, 2)
for i := 0; i < 2; i++ {
resp, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
Key: &webkey.CreateWebKeyRequest_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
},
})
require.NoError(t, err)
keyIDs[i] = resp.GetId()
}
_, err := client.ActivateWebKey(iamCtx, &webkey.ActivateWebKeyRequest{
Id: keyIDs[0],
})
require.NoError(t, err)
ok := t.Run("cannot delete active key", func(t *testing.T) {
_, err := client.DeleteWebKey(iamCtx, &webkey.DeleteWebKeyRequest{
Id: keyIDs[0],
})
require.Error(t, err)
s := status.Convert(err)
assert.Equal(t, codes.FailedPrecondition, s.Code())
assert.Contains(t, s.Message(), "COMMAND-Chai1")
})
if !ok {
return
}
start := time.Now()
ok = t.Run("delete inactive key", func(t *testing.T) {
resp, err := client.DeleteWebKey(iamCtx, &webkey.DeleteWebKeyRequest{
Id: keyIDs[1],
})
require.NoError(t, err)
require.WithinRange(t, resp.GetDeletionDate().AsTime(), start, time.Now())
})
if !ok {
return
}
ok = t.Run("delete inactive key again", func(t *testing.T) {
resp, err := client.DeleteWebKey(iamCtx, &webkey.DeleteWebKeyRequest{
Id: keyIDs[1],
})
require.NoError(t, err)
require.WithinRange(t, resp.GetDeletionDate().AsTime(), start, time.Now())
})
if !ok {
return
}
ok = t.Run("delete not existing key", func(t *testing.T) {
resp, err := client.DeleteWebKey(iamCtx, &webkey.DeleteWebKeyRequest{
Id: "not-existing",
})
require.NoError(t, err)
require.Nil(t, resp.DeletionDate)
})
if !ok {
return
}
// There are 2 keys from feature setup, +2 created, -1 deleted = 3
checkWebKeyListState(iamCtx, t, instance, 3, keyIDs[0], &webkey.WebKey_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
}, creationDate)
}
func createInstance(t *testing.T, enableFeature bool) (*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)
}
}, 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()
retryDuration, tick := integration.WaitForAndTickWithMaxDuration(ctx, time.Minute)
assert.EventuallyWithT(t, func(collect *assert.CollectT) {
resp, err := instance.Client.WebKeyV2Beta.ListWebKeys(ctx, &webkey.ListWebKeysRequest{})
require.NoError(collect, err)
list := resp.GetWebKeys()
assert.Len(collect, list, nKeys)
now := time.Now()
var gotActiveKeyID string
for _, key := range list {
assert.WithinRange(collect, key.GetCreationDate().AsTime(), now.Add(-time.Minute), now.Add(time.Minute))
assert.WithinRange(collect, key.GetChangeDate().AsTime(), now.Add(-time.Minute), now.Add(time.Minute))
assert.NotEqual(collect, webkey.State_STATE_UNSPECIFIED, key.GetState())
assert.NotEqual(collect, webkey.State_STATE_REMOVED, key.GetState())
assert.Equal(collect, config, key.GetKey())
if key.GetState() == webkey.State_STATE_ACTIVE {
gotActiveKeyID = key.GetId()
}
}
assert.NotEmpty(collect, gotActiveKeyID)
if expectActiveKeyID != "" {
assert.Equal(collect, expectActiveKeyID, gotActiveKeyID)
}
}, retryDuration, tick)
}

View File

@@ -0,0 +1,47 @@
package webkey
import (
"google.golang.org/grpc"
"github.com/zitadel/zitadel/internal/api/authz"
"github.com/zitadel/zitadel/internal/api/grpc/server"
"github.com/zitadel/zitadel/internal/command"
"github.com/zitadel/zitadel/internal/query"
webkey "github.com/zitadel/zitadel/pkg/grpc/webkey/v2beta"
)
type Server struct {
webkey.UnimplementedWebKeyServiceServer
command *command.Commands
query *query.Queries
}
func CreateServer(
command *command.Commands,
query *query.Queries,
) *Server {
return &Server{
command: command,
query: query,
}
}
func (s *Server) RegisterServer(grpcServer *grpc.Server) {
webkey.RegisterWebKeyServiceServer(grpcServer, s)
}
func (s *Server) AppName() string {
return webkey.WebKeyService_ServiceDesc.ServiceName
}
func (s *Server) MethodPrefix() string {
return webkey.WebKeyService_ServiceDesc.ServiceName
}
func (s *Server) AuthMethods() authz.MethodMapping {
return webkey.WebKeyService_AuthMethods
}
func (s *Server) RegisterGateway() server.RegisterGatewayFunc {
return webkey.RegisterWebKeyServiceHandler
}

View File

@@ -0,0 +1,92 @@
package webkey
import (
"context"
"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"
)
func (s *Server) CreateWebKey(ctx context.Context, req *webkey.CreateWebKeyRequest) (_ *webkey.CreateWebKeyResponse, err error) {
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
}
return &webkey.CreateWebKeyResponse{
Id: webKey.KeyID,
CreationDate: timestamppb.New(webKey.ObjectDetails.EventDate),
}, nil
}
func (s *Server) ActivateWebKey(ctx context.Context, req *webkey.ActivateWebKeyRequest) (_ *webkey.ActivateWebKeyResponse, err error) {
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
}
return &webkey.ActivateWebKeyResponse{
ChangeDate: timestamppb.New(details.EventDate),
}, nil
}
func (s *Server) DeleteWebKey(ctx context.Context, req *webkey.DeleteWebKeyRequest) (_ *webkey.DeleteWebKeyResponse, err error) {
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
}
var deletionDate *timestamppb.Timestamp
if !deletedAt.IsZero() {
deletionDate = timestamppb.New(deletedAt)
}
return &webkey.DeleteWebKeyResponse{
DeletionDate: deletionDate,
}, nil
}
func (s *Server) ListWebKeys(ctx context.Context, _ *webkey.ListWebKeysRequest) (_ *webkey.ListWebKeysResponse, err error) {
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
}
return &webkey.ListWebKeysResponse{
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
}

View File

@@ -0,0 +1,170 @@
package webkey
import (
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
webkey "github.com/zitadel/zitadel/pkg/grpc/webkey/v2beta"
)
func createWebKeyRequestToConfig(req *webkey.CreateWebKeyRequest) crypto.WebKeyConfig {
switch config := req.GetKey().(type) {
case *webkey.CreateWebKeyRequest_Rsa:
return rsaToCrypto(config.Rsa)
case *webkey.CreateWebKeyRequest_Ecdsa:
return ecdsaToCrypto(config.Ecdsa)
case *webkey.CreateWebKeyRequest_Ed25519:
return new(crypto.WebKeyED25519Config)
default:
return rsaToCrypto(nil)
}
}
func rsaToCrypto(config *webkey.RSA) *crypto.WebKeyRSAConfig {
out := new(crypto.WebKeyRSAConfig)
switch config.GetBits() {
case webkey.RSABits_RSA_BITS_UNSPECIFIED:
out.Bits = crypto.RSABits2048
case webkey.RSABits_RSA_BITS_2048:
out.Bits = crypto.RSABits2048
case webkey.RSABits_RSA_BITS_3072:
out.Bits = crypto.RSABits3072
case webkey.RSABits_RSA_BITS_4096:
out.Bits = crypto.RSABits4096
default:
out.Bits = crypto.RSABits2048
}
switch config.GetHasher() {
case webkey.RSAHasher_RSA_HASHER_UNSPECIFIED:
out.Hasher = crypto.RSAHasherSHA256
case webkey.RSAHasher_RSA_HASHER_SHA256:
out.Hasher = crypto.RSAHasherSHA256
case webkey.RSAHasher_RSA_HASHER_SHA384:
out.Hasher = crypto.RSAHasherSHA384
case webkey.RSAHasher_RSA_HASHER_SHA512:
out.Hasher = crypto.RSAHasherSHA512
default:
out.Hasher = crypto.RSAHasherSHA256
}
return out
}
func ecdsaToCrypto(config *webkey.ECDSA) *crypto.WebKeyECDSAConfig {
out := new(crypto.WebKeyECDSAConfig)
switch config.GetCurve() {
case webkey.ECDSACurve_ECDSA_CURVE_UNSPECIFIED:
out.Curve = crypto.EllipticCurveP256
case webkey.ECDSACurve_ECDSA_CURVE_P256:
out.Curve = crypto.EllipticCurveP256
case webkey.ECDSACurve_ECDSA_CURVE_P384:
out.Curve = crypto.EllipticCurveP384
case webkey.ECDSACurve_ECDSA_CURVE_P512:
out.Curve = crypto.EllipticCurveP512
default:
out.Curve = crypto.EllipticCurveP256
}
return out
}
func webKeyDetailsListToPb(list []query.WebKeyDetails) []*webkey.WebKey {
out := make([]*webkey.WebKey, len(list))
for i := range list {
out[i] = webKeyDetailsToPb(&list[i])
}
return out
}
func webKeyDetailsToPb(details *query.WebKeyDetails) *webkey.WebKey {
out := &webkey.WebKey{
Id: details.KeyID,
CreationDate: timestamppb.New(details.CreationDate),
ChangeDate: timestamppb.New(details.ChangeDate),
State: webKeyStateToPb(details.State),
}
switch config := details.Config.(type) {
case *crypto.WebKeyRSAConfig:
out.Key = &webkey.WebKey_Rsa{
Rsa: webKeyRSAConfigToPb(config),
}
case *crypto.WebKeyECDSAConfig:
out.Key = &webkey.WebKey_Ecdsa{
Ecdsa: webKeyECDSAConfigToPb(config),
}
case *crypto.WebKeyED25519Config:
out.Key = &webkey.WebKey_Ed25519{
Ed25519: new(webkey.ED25519),
}
}
return out
}
func webKeyStateToPb(state domain.WebKeyState) webkey.State {
switch state {
case domain.WebKeyStateUnspecified:
return webkey.State_STATE_UNSPECIFIED
case domain.WebKeyStateInitial:
return webkey.State_STATE_INITIAL
case domain.WebKeyStateActive:
return webkey.State_STATE_ACTIVE
case domain.WebKeyStateInactive:
return webkey.State_STATE_INACTIVE
case domain.WebKeyStateRemoved:
return webkey.State_STATE_REMOVED
default:
return webkey.State_STATE_UNSPECIFIED
}
}
func webKeyRSAConfigToPb(config *crypto.WebKeyRSAConfig) *webkey.RSA {
out := new(webkey.RSA)
switch config.Bits {
case crypto.RSABitsUnspecified:
out.Bits = webkey.RSABits_RSA_BITS_UNSPECIFIED
case crypto.RSABits2048:
out.Bits = webkey.RSABits_RSA_BITS_2048
case crypto.RSABits3072:
out.Bits = webkey.RSABits_RSA_BITS_3072
case crypto.RSABits4096:
out.Bits = webkey.RSABits_RSA_BITS_4096
}
switch config.Hasher {
case crypto.RSAHasherUnspecified:
out.Hasher = webkey.RSAHasher_RSA_HASHER_UNSPECIFIED
case crypto.RSAHasherSHA256:
out.Hasher = webkey.RSAHasher_RSA_HASHER_SHA256
case crypto.RSAHasherSHA384:
out.Hasher = webkey.RSAHasher_RSA_HASHER_SHA384
case crypto.RSAHasherSHA512:
out.Hasher = webkey.RSAHasher_RSA_HASHER_SHA512
}
return out
}
func webKeyECDSAConfigToPb(config *crypto.WebKeyECDSAConfig) *webkey.ECDSA {
out := new(webkey.ECDSA)
switch config.Curve {
case crypto.EllipticCurveUnspecified:
out.Curve = webkey.ECDSACurve_ECDSA_CURVE_UNSPECIFIED
case crypto.EllipticCurveP256:
out.Curve = webkey.ECDSACurve_ECDSA_CURVE_P256
case crypto.EllipticCurveP384:
out.Curve = webkey.ECDSACurve_ECDSA_CURVE_P384
case crypto.EllipticCurveP512:
out.Curve = webkey.ECDSACurve_ECDSA_CURVE_P512
}
return out
}

View File

@@ -0,0 +1,494 @@
package webkey
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/query"
webkey "github.com/zitadel/zitadel/pkg/grpc/webkey/v2beta"
)
func Test_createWebKeyRequestToConfig(t *testing.T) {
type args struct {
req *webkey.CreateWebKeyRequest
}
tests := []struct {
name string
args args
want crypto.WebKeyConfig
}{
{
name: "RSA",
args: args{&webkey.CreateWebKeyRequest{
Key: &webkey.CreateWebKeyRequest_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_3072,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA384,
},
},
}},
want: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits3072,
Hasher: crypto.RSAHasherSHA384,
},
},
{
name: "ECDSA",
args: args{&webkey.CreateWebKeyRequest{
Key: &webkey.CreateWebKeyRequest_Ecdsa{
Ecdsa: &webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P384,
},
},
}},
want: &crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP384,
},
},
{
name: "ED25519",
args: args{&webkey.CreateWebKeyRequest{
Key: &webkey.CreateWebKeyRequest_Ed25519{
Ed25519: &webkey.ED25519{},
},
}},
want: &crypto.WebKeyED25519Config{},
},
{
name: "default",
args: args{&webkey.CreateWebKeyRequest{}},
want: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits2048,
Hasher: crypto.RSAHasherSHA256,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := createWebKeyRequestToConfig(tt.args.req)
assert.Equal(t, tt.want, got)
})
}
}
func Test_webKeyRSAConfigToCrypto(t *testing.T) {
type args struct {
config *webkey.RSA
}
tests := []struct {
name string
args args
want *crypto.WebKeyRSAConfig
}{
{
name: "unspecified",
args: args{&webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_UNSPECIFIED,
Hasher: webkey.RSAHasher_RSA_HASHER_UNSPECIFIED,
}},
want: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits2048,
Hasher: crypto.RSAHasherSHA256,
},
},
{
name: "2048, RSA256",
args: args{&webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
}},
want: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits2048,
Hasher: crypto.RSAHasherSHA256,
},
},
{
name: "3072, RSA384",
args: args{&webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_3072,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA384,
}},
want: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits3072,
Hasher: crypto.RSAHasherSHA384,
},
},
{
name: "4096, RSA512",
args: args{&webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_4096,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA512,
}},
want: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits4096,
Hasher: crypto.RSAHasherSHA512,
},
},
{
name: "invalid",
args: args{&webkey.RSA{
Bits: 99,
Hasher: 99,
}},
want: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits2048,
Hasher: crypto.RSAHasherSHA256,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := rsaToCrypto(tt.args.config)
assert.Equal(t, tt.want, got)
})
}
}
func Test_webKeyECDSAConfigToCrypto(t *testing.T) {
type args struct {
config *webkey.ECDSA
}
tests := []struct {
name string
args args
want *crypto.WebKeyECDSAConfig
}{
{
name: "unspecified",
args: args{&webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_UNSPECIFIED,
}},
want: &crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP256,
},
},
{
name: "P256",
args: args{&webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P256,
}},
want: &crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP256,
},
},
{
name: "P384",
args: args{&webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P384,
}},
want: &crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP384,
},
},
{
name: "P512",
args: args{&webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P512,
}},
want: &crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP512,
},
},
{
name: "invalid",
args: args{&webkey.ECDSA{
Curve: 99,
}},
want: &crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP256,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := ecdsaToCrypto(tt.args.config)
assert.Equal(t, tt.want, got)
})
}
}
func Test_webKeyDetailsListToPb(t *testing.T) {
list := []query.WebKeyDetails{
{
KeyID: "key1",
CreationDate: time.Unix(123, 456),
ChangeDate: time.Unix(789, 0),
Sequence: 123,
State: domain.WebKeyStateActive,
Config: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits3072,
Hasher: crypto.RSAHasherSHA384,
},
},
{
KeyID: "key2",
CreationDate: time.Unix(123, 456),
ChangeDate: time.Unix(789, 0),
Sequence: 123,
State: domain.WebKeyStateActive,
Config: &crypto.WebKeyED25519Config{},
},
}
want := []*webkey.WebKey{
{
Id: "key1",
CreationDate: &timestamppb.Timestamp{Seconds: 123, Nanos: 456},
ChangeDate: &timestamppb.Timestamp{Seconds: 789, Nanos: 0},
State: webkey.State_STATE_ACTIVE,
Key: &webkey.WebKey_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_3072,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA384,
},
},
},
{
Id: "key2",
CreationDate: &timestamppb.Timestamp{Seconds: 123, Nanos: 456},
ChangeDate: &timestamppb.Timestamp{Seconds: 789, Nanos: 0},
State: webkey.State_STATE_ACTIVE,
Key: &webkey.WebKey_Ed25519{
Ed25519: &webkey.ED25519{},
},
},
}
got := webKeyDetailsListToPb(list)
assert.Equal(t, want, got)
}
func Test_webKeyDetailsToPb(t *testing.T) {
type args struct {
details *query.WebKeyDetails
}
tests := []struct {
name string
args args
want *webkey.WebKey
}{
{
name: "RSA",
args: args{&query.WebKeyDetails{
KeyID: "keyID",
CreationDate: time.Unix(123, 456),
ChangeDate: time.Unix(789, 0),
Sequence: 123,
State: domain.WebKeyStateActive,
Config: &crypto.WebKeyRSAConfig{
Bits: crypto.RSABits3072,
Hasher: crypto.RSAHasherSHA384,
},
}},
want: &webkey.WebKey{
Id: "keyID",
CreationDate: &timestamppb.Timestamp{Seconds: 123, Nanos: 456},
ChangeDate: &timestamppb.Timestamp{Seconds: 789, Nanos: 0},
State: webkey.State_STATE_ACTIVE,
Key: &webkey.WebKey_Rsa{
Rsa: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_3072,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA384,
},
},
},
},
{
name: "ECDSA",
args: args{&query.WebKeyDetails{
KeyID: "keyID",
CreationDate: time.Unix(123, 456),
ChangeDate: time.Unix(789, 0),
Sequence: 123,
State: domain.WebKeyStateActive,
Config: &crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP384,
},
}},
want: &webkey.WebKey{
Id: "keyID",
CreationDate: &timestamppb.Timestamp{Seconds: 123, Nanos: 456},
ChangeDate: &timestamppb.Timestamp{Seconds: 789, Nanos: 0},
State: webkey.State_STATE_ACTIVE,
Key: &webkey.WebKey_Ecdsa{
Ecdsa: &webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P384,
},
},
},
},
{
name: "ED25519",
args: args{&query.WebKeyDetails{
KeyID: "keyID",
CreationDate: time.Unix(123, 456),
ChangeDate: time.Unix(789, 0),
Sequence: 123,
State: domain.WebKeyStateActive,
Config: &crypto.WebKeyED25519Config{},
}},
want: &webkey.WebKey{
Id: "keyID",
CreationDate: &timestamppb.Timestamp{Seconds: 123, Nanos: 456},
ChangeDate: &timestamppb.Timestamp{Seconds: 789, Nanos: 0},
State: webkey.State_STATE_ACTIVE,
Key: &webkey.WebKey_Ed25519{
Ed25519: &webkey.ED25519{},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := webKeyDetailsToPb(tt.args.details)
assert.Equal(t, tt.want, got)
})
}
}
func Test_webKeyStateToPb(t *testing.T) {
type args struct {
state domain.WebKeyState
}
tests := []struct {
name string
args args
want webkey.State
}{
{
name: "unspecified",
args: args{domain.WebKeyStateUnspecified},
want: webkey.State_STATE_UNSPECIFIED,
},
{
name: "initial",
args: args{domain.WebKeyStateInitial},
want: webkey.State_STATE_INITIAL,
},
{
name: "active",
args: args{domain.WebKeyStateActive},
want: webkey.State_STATE_ACTIVE,
},
{
name: "inactive",
args: args{domain.WebKeyStateInactive},
want: webkey.State_STATE_INACTIVE,
},
{
name: "removed",
args: args{domain.WebKeyStateRemoved},
want: webkey.State_STATE_REMOVED,
},
{
name: "invalid",
args: args{99},
want: webkey.State_STATE_UNSPECIFIED,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := webKeyStateToPb(tt.args.state)
assert.Equal(t, tt.want, got)
})
}
}
func Test_webKeyRSAConfigToPb(t *testing.T) {
type args struct {
config *crypto.WebKeyRSAConfig
}
tests := []struct {
name string
args args
want *webkey.RSA
}{
{
name: "2048, RSA256",
args: args{&crypto.WebKeyRSAConfig{
Bits: crypto.RSABits2048,
Hasher: crypto.RSAHasherSHA256,
}},
want: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_2048,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA256,
},
},
{
name: "3072, RSA384",
args: args{&crypto.WebKeyRSAConfig{
Bits: crypto.RSABits3072,
Hasher: crypto.RSAHasherSHA384,
}},
want: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_3072,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA384,
},
},
{
name: "4096, RSA512",
args: args{&crypto.WebKeyRSAConfig{
Bits: crypto.RSABits4096,
Hasher: crypto.RSAHasherSHA512,
}},
want: &webkey.RSA{
Bits: webkey.RSABits_RSA_BITS_4096,
Hasher: webkey.RSAHasher_RSA_HASHER_SHA512,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := webKeyRSAConfigToPb(tt.args.config)
assert.Equal(t, tt.want, got)
})
}
}
func Test_webKeyECDSAConfigToPb(t *testing.T) {
type args struct {
config *crypto.WebKeyECDSAConfig
}
tests := []struct {
name string
args args
want *webkey.ECDSA
}{
{
name: "P256",
args: args{&crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP256,
}},
want: &webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P256,
},
},
{
name: "P384",
args: args{&crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP384,
}},
want: &webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P384,
},
},
{
name: "P512",
args: args{&crypto.WebKeyECDSAConfig{
Curve: crypto.EllipticCurveP512,
}},
want: &webkey.ECDSA{
Curve: webkey.ECDSACurve_ECDSA_CURVE_P512,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := webKeyECDSAConfigToPb(tt.args.config)
assert.Equal(t, tt.want, got)
})
}
}