PLT-7633 (E20) Add session idle timeout config setting (#7524)
* Add session idle timeout config setting * Modify config setting name to SessionIdleTimeoutInMinutes * Small re-org of if statement * Merge with latest master
Этот коммит содержится в:
коммит произвёл
George Goldberg
родитель
8d662105d3
Коммит
15b361094a
@@ -157,6 +157,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
c.Err = model.NewAppError("ServeHTTP", "api.context.token_provided.app_error", nil, "token="+token, http.StatusUnauthorized)
|
c.Err = model.NewAppError("ServeHTTP", "api.context.token_provided.app_error", nil, "token="+token, http.StatusUnauthorized)
|
||||||
} else {
|
} else {
|
||||||
c.Session = *session
|
c.Session = *session
|
||||||
|
c.App.UpdateLastActivityAtIfNeeded(*session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,18 @@ func (a *App) GetSession(token string) (*model.Session, *model.AppError) {
|
|||||||
return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "", http.StatusUnauthorized)
|
return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "", http.StatusUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if *utils.Cfg.ServiceSettings.SessionIdleTimeoutInMinutes > 0 &&
|
||||||
|
utils.IsLicensed() && *utils.License().Features.Compliance &&
|
||||||
|
session != nil && !session.IsOAuth && !session.IsMobileApp() &&
|
||||||
|
session.Props[model.SESSION_PROP_TYPE] != model.SESSION_TYPE_USER_ACCESS_TOKEN {
|
||||||
|
|
||||||
|
timeout := int64(*utils.Cfg.ServiceSettings.SessionIdleTimeoutInMinutes) * 1000 * 60
|
||||||
|
if model.GetMillis()-session.LastActivityAt > timeout {
|
||||||
|
a.RevokeSessionById(session.Id)
|
||||||
|
return nil, model.NewAppError("GetSession", "api.context.invalid_token.error", map[string]interface{}{"Token": token}, "idle timeout", http.StatusUnauthorized)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return session, nil
|
return session, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/model"
|
"github.com/mattermost/mattermost-server/model"
|
||||||
|
"github.com/mattermost/mattermost-server/utils"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCache(t *testing.T) {
|
func TestCache(t *testing.T) {
|
||||||
@@ -32,3 +36,118 @@ func TestCache(t *testing.T) {
|
|||||||
t.Fatal("should have one less")
|
t.Fatal("should have one less")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetSessionIdleTimeoutInMinutes(t *testing.T) {
|
||||||
|
th := Setup().InitBasic()
|
||||||
|
|
||||||
|
session := &model.Session{
|
||||||
|
UserId: model.NewId(),
|
||||||
|
}
|
||||||
|
|
||||||
|
session, _ = th.App.CreateSession(session)
|
||||||
|
|
||||||
|
isLicensed := utils.IsLicensed()
|
||||||
|
license := utils.License()
|
||||||
|
timeout := *utils.Cfg.ServiceSettings.SessionIdleTimeoutInMinutes
|
||||||
|
defer func() {
|
||||||
|
utils.SetIsLicensed(isLicensed)
|
||||||
|
utils.SetLicense(license)
|
||||||
|
*utils.Cfg.ServiceSettings.SessionIdleTimeoutInMinutes = timeout
|
||||||
|
}()
|
||||||
|
utils.SetIsLicensed(true)
|
||||||
|
utils.SetLicense(&model.License{Features: &model.Features{}})
|
||||||
|
utils.License().Features.SetDefaults()
|
||||||
|
*utils.License().Features.Compliance = true
|
||||||
|
*utils.Cfg.ServiceSettings.SessionIdleTimeoutInMinutes = 5
|
||||||
|
|
||||||
|
rsession, err := th.App.GetSession(session.Token)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, rsession.Id, session.Id)
|
||||||
|
|
||||||
|
rsession, err = th.App.GetSession(session.Token)
|
||||||
|
|
||||||
|
// Test regular session, should timeout
|
||||||
|
time := session.LastActivityAt - (1000 * 60 * 6)
|
||||||
|
<-th.App.Srv.Store.Session().UpdateLastActivityAt(session.Id, time)
|
||||||
|
th.App.ClearSessionCacheForUserSkipClusterSend(session.UserId)
|
||||||
|
|
||||||
|
rsession, err = th.App.GetSession(session.Token)
|
||||||
|
require.NotNil(t, err)
|
||||||
|
assert.Equal(t, "api.context.invalid_token.error", err.Id)
|
||||||
|
assert.Equal(t, "idle timeout", err.DetailedError)
|
||||||
|
assert.Nil(t, rsession)
|
||||||
|
|
||||||
|
// Test mobile session, should not timeout
|
||||||
|
session = &model.Session{
|
||||||
|
UserId: model.NewId(),
|
||||||
|
DeviceId: "android:" + model.NewId(),
|
||||||
|
}
|
||||||
|
|
||||||
|
session, _ = th.App.CreateSession(session)
|
||||||
|
time = session.LastActivityAt - (1000 * 60 * 6)
|
||||||
|
<-th.App.Srv.Store.Session().UpdateLastActivityAt(session.Id, time)
|
||||||
|
th.App.ClearSessionCacheForUserSkipClusterSend(session.UserId)
|
||||||
|
|
||||||
|
_, err = th.App.GetSession(session.Token)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// Test oauth session, should not timeout
|
||||||
|
session = &model.Session{
|
||||||
|
UserId: model.NewId(),
|
||||||
|
IsOAuth: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
session, _ = th.App.CreateSession(session)
|
||||||
|
time = session.LastActivityAt - (1000 * 60 * 6)
|
||||||
|
<-th.App.Srv.Store.Session().UpdateLastActivityAt(session.Id, time)
|
||||||
|
th.App.ClearSessionCacheForUserSkipClusterSend(session.UserId)
|
||||||
|
|
||||||
|
_, err = th.App.GetSession(session.Token)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// Test personal access token session, should not timeout
|
||||||
|
session = &model.Session{
|
||||||
|
UserId: model.NewId(),
|
||||||
|
}
|
||||||
|
session.AddProp(model.SESSION_PROP_TYPE, model.SESSION_TYPE_USER_ACCESS_TOKEN)
|
||||||
|
|
||||||
|
session, _ = th.App.CreateSession(session)
|
||||||
|
time = session.LastActivityAt - (1000 * 60 * 6)
|
||||||
|
<-th.App.Srv.Store.Session().UpdateLastActivityAt(session.Id, time)
|
||||||
|
th.App.ClearSessionCacheForUserSkipClusterSend(session.UserId)
|
||||||
|
|
||||||
|
_, err = th.App.GetSession(session.Token)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
// Test regular session with license off, should not timeout
|
||||||
|
*utils.License().Features.Compliance = false
|
||||||
|
|
||||||
|
session = &model.Session{
|
||||||
|
UserId: model.NewId(),
|
||||||
|
}
|
||||||
|
|
||||||
|
session, _ = th.App.CreateSession(session)
|
||||||
|
time = session.LastActivityAt - (1000 * 60 * 6)
|
||||||
|
<-th.App.Srv.Store.Session().UpdateLastActivityAt(session.Id, time)
|
||||||
|
th.App.ClearSessionCacheForUserSkipClusterSend(session.UserId)
|
||||||
|
|
||||||
|
_, err = th.App.GetSession(session.Token)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
|
*utils.License().Features.Compliance = true
|
||||||
|
|
||||||
|
// Test regular session with timeout set to 0, should not timeout
|
||||||
|
*utils.Cfg.ServiceSettings.SessionIdleTimeoutInMinutes = 0
|
||||||
|
|
||||||
|
session = &model.Session{
|
||||||
|
UserId: model.NewId(),
|
||||||
|
}
|
||||||
|
|
||||||
|
session, _ = th.App.CreateSession(session)
|
||||||
|
time = session.LastActivityAt - (1000 * 60 * 6)
|
||||||
|
<-th.App.Srv.Store.Session().UpdateLastActivityAt(session.Id, time)
|
||||||
|
th.App.ClearSessionCacheForUserSkipClusterSend(session.UserId)
|
||||||
|
|
||||||
|
_, err = th.App.GetSession(session.Token)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@
|
|||||||
"SessionLengthMobileInDays": 30,
|
"SessionLengthMobileInDays": 30,
|
||||||
"SessionLengthSSOInDays": 30,
|
"SessionLengthSSOInDays": 30,
|
||||||
"SessionCacheInMinutes": 10,
|
"SessionCacheInMinutes": 10,
|
||||||
|
"SessionIdleTimeout": 0,
|
||||||
"WebsocketSecurePort": 443,
|
"WebsocketSecurePort": 443,
|
||||||
"WebsocketPort": 80,
|
"WebsocketPort": 80,
|
||||||
"WebserverMode": "gzip",
|
"WebserverMode": "gzip",
|
||||||
|
|||||||
@@ -182,6 +182,7 @@ type ServiceSettings struct {
|
|||||||
SessionLengthMobileInDays *int
|
SessionLengthMobileInDays *int
|
||||||
SessionLengthSSOInDays *int
|
SessionLengthSSOInDays *int
|
||||||
SessionCacheInMinutes *int
|
SessionCacheInMinutes *int
|
||||||
|
SessionIdleTimeoutInMinutes *int
|
||||||
WebsocketSecurePort *int
|
WebsocketSecurePort *int
|
||||||
WebsocketPort *int
|
WebsocketPort *int
|
||||||
WebserverMode *string
|
WebserverMode *string
|
||||||
@@ -1155,6 +1156,11 @@ func (o *Config) SetDefaults() {
|
|||||||
*o.ServiceSettings.SessionCacheInMinutes = 10
|
*o.ServiceSettings.SessionCacheInMinutes = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.ServiceSettings.SessionIdleTimeoutInMinutes == nil {
|
||||||
|
o.ServiceSettings.SessionIdleTimeoutInMinutes = new(int)
|
||||||
|
*o.ServiceSettings.SessionIdleTimeoutInMinutes = 0
|
||||||
|
}
|
||||||
|
|
||||||
if o.ServiceSettings.EnableCommands == nil {
|
if o.ServiceSettings.EnableCommands == nil {
|
||||||
o.ServiceSettings.EnableCommands = new(bool)
|
o.ServiceSettings.EnableCommands = new(bool)
|
||||||
*o.ServiceSettings.EnableCommands = false
|
*o.ServiceSettings.EnableCommands = false
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user