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 <chenyuzh@vmware.com>

Signed-off-by: chlins <chenyuzh@vmware.com>
This commit is contained in:
Chlins Zhang 2022-11-15 11:30:01 +08:00 committed by GitHub
parent cf036df68b
commit 9c9aa58d6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 46 additions and 6 deletions

View File

@ -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:
@ -8884,6 +8887,11 @@ definitions:
description: Skip audit log database
x-omitempty: 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:

View File

@ -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"
)

View File

@ -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)
}

View File

@ -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")

View File

@ -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`},
}
)

View File

@ -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