diff --git a/internal/config/layers.go b/internal/config/layers.go index a2d9384..97fc5d3 100644 --- a/internal/config/layers.go +++ b/internal/config/layers.go @@ -21,6 +21,9 @@ func NewDefaultLayersConfig() LayersConfig { Timeout: NewInterpolatedDuration(10 * time.Second), }, }, + Sessions: AuthnLayerSessionConfig{ + TTL: NewInterpolatedDuration(time.Hour), + }, }, } } @@ -31,9 +34,14 @@ type QueueLayerConfig struct { } type AuthnLayerConfig struct { - Debug InterpolatedBool `yaml:"debug"` - TemplateDir InterpolatedString `yaml:"templateDir"` - OIDC AuthnOIDCLayerConfig `yaml:"oidc"` + Debug InterpolatedBool `yaml:"debug"` + TemplateDir InterpolatedString `yaml:"templateDir"` + OIDC AuthnOIDCLayerConfig `yaml:"oidc"` + Sessions AuthnLayerSessionConfig `yaml:"sessions"` +} + +type AuthnLayerSessionConfig struct { + TTL *InterpolatedDuration `yaml:"ttl"` } type AuthnOIDCLayerConfig struct { diff --git a/internal/session/options.go b/internal/session/options.go index 7110beb..cb11072 100644 --- a/internal/session/options.go +++ b/internal/session/options.go @@ -10,6 +10,7 @@ import ( type Options struct { Session sessions.Options KeyPrefix string + TTL time.Duration } type OptionFunc func(opts *Options) @@ -25,6 +26,7 @@ func NewOptions(funcs ...OptionFunc) *Options { SameSite: http.SameSiteDefaultMode, }, KeyPrefix: "session:", + TTL: time.Hour, } for _, fn := range funcs { @@ -45,3 +47,9 @@ func WithKeyPrefix(prefix string) OptionFunc { opts.KeyPrefix = prefix } } + +func WithTTL(ttl time.Duration) OptionFunc { + return func(opts *Options) { + opts.TTL = ttl + } +} diff --git a/internal/session/store.go b/internal/session/store.go index e1ea49e..3a9627f 100644 --- a/internal/session/store.go +++ b/internal/session/store.go @@ -31,6 +31,7 @@ type Store struct { keyPrefix string keyGen KeyGenFunc serializer SessionSerializer + ttl time.Duration } type KeyGenFunc func() (string, error) @@ -43,6 +44,7 @@ func NewStore(adapter StoreAdapter, funcs ...OptionFunc) *Store { keyPrefix: opts.KeyPrefix, keyGen: generateRandomKey, serializer: GobSerializer{}, + ttl: opts.TTL, } return rs @@ -120,7 +122,12 @@ func (s *Store) save(ctx context.Context, session *sessions.Session) error { return errors.WithStack(err) } - if err := s.adapter.Set(ctx, s.keyPrefix+session.ID, b, time.Duration(session.Options.MaxAge)*time.Second); err != nil { + ttl := time.Duration(session.Options.MaxAge) * time.Second + if s.ttl < ttl || ttl == 0 { + ttl = s.ttl + } + + if err := s.adapter.Set(ctx, s.keyPrefix+session.ID, b, ttl); err != nil { return errors.WithStack(err) } diff --git a/misc/packaging/common/config.yml b/misc/packaging/common/config.yml index 85d454d..745ac6a 100644 --- a/misc/packaging/common/config.yml +++ b/misc/packaging/common/config.yml @@ -218,6 +218,11 @@ layers: authn: # Répertoire contenant les templates templateDir: "/etc/bouncer/layers/authn/templates" + # Configuration des sessions + sessions: + # Temps de persistence sans actualisation des sessions dans le store + # (prévalent sur le MaxAge de la session) + ttl: "1h" # Configuration d'une série de proxy/layers # à créer par défaut par le serveur d'administration