fix: prevent intent token reuse and add expiry

(cherry picked from commit b1e60e7398)
This commit is contained in:
Livio Spring
2025-05-02 13:44:24 +02:00
parent 5e48ee2c15
commit 4c5769355b
48 changed files with 673 additions and 123 deletions

View File

@@ -17,6 +17,7 @@ import (
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/id"
"github.com/zitadel/zitadel/internal/notification/senders"
"github.com/zitadel/zitadel/internal/repository/idpintent"
"github.com/zitadel/zitadel/internal/repository/session"
"github.com/zitadel/zitadel/internal/repository/user"
"github.com/zitadel/zitadel/internal/zerrors"
@@ -32,31 +33,33 @@ type SessionCommands struct {
eventstore *eventstore.Eventstore
eventCommands []eventstore.Command
hasher *crypto.Hasher
intentAlg crypto.EncryptionAlgorithm
totpAlg crypto.EncryptionAlgorithm
otpAlg crypto.EncryptionAlgorithm
createCode encryptedCodeWithDefaultFunc
createPhoneCode encryptedCodeGeneratorWithDefaultFunc
createToken func(sessionID string) (id string, token string, err error)
getCodeVerifier func(ctx context.Context, id string) (senders.CodeGenerator, error)
now func() time.Time
hasher *crypto.Hasher
intentAlg crypto.EncryptionAlgorithm
totpAlg crypto.EncryptionAlgorithm
otpAlg crypto.EncryptionAlgorithm
createCode encryptedCodeWithDefaultFunc
createPhoneCode encryptedCodeGeneratorWithDefaultFunc
createToken func(sessionID string) (id string, token string, err error)
getCodeVerifier func(ctx context.Context, id string) (senders.CodeGenerator, error)
now func() time.Time
maxIdPIntentLifetime time.Duration
}
func (c *Commands) NewSessionCommands(cmds []SessionCommand, session *SessionWriteModel) *SessionCommands {
return &SessionCommands{
sessionCommands: cmds,
sessionWriteModel: session,
eventstore: c.eventstore,
hasher: c.userPasswordHasher,
intentAlg: c.idpConfigEncryption,
totpAlg: c.multifactors.OTP.CryptoMFA,
otpAlg: c.userEncryption,
createCode: c.newEncryptedCodeWithDefault,
createPhoneCode: c.newPhoneCode,
createToken: c.sessionTokenCreator,
getCodeVerifier: c.phoneCodeVerifierFromConfig,
now: time.Now,
sessionCommands: cmds,
sessionWriteModel: session,
eventstore: c.eventstore,
hasher: c.userPasswordHasher,
intentAlg: c.idpConfigEncryption,
totpAlg: c.multifactors.OTP.CryptoMFA,
otpAlg: c.userEncryption,
createCode: c.newEncryptedCodeWithDefault,
createPhoneCode: c.newPhoneCode,
createToken: c.sessionTokenCreator,
getCodeVerifier: c.phoneCodeVerifierFromConfig,
now: time.Now,
maxIdPIntentLifetime: c.maxIdPIntentLifetime,
}
}
@@ -92,7 +95,7 @@ func CheckIntent(intentID, token string) SessionCommand {
if err := crypto.CheckToken(cmd.intentAlg, token, intentID); err != nil {
return nil, err
}
cmd.intentWriteModel = NewIDPIntentWriteModel(intentID, "")
cmd.intentWriteModel = NewIDPIntentWriteModel(intentID, "", cmd.maxIdPIntentLifetime)
err := cmd.eventstore.FilterToQueryReducer(ctx, cmd.intentWriteModel)
if err != nil {
return nil, err
@@ -100,6 +103,9 @@ func CheckIntent(intentID, token string) SessionCommand {
if cmd.intentWriteModel.State != domain.IDPIntentStateSucceeded {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-Df4bw", "Errors.Intent.NotSucceeded")
}
if time.Now().After(cmd.intentWriteModel.ExpiresAt()) {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-SAf42", "Errors.Intent.Expired")
}
if cmd.intentWriteModel.UserID != "" {
if cmd.intentWriteModel.UserID != cmd.sessionWriteModel.UserID {
return nil, zerrors.ThrowPreconditionFailed(nil, "COMMAND-O8xk3w", "Errors.Intent.OtherUser")
@@ -168,6 +174,7 @@ func (s *SessionCommands) PasswordChecked(ctx context.Context, checkedAt time.Ti
func (s *SessionCommands) IntentChecked(ctx context.Context, checkedAt time.Time) {
s.eventCommands = append(s.eventCommands, session.NewIntentCheckedEvent(ctx, s.sessionWriteModel.aggregate, checkedAt))
s.eventCommands = append(s.eventCommands, idpintent.NewConsumedEvent(ctx, IDPIntentAggregateFromWriteModel(&s.intentWriteModel.WriteModel)))
}
func (s *SessionCommands) WebAuthNChallenged(ctx context.Context, challenge string, allowedCrentialIDs [][]byte, userVerification domain.UserVerificationRequirement, rpid string) {