From 9c9aa58d6afb0b3d2b0b5815bc77e1999110b027 Mon Sep 17 00:00:00 2001 From: Chlins Zhang Date: Tue, 15 Nov 2022 11:30:01 +0800 Subject: [PATCH] feat: support customize session timeout (#17767) Add configuration session_timeout for API, then user can customize the timeout from system config page or API. The timeout is 60 minutes by default. Signed-off-by: chlins Signed-off-by: chlins --- api/v2.0/swagger.yaml | 10 +++++++++- src/common/const.go | 3 +++ src/core/session/session.go | 24 ++++++++++++++++++++---- src/core/session/session_test.go | 8 +++++++- src/lib/config/metadata/metadatalist.go | 2 ++ src/lib/config/userconfig.go | 5 +++++ 6 files changed, 46 insertions(+), 6 deletions(-) diff --git a/api/v2.0/swagger.yaml b/api/v2.0/swagger.yaml index 45decdd95..16428b152 100644 --- a/api/v2.0/swagger.yaml +++ b/api/v2.0/swagger.yaml @@ -8631,6 +8631,9 @@ definitions: type: integer description: 'The offset in seconds of UTC 0 o''clock, only valid when the policy type is "daily"' description: 'The parameters of the policy, the values are dependent on the type of the policy.' + session_timeout: + $ref: '#/definitions/IntegerConfigItem' + description: The session timeout in minutes Configurations: type: object properties: @@ -8883,7 +8886,12 @@ definitions: type: boolean description: Skip audit log database x-omitempty: true - x-isnullable: true + x-isnullable: true + session_timeout: + type: integer + description: The session timeout for harbor, in minutes. + x-omitempty: true + x-isnullable: true StringConfigItem: type: object properties: diff --git a/src/common/const.go b/src/common/const.go index a2e214f62..dd0ce0889 100755 --- a/src/common/const.go +++ b/src/common/const.go @@ -218,4 +218,7 @@ const ( SkipAuditLogDatabase = "skip_audit_log_database" // MaxAuditRetentionHour allowed in audit log purge MaxAuditRetentionHour = 240000 + + // SessionTimeout defines the web session timeout + SessionTimeout = "session_timeout" ) diff --git a/src/core/session/session.go b/src/core/session/session.go index d9d41321f..bca0c2f72 100644 --- a/src/core/session/session.go +++ b/src/core/session/session.go @@ -26,6 +26,7 @@ import ( "github.com/goharbor/harbor/src/lib/cache" "github.com/goharbor/harbor/src/lib/cache/redis" + "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/lib/log" ) @@ -91,8 +92,10 @@ func (rs *Store) SessionRelease(w http.ResponseWriter) { return } + ctx := context.TODO() + maxlifetime := time.Duration(systemSessionTimeout(ctx, rs.maxlifetime)) if rdb, ok := rs.c.(*redis.Cache); ok { - cmd := rdb.Client.Set(context.TODO(), rs.sid, string(b), time.Duration(rs.maxlifetime)) + cmd := rdb.Client.Set(ctx, rs.sid, string(b), maxlifetime) if cmd.Err() != nil { log.Debugf("release session error: %v", err) } @@ -136,8 +139,9 @@ func (rp *Provider) SessionExist(sid string) bool { // SessionRegenerate generate new sid for redis session func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { ctx := context.TODO() + maxlifetime := time.Duration(systemSessionTimeout(ctx, rp.maxlifetime)) if !rp.SessionExist(oldsid) { - err := rp.c.Save(ctx, sid, "", time.Duration(rp.maxlifetime)) + err := rp.c.Save(ctx, sid, "", maxlifetime) if err != nil { log.Debugf("failed to save sid=%s, where oldsid=%s, error: %s", sid, oldsid, err) } @@ -145,7 +149,7 @@ func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) if rdb, ok := rp.c.(*redis.Cache); ok { // redis has rename command rdb.Rename(ctx, oldsid, sid) - rdb.Expire(ctx, sid, time.Duration(rp.maxlifetime)) + rdb.Expire(ctx, sid, maxlifetime) } else { kv := make(map[interface{}]interface{}) err := rp.c.Fetch(ctx, sid, &kv) @@ -157,7 +161,7 @@ func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) if err != nil { log.Debugf("failed to delete oldsid=%s, error: %s", oldsid, err) } - err = rp.c.Save(ctx, sid, kv) + err = rp.c.Save(ctx, sid, kv, maxlifetime) if err != nil { log.Debugf("failed to save sid=%s, error: %s", sid, err) } @@ -181,6 +185,18 @@ func (rp *Provider) SessionAll() int { return 0 } +// systemSessionTimeout return the system session timeout set by user. +func systemSessionTimeout(ctx context.Context, beegoTimeout int64) int64 { + // read from system config if it is meaningful to support change session timeout in runtime for user. + // otherwise, use parameters beegoTimeout which set from beego. + timeout := beegoTimeout + if sysTimeout := config.SessionTimeout(ctx); sysTimeout > 0 { + timeout = sysTimeout * int64(time.Minute) + } + + return timeout +} + func init() { session.Register(HarborProviderName, harborpder) } diff --git a/src/core/session/session_test.go b/src/core/session/session_test.go index bccd365af..85b0c2e81 100644 --- a/src/core/session/session_test.go +++ b/src/core/session/session_test.go @@ -19,6 +19,10 @@ import ( "github.com/beego/beego/session" "github.com/stretchr/testify/suite" + + "github.com/goharbor/harbor/src/lib/config" + _ "github.com/goharbor/harbor/src/pkg/config/db" + _ "github.com/goharbor/harbor/src/pkg/config/inmemory" ) type sessionTestSuite struct { @@ -27,7 +31,9 @@ type sessionTestSuite struct { provider session.Provider } -func (s *sessionTestSuite) SetupTest() { +func (s *sessionTestSuite) SetupSuite() { + config.Init() + var err error s.provider, err = session.GetProvider("harbor") s.NoError(err, "should get harbor provider") diff --git a/src/lib/config/metadata/metadatalist.go b/src/lib/config/metadata/metadatalist.go index 534afcd8d..601abd8ab 100644 --- a/src/lib/config/metadata/metadatalist.go +++ b/src/lib/config/metadata/metadatalist.go @@ -183,5 +183,7 @@ var ( {Name: common.AuditLogForwardEndpoint, Scope: UserScope, Group: BasicGroup, EnvKey: "AUDIT_LOG_FORWARD_ENDPOINT", DefaultValue: "", ItemType: &StringType{}, Editable: false, Description: `The endpoint to forward the audit log.`}, {Name: common.SkipAuditLogDatabase, Scope: UserScope, Group: BasicGroup, EnvKey: "SKIP_LOG_AUDIT_DATABASE", DefaultValue: "false", ItemType: &BoolType{}, Editable: false, Description: `The option to skip audit log in database`}, + + {Name: common.SessionTimeout, Scope: UserScope, Group: BasicGroup, EnvKey: "SESSION_TIMEOUT", DefaultValue: "60", ItemType: &Int64Type{}, Editable: true, Description: `The session timeout in minutes`}, } ) diff --git a/src/lib/config/userconfig.go b/src/lib/config/userconfig.go index cd1adef93..b7a38c3d7 100644 --- a/src/lib/config/userconfig.go +++ b/src/lib/config/userconfig.go @@ -84,6 +84,11 @@ func LDAPGroupConf(ctx context.Context) (*cfgModels.GroupConf, error) { }, nil } +// SessionTimeout returns the session timeout for web (in minute). +func SessionTimeout(ctx context.Context) int64 { + return DefaultMgr().Get(ctx, common.SessionTimeout).GetInt64() +} + // TokenExpiration returns the token expiration time (in minute) func TokenExpiration(ctx context.Context) (int, error) { return DefaultMgr().Get(ctx, common.TokenExpiration).GetInt(), nil