Skip to content

Commit d36a68d

Browse files
authored
Merge pull request #4675 from mudit06mah/feat/session-ttl
backend: charts: Add session-ttl flag and logic
2 parents 866b0d6 + 1d09077 commit d36a68d

33 files changed

+67
-9
lines changed

backend/cmd/headlamp.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,7 @@ func createHeadlampHandler(config *HeadlampConfig) http.Handler {
391391
logger.Log(logger.LevelInfo, nil, nil, "me Groups Paths: "+config.MeGroupsPaths)
392392
logger.Log(logger.LevelInfo, nil, nil, "me User Info URL: "+config.MeUserInfoURL)
393393
logger.Log(logger.LevelInfo, nil, nil, "Base URL: "+config.BaseURL)
394+
logger.Log(logger.LevelInfo, nil, nil, "Session TTL: "+fmt.Sprint(config.SessionTTL))
394395
logger.Log(logger.LevelInfo, nil, nil, "Use In Cluster: "+fmt.Sprint(config.UseInCluster))
395396
logger.Log(logger.LevelInfo, nil, nil, "Watch Plugins Changes: "+fmt.Sprint(config.WatchPluginsChanges))
396397

@@ -859,7 +860,7 @@ func createHeadlampHandler(config *HeadlampConfig) http.Handler {
859860
}
860861

861862
// Set auth cookie
862-
auth.SetTokenCookie(w, r, oauthConfig.Cluster, rawUserToken, config.BaseURL)
863+
auth.SetTokenCookie(w, r, oauthConfig.Cluster, rawUserToken, config.BaseURL, config.SessionTTL)
863864

864865
redirectURL += fmt.Sprintf("auth?cluster=%1s", oauthConfig.Cluster)
865866

@@ -942,7 +943,7 @@ func (c *HeadlampConfig) refreshAndSetToken(oidcAuthConfig *kubeconfig.OidcConfi
942943
}
943944

944945
// Set refreshed token in cookie
945-
auth.SetTokenCookie(w, r, cluster, newTokenString, c.BaseURL)
946+
auth.SetTokenCookie(w, r, cluster, newTokenString, c.BaseURL, c.SessionTTL)
946947

947948
c.TelemetryHandler.RecordEvent(span, "Token refreshed successfully")
948949
}
@@ -2534,7 +2535,7 @@ func (c *HeadlampConfig) handleSetToken(w http.ResponseWriter, r *http.Request)
25342535
if req.Token == "" {
25352536
auth.ClearTokenCookie(w, r, cluster, c.BaseURL)
25362537
} else {
2537-
auth.SetTokenCookie(w, r, cluster, req.Token, c.BaseURL)
2538+
auth.SetTokenCookie(w, r, cluster, req.Token, c.BaseURL, c.SessionTTL)
25382539
}
25392540

25402541
w.WriteHeader(http.StatusOK)

backend/cmd/server.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ func buildHeadlampCFG(conf *config.Config, kubeConfigStore kubeconfig.ContextSto
100100
ProxyURLs: strings.Split(conf.ProxyURLs, ","),
101101
TLSCertPath: conf.TLSCertPath,
102102
TLSKeyPath: conf.TLSKeyPath,
103+
SessionTTL: conf.SessionTTL,
103104
}
104105
}
105106

backend/pkg/auth/cookies.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func IsSecureContext(r *http.Request) bool {
7575
}
7676

