mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-29 17:58:15 +08:00
Adds WebClientTimeout to config (#7497)
Adds `web_client_timeout` to the Teleport config file and exposes it via the Cluster Network Settings. See-Also: #6092
This commit is contained in:
+576
-544
File diff suppressed because it is too large
Load Diff
@@ -692,6 +692,11 @@ message ClusterNetworkingConfigSpecV2 {
|
||||
|
||||
// ClientIdleTimeoutMessage is the message sent to the user when a connection times out.
|
||||
string ClientIdleTimeoutMessage = 5 [ (gogoproto.jsontag) = "idle_timeout_message" ];
|
||||
|
||||
// WebIdleTimeout sets global cluster default setting for the web UI idle
|
||||
// timeouts.
|
||||
int64 WebIdleTimeout = 6
|
||||
[ (gogoproto.jsontag) = "web_idle_timeout", (gogoproto.casttype) = "Duration" ];
|
||||
}
|
||||
|
||||
// SessionRecordingConfigV2 contains session recording configuration.
|
||||
|
||||
@@ -536,6 +536,7 @@ func applyAuthConfig(fc *FileConfig, cfg *service.Config) error {
|
||||
cfg.Auth.NetworkingConfig, err = types.NewClusterNetworkingConfigFromConfigFile(types.ClusterNetworkingConfigSpecV2{
|
||||
ClientIdleTimeout: fc.Auth.ClientIdleTimeout,
|
||||
ClientIdleTimeoutMessage: fc.Auth.ClientIdleTimeoutMessage,
|
||||
WebIdleTimeout: fc.Auth.WebIdleTimeout,
|
||||
KeepAliveInterval: fc.Auth.KeepAliveInterval,
|
||||
KeepAliveCountMax: fc.Auth.KeepAliveCountMax,
|
||||
SessionControlTimeout: fc.Auth.SessionControlTimeout,
|
||||
|
||||
@@ -244,6 +244,7 @@ func TestConfigReading(t *testing.T) {
|
||||
LicenseFile: "lic.pem",
|
||||
DisconnectExpiredCert: types.NewBoolOption(true),
|
||||
ClientIdleTimeout: types.Duration(17 * time.Second),
|
||||
WebIdleTimeout: types.Duration(19 * time.Second),
|
||||
},
|
||||
SSH: SSH{
|
||||
Service: Service{
|
||||
@@ -909,6 +910,7 @@ func makeConfigFixture() string {
|
||||
conf.Auth.ListenAddress = "tcp://auth"
|
||||
conf.Auth.LicenseFile = "lic.pem"
|
||||
conf.Auth.ClientIdleTimeout = types.NewDuration(17 * time.Second)
|
||||
conf.Auth.WebIdleTimeout = types.NewDuration(19 * time.Second)
|
||||
conf.Auth.DisconnectExpiredCert = types.NewBoolOption(true)
|
||||
|
||||
// ssh service:
|
||||
|
||||
@@ -523,6 +523,10 @@ type Auth struct {
|
||||
|
||||
// MessageOfTheDay is a banner that a user must acknowledge during a `tsh login`.
|
||||
MessageOfTheDay string `yaml:"message_of_the_day,omitempty"`
|
||||
|
||||
// WebIdleTimeout sets global cluster default setting for WebUI client
|
||||
// idle timeouts
|
||||
WebIdleTimeout types.Duration `yaml:"web_idle_timeout,omitempty"`
|
||||
}
|
||||
|
||||
// TrustedCluster struct holds configuration values under "trusted_clusters" key
|
||||
|
||||
+35
-12
@@ -19,8 +19,10 @@ package config
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/gravitational/teleport/api/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
@@ -71,20 +73,22 @@ func TestAuthSection(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := []struct {
|
||||
desc string
|
||||
mutate func(cfgMap)
|
||||
expectError require.ErrorAssertionFunc
|
||||
expectEnabled require.BoolAssertionFunc
|
||||
expectIdleMsg require.ValueAssertionFunc
|
||||
expectMotd require.ValueAssertionFunc
|
||||
desc string
|
||||
mutate func(cfgMap)
|
||||
expectError require.ErrorAssertionFunc
|
||||
expectEnabled require.BoolAssertionFunc
|
||||
expectIdleMsg require.ValueAssertionFunc
|
||||
expectMotd require.ValueAssertionFunc
|
||||
expectWebIdleTimeout require.ValueAssertionFunc
|
||||
}{
|
||||
{
|
||||
desc: "Default",
|
||||
mutate: func(cfg cfgMap) {},
|
||||
expectError: require.NoError,
|
||||
expectEnabled: require.True,
|
||||
expectIdleMsg: require.Empty,
|
||||
expectMotd: require.Empty,
|
||||
desc: "Default",
|
||||
mutate: func(cfg cfgMap) {},
|
||||
expectError: require.NoError,
|
||||
expectEnabled: require.True,
|
||||
expectIdleMsg: require.Empty,
|
||||
expectMotd: require.Empty,
|
||||
expectWebIdleTimeout: require.Empty,
|
||||
}, {
|
||||
desc: "Enabled",
|
||||
mutate: func(cfg cfgMap) {
|
||||
@@ -113,6 +117,21 @@ func TestAuthSection(t *testing.T) {
|
||||
},
|
||||
expectError: require.NoError,
|
||||
expectMotd: requireEqual("Are you pondering what I'm pondering?"),
|
||||
}, {
|
||||
desc: "Web idle timeout",
|
||||
mutate: func(cfg cfgMap) {
|
||||
cfg["auth_service"].(cfgMap)["web_idle_timeout"] = "10m"
|
||||
|
||||
},
|
||||
expectError: require.NoError,
|
||||
expectWebIdleTimeout: requireEqual(types.Duration(10 * time.Minute)),
|
||||
}, {
|
||||
desc: "Web idle timeout (invalid)",
|
||||
mutate: func(cfg cfgMap) {
|
||||
cfg["auth_service"].(cfgMap)["web_idle_timeout"] = "potato"
|
||||
|
||||
},
|
||||
expectError: require.Error,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -134,6 +153,10 @@ func TestAuthSection(t *testing.T) {
|
||||
if tt.expectMotd != nil {
|
||||
tt.expectMotd(t, cfg.Auth.MessageOfTheDay)
|
||||
}
|
||||
|
||||
if tt.expectWebIdleTimeout != nil {
|
||||
tt.expectWebIdleTimeout(t, cfg.Auth.WebIdleTimeout)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +168,11 @@ type Config struct {
|
||||
|
||||
// ClusterFeatures contains flags for supported/unsupported features.
|
||||
ClusterFeatures proto.Features
|
||||
|
||||
// WebIdleTimeout specifies how long a user WebUI session can be left
|
||||
// idle before being logged by the server. A zero value means there
|
||||
// is no idle timeout set.
|
||||
WebIdleTimeout time.Duration
|
||||
}
|
||||
|
||||
type RewritingHandler struct {
|
||||
|
||||
+14
-2
@@ -361,20 +361,32 @@ func (c *SessionContext) getToken() (types.WebToken, error) {
|
||||
}
|
||||
|
||||
// expired returns whether this context has expired.
|
||||
// The context is considered expired when its bearer token TTL
|
||||
// is in the past (subject to lingering threshold)
|
||||
// Session records in the backend are created with a built-in expiry that
|
||||
// automatically deletes the session record from the back-end database at
|
||||
// the end of its natural life.
|
||||
// If a session record still exists in the backend, it is considered still
|
||||
// alive, regardless of the time. If no such record exists then a record is
|
||||
// considered expired when its bearer token TTL is in the past (subject to
|
||||
// lingering threshold)
|
||||
func (c *SessionContext) expired(ctx context.Context) bool {
|
||||
_, err := c.parent.readSession(ctx, types.GetWebSessionRequest{
|
||||
User: c.user,
|
||||
SessionID: c.session.GetName(),
|
||||
})
|
||||
|
||||
// If looking up the session in the cache or backend succeeds, then
|
||||
// it by definition must not have expired yet.
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// If the session has no expiry time, then also by definition it
|
||||
// cannot be expired
|
||||
expiry := c.session.GetBearerTokenExpiryTime()
|
||||
if expiry.IsZero() {
|
||||
return false
|
||||
}
|
||||
|
||||
if !trace.IsNotFound(err) {
|
||||
c.log.WithError(err).Debug("Failed to query web session.")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user