Skip to content

Commit c9c3784

Browse files
committed
WIP: Add session persistence across config reloads
- Cache session state (authenticator, CSRF verifier) across server restarts - Only recreate sessions when session-related config changes - Update run-bridge.sh to use static config file for testing - Add examples/bridge-config.yaml with static development settings Users now stay logged in when non-session config changes (branding, plugins, etc.) Sessions are only invalidated when auth config actually changes.
1 parent 842ec57 commit c9c3784

File tree

3 files changed

+133
-22
lines changed

3 files changed

+133
-22
lines changed

cmd/bridge/main.go

Lines changed: 116 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
authopts "github.com/openshift/console/cmd/bridge/config/auth"
2121
"github.com/openshift/console/cmd/bridge/config/session"
2222
"github.com/openshift/console/pkg/auth"
23+
"github.com/openshift/console/pkg/auth/csrfverifier"
2324
"github.com/openshift/console/pkg/controllers"
2425
"github.com/openshift/console/pkg/flags"
2526
"github.com/openshift/console/pkg/knative"
@@ -148,13 +149,35 @@ func main() {
148149

149150
configFile := fs.Lookup("config").Value.String()
150151

152+
// Track session-related config to determine if we need to recreate sessions
153+
var (
154+
cachedCompletedAuthnOptions *authopts.CompletedOptions
155+
cachedCompletedSessionOptions *session.CompletedOptions
156+
cachedAuthenticator auth.Authenticator
157+
cachedCSRFVerifier *csrfverifier.CSRFVerifier
158+
)
159+
151160
// Run server in a loop to support restarts
152161
for {
153162
// Parse and apply config
154163
applyConfig(fs, bridgeOptions, authOptions, sessionOptions)
155164

156-
// Build the server with current config
157-
srv := createServer(bridgeOptions, authOptions, sessionOptions)
165+
// Build the server with current config, potentially reusing session state
166+
srv, newAuthn, newSession := createServer(
167+
bridgeOptions,
168+
authOptions,
169+
sessionOptions,
170+
cachedCompletedAuthnOptions,
171+
cachedCompletedSessionOptions,
172+
cachedAuthenticator,
173+
cachedCSRFVerifier,
174+
)
175+
176+
// Cache the new session state for next iteration
177+
cachedCompletedAuthnOptions = newAuthn
178+
cachedCompletedSessionOptions = newSession
179+
cachedAuthenticator = srv.Authenticator
180+
cachedCSRFVerifier = srv.CSRFVerifier
158181

159182
// Run the server with config file watching
160183
shouldRestart := runServer(bridgeOptions, srv, configFile)
@@ -164,6 +187,51 @@ func main() {
164187
}
165188
}
166189

190+
func sessionConfigHasChanged(
191+
authOptions *authopts.AuthOptions,
192+
sessionOptions *session.SessionOptions,
193+
cachedAuthnOptions *authopts.CompletedOptions,
194+
cachedSessionOptions *session.CompletedOptions,
195+
) bool {
196+
// If no cached options, session config has "changed" (needs to be created)
197+
if cachedAuthnOptions == nil || cachedSessionOptions == nil {
198+
return true
199+
}
200+
201+
// Compare authentication options that affect sessions
202+
if authOptions.AuthType != cachedAuthnOptions.AuthType {
203+
return true
204+
}
205+
206+
// Compare issuer URLs
207+
cachedIssuerURL := ""
208+
if cachedAuthnOptions.IssuerURL != nil {
209+
cachedIssuerURL = cachedAuthnOptions.IssuerURL.String()
210+
}
211+
if authOptions.IssuerURL != cachedIssuerURL {
212+
return true
213+
}
214+
215+
if authOptions.ClientID != cachedAuthnOptions.ClientID {
216+
return true
217+
}
218+
if authOptions.ClientSecretFilePath != "" {
219+
// Client secret file path changed - assume secret might have changed
220+
return true
221+
}
222+
if authOptions.InactivityTimeoutSeconds != cachedAuthnOptions.InactivityTimeoutSeconds {
223+
return true
224+
}
225+
226+
// Compare session options
227+
if sessionOptions.CookieEncryptionKeyPath != "" || sessionOptions.CookieAuthenticationKeyPath != "" {
228+
// If key paths are set, assume keys might have changed
229+
return true
230+
}
231+
232+
return false
233+
}
234+
167235
func addFlags(fs *flag.FlagSet, bridgeOptions *BridgeOptions, authOptions *authopts.AuthOptions, sessionOptions *session.SessionOptions) {
168236
authOptions.AddFlags(fs)
169237
sessionOptions.AddFlags(fs)
@@ -254,7 +322,15 @@ func applyConfig(fs *flag.FlagSet, bridgeOptions *BridgeOptions, authOptions *au
254322
sessionOptions.ApplyConfig(&cfg.Session)
255323
}
256324

257-
func createServer(bridgeOptions *BridgeOptions, authOptions *authopts.AuthOptions, sessionOptions *session.SessionOptions) *server.Server {
325+
func createServer(
326+
bridgeOptions *BridgeOptions,
327+
authOptions *authopts.AuthOptions,
328+
sessionOptions *session.SessionOptions,
329+
cachedAuthnOptions *authopts.CompletedOptions,
330+
cachedSessionOptions *session.CompletedOptions,
331+
cachedAuthenticator auth.Authenticator,
332+
cachedCSRFVerifier *csrfverifier.CSRFVerifier,
333+
) (*server.Server, *authopts.CompletedOptions, *session.CompletedOptions) {
258334
baseURL, err := flags.ValidateFlagIsURL("base-address", bridgeOptions.fBaseAddress, true)
259335
flags.FatalIfFailed(err)
260336

@@ -418,16 +494,34 @@ func createServer(bridgeOptions *BridgeOptions, authOptions *authopts.AuthOption
418494
Capabilities: capabilities,
419495
}
420496

421-
completedAuthnOptions, err := authOptions.Complete()
422-
if err != nil {
423-
klog.Fatalf("failed to complete authentication options: %v", err)
424-
os.Exit(1)
425-
}
497+
// Check if we can reuse cached session config
498+
var completedAuthnOptions *authopts.CompletedOptions
499+
var completedSessionOptions *session.CompletedOptions
500+
sessionConfigChanged := sessionConfigHasChanged(authOptions, sessionOptions, cachedAuthnOptions, cachedSessionOptions)
501+
502+
if !sessionConfigChanged && cachedAuthnOptions != nil && cachedSessionOptions != nil {
503+
// Reuse cached session configuration
504+
klog.Info("Reusing existing session configuration")
505+
completedAuthnOptions = cachedAuthnOptions
506+
completedSessionOptions = cachedSessionOptions
507+
} else {
508+
// Create session configuration
509+
if cachedAuthnOptions != nil {
510+
klog.Info("Creating new session state")
511+
}
426512

427-
completedSessionOptions, err := sessionOptions.Complete(completedAuthnOptions.AuthType)
428-
if err != nil {
429-
klog.Fatalf("failed to complete session options: %v", err)
430-
os.Exit(1)
513+
var err error
514+
completedAuthnOptions, err = authOptions.Complete()
515+
if err != nil {
516+
klog.Fatalf("failed to complete authentication options: %v", err)
517+
os.Exit(1)
518+
}
519+
520+
completedSessionOptions, err = sessionOptions.Complete(completedAuthnOptions.AuthType)
521+
if err != nil {
522+
klog.Fatalf("failed to complete session options: %v", err)
523+
os.Exit(1)
524+
}
431525
}
432526

433527
// if !in-cluster (dev) we should not pass these values to the frontend
@@ -755,11 +849,18 @@ func createServer(bridgeOptions *BridgeOptions, authOptions *authopts.AuthOption
755849
}
756850
srv.TokenReviewer = tokenReviewer
757851

758-
if err := completedAuthnOptions.ApplyTo(srv, k8sEndpoint, caCertFilePath, completedSessionOptions); err != nil {
759-
klog.Fatalf("failed to apply configuration to server: %v", err)
852+
// Reuse cached authenticator and CSRF verifier if session config hasn't changed
853+
if !sessionConfigChanged && cachedAuthenticator != nil && cachedCSRFVerifier != nil {
854+
klog.Info("Reusing existing authenticator")
855+
srv.Authenticator = cachedAuthenticator
856+
srv.CSRFVerifier = cachedCSRFVerifier
857+
} else {
858+
if err := completedAuthnOptions.ApplyTo(srv, k8sEndpoint, caCertFilePath, completedSessionOptions); err != nil {
859+
klog.Fatalf("failed to apply configuration to server: %v", err)
860+
}
760861
}
761862

762-
return srv
863+
return srv, completedAuthnOptions, completedSessionOptions
763864
}
764865

765866
func runServer(bridgeOptions *BridgeOptions, srv *server.Server, configFile string) bool {

examples/bridge-config.yaml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: console.openshift.io/v1
2+
kind: ConsoleConfig
3+
servingInfo:
4+
bindAddress: http://0.0.0.0:9000
5+
clusterInfo:
6+
consoleBaseAddress: http://localhost:9000
7+
consoleBasePath: /
8+
customization:
9+
branding: okd
10+
documentationBaseURL: https://docs.okd.io/latest/
11+
auth:
12+
authType: openshift
13+
clientID: console-oauth-client
14+
clientSecretFile: examples/console-client-secret
15+
oauthEndpointCAFile: examples/ca.crt

examples/run-bridge.sh

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,13 @@
33
set -exuo pipefail
44

55
./bin/bridge \
6-
--base-address=http://localhost:9000 \
6+
--config=examples/bridge-config.yaml \
77
--ca-file=examples/ca.crt \
88
--k8s-mode=off-cluster \
99
--k8s-mode-off-cluster-endpoint="$(oc whoami --show-server)" \
1010
--k8s-mode-off-cluster-skip-verify-tls=true \
11-
--listen=http://127.0.0.1:9000 \
12-
--public-dir=./frontend/public/dist \
13-
--user-auth=openshift \
14-
--user-auth-oidc-client-id=console-oauth-client \
15-
--user-auth-oidc-client-secret-file=examples/console-client-secret \
16-
--user-auth-oidc-ca-file=examples/ca.crt \
1711
--k8s-mode-off-cluster-service-account-bearer-token-file=examples/token \
1812
--k8s-mode-off-cluster-alertmanager="$(oc -n openshift-config-managed get configmap monitoring-shared-config -o jsonpath='{.data.alertmanagerPublicURL}')" \
1913
--k8s-mode-off-cluster-thanos="$(oc -n openshift-config-managed get configmap monitoring-shared-config -o jsonpath='{.data.thanosPublicURL}')" \
14+
--public-dir=./frontend/public/dist \
2015
$@

0 commit comments

Comments
 (0)