7777
// SetTokenCookie sets an authentication cookie for a specific cluster.
78-
func SetTokenCookie(w http.ResponseWriter, r *http.Request, cluster, token, baseURL string) {
78+
func SetTokenCookie(w http.ResponseWriter, r *http.Request, cluster, token, baseURL string, sessionTTL int) {
7979
// Validate inputs
8080
if cluster == "" || token == "" {
8181
return
@@ -101,7 +101,7 @@ func SetTokenCookie(w http.ResponseWriter, r *http.Request, cluster, token, base
101101
Secure: secure,
102102
SameSite: http.SameSiteStrictMode,
103103
Path: GetCookiePath(baseURL, cluster),
104-
MaxAge: 86400, // 24 hours
104+
MaxAge: sessionTTL,
105105
}
106106

107107
http.SetCookie(w, cookie)

backend/pkg/auth/cookies_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,8 @@ func TestSetAndGetAuthCookie(t *testing.T) {
166166
w := httptest.NewRecorder()
167167

168168
// Test setting a cookie
169-
auth.SetTokenCookie(w, req, "test-cluster", "test-token", "")
169+
testTTL := 100
170+
auth.SetTokenCookie(w, req, "test-cluster", "test-token", "", testTTL)
170171

171172
// Check if cookie was set
172173
cookies := w.Result().Cookies()
@@ -191,6 +192,10 @@ func TestSetAndGetAuthCookie(t *testing.T) {
191192
t.Error("Expected SameSite to be SameSiteStrictMode")
192193
}
193194

195+
if cookie.MaxAge != testTTL {
196+
t.Errorf("Expected MaxAge to be %d, got %d", testTTL, cookie.MaxAge)
197+
}
198+
194199
// Test getting the cookie
195200
req.AddCookie(cookie)
196201

@@ -213,7 +218,7 @@ func TestGetAuthCookieChunked(t *testing.T) {
213218
longToken := strings.Repeat("a", 5000)
214219

215220
// Test setting a cookie
216-
auth.SetTokenCookie(w, req, "test-cluster", longToken, "")
221+
auth.SetTokenCookie(w, req, "test-cluster", longToken, "", 86400)
217222

218223
// Check if cookie was set
219224
cookies := w.Result().Cookies()

backend/pkg/config/config.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ import (
2020
)
2121

2222
const (
23-
defaultPort = 4466
24-
osWindows = "windows"
23+
defaultPort = 4466
24+
defaultSessionTTL = 86400 // 24 hours in seconds
25+
osWindows = "windows"
2526
)
2627

2728
const (
@@ -54,6 +55,7 @@ type Config struct {
5455
PluginsDir string `koanf:"plugins-dir"`
5556
UserPluginsDir string `koanf:"user-plugins-dir"`
5657
BaseURL string `koanf:"base-url"`
58+
SessionTTL int `koanf:"session-ttl"`
5759
ProxyURLs string `koanf:"proxy-urls"`
5860
OidcClientID string `koanf:"oidc-client-id"`
5961
OidcValidatorClientID string `koanf:"oidc-validator-client-id"`
@@ -115,6 +117,16 @@ func (c *Config) Validate() error {
115117
return errors.New("base-url needs to start with a '/' or be empty")
116118
}
117119

120+
if c.SessionTTL <= 0 {
121+
return errors.New("session-ttl cannot be negative or equal to zero")
122+
}
123+
124+
const oneYearInSeconds = 31536000
125+
126+
if c.SessionTTL > oneYearInSeconds {
127+
return errors.New("session-ttl cannot be greater than 1 year")
128+
}
129+
118130
if c.TracingEnabled != nil && *c.TracingEnabled {
119131
if c.ServiceName == "" {
120132
return errors.New("service-name is required when tracing is enabled")
@@ -430,6 +442,8 @@ func addGeneralFlags(f *flag.FlagSet) {
430442
f.String("plugins-dir", defaultPluginDir(), "Specify the plugins directory to build the backend with")
431443
f.String("user-plugins-dir", defaultUserPluginDir(), "Specify the user-installed plugins directory")
432444
f.String("base-url", "", "Base URL path. eg. /headlamp")
445+
f.Int("session-ttl", defaultSessionTTL, "The time in seconds for the session to be valid"+
446+
"(Default: 86400/24h, Min: 1 , Max: 31536000/1yr )")
433447
f.String("listen-addr", "", "Address to listen on; default is empty, which means listening to any address")
434448
f.Uint("port", defaultPort, "Port to listen from")
435449
f.String("proxy-urls", "", "Allow proxy requests to specified URLs")

backend/pkg/headlampconfig/headlampConfig.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,5 @@ type HeadlampCFG struct {
6262
ProxyURLs []string
6363
TLSCertPath string
6464
TLSKeyPath string
65+
SessionTTL int
6566
}

charts/headlamp/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ $ helm install my-headlamp headlamp/headlamp \
7171
|--------------------|--------|-----------------------|---------------------------------------------------------------------------|
7272
| config.inCluster | bool | `true` | Run Headlamp in-cluster |
7373
| config.baseURL | string | `""` | Base URL path for Headlamp UI |
74+
| config.sessionTTL | int | `86400` | The time in seconds for the internal session to remain valid (Default: 86400/24h, Min: 1 , Max: 31536000/1yr) |
7475
| config.pluginsDir | string | `"/headlamp/plugins"` | Directory to load Headlamp plugins from |
7576
| config.enableHelm | bool | `false` | Enable Helm operations like install, upgrade and uninstall of Helm charts |
7677
| config.extraArgs | array | `[]` | Additional arguments for Headlamp server |

charts/headlamp/templates/deployment.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,9 @@ spec:
245245
{{- with .Values.config.pluginsDir}}
246246
- "-plugins-dir={{ . }}"
247247
{{- end }}
248+
{{- if hasKey .Values.config "sessionTTL" }}
249+
- "-session-ttl={{ .Values.config.sessionTTL }}"
250+
{{- end }}
248251
{{- if not $oidc.externalSecret.enabled}}
249252
# Check if externalSecret is disabled
250253
{{- if or (ne $oidc.clientID "") (ne $clientID "") }}

charts/headlamp/tests/expected_templates/azure-oidc-with-validators.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ spec:
115115
- "-in-cluster"
116116
- "-in-cluster-context-name=main"
117117
- "-plugins-dir=/headlamp/plugins"
118+
- "-session-ttl=86400"
118119
# Check if externalSecret is disabled
119120
# Check if clientID is non empty either from env or oidc.config
120121
- "-oidc-client-id=$(OIDC_CLIENT_ID)"

charts/headlamp/tests/expected_templates/default.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ spec:
112112
- "-in-cluster"
113113
- "-in-cluster-context-name=main"
114114
- "-plugins-dir=/headlamp/plugins"
115+
- "-session-ttl=86400"
115116
# Check if externalSecret is disabled
116117
ports:
117118
- name: http

0 commit comments

Comments
 (0)