feat: api v2beta to api v2 (#8283)

# Which Problems Are Solved

The v2beta services are stable but not GA.

# How the Problems Are Solved

The v2beta services are copied to v2. The corresponding v1 and v2beta
services are deprecated.

# Additional Context

Closes #7236

---------

Co-authored-by: Elio Bischof <elio@zitadel.com>
This commit is contained in:
Stefan Benz
2024-07-26 22:39:55 +02:00
committed by GitHub
parent bc16962aac
commit 7d2d85f57c
142 changed files with 15170 additions and 386 deletions

View File

@@ -5,6 +5,7 @@ package user_test
import (
"context"
"testing"
"time"
"github.com/muhlemmer/gu"
"github.com/stretchr/testify/assert"
@@ -12,9 +13,10 @@ import (
"google.golang.org/protobuf/types/known/structpb"
"google.golang.org/protobuf/types/known/timestamppb"
"github.com/zitadel/zitadel/pkg/grpc/object/v2"
"github.com/zitadel/zitadel/pkg/grpc/user/v2"
"github.com/zitadel/zitadel/internal/integration"
object "github.com/zitadel/zitadel/pkg/grpc/object/v2beta"
user "github.com/zitadel/zitadel/pkg/grpc/user/v2beta"
)
func TestServer_RegisterPasskey(t *testing.T) {
@@ -138,19 +140,7 @@ func TestServer_RegisterPasskey(t *testing.T) {
}
func TestServer_VerifyPasskeyRegistration(t *testing.T) {
userID := Tester.CreateHumanUser(CTX).GetUserId()
reg, err := Client.CreatePasskeyRegistrationLink(CTX, &user.CreatePasskeyRegistrationLinkRequest{
UserId: userID,
Medium: &user.CreatePasskeyRegistrationLinkRequest_ReturnCode{},
})
require.NoError(t, err)
pkr, err := Client.RegisterPasskey(CTX, &user.RegisterPasskeyRequest{
UserId: userID,
Code: reg.GetCode(),
})
require.NoError(t, err)
require.NotEmpty(t, pkr.GetPasskeyId())
require.NotEmpty(t, pkr.GetPublicKeyCredentialCreationOptions())
userID, pkr := userWithPasskeyRegistered(t)
attestationResponse, err := Tester.WebAuthN.CreateAttestationResponse(pkr.GetPublicKeyCredentialCreationOptions())
require.NoError(t, err)
@@ -317,3 +307,291 @@ func TestServer_CreatePasskeyRegistrationLink(t *testing.T) {
})
}
}
func userWithPasskeyRegistered(t *testing.T) (string, *user.RegisterPasskeyResponse) {
userID := Tester.CreateHumanUser(CTX).GetUserId()
return userID, passkeyRegister(t, userID)
}
func userWithPasskeyVerified(t *testing.T) (string, string) {
userID, pkr := userWithPasskeyRegistered(t)
return userID, passkeyVerify(t, userID, pkr)
}
func passkeyRegister(t *testing.T, userID string) *user.RegisterPasskeyResponse {
reg, err := Client.CreatePasskeyRegistrationLink(CTX, &user.CreatePasskeyRegistrationLinkRequest{
UserId: userID,
Medium: &user.CreatePasskeyRegistrationLinkRequest_ReturnCode{},
})
require.NoError(t, err)
pkr, err := Client.RegisterPasskey(CTX, &user.RegisterPasskeyRequest{
UserId: userID,
Code: reg.GetCode(),
})
require.NoError(t, err)
require.NotEmpty(t, pkr.GetPasskeyId())
require.NotEmpty(t, pkr.GetPublicKeyCredentialCreationOptions())
return pkr
}
func passkeyVerify(t *testing.T, userID string, pkr *user.RegisterPasskeyResponse) string {
attestationResponse, err := Tester.WebAuthN.CreateAttestationResponse(pkr.GetPublicKeyCredentialCreationOptions())
require.NoError(t, err)
_, err = Client.VerifyPasskeyRegistration(CTX, &user.VerifyPasskeyRegistrationRequest{
UserId: userID,
PasskeyId: pkr.GetPasskeyId(),
PublicKeyCredential: attestationResponse,
PasskeyName: "nice name",
})
require.NoError(t, err)
return pkr.GetPasskeyId()
}
func TestServer_RemovePasskey(t *testing.T) {
userIDWithout := Tester.CreateHumanUser(CTX).GetUserId()
userIDRegistered, pkrRegistered := userWithPasskeyRegistered(t)
userIDVerified, passkeyIDVerified := userWithPasskeyVerified(t)
userIDVerifiedPermission, passkeyIDVerifiedPermission := userWithPasskeyVerified(t)
type args struct {
ctx context.Context
req *user.RemovePasskeyRequest
}
tests := []struct {
name string
args args
want *user.RemovePasskeyResponse
wantErr bool
}{
{
name: "missing user id",
args: args{
ctx: IamCTX,
req: &user.RemovePasskeyRequest{
PasskeyId: "123",
},
},
wantErr: true,
},
{
name: "missing passkey id",
args: args{
ctx: IamCTX,
req: &user.RemovePasskeyRequest{
UserId: "123",
},
},
wantErr: true,
},
{
name: "success, registered",
args: args{
ctx: IamCTX,
req: &user.RemovePasskeyRequest{
UserId: userIDRegistered,
PasskeyId: pkrRegistered.GetPasskeyId(),
},
},
want: &user.RemovePasskeyResponse{
Details: &object.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Organisation.ID,
},
},
},
{
name: "no passkey, error",
args: args{
ctx: IamCTX,
req: &user.RemovePasskeyRequest{
UserId: userIDWithout,
PasskeyId: pkrRegistered.GetPasskeyId(),
},
},
wantErr: true,
},
{
name: "success, verified",
args: args{
ctx: IamCTX,
req: &user.RemovePasskeyRequest{
UserId: userIDVerified,
PasskeyId: passkeyIDVerified,
},
},
want: &user.RemovePasskeyResponse{
Details: &object.Details{
ChangeDate: timestamppb.Now(),
ResourceOwner: Tester.Organisation.ID,
},
},
},
{
name: "verified, permission error",
args: args{
ctx: UserCTX,
req: &user.RemovePasskeyRequest{
UserId: userIDVerifiedPermission,
PasskeyId: passkeyIDVerifiedPermission,
},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Client.RemovePasskey(tt.args.ctx, tt.args.req)
if tt.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.NotNil(t, got)
integration.AssertDetails(t, tt.want, got)
})
}
}
func TestServer_ListPasskeys(t *testing.T) {
userIDWithout := Tester.CreateHumanUser(CTX).GetUserId()
userIDRegistered, _ := userWithPasskeyRegistered(t)
userIDVerified, passkeyIDVerified := userWithPasskeyVerified(t)
userIDMulti, passkeyIDMulti1 := userWithPasskeyVerified(t)
passkeyIDMulti2 := passkeyVerify(t, userIDMulti, passkeyRegister(t, userIDMulti))
type args struct {
ctx context.Context
req *user.ListPasskeysRequest
}
tests := []struct {
name string
args args
want *user.ListPasskeysResponse
wantErr bool
}{
{
name: "list passkeys, no permission",
args: args{
UserCTX,
&user.ListPasskeysRequest{
UserId: userIDVerified,
},
},
want: &user.ListPasskeysResponse{
Details: &object.ListDetails{
TotalResult: 0,
Timestamp: timestamppb.Now(),
},
Result: []*user.Passkey{},
},
},
{
name: "list passkeys, none",
args: args{
UserCTX,
&user.ListPasskeysRequest{
UserId: userIDWithout,
},
},
want: &user.ListPasskeysResponse{
Details: &object.ListDetails{
TotalResult: 0,
Timestamp: timestamppb.Now(),
},
Result: []*user.Passkey{},
},
},
{
name: "list passkeys, registered",
args: args{
UserCTX,
&user.ListPasskeysRequest{
UserId: userIDRegistered,
},
},
want: &user.ListPasskeysResponse{
Details: &object.ListDetails{
TotalResult: 0,
Timestamp: timestamppb.Now(),
},
Result: []*user.Passkey{},
},
},
{
name: "list passkeys, ok",
args: args{
IamCTX,
&user.ListPasskeysRequest{
UserId: userIDVerified,
},
},
want: &user.ListPasskeysResponse{
Details: &object.ListDetails{
TotalResult: 1,
Timestamp: timestamppb.Now(),
},
Result: []*user.Passkey{
{
Id: passkeyIDVerified,
State: user.AuthFactorState_AUTH_FACTOR_STATE_READY,
Name: "nice name",
},
},
},
},
{
name: "list idp links, multi, ok",
args: args{
IamCTX,
&user.ListPasskeysRequest{
UserId: userIDMulti,
},
},
want: &user.ListPasskeysResponse{
Details: &object.ListDetails{
TotalResult: 2,
Timestamp: timestamppb.Now(),
},
Result: []*user.Passkey{
{
Id: passkeyIDMulti1,
State: user.AuthFactorState_AUTH_FACTOR_STATE_READY,
Name: "nice name",
},
{
Id: passkeyIDMulti2,
State: user.AuthFactorState_AUTH_FACTOR_STATE_READY,
Name: "nice name",
},
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
retryDuration := time.Minute
if ctxDeadline, ok := CTX.Deadline(); ok {
retryDuration = time.Until(ctxDeadline)
}
require.EventuallyWithT(t, func(ttt *assert.CollectT) {
got, listErr := Client.ListPasskeys(tt.args.ctx, tt.args.req)
assertErr := assert.NoError
if tt.wantErr {
assertErr = assert.Error
}
assertErr(ttt, listErr)
if listErr != nil {
return
}
// always first check length, otherwise its failed anyway
assert.Len(ttt, got.Result, len(tt.want.Result))
for i := range tt.want.Result {
assert.Contains(ttt, got.Result, tt.want.Result[i])
}
integration.AssertListDetails(t, tt.want, got)
}, retryDuration, time.Millisecond*100, "timeout waiting for expected idplinks result")
})
}
}