feat: add possibility to set an expiration to a session (#6851)

* add lifetime to session api

* extend session with lifetime

* check session token expiration

* fix typo

* integration test to check session token expiration

* integration test to check session token expiration

* i18n

* cleanup

* improve tests

* prevent negative lifetime

* fix error message

* fix lifetime check
This commit is contained in:
Livio Spring
2023-11-06 11:48:28 +02:00
committed by GitHub
parent ce322323aa
commit f3b8a3aece
35 changed files with 608 additions and 151 deletions

View File

@@ -5,6 +5,7 @@ import (
"github.com/zitadel/zitadel/internal/crypto"
"github.com/zitadel/zitadel/internal/domain"
"github.com/zitadel/zitadel/internal/errors"
"github.com/zitadel/zitadel/internal/eventstore"
"github.com/zitadel/zitadel/internal/repository/session"
)
@@ -48,6 +49,7 @@ type SessionWriteModel struct {
WebAuthNUserVerified bool
Metadata map[string][]byte
State domain.SessionState
Expiration time.Time
WebAuthNChallenge *WebAuthNChallengeModel
OTPSMSCodeChallenge *OTPCode
@@ -94,6 +96,8 @@ func (wm *SessionWriteModel) Reduce() error {
wm.reduceOTPEmailChecked(e)
case *session.TokenSetEvent:
wm.reduceTokenSet(e)
case *session.LifetimeSetEvent:
wm.reduceLifetimeSet(e)
case *session.TerminateEvent:
wm.reduceTerminate()
}
@@ -120,6 +124,7 @@ func (wm *SessionWriteModel) Query() *eventstore.SearchQueryBuilder {
session.OTPEmailCheckedType,
session.TokenSetType,
session.MetadataSetType,
session.LifetimeSetType,
session.TerminateType,
).
Builder()
@@ -196,6 +201,10 @@ func (wm *SessionWriteModel) reduceTokenSet(e *session.TokenSetEvent) {
wm.TokenID = e.TokenID
}
func (wm *SessionWriteModel) reduceLifetimeSet(e *session.LifetimeSetEvent) {
wm.Expiration = e.CreationDate().Add(e.Lifetime)
}
func (wm *SessionWriteModel) reduceTerminate() {
wm.State = domain.SessionStateTerminated
}
@@ -245,3 +254,23 @@ func (wm *SessionWriteModel) AuthMethodTypes() []domain.UserAuthMethodType {
}
return types
}
// CheckNotInvalidated checks that the session was not invalidated either manually ([session.TerminateType])
// or automatically (expired).
func (wm *SessionWriteModel) CheckNotInvalidated() error {
if wm.State == domain.SessionStateTerminated {
return errors.ThrowPreconditionFailed(nil, "COMMAND-Hewfq", "Errors.Session.Terminated")
}
if !wm.Expiration.IsZero() && wm.Expiration.Before(time.Now()) {
return errors.ThrowPreconditionFailed(nil, "COMMAND-Hkl3d", "Errors.Session.Expired")
}
return nil
}
// CheckIsActive checks that the session was not invalidated ([CheckNotInvalidated]) and actually already exists.
func (wm *SessionWriteModel) CheckIsActive() error {
if wm.State == domain.SessionStateUnspecified {
return errors.ThrowPreconditionFailed(nil, "COMMAND-Flk38", "Errors.Session.NotExisting")
}
return wm.CheckNotInvalidated()
}