mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
fix: reducer for PasskeyVerified sets VerifiedAt (#11929)
# Which Problems Are Solved In https://github.com/zitadel/zitadel/pull/11858#discussion_r2993742914 we discussed on how to translate the ES passkey state to a relational one. That is used to filter out passkeys during convertion to webauthn credentials. It was decided to consider passkeys in ready state those that have a verified at `time.Time` set. The change required fixing the reducer for the eventstore event. # How the Problems Are Solved - Set `VerifiedAt` once `HumanWebAuthNVerifiedEvent` is received - Also set the verification to `nil` # Additional Context - Discussion #11858 - Follow-up for PR #11858
This commit is contained in:
@@ -185,7 +185,7 @@ CREATE TYPE zitadel.passkey_type AS ENUM (
|
||||
CREATE TABLE zitadel.user_passkeys(
|
||||
instance_id TEXT NOT NULL
|
||||
, token_id TEXT NOT NULL
|
||||
, key_id BYTEA NOT NULL
|
||||
, key_id BYTEA
|
||||
|
||||
, user_id TEXT NOT NULL
|
||||
|
||||
@@ -194,12 +194,12 @@ CREATE TABLE zitadel.user_passkeys(
|
||||
, verified_at TIMESTAMPTZ
|
||||
|
||||
, type zitadel.passkey_type NOT NULL
|
||||
, name TEXT NOT NULL CHECK (name <> '')
|
||||
, name TEXT NOT NULL DEFAULT ''
|
||||
, sign_count INT NOT NULL DEFAULT 0 CHECK (sign_count >= 0)
|
||||
, challenge BYTEA NOT NULL
|
||||
, public_key BYTEA NOT NULL
|
||||
, attestation_type TEXT NOT NULL CHECK (attestation_type <> '')
|
||||
, authenticator_attestation_guid BYTEA NOT NULL
|
||||
, public_key BYTEA
|
||||
, attestation_type TEXT NOT NULL
|
||||
, authenticator_attestation_guid BYTEA
|
||||
, relying_party_id TEXT NOT NULL CHECK (relying_party_id <> '')
|
||||
|
||||
, PRIMARY KEY (instance_id, token_id)
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package projection
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -8,7 +10,7 @@ import (
|
||||
func assertEvent[T eventstore.Event](event eventstore.Event) (T, error) {
|
||||
e, ok := event.(T)
|
||||
if !ok {
|
||||
return e, zerrors.ThrowInvalidArgumentf(nil, "HANDL-1m9fS", "reduce.wrong.event.type %T", event)
|
||||
return e, zerrors.CreateZitadelError(zerrors.KindInvalidArgument, nil, "HANDL-1m9fS", fmt.Sprintf("reduce.wrong.event.type %T", event), 1)
|
||||
}
|
||||
return e, nil
|
||||
}
|
||||
|
||||
@@ -1124,6 +1124,7 @@ func (p *relationalTablesProjection) reducePasskeyVerified(event eventstore.Even
|
||||
repo.SetPasskeySignCount(e.SignCount),
|
||||
repo.SetPasskeyName(e.WebAuthNTokenName),
|
||||
repo.SetPasskeyUpdatedAt(e.CreatedAt()),
|
||||
repo.SetPasskeyVerifiedAt(e.CreatedAt()),
|
||||
),
|
||||
repo.SetUpdatedAt(e.CreatedAt()),
|
||||
)
|
||||
|
||||
@@ -181,6 +181,66 @@ func TestUserRelationalProjection_Reducers(t *testing.T) {
|
||||
assert.Zero(t, gotUser.Human.RecoveryCodes.LastSuccessfullyCheckedAt)
|
||||
assert.Equal(t, uint8(1), gotUser.Human.RecoveryCodes.FailedAttempts)
|
||||
})
|
||||
|
||||
t.Run("reduce user.HumanWebAuthNVerifiedEvent event", func(t *testing.T) {
|
||||
// Given
|
||||
|
||||
// create user
|
||||
existingUserID := gofakeit.UUID()
|
||||
existingUserAgg := createUser(t, tx, userRepo, instanceID, orgID, existingUserID)
|
||||
now := time.Now()
|
||||
|
||||
// add passkey to the user
|
||||
pkey := &domain.Passkey{
|
||||
ID: "pkey-id",
|
||||
Challenge: []byte("some challenge"),
|
||||
RelyingPartyID: "rpID",
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Type: domain.PasskeyTypePasswordless,
|
||||
}
|
||||
|
||||
_, err = userRepo.Update(t.Context(), tx,
|
||||
userRepo.PrimaryKeyCondition(instanceID, existingUserID),
|
||||
userRepo.Human().AddPasskey(pkey),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
pkeyVerifiedEvt := user.NewHumanPasswordlessVerifiedEvent(
|
||||
t.Context(),
|
||||
&existingUserAgg.Aggregate,
|
||||
pkey.ID,
|
||||
"some-token-name",
|
||||
"attestation-type",
|
||||
[]byte("key-id"),
|
||||
[]byte("public-key-id"),
|
||||
[]byte("authenticator-attestation-guid"),
|
||||
33,
|
||||
"",
|
||||
)
|
||||
|
||||
// Test
|
||||
eventReduced := callReduce(t, rawTx, handler, pkeyVerifiedEvt)
|
||||
require.True(t, eventReduced)
|
||||
|
||||
// Verify
|
||||
gotUser, err := userRepo.Get(t.Context(), tx, database.WithCondition(
|
||||
database.And(
|
||||
userRepo.IDCondition(existingUserID),
|
||||
userRepo.InstanceIDCondition(instanceID),
|
||||
),
|
||||
))
|
||||
require.NoError(t, err)
|
||||
require.Len(t, gotUser.Human.Passkeys, 1)
|
||||
gotPKey := gotUser.Human.Passkeys[0]
|
||||
assert.Equal(t, pkeyVerifiedEvt.KeyID, gotPKey.KeyID)
|
||||
assert.Equal(t, pkeyVerifiedEvt.PublicKey, gotPKey.PublicKey)
|
||||
assert.Equal(t, pkeyVerifiedEvt.AttestationType, gotPKey.AttestationType)
|
||||
assert.Equal(t, pkeyVerifiedEvt.AAGUID, gotPKey.AuthenticatorAttestationGUID)
|
||||
assert.Equal(t, pkeyVerifiedEvt.SignCount, gotPKey.SignCount)
|
||||
assert.Equal(t, pkeyVerifiedEvt.WebAuthNTokenName, gotPKey.Name)
|
||||
assert.NotZero(t, gotPKey.VerifiedAt)
|
||||
})
|
||||
}
|
||||
|
||||
func createUser(t *testing.T,
|
||||
|
||||
Reference in New Issue
Block a user