mirror of
https://github.com/ClusterCockpit/cc-backend
synced 2026-06-17 17:07:29 +02:00
feat: replace gorilla/sessions with alexedwards/scs/v2
Browser sessions are now server-side, stored in the SQLite database via scs/sqlite3store (new `sessions` table, DB migration to version 12) instead of gorilla/sessions client-side cookie storage. Only an opaque random token is kept in the cookie; session data lives server-side and survives restarts. Session middleware is wired as a hybrid to avoid buffering large responses: scs.LoadAndSave on the login/logout write paths, and a non-buffering read-only LoadSession middleware on the secured/config/frontend read paths so the large GraphQL /query responses stream unbuffered. JWT-only APIs (/api, /userapi, /api/metricstore) and static files are left unwrapped. The session cookie Secure flag is now derived from the server config (set when cc-backend terminates TLS itself); previously it was effectively never set. The SESSION_KEY env var is removed as server-side tokens need no signing secret. The dormant Bearer-JWT branch in the frontend urql client is removed; the web UI authenticates GraphQL via the session cookie. Closes #558 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Entire-Checkpoint: b51075f43cc7
This commit is contained in:
@@ -23,9 +23,6 @@ const envString = `
|
||||
# You can generate your own keypair using the gen-keypair tool
|
||||
JWT_PUBLIC_KEY="kzfYrYy+TzpanWZHJ5qSdMj5uKUWgq74BWhQG6copP0="
|
||||
JWT_PRIVATE_KEY="dtPC/6dWJFKZK7KZ78CvWuynylOmjBFyMsUWArwmodOTN9itjL5POlqdZkcnmpJ0yPm4pRaCrvgFaFAbpyik/Q=="
|
||||
|
||||
# Some random bytes used as secret for cookie-based sessions (DO NOT USE THIS ONE IN PRODUCTION)
|
||||
SESSION_KEY="67d829bf61dc5f87a73fd814e2c9f629"
|
||||
`
|
||||
|
||||
const configString = `
|
||||
|
||||
@@ -121,6 +121,7 @@ func (s *Server) init() error {
|
||||
}
|
||||
|
||||
authHandle := auth.GetAuthInstance()
|
||||
sessionManager := authHandle.SessionManager()
|
||||
|
||||
// Middleware must be defined before routes in chi
|
||||
s.router.Use(func(next http.Handler) http.Handler {
|
||||
@@ -220,10 +221,12 @@ func (s *Server) init() error {
|
||||
})
|
||||
}
|
||||
|
||||
s.router.Post("/login", authHandle.Login(loginFailureHandler).ServeHTTP)
|
||||
s.router.HandleFunc("/jwt-login", authHandle.Login(loginFailureHandler).ServeHTTP)
|
||||
// Login/logout mutate the session, so they are wrapped with
|
||||
// scs.LoadAndSave, which commits the session and writes the cookie.
|
||||
s.router.Post("/login", sessionManager.LoadAndSave(authHandle.Login(loginFailureHandler)).ServeHTTP)
|
||||
s.router.Handle("/jwt-login", sessionManager.LoadAndSave(authHandle.Login(loginFailureHandler)))
|
||||
|
||||
s.router.Post("/logout", authHandle.Logout(
|
||||
s.router.Post("/logout", sessionManager.LoadAndSave(authHandle.Logout(
|
||||
http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
rw.Header().Add("Content-Type", "text/html; charset=utf-8")
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
@@ -234,7 +237,7 @@ func (s *Server) init() error {
|
||||
Build: buildInfo,
|
||||
Infos: info,
|
||||
})
|
||||
})).ServeHTTP)
|
||||
}))).ServeHTTP)
|
||||
}
|
||||
|
||||
if flagDev {
|
||||
@@ -246,6 +249,10 @@ func (s *Server) init() error {
|
||||
// Secured routes (require authentication)
|
||||
s.router.Group(func(secured chi.Router) {
|
||||
if !config.Keys.DisableAuthentication {
|
||||
// Non-buffering session load: makes the session available to
|
||||
// AuthViaSession without wrapping/buffering the (potentially large,
|
||||
// e.g. GraphQL /query) response.
|
||||
secured.Use(authHandle.LoadSession)
|
||||
secured.Use(func(next http.Handler) http.Handler {
|
||||
return authHandle.Auth(
|
||||
next,
|
||||
@@ -309,6 +316,7 @@ func (s *Server) init() error {
|
||||
// the /config page route that is registered in the secured group)
|
||||
s.router.Group(func(configapi chi.Router) {
|
||||
if !config.Keys.DisableAuthentication {
|
||||
configapi.Use(authHandle.LoadSession)
|
||||
configapi.Use(func(next http.Handler) http.Handler {
|
||||
return authHandle.AuthConfigAPI(next, onFailureResponse)
|
||||
})
|
||||
@@ -319,6 +327,7 @@ func (s *Server) init() error {
|
||||
// Frontend API routes
|
||||
s.router.Route("/frontend", func(frontendapi chi.Router) {
|
||||
if !config.Keys.DisableAuthentication {
|
||||
frontendapi.Use(authHandle.LoadSession)
|
||||
frontendapi.Use(func(next http.Handler) http.Handler {
|
||||
return authHandle.AuthFrontendAPI(next, onFailureResponse)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user