mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-16 21:08:00 +00:00
246 lines
7.1 KiB
Go
246 lines
7.1 KiB
Go
|
//go:build integration
|
||
|
|
||
|
package webkey_test
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"net"
|
||
|
"os"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/stretchr/testify/assert"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
"google.golang.org/grpc"
|
||
|
"google.golang.org/grpc/codes"
|
||
|
"google.golang.org/grpc/credentials/insecure"
|
||
|
"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"
|
||
|
object "github.com/zitadel/zitadel/pkg/grpc/object/v3alpha"
|
||
|
resource_object "github.com/zitadel/zitadel/pkg/grpc/resources/object/v3alpha"
|
||
|
webkey "github.com/zitadel/zitadel/pkg/grpc/resources/webkey/v3alpha"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
CTX context.Context
|
||
|
SystemCTX context.Context
|
||
|
Tester *integration.Tester
|
||
|
)
|
||
|
|
||
|
func TestMain(m *testing.M) {
|
||
|
os.Exit(func() int {
|
||
|
ctx, _, cancel := integration.Contexts(time.Hour)
|
||
|
defer cancel()
|
||
|
|
||
|
Tester = integration.NewTester(ctx)
|
||
|
defer Tester.Done()
|
||
|
|
||
|
SystemCTX = Tester.WithAuthorization(ctx, integration.SystemUser)
|
||
|
CTX = Tester.WithAuthorization(ctx, integration.IAMOwner)
|
||
|
return m.Run()
|
||
|
}())
|
||
|
}
|
||
|
|
||
|
func TestServer_Feature_Disabled(t *testing.T) {
|
||
|
client, iamCTX := createInstanceAndClients(t, false)
|
||
|
|
||
|
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) {
|
||
|
client, iamCtx := createInstanceAndClients(t, true)
|
||
|
// After the feature is first enabled, we can expect 2 generated keys with the default config.
|
||
|
checkWebKeyListState(iamCtx, t, client, 2, "", &webkey.WebKey_Rsa{
|
||
|
Rsa: &webkey.WebKeyRSAConfig{
|
||
|
Bits: webkey.WebKeyRSAConfig_RSA_BITS_2048,
|
||
|
Hasher: webkey.WebKeyRSAConfig_RSA_HASHER_SHA256,
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestServer_CreateWebKey(t *testing.T) {
|
||
|
client, iamCtx := createInstanceAndClients(t, true)
|
||
|
_, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
|
||
|
Key: &webkey.WebKey{
|
||
|
Config: &webkey.WebKey_Rsa{
|
||
|
Rsa: &webkey.WebKeyRSAConfig{
|
||
|
Bits: webkey.WebKeyRSAConfig_RSA_BITS_2048,
|
||
|
Hasher: webkey.WebKeyRSAConfig_RSA_HASHER_SHA256,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
})
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
checkWebKeyListState(iamCtx, t, client, 3, "", &webkey.WebKey_Rsa{
|
||
|
Rsa: &webkey.WebKeyRSAConfig{
|
||
|
Bits: webkey.WebKeyRSAConfig_RSA_BITS_2048,
|
||
|
Hasher: webkey.WebKeyRSAConfig_RSA_HASHER_SHA256,
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestServer_ActivateWebKey(t *testing.T) {
|
||
|
client, iamCtx := createInstanceAndClients(t, true)
|
||
|
resp, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
|
||
|
Key: &webkey.WebKey{
|
||
|
Config: &webkey.WebKey_Rsa{
|
||
|
Rsa: &webkey.WebKeyRSAConfig{
|
||
|
Bits: webkey.WebKeyRSAConfig_RSA_BITS_2048,
|
||
|
Hasher: webkey.WebKeyRSAConfig_RSA_HASHER_SHA256,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
})
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
_, err = client.ActivateWebKey(iamCtx, &webkey.ActivateWebKeyRequest{
|
||
|
Id: resp.GetDetails().GetId(),
|
||
|
})
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
checkWebKeyListState(iamCtx, t, client, 3, resp.GetDetails().GetId(), &webkey.WebKey_Rsa{
|
||
|
Rsa: &webkey.WebKeyRSAConfig{
|
||
|
Bits: webkey.WebKeyRSAConfig_RSA_BITS_2048,
|
||
|
Hasher: webkey.WebKeyRSAConfig_RSA_HASHER_SHA256,
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func TestServer_DeleteWebKey(t *testing.T) {
|
||
|
client, iamCtx := createInstanceAndClients(t, true)
|
||
|
keyIDs := make([]string, 2)
|
||
|
for i := 0; i < 2; i++ {
|
||
|
resp, err := client.CreateWebKey(iamCtx, &webkey.CreateWebKeyRequest{
|
||
|
Key: &webkey.WebKey{
|
||
|
Config: &webkey.WebKey_Rsa{
|
||
|
Rsa: &webkey.WebKeyRSAConfig{
|
||
|
Bits: webkey.WebKeyRSAConfig_RSA_BITS_2048,
|
||
|
Hasher: webkey.WebKeyRSAConfig_RSA_HASHER_SHA256,
|
||
|
},
|
||
|
},
|
||
|
},
|
||
|
})
|
||
|
require.NoError(t, err)
|
||
|
keyIDs[i] = resp.GetDetails().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
|
||
|
}
|
||
|
|
||
|
ok = t.Run("delete inactive key", func(t *testing.T) {
|
||
|
_, err := client.DeleteWebKey(iamCtx, &webkey.DeleteWebKeyRequest{
|
||
|
Id: keyIDs[1],
|
||
|
})
|
||
|
require.NoError(t, err)
|
||
|
})
|
||
|
if !ok {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// There are 2 keys from feature setup, +2 created, -1 deleted = 3
|
||
|
checkWebKeyListState(iamCtx, t, client, 3, keyIDs[0], &webkey.WebKey_Rsa{
|
||
|
Rsa: &webkey.WebKeyRSAConfig{
|
||
|
Bits: webkey.WebKeyRSAConfig_RSA_BITS_2048,
|
||
|
Hasher: webkey.WebKeyRSAConfig_RSA_HASHER_SHA256,
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func createInstanceAndClients(t *testing.T, enableFeature bool) (webkey.ZITADELWebKeysClient, context.Context) {
|
||
|
domain, _, _, iamCTX := Tester.UseIsolatedInstance(t, CTX, SystemCTX)
|
||
|
cc, err := grpc.NewClient(
|
||
|
net.JoinHostPort(domain, "8080"),
|
||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||
|
)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
if enableFeature {
|
||
|
features := feature.NewFeatureServiceClient(cc)
|
||
|
_, err = features.SetInstanceFeatures(iamCTX, &feature.SetInstanceFeaturesRequest{
|
||
|
WebKey: proto.Bool(true),
|
||
|
})
|
||
|
require.NoError(t, err)
|
||
|
time.Sleep(time.Second)
|
||
|
}
|
||
|
|
||
|
return webkey.NewZITADELWebKeysClient(cc), iamCTX
|
||
|
}
|
||
|
|
||
|
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, client webkey.ZITADELWebKeysClient, nKeys int, expectActiveKeyID string, config any) {
|
||
|
resp, err := client.ListWebKeys(ctx, &webkey.ListWebKeysRequest{})
|
||
|
require.NoError(t, err)
|
||
|
list := resp.GetWebKeys()
|
||
|
require.Len(t, list, nKeys)
|
||
|
|
||
|
now := time.Now()
|
||
|
var gotActiveKeyID string
|
||
|
for _, key := range list {
|
||
|
integration.AssertResourceDetails(t, &resource_object.Details{
|
||
|
Created: timestamppb.Now(),
|
||
|
Changed: timestamppb.Now(),
|
||
|
Owner: &object.Owner{
|
||
|
Type: object.OwnerType_OWNER_TYPE_INSTANCE,
|
||
|
Id: Tester.Instance.InstanceID(),
|
||
|
},
|
||
|
}, key.GetDetails())
|
||
|
assert.WithinRange(t, key.GetDetails().GetChanged().AsTime(), now.Add(-time.Minute), now.Add(time.Minute))
|
||
|
assert.NotEqual(t, webkey.WebKeyState_STATE_UNSPECIFIED, key.GetState())
|
||
|
assert.NotEqual(t, webkey.WebKeyState_STATE_REMOVED, key.GetState())
|
||
|
assert.Equal(t, config, key.GetConfig().GetConfig())
|
||
|
|
||
|
if key.GetState() == webkey.WebKeyState_STATE_ACTIVE {
|
||
|
gotActiveKeyID = key.GetDetails().GetId()
|
||
|
}
|
||
|
}
|
||
|
assert.NotEmpty(t, gotActiveKeyID)
|
||
|
if expectActiveKeyID != "" {
|
||
|
assert.Equal(t, expectActiveKeyID, gotActiveKeyID)
|
||
|
}
|
||
|
}
|