diff --git a/api4/user.go b/api4/user.go index 748950da7a..2d96912499 100644 --- a/api4/user.go +++ b/api4/user.go @@ -2085,9 +2085,9 @@ func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) { } c.App.ClearSessionCacheForUser(c.AppContext.Session().UserId) - c.App.SetSessionExpireInDays(c.AppContext.Session(), *c.App.Config().ServiceSettings.SessionLengthMobileInDays) + c.App.SetSessionExpireInHours(c.AppContext.Session(), *c.App.Config().ServiceSettings.SessionLengthMobileInHours) - maxAge := *c.App.Config().ServiceSettings.SessionLengthMobileInDays * 60 * 60 * 24 + maxAgeSeconds := *c.App.Config().ServiceSettings.SessionLengthMobileInHours * 60 * 60 secure := false if app.GetProtocol(r) == "https" { @@ -2096,12 +2096,12 @@ func attachDeviceId(c *Context, w http.ResponseWriter, r *http.Request) { subpath, _ := utils.GetSubpathFromConfig(c.App.Config()) - expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0) + expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAgeSeconds), 0) sessionCookie := &http.Cookie{ Name: model.SessionCookieToken, Value: c.AppContext.Session().Token, Path: subpath, - MaxAge: maxAge, + MaxAge: maxAgeSeconds, Expires: expiresAt, HttpOnly: true, Domain: c.App.GetCookieDomain(), diff --git a/app/app_iface.go b/app/app_iface.go index a10dff06f8..d25eede7c7 100644 --- a/app/app_iface.go +++ b/app/app_iface.go @@ -277,10 +277,10 @@ type AppIface interface { SessionHasPermissionToManageBot(session model.Session, botUserId string) *model.AppError // SessionIsRegistered determines if a specific session has been registered SessionIsRegistered(session model.Session) bool - // SetSessionExpireInDays sets the session's expiry the specified number of days + // SetSessionExpireInHours sets the session's expiry the specified number of hours // relative to either the session creation date or the current time, depending // on the `ExtendSessionOnActivity` config setting. - SetSessionExpireInDays(session *model.Session, days int) + SetSessionExpireInHours(session *model.Session, hours int) // SetStatusDoNotDisturbTimed takes endtime in unix epoch format in UTC // and sets status of given userId to dnd which will be restored back after endtime SetStatusDoNotDisturbTimed(userId string, endtime int64) diff --git a/app/expirynotify.go b/app/expirynotify.go index bf29a21265..8d1dbdbea0 100644 --- a/app/expirynotify.go +++ b/app/expirynotify.go @@ -83,7 +83,7 @@ func (a *App) getSessionExpiredPushMessage(session *model.Session) string { T := i18n.GetUserTranslations(locale) siteName := *a.Config().TeamSettings.SiteName - props := map[string]interface{}{"siteName": siteName, "daysCount": *a.Config().ServiceSettings.SessionLengthMobileInDays} + props := map[string]interface{}{"siteName": siteName, "hoursCount": *a.Config().ServiceSettings.SessionLengthMobileInHours} return T("api.push_notifications.session.expired", props) } diff --git a/app/login.go b/app/login.go index 255595d7cb..e67db2fe38 100644 --- a/app/login.go +++ b/app/login.go @@ -178,7 +178,7 @@ func (a *App) DoLogin(c *request.Context, w http.ResponseWriter, r *http.Request session.GenerateCSRF() if deviceID != "" { - a.ch.srv.userService.SetSessionExpireInDays(session, *a.Config().ServiceSettings.SessionLengthMobileInDays) + a.ch.srv.userService.SetSessionExpireInHours(session, *a.Config().ServiceSettings.SessionLengthMobileInHours) // A special case where we logout of all other sessions with the same Id if err := a.RevokeSessionsForDeviceId(user.Id, deviceID, ""); err != nil { @@ -186,11 +186,11 @@ func (a *App) DoLogin(c *request.Context, w http.ResponseWriter, r *http.Request return err } } else if isMobile { - a.ch.srv.userService.SetSessionExpireInDays(session, *a.Config().ServiceSettings.SessionLengthMobileInDays) + a.ch.srv.userService.SetSessionExpireInHours(session, *a.Config().ServiceSettings.SessionLengthMobileInHours) } else if isOAuthUser || isSaml { - a.ch.srv.userService.SetSessionExpireInDays(session, *a.Config().ServiceSettings.SessionLengthSSOInDays) + a.ch.srv.userService.SetSessionExpireInHours(session, *a.Config().ServiceSettings.SessionLengthSSOInHours) } else { - a.ch.srv.userService.SetSessionExpireInDays(session, *a.Config().ServiceSettings.SessionLengthWebInDays) + a.ch.srv.userService.SetSessionExpireInHours(session, *a.Config().ServiceSettings.SessionLengthWebInHours) } ua := uasurfer.Parse(r.UserAgent()) @@ -245,9 +245,9 @@ func (a *App) AttachCloudSessionCookie(c *request.Context, w http.ResponseWriter secure = true } - maxAge := *a.Config().ServiceSettings.SessionLengthWebInDays * 60 * 60 * 24 + maxAgeSeconds := *a.Config().ServiceSettings.SessionLengthWebInHours * 60 * 60 subpath, _ := utils.GetSubpathFromConfig(a.Config()) - expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0) + expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAgeSeconds), 0) domain := "" if siteURL, err := url.Parse(a.GetSiteURL()); err == nil { @@ -276,7 +276,7 @@ func (a *App) AttachCloudSessionCookie(c *request.Context, w http.ResponseWriter Name: model.SessionCookieCloudUrl, Value: workspaceName, Path: subpath, - MaxAge: maxAge, + MaxAge: maxAgeSeconds, Expires: expiresAt, Domain: domain, Secure: secure, @@ -292,16 +292,16 @@ func (a *App) AttachSessionCookies(c *request.Context, w http.ResponseWriter, r secure = true } - maxAge := *a.Config().ServiceSettings.SessionLengthWebInDays * 60 * 60 * 24 + maxAgeSeconds := *a.Config().ServiceSettings.SessionLengthWebInHours * 60 * 60 domain := a.GetCookieDomain() subpath, _ := utils.GetSubpathFromConfig(a.Config()) - expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAge), 0) + expiresAt := time.Unix(model.GetMillis()/1000+int64(maxAgeSeconds), 0) sessionCookie := &http.Cookie{ Name: model.SessionCookieToken, Value: c.Session().Token, Path: subpath, - MaxAge: maxAge, + MaxAge: maxAgeSeconds, Expires: expiresAt, HttpOnly: true, Domain: domain, @@ -312,7 +312,7 @@ func (a *App) AttachSessionCookies(c *request.Context, w http.ResponseWriter, r Name: model.SessionCookieUser, Value: c.Session().UserId, Path: subpath, - MaxAge: maxAge, + MaxAge: maxAgeSeconds, Expires: expiresAt, Domain: domain, Secure: secure, @@ -322,7 +322,7 @@ func (a *App) AttachSessionCookies(c *request.Context, w http.ResponseWriter, r Name: model.SessionCookieCsrf, Value: c.Session().GetCSRF(), Path: subpath, - MaxAge: maxAge, + MaxAge: maxAgeSeconds, Expires: expiresAt, Domain: domain, Secure: secure, diff --git a/app/oauth.go b/app/oauth.go index b1a565159b..eb5126ab7a 100644 --- a/app/oauth.go +++ b/app/oauth.go @@ -314,10 +314,10 @@ func (a *App) GetOAuthAccessTokenForCodeFlow(clientId, grantType, redirectURI, c } else { // Return the same token and no need to create a new session accessRsp = &model.AccessResponse{ - AccessToken: accessData.Token, - TokenType: model.AccessTokenType, - RefreshToken: accessData.RefreshToken, - ExpiresIn: int32((accessData.ExpiresAt - model.GetMillis()) / 1000), + AccessToken: accessData.Token, + TokenType: model.AccessTokenType, + RefreshToken: accessData.RefreshToken, + ExpiresInSeconds: int32((accessData.ExpiresAt - model.GetMillis()) / 1000), } } } else { @@ -335,10 +335,10 @@ func (a *App) GetOAuthAccessTokenForCodeFlow(clientId, grantType, redirectURI, c } accessRsp = &model.AccessResponse{ - AccessToken: session.Token, - TokenType: model.AccessTokenType, - RefreshToken: accessData.RefreshToken, - ExpiresIn: int32(*a.Config().ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24), + AccessToken: session.Token, + TokenType: model.AccessTokenType, + RefreshToken: accessData.RefreshToken, + ExpiresInSeconds: int32(*a.Config().ServiceSettings.SessionLengthSSOInHours * 60 * 60), } } @@ -371,7 +371,7 @@ func (a *App) newSession(app *model.OAuthApp, user *model.User) (*model.Session, // Set new token an session session := &model.Session{UserId: user.Id, Roles: user.Roles, IsOAuth: true} session.GenerateCSRF() - a.ch.srv.userService.SetSessionExpireInDays(session, *a.Config().ServiceSettings.SessionLengthSSOInDays) + a.ch.srv.userService.SetSessionExpireInHours(session, *a.Config().ServiceSettings.SessionLengthSSOInHours) session.AddProp(model.SessionPropPlatform, app.Name) session.AddProp(model.SessionPropOAuthAppID, app.Id) session.AddProp(model.SessionPropMattermostAppID, app.MattermostAppID) @@ -407,10 +407,10 @@ func (a *App) newSessionUpdateToken(app *model.OAuthApp, accessData *model.Acces return nil, model.NewAppError("newSessionUpdateToken", "web.get_access_token.internal_saving.app_error", nil, "", http.StatusInternalServerError) } accessRsp := &model.AccessResponse{ - AccessToken: session.Token, - RefreshToken: accessData.RefreshToken, - TokenType: model.AccessTokenType, - ExpiresIn: int32(*a.Config().ServiceSettings.SessionLengthSSOInDays * 60 * 60 * 24), + AccessToken: session.Token, + RefreshToken: accessData.RefreshToken, + TokenType: model.AccessTokenType, + ExpiresInSeconds: int32(*a.Config().ServiceSettings.SessionLengthSSOInHours * 60 * 60), } return accessRsp, nil diff --git a/app/oauth_test.go b/app/oauth_test.go index 35c2904b94..1d7807fa3b 100644 --- a/app/oauth_test.go +++ b/app/oauth_test.go @@ -79,7 +79,7 @@ func TestOAuthRevokeAccessToken(t *testing.T) { session.UserId = model.NewId() session.Token = model.NewId() session.Roles = model.SystemUserRoleId - th.App.SetSessionExpireInDays(session, 1) + th.App.SetSessionExpireInHours(session, 24) var err *model.AppError session, err = th.App.CreateSession(session) @@ -111,7 +111,7 @@ func TestOAuthDeleteApp(t *testing.T) { session.Token = model.NewId() session.Roles = model.SystemUserRoleId session.IsOAuth = true - th.App.ch.srv.userService.SetSessionExpireInDays(session, 1) + th.App.ch.srv.userService.SetSessionExpireInHours(session, 24) session, _ = th.App.CreateSession(session) diff --git a/app/opentracing/opentracing_layer.go b/app/opentracing/opentracing_layer.go index 37a72fb667..60be666e46 100644 --- a/app/opentracing/opentracing_layer.go +++ b/app/opentracing/opentracing_layer.go @@ -15309,9 +15309,9 @@ func (a *OpenTracingAppLayer) SetSearchEngine(se *searchengine.Broker) { a.app.SetSearchEngine(se) } -func (a *OpenTracingAppLayer) SetSessionExpireInDays(session *model.Session, days int) { +func (a *OpenTracingAppLayer) SetSessionExpireInHours(session *model.Session, hours int) { origCtx := a.ctx - span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SetSessionExpireInDays") + span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SetSessionExpireInHours") a.ctx = newCtx a.app.Srv().Store.SetContext(newCtx) @@ -15321,7 +15321,7 @@ func (a *OpenTracingAppLayer) SetSessionExpireInDays(session *model.Session, day }() defer span.Finish() - a.app.SetSessionExpireInDays(session, days) + a.app.SetSessionExpireInHours(session, hours) } func (a *OpenTracingAppLayer) SetStatusAwayIfNeeded(userID string, manual bool) { diff --git a/app/session.go b/app/session.go index cfa188360e..e1a4e1c913 100644 --- a/app/session.go +++ b/app/session.go @@ -307,22 +307,22 @@ func (a *App) GetSessionLengthInMillis(session *model.Session) int64 { return 0 } - var days int + var hours int if session.IsMobileApp() { - days = *a.Config().ServiceSettings.SessionLengthMobileInDays + hours = *a.Config().ServiceSettings.SessionLengthMobileInHours } else if session.IsSSOLogin() { - days = *a.Config().ServiceSettings.SessionLengthSSOInDays + hours = *a.Config().ServiceSettings.SessionLengthSSOInHours } else { - days = *a.Config().ServiceSettings.SessionLengthWebInDays + hours = *a.Config().ServiceSettings.SessionLengthWebInHours } - return int64(days * 24 * 60 * 60 * 1000) + return int64(hours * 60 * 60 * 1000) } -// SetSessionExpireInDays sets the session's expiry the specified number of days +// SetSessionExpireInHours sets the session's expiry the specified number of hours // relative to either the session creation date or the current time, depending // on the `ExtendSessionOnActivity` config setting. -func (a *App) SetSessionExpireInDays(session *model.Session, days int) { - a.ch.srv.userService.SetSessionExpireInDays(session, days) +func (a *App) SetSessionExpireInHours(session *model.Session, hours int) { + a.ch.srv.userService.SetSessionExpireInHours(session, hours) } func (a *App) CreateUserAccessToken(token *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) { @@ -411,7 +411,7 @@ func (a *App) createSessionForUserAccessToken(tokenString string) (*model.Sessio } else { session.AddProp(model.SessionPropIsGuest, "false") } - a.ch.srv.userService.SetSessionExpireInDays(session, model.SessionUserAccessTokenExpiry) + a.ch.srv.userService.SetSessionExpireInHours(session, model.SessionUserAccessTokenExpiryHours) session, nErr = a.Srv().Store.Session().Save(session) if nErr != nil { diff --git a/app/session_test.go b/app/session_test.go index 4b4ee8ce83..9aaa629d73 100644 --- a/app/session_test.go +++ b/app/session_test.go @@ -155,9 +155,9 @@ func TestApp_GetSessionLengthInMillis(t *testing.T) { th := Setup(t) defer th.TearDown() - th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthMobileInDays = 3 }) - th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthSSOInDays = 2 }) - th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthWebInDays = 1 }) + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthMobileInHours = 3 * 24 }) + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthSSOInHours = 2 * 24 }) + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthWebInHours = 24 }) t.Run("get session length mobile", func(t *testing.T) { session := &model.Session{ @@ -244,9 +244,9 @@ func TestApp_ExtendExpiryIfNeeded(t *testing.T) { defer th.TearDown() th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.ExtendSessionLengthWithActivity = true }) - th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthMobileInDays = 3 }) - th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthSSOInDays = 2 }) - th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthWebInDays = 1 }) + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthMobileInHours = 3 * 24 }) + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthSSOInHours = 2 * 24 }) + th.App.UpdateConfig(func(cfg *model.Config) { *cfg.ServiceSettings.SessionLengthWebInHours = 24 }) t.Run("expired session should not be extended", func(t *testing.T) { expires := model.GetMillis() - hourMillis diff --git a/app/users/session.go b/app/users/session.go index f21a083b5e..7deed60df1 100644 --- a/app/users/session.go +++ b/app/users/session.go @@ -199,14 +199,14 @@ func (us *UserService) RevokeAccessToken(token string) error { return nil } -// SetSessionExpireInDays sets the session's expiry the specified number of days +// SetSessionExpireInHours sets the session's expiry the specified number of hours // relative to either the session creation date or the current time, depending // on the `ExtendSessionOnActivity` config setting. -func (us *UserService) SetSessionExpireInDays(session *model.Session, days int) { +func (us *UserService) SetSessionExpireInHours(session *model.Session, hours int) { if session.CreateAt == 0 || *us.config().ServiceSettings.ExtendSessionLengthWithActivity { - session.ExpiresAt = model.GetMillis() + (1000 * 60 * 60 * 24 * int64(days)) + session.ExpiresAt = model.GetMillis() + (1000 * 60 * 60 * int64(hours)) } else { - session.ExpiresAt = session.CreateAt + (1000 * 60 * 60 * 24 * int64(days)) + session.ExpiresAt = session.CreateAt + (1000 * 60 * 60 * int64(hours)) } } diff --git a/app/users/session_test.go b/app/users/session_test.go index cee66b9af1..4197a28cc8 100644 --- a/app/users/session_test.go +++ b/app/users/session_test.go @@ -54,7 +54,7 @@ func TestCache(t *testing.T) { require.Empty(t, rkeys) } -func TestSetSessionExpireInDays(t *testing.T) { +func TestSetSessionExpireInHours(t *testing.T) { th := Setup(t) defer th.TearDown() @@ -91,7 +91,7 @@ func TestSetSessionExpireInDays(t *testing.T) { CreateAt: create, ExpiresAt: model.GetMillis() + dayInMillis, } - th.service.SetSessionExpireInDays(session, tt.days) + th.service.SetSessionExpireInHours(session, tt.days*24) // must be within 5 seconds of expected time. require.GreaterOrEqual(t, session.ExpiresAt, tt.want-grace) @@ -112,7 +112,7 @@ func TestOAuthRevokeAccessToken(t *testing.T) { session.UserId = model.NewId() session.Token = model.NewId() session.Roles = model.SystemUserRoleId - th.service.SetSessionExpireInDays(session, 1) + th.service.SetSessionExpireInHours(session, 24) session, _ = th.service.CreateSession(session) err = th.service.RevokeAccessToken(session.Token) diff --git a/i18n/en.json b/i18n/en.json index 6eb506c34b..93dd68c097 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -2393,7 +2393,7 @@ }, { "id": "api.push_notifications.session.expired", - "translation": "Session Expired: Please log in to continue receiving notifications. Sessions for {{.siteName}} are configured by your System Administrator to expire every {{.daysCount}} day(s)." + "translation": "Session Expired: Please log in to continue receiving notifications. Sessions for {{.siteName}} are configured by your System Administrator to expire every {{.hoursCount}} hour(s)." }, { "id": "api.push_notifications_ack.forward.app_error", diff --git a/manualtesting/manual_testing.go b/manualtesting/manual_testing.go index 9423f1baa7..ae15be9814 100644 --- a/manualtesting/manual_testing.go +++ b/manualtesting/manual_testing.go @@ -143,7 +143,7 @@ func manualTest(c *web.Context, w http.ResponseWriter, r *http.Request) { Name: model.SessionCookieToken, Value: client.AuthToken, Path: "/", - MaxAge: *c.App.Config().ServiceSettings.SessionLengthWebInDays * 60 * 60 * 24, + MaxAge: *c.App.Config().ServiceSettings.SessionLengthWebInHours * 60 * 60, HttpOnly: true, } http.SetCookie(w, sessionCookie) diff --git a/model/access.go b/model/access.go index f17c8fbe95..c373f64523 100644 --- a/model/access.go +++ b/model/access.go @@ -24,12 +24,12 @@ type AccessData struct { } type AccessResponse struct { - AccessToken string `json:"access_token"` - TokenType string `json:"token_type"` - ExpiresIn int32 `json:"expires_in"` - Scope string `json:"scope"` - RefreshToken string `json:"refresh_token"` - IdToken string `json:"id_token"` + AccessToken string `json:"access_token"` + TokenType string `json:"token_type"` + ExpiresInSeconds int32 `json:"expires_in"` + Scope string `json:"scope"` + RefreshToken string `json:"refresh_token"` + IdToken string `json:"id_token"` } // IsValid validates the AccessData and returns an error if it isn't configured diff --git a/model/config.go b/model/config.go index 5fb29be8c0..50b62204d7 100644 --- a/model/config.go +++ b/model/config.go @@ -285,72 +285,80 @@ type ServiceSettings struct { TLSMinVer *string `access:"write_restrictable,cloud_restrictable"` // telemetry: none TLSStrictTransport *bool `access:"write_restrictable,cloud_restrictable"` // In seconds. - TLSStrictTransportMaxAge *int64 `access:"write_restrictable,cloud_restrictable"` // telemetry: none - TLSOverwriteCiphers []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none - UseLetsEncrypt *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` - LetsEncryptCertificateCacheFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` // telemetry: none - Forward80To443 *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` - TrustedProxyIPHeader []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none - ReadTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` - WriteTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` - IdleTimeout *int `access:"write_restrictable,cloud_restrictable"` - MaximumLoginAttempts *int `access:"authentication_password,write_restrictable,cloud_restrictable"` - GoroutineHealthThreshold *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none - EnableOAuthServiceProvider *bool `access:"integrations_integration_management"` - EnableIncomingWebhooks *bool `access:"integrations_integration_management"` - EnableOutgoingWebhooks *bool `access:"integrations_integration_management"` - EnableCommands *bool `access:"integrations_integration_management"` - EnablePostUsernameOverride *bool `access:"integrations_integration_management"` - EnablePostIconOverride *bool `access:"integrations_integration_management"` - GoogleDeveloperKey *string `access:"site_posts,write_restrictable,cloud_restrictable"` - EnableLinkPreviews *bool `access:"site_posts"` - EnablePermalinkPreviews *bool `access:"site_posts"` - RestrictLinkPreviews *string `access:"site_posts"` - EnableTesting *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` - EnableDeveloper *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` - DeveloperFlags *string `access:"environment_developer"` - EnableClientPerformanceDebugging *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` - EnableOpenTracing *bool `access:"write_restrictable,cloud_restrictable"` - EnableSecurityFixAlert *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` - EnableInsecureOutgoingConnections *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` - AllowedUntrustedInternalConnections *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - EnableMultifactorAuthentication *bool `access:"authentication_mfa"` - EnforceMultifactorAuthentication *bool `access:"authentication_mfa"` - EnableUserAccessTokens *bool `access:"integrations_integration_management"` - AllowCorsFrom *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` - CorsExposedHeaders *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` - CorsAllowCredentials *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` - CorsDebug *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` - AllowCookiesForSubdomains *bool `access:"write_restrictable,cloud_restrictable"` - ExtendSessionLengthWithActivity *bool `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionLengthWebInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionLengthMobileInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionLengthSSOInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionCacheInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - SessionIdleTimeoutInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` - WebsocketSecurePort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none - WebsocketPort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none - WebserverMode *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` - EnableGifPicker *bool `access:"integrations_gif"` - GfycatAPIKey *string `access:"integrations_gif"` - GfycatAPISecret *string `access:"integrations_gif"` - EnableCustomEmoji *bool `access:"site_emoji"` - EnableEmojiPicker *bool `access:"site_emoji"` - PostEditTimeLimit *int `access:"user_management_permissions"` - TimeBetweenUserTypingUpdatesMilliseconds *int64 `access:"experimental_features,write_restrictable,cloud_restrictable"` - EnablePostSearch *bool `access:"write_restrictable,cloud_restrictable"` - EnableFileSearch *bool `access:"write_restrictable"` - MinimumHashtagLength *int `access:"environment_database,write_restrictable,cloud_restrictable"` - EnableUserTypingMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - EnableChannelViewedMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - EnableUserStatuses *bool `access:"write_restrictable,cloud_restrictable"` - ExperimentalEnableAuthenticationTransfer *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` - ClusterLogTimeoutMilliseconds *int `access:"write_restrictable,cloud_restrictable"` - EnablePreviewFeatures *bool `access:"experimental_features"` - EnableTutorial *bool `access:"experimental_features"` - EnableOnboardingFlow *bool `access:"experimental_features"` - ExperimentalEnableDefaultChannelLeaveJoinMessages *bool `access:"experimental_features"` - ExperimentalGroupUnreadChannels *string `access:"experimental_features"` + TLSStrictTransportMaxAge *int64 `access:"write_restrictable,cloud_restrictable"` // telemetry: none + TLSOverwriteCiphers []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none + UseLetsEncrypt *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` + LetsEncryptCertificateCacheFile *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` // telemetry: none + Forward80To443 *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` + TrustedProxyIPHeader []string `access:"write_restrictable,cloud_restrictable"` // telemetry: none + ReadTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` + WriteTimeout *int `access:"environment_web_server,write_restrictable,cloud_restrictable"` + IdleTimeout *int `access:"write_restrictable,cloud_restrictable"` + MaximumLoginAttempts *int `access:"authentication_password,write_restrictable,cloud_restrictable"` + GoroutineHealthThreshold *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none + EnableOAuthServiceProvider *bool `access:"integrations_integration_management"` + EnableIncomingWebhooks *bool `access:"integrations_integration_management"` + EnableOutgoingWebhooks *bool `access:"integrations_integration_management"` + EnableCommands *bool `access:"integrations_integration_management"` + EnablePostUsernameOverride *bool `access:"integrations_integration_management"` + EnablePostIconOverride *bool `access:"integrations_integration_management"` + GoogleDeveloperKey *string `access:"site_posts,write_restrictable,cloud_restrictable"` + EnableLinkPreviews *bool `access:"site_posts"` + EnablePermalinkPreviews *bool `access:"site_posts"` + RestrictLinkPreviews *string `access:"site_posts"` + EnableTesting *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` + EnableDeveloper *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` + DeveloperFlags *string `access:"environment_developer"` + EnableClientPerformanceDebugging *bool `access:"environment_developer,write_restrictable,cloud_restrictable"` + EnableOpenTracing *bool `access:"write_restrictable,cloud_restrictable"` + EnableSecurityFixAlert *bool `access:"environment_smtp,write_restrictable,cloud_restrictable"` + EnableInsecureOutgoingConnections *bool `access:"environment_web_server,write_restrictable,cloud_restrictable"` + AllowedUntrustedInternalConnections *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + EnableMultifactorAuthentication *bool `access:"authentication_mfa"` + EnforceMultifactorAuthentication *bool `access:"authentication_mfa"` + EnableUserAccessTokens *bool `access:"integrations_integration_management"` + AllowCorsFrom *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` + CorsExposedHeaders *string `access:"integrations_cors,write_restrictable,cloud_restrictable"` + CorsAllowCredentials *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` + CorsDebug *bool `access:"integrations_cors,write_restrictable,cloud_restrictable"` + AllowCookiesForSubdomains *bool `access:"write_restrictable,cloud_restrictable"` + ExtendSessionLengthWithActivity *bool `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + + // Deprecated + SessionLengthWebInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` // telemetry: none + SessionLengthWebInHours *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + // Deprecated + SessionLengthMobileInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` // telemetry: none + SessionLengthMobileInHours *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + // Deprecated + SessionLengthSSOInDays *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` // telemetry: none + SessionLengthSSOInHours *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + + SessionCacheInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + SessionIdleTimeoutInMinutes *int `access:"environment_session_lengths,write_restrictable,cloud_restrictable"` + WebsocketSecurePort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none + WebsocketPort *int `access:"write_restrictable,cloud_restrictable"` // telemetry: none + WebserverMode *string `access:"environment_web_server,write_restrictable,cloud_restrictable"` + EnableGifPicker *bool `access:"integrations_gif"` + GfycatAPIKey *string `access:"integrations_gif"` + GfycatAPISecret *string `access:"integrations_gif"` + EnableCustomEmoji *bool `access:"site_emoji"` + EnableEmojiPicker *bool `access:"site_emoji"` + PostEditTimeLimit *int `access:"user_management_permissions"` + TimeBetweenUserTypingUpdatesMilliseconds *int64 `access:"experimental_features,write_restrictable,cloud_restrictable"` + EnablePostSearch *bool `access:"write_restrictable,cloud_restrictable"` + EnableFileSearch *bool `access:"write_restrictable"` + MinimumHashtagLength *int `access:"environment_database,write_restrictable,cloud_restrictable"` + EnableUserTypingMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + EnableChannelViewedMessages *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + EnableUserStatuses *bool `access:"write_restrictable,cloud_restrictable"` + ExperimentalEnableAuthenticationTransfer *bool `access:"experimental_features,write_restrictable,cloud_restrictable"` + ClusterLogTimeoutMilliseconds *int `access:"write_restrictable,cloud_restrictable"` + EnablePreviewFeatures *bool `access:"experimental_features"` + EnableTutorial *bool `access:"experimental_features"` + EnableOnboardingFlow *bool `access:"experimental_features"` + ExperimentalEnableDefaultChannelLeaveJoinMessages *bool `access:"experimental_features"` + ExperimentalGroupUnreadChannels *string `access:"experimental_features"` EnableAPITeamDeletion *bool EnableAPIUserDeletion *bool ExperimentalEnableHardenedMode *bool `access:"experimental_features"` @@ -591,25 +599,46 @@ func (s *ServiceSettings) SetDefaults(isUpdate bool) { s.ExtendSessionLengthWithActivity = NewBool(!isUpdate) } - if s.SessionLengthWebInDays == nil { - if isUpdate { - s.SessionLengthWebInDays = NewInt(180) + if s.SessionLengthWebInHours == nil { + var webTTLDays int + if s.SessionLengthWebInDays == nil { + if isUpdate { + webTTLDays = 180 + } else { + webTTLDays = 30 + } } else { - s.SessionLengthWebInDays = NewInt(30) + webTTLDays = *s.SessionLengthWebInDays } + s.SessionLengthWebInHours = NewInt(webTTLDays * 24) } + s.SessionLengthWebInDays = NewInt(-1) - if s.SessionLengthMobileInDays == nil { - if isUpdate { - s.SessionLengthMobileInDays = NewInt(180) + if s.SessionLengthMobileInHours == nil { + var mobileTTLDays int + if s.SessionLengthMobileInDays == nil { + if isUpdate { + mobileTTLDays = 180 + } else { + mobileTTLDays = 30 + } } else { - s.SessionLengthMobileInDays = NewInt(30) + mobileTTLDays = *s.SessionLengthMobileInDays } + s.SessionLengthMobileInHours = NewInt(mobileTTLDays * 24) } + s.SessionLengthMobileInDays = NewInt(-1) - if s.SessionLengthSSOInDays == nil { - s.SessionLengthSSOInDays = NewInt(30) + if s.SessionLengthSSOInHours == nil { + var ssoTTLDays int + if s.SessionLengthSSOInDays == nil { + ssoTTLDays = 30 + } else { + ssoTTLDays = *s.SessionLengthSSOInDays + } + s.SessionLengthSSOInHours = NewInt(ssoTTLDays * 24) } + s.SessionLengthSSOInDays = NewInt(-1) if s.SessionCacheInMinutes == nil { s.SessionCacheInMinutes = NewInt(10) diff --git a/model/session.go b/model/session.go index fcf8eea12d..f8e996b5c1 100644 --- a/model/session.go +++ b/model/session.go @@ -12,26 +12,26 @@ import ( ) const ( - SessionCookieToken = "MMAUTHTOKEN" - SessionCookieUser = "MMUSERID" - SessionCookieCsrf = "MMCSRF" - SessionCookieCloudUrl = "MMCLOUDURL" - SessionCacheSize = 35000 - SessionPropPlatform = "platform" - SessionPropOs = "os" - SessionPropBrowser = "browser" - SessionPropType = "type" - SessionPropUserAccessTokenId = "user_access_token_id" - SessionPropIsBot = "is_bot" - SessionPropIsBotValue = "true" - SessionPropOAuthAppID = "oauth_app_id" - SessionPropMattermostAppID = "mattermost_app_id" - SessionTypeUserAccessToken = "UserAccessToken" - SessionTypeCloudKey = "CloudKey" - SessionTypeRemoteclusterToken = "RemoteClusterToken" - SessionPropIsGuest = "is_guest" - SessionActivityTimeout = 1000 * 60 * 5 // 5 minutes - SessionUserAccessTokenExpiry = 100 * 365 // 100 years + SessionCookieToken = "MMAUTHTOKEN" + SessionCookieUser = "MMUSERID" + SessionCookieCsrf = "MMCSRF" + SessionCookieCloudUrl = "MMCLOUDURL" + SessionCacheSize = 35000 + SessionPropPlatform = "platform" + SessionPropOs = "os" + SessionPropBrowser = "browser" + SessionPropType = "type" + SessionPropUserAccessTokenId = "user_access_token_id" + SessionPropIsBot = "is_bot" + SessionPropIsBotValue = "true" + SessionPropOAuthAppID = "oauth_app_id" + SessionPropMattermostAppID = "mattermost_app_id" + SessionTypeUserAccessToken = "UserAccessToken" + SessionTypeCloudKey = "CloudKey" + SessionTypeRemoteclusterToken = "RemoteClusterToken" + SessionPropIsGuest = "is_guest" + SessionActivityTimeout = 1000 * 60 * 5 // 5 minutes + SessionUserAccessTokenExpiryHours = 100 * 365 * 24 // 100 years ) //msgp StringMap diff --git a/services/telemetry/telemetry.go b/services/telemetry/telemetry.go index 6c6dc0921b..7974d77ee0 100644 --- a/services/telemetry/telemetry.go +++ b/services/telemetry/telemetry.go @@ -384,9 +384,9 @@ func (ts *TelemetryService) trackConfig() { "forward_80_to_443": *cfg.ServiceSettings.Forward80To443, "maximum_login_attempts": *cfg.ServiceSettings.MaximumLoginAttempts, "extend_session_length_with_activity": *cfg.ServiceSettings.ExtendSessionLengthWithActivity, - "session_length_web_in_days": *cfg.ServiceSettings.SessionLengthWebInDays, - "session_length_mobile_in_days": *cfg.ServiceSettings.SessionLengthMobileInDays, - "session_length_sso_in_days": *cfg.ServiceSettings.SessionLengthSSOInDays, + "session_length_web_in_hours": *cfg.ServiceSettings.SessionLengthWebInHours, + "session_length_mobile_in_hours": *cfg.ServiceSettings.SessionLengthMobileInHours, + "session_length_sso_in_hours": *cfg.ServiceSettings.SessionLengthSSOInHours, "session_cache_in_minutes": *cfg.ServiceSettings.SessionCacheInMinutes, "session_idle_timeout_in_minutes": *cfg.ServiceSettings.SessionIdleTimeoutInMinutes, "isdefault_site_url": isDefault(*cfg.ServiceSettings.SiteURL, model.ServiceSettingsDefaultSiteURL), diff --git a/tests/test-config.json b/tests/test-config.json index 3f8cc1a4e7..543db3950e 100644 --- a/tests/test-config.json +++ b/tests/test-config.json @@ -36,7 +36,8 @@ "ExtendSessionLengthWithActivity": true, "SessionLengthWebInDays": 30, "SessionLengthMobileInDays": 30, - "SessionLengthSSOInDays": 30, + "SessionLengthSSOInDays": -1, + "SessionLengthSSOInHours": 720, "SessionCacheInMinutes": 10, "SessionIdleTimeoutInMinutes": 0, "WebsocketSecurePort": 443, diff --git a/web/handlers_test.go b/web/handlers_test.go index 5ae26292c6..4651bb99e6 100644 --- a/web/handlers_test.go +++ b/web/handlers_test.go @@ -132,7 +132,7 @@ func TestHandlerServeCSRFToken(t *testing.T) { IsOAuth: false, } session.GenerateCSRF() - th.App.SetSessionExpireInDays(session, 1) + th.App.SetSessionExpireInHours(session, 24) session, err := th.App.CreateSession(session) if err != nil { t.Errorf("Expected nil, got %s", err)