Browse Source

[Admin UI] Login not possible due to securecookie error (#7374)

* [Admin UI] Login not possible due to securecookie error

* avoid 404 favicon

* Update weed/admin/dash/auth_middleware.go

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>

* address comments

* avoid variable over shadowing

* log session save error

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
pull/7380/head
Chris Lu 5 days ago
committed by GitHub
parent
commit
9f4075441c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 14
      weed/admin/dash/auth_middleware.go
  2. 5
      weed/admin/handlers/admin_handlers.go
  3. 95
      weed/command/admin.go

14
weed/admin/dash/auth_middleware.go

@ -5,6 +5,7 @@ import (
"github.com/gin-contrib/sessions"
"github.com/gin-gonic/gin"
"github.com/seaweedfs/seaweedfs/weed/glog"
)
// ShowLogin displays the login page
@ -31,9 +32,16 @@ func (s *AdminServer) HandleLogin(username, password string) gin.HandlerFunc {
if loginUsername == username && loginPassword == password {
session := sessions.Default(c)
// Clear any existing invalid session data before setting new values
session.Clear()
session.Set("authenticated", true)
session.Set("username", loginUsername)
session.Save()
if err := session.Save(); err != nil {
// Log the detailed error server-side for diagnostics
glog.Errorf("Failed to save session for user %s: %v", loginUsername, err)
c.Redirect(http.StatusSeeOther, "/login?error=Unable to create session. Please try again or contact administrator.")
return
}
c.Redirect(http.StatusSeeOther, "/admin")
return
@ -48,6 +56,8 @@ func (s *AdminServer) HandleLogin(username, password string) gin.HandlerFunc {
func (s *AdminServer) HandleLogout(c *gin.Context) {
session := sessions.Default(c)
session.Clear()
session.Save()
if err := session.Save(); err != nil {
glog.Warningf("Failed to save session during logout: %v", err)
}
c.Redirect(http.StatusSeeOther, "/login")
}

5
weed/admin/handlers/admin_handlers.go

@ -48,6 +48,11 @@ func (h *AdminHandlers) SetupRoutes(r *gin.Engine, authRequired bool, username,
// Health check (no auth required)
r.GET("/health", h.HealthCheck)
// Favicon route (no auth required) - redirect to static version
r.GET("/favicon.ico", func(c *gin.Context) {
c.Redirect(http.StatusMovedPermanently, "/static/favicon.ico")
})
if authRequired {
// Authentication routes (no auth required)
r.GET("/login", h.authHandlers.ShowLogin)

95
weed/command/admin.go

@ -191,31 +191,7 @@ func startAdminServer(ctx context.Context, options AdminOptions) error {
r := gin.New()
r.Use(gin.Logger(), gin.Recovery())
// Session store - always auto-generate session key
sessionKeyBytes := make([]byte, 32)
_, err := rand.Read(sessionKeyBytes)
if err != nil {
return fmt.Errorf("failed to generate session key: %w", err)
}
store := cookie.NewStore(sessionKeyBytes)
// Configure session options to ensure cookies are properly saved
store.Options(sessions.Options{
Path: "/",
MaxAge: 3600 * 24, // 24 hours
})
r.Use(sessions.Sessions("admin-session", store))
// Static files - serve from embedded filesystem
staticFS, err := admin.GetStaticFS()
if err != nil {
log.Printf("Warning: Failed to load embedded static files: %v", err)
} else {
r.StaticFS("/static", http.FS(staticFS))
}
// Create data directory if specified
// Create data directory first if specified (needed for session key storage)
var dataDir string
if *options.dataDir != "" {
// Expand tilde (~) to home directory
@ -236,6 +212,35 @@ func startAdminServer(ctx context.Context, options AdminOptions) error {
fmt.Printf("Data directory created/verified: %s\n", dataDir)
}
// Detect TLS configuration to set Secure cookie flag
cookieSecure := viper.GetString("https.admin.key") != ""
// Session store - load or generate session key
sessionKeyBytes, err := loadOrGenerateSessionKey(dataDir)
if err != nil {
return fmt.Errorf("failed to get session key: %w", err)
}
store := cookie.NewStore(sessionKeyBytes)
// Configure session options to ensure cookies are properly saved
store.Options(sessions.Options{
Path: "/",
MaxAge: 3600 * 24, // 24 hours
HttpOnly: true, // Prevent JavaScript access
Secure: cookieSecure, // Set based on actual TLS configuration
SameSite: http.SameSiteLaxMode,
})
r.Use(sessions.Sessions("admin-session", store))
// Static files - serve from embedded filesystem
staticFS, err := admin.GetStaticFS()
if err != nil {
log.Printf("Warning: Failed to load embedded static files: %v", err)
} else {
r.StaticFS("/static", http.FS(staticFS))
}
// Create admin server
adminServer := dash.NewAdminServer(*options.masters, nil, dataDir)
@ -331,6 +336,46 @@ func GetAdminOptions() *AdminOptions {
return &AdminOptions{}
}
// loadOrGenerateSessionKey loads an existing session key from dataDir or generates a new one
func loadOrGenerateSessionKey(dataDir string) ([]byte, error) {
const sessionKeyLength = 32
if dataDir == "" {
// No persistence, generate random key
log.Println("No dataDir specified, generating ephemeral session key")
key := make([]byte, sessionKeyLength)
_, err := rand.Read(key)
return key, err
}
sessionKeyPath := filepath.Join(dataDir, ".session_key")
// Try to load existing key
if data, err := os.ReadFile(sessionKeyPath); err == nil {
if len(data) == sessionKeyLength {
log.Printf("Loaded persisted session key from %s", sessionKeyPath)
return data, nil
}
log.Printf("Warning: Invalid session key file (expected %d bytes, got %d), generating new key", sessionKeyLength, len(data))
} else if !os.IsNotExist(err) {
log.Printf("Warning: Failed to read session key from %s: %v. A new key will be generated.", sessionKeyPath, err)
}
// Generate new key
key := make([]byte, sessionKeyLength)
if _, err := rand.Read(key); err != nil {
return nil, err
}
// Save key for future use
if err := os.WriteFile(sessionKeyPath, key, 0600); err != nil {
log.Printf("Warning: Failed to persist session key: %v", err)
} else {
log.Printf("Generated and persisted new session key to %s", sessionKeyPath)
}
return key, nil
}
// expandHomeDir expands the tilde (~) in a path to the user's home directory
func expandHomeDir(path string) (string, error) {
if path == "" {

Loading…
Cancel
Save