perf(oidc): optimize client verification (#6999)

* fix some spelling errors

* client credential auth

* implementation of client auth

* improve error handling

* unit test command package

* unit test database package

* unit test query package

* cleanup unused tracing func

* fix integration tests

* errz to zerrors

* fix linting and import issues

* fix another linting error

* integration test with client secret

* Revert "integration test with client secret"

This reverts commit 0814ba522f.

* add integration tests

* client credentials integration test

* resolve comments

* pin oidc v3.5.0
This commit is contained in:
Tim Möhlmann
2023-12-05 19:01:03 +02:00
committed by GitHub
parent 51cfb9564a
commit ec03340b67
46 changed files with 1666 additions and 781 deletions

View File

@@ -3,8 +3,10 @@ package command
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
@@ -319,212 +321,34 @@ func TestCommandSide_RemoveMachineSecret(t *testing.T) {
}
}
func TestCommandSide_VerifyMachineSecret(t *testing.T) {
type fields struct {
eventstore *eventstore.Eventstore
}
type args struct {
ctx context.Context
userID string
resourceOwner string
secret string
}
type res struct {
want *domain.ObjectDetails
err func(error) bool
}
tests := []struct {
name string
fields fields
args args
res res
}{
{
name: "user invalid, invalid argument error userID",
fields: fields{
eventstore: eventstoreExpect(
t,
),
},
args: args{
ctx: context.Background(),
userID: "",
resourceOwner: "org1",
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
},
},
{
name: "user invalid, invalid argument error resourceowner",
fields: fields{
eventstore: eventstoreExpect(
t,
),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "",
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
},
},
{
name: "user not existing, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(),
),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
},
res: res{
err: caos_errs.IsPreconditionFailed,
},
},
{
name: "user existing without secret, precondition error",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"user1",
"username",
"user",
false,
domain.OIDCTokenTypeBearer,
),
),
),
),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
},
res: res{
err: caos_errs.IsPreconditionFailed,
},
},
{
name: "verify machine secret, ok",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"user1",
"username",
"user",
false,
domain.OIDCTokenTypeBearer,
),
),
eventFromEventPusher(
user.NewMachineSecretSetEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "bcrypt",
KeyID: "id",
Crypted: []byte("$2a$14$HxC7TAXMeowdqHdSBUfsjOUc0IGajYeApxdYl9lAYC0duZmSkgFia"),
},
),
),
),
expectPush(
user.NewMachineSecretCheckSucceededEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
),
),
),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
secret: "test",
},
res: res{
want: &domain.ObjectDetails{
ResourceOwner: "org1",
},
},
},
{
name: "verify machine secret, failed",
fields: fields{
eventstore: eventstoreExpect(
t,
expectFilter(
eventFromEventPusher(
user.NewMachineAddedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
"user1",
"username",
"user",
false,
domain.OIDCTokenTypeBearer,
),
),
eventFromEventPusher(
user.NewMachineSecretSetEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
&crypto.CryptoValue{
CryptoType: crypto.TypeEncryption,
Algorithm: "bcrypt",
KeyID: "id",
Crypted: []byte("$2a$14$HxC7TAXMeowdqHdSBUfsjOUc0IGajYeApxdYl9lAYC0duZmSkgFia"),
},
),
),
),
expectPush(
user.NewMachineSecretCheckFailedEvent(context.Background(),
&user.NewAggregate("user1", "org1").Aggregate,
),
),
),
},
args: args{
ctx: context.Background(),
userID: "user1",
resourceOwner: "org1",
secret: "wrong",
},
res: res{
err: caos_errs.IsErrorInvalidArgument,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Commands{
eventstore: tt.fields.eventstore,
codeAlg: crypto.NewBCrypt(14),
}
got, err := r.VerifyMachineSecret(tt.args.ctx, tt.args.userID, tt.args.resourceOwner, tt.args.secret)
if tt.res.err == nil {
assert.NoError(t, err)
}
if tt.res.err != nil && !tt.res.err(err) {
t.Errorf("got wrong err: %v ", err)
}
if tt.res.err == nil {
assert.Equal(t, tt.res.want, got)
}
})
func TestCommands_MachineSecretCheckSucceeded(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
agg := user.NewAggregate("userID", "orgID")
cmd := user.NewMachineSecretCheckSucceededEvent(ctx, &agg.Aggregate)
c := &Commands{
eventstore: eventstoreExpect(t,
expectPushSlow(time.Second/100, cmd),
),
}
c.MachineSecretCheckSucceeded(ctx, "userID", "orgID")
require.NoError(t, c.Close(ctx))
}
func TestCommands_MachineSecretCheckFailed(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
agg := user.NewAggregate("userID", "orgID")
cmd := user.NewMachineSecretCheckFailedEvent(ctx, &agg.Aggregate)
c := &Commands{
eventstore: eventstoreExpect(t,
expectPushSlow(time.Second/100, cmd),
),
}
c.MachineSecretCheckFailed(ctx, "userID", "orgID")
require.NoError(t, c.Close(ctx))
}