Cleanup: remove dead auth middleware and fix security log leak
CI / test (push) Failing after 12m28s

- Remove dead AdminOnly() and AdminTokenAuth() middleware (unused since JWT switch)
- Remove dead RequireScope() middleware (also unused)
- Fix seed.go: only log password when auto-generated (was logging every time)
- Fix seed.go: use admin.Username (normalized) instead of raw username in log
- Simplify generateRandomPassword: 12 bytes (24 hex chars) instead of 24 bytes then truncate
- Me handler: use claims.Subject (UUID) for lookup instead of username
- Remove unused /logout endpoint (stateless JWT)
This commit is contained in:
2026-07-31 17:26:31 -04:00
parent ddc73957cb
commit de5f7ca4ee
5 changed files with 14 additions and 87 deletions
+1 -3
View File
@@ -66,6 +66,4 @@ func (h *LoginHandler) Login(c *gin.Context) {
})
}
func (h *LoginHandler) Logout(c *gin.Context) {
c.Status(http.StatusOK)
}
+6 -1
View File
@@ -29,7 +29,12 @@ func (h *MeHandler) Me(c *gin.Context) {
}
var user db.AdminUser
if err := h.db.Where("username = ?", claims.Username).First(&user).Error; err != nil {
userID, err := uuid.Parse(claims.Subject)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "unauthorized", "message": "Invalid token claims"}})
return
}
if err := h.db.Where("id = ?", userID).First(&user).Error; err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": gin.H{"code": "unauthorized", "message": "User not found"}})
return
}
-78
View File
@@ -65,84 +65,6 @@ func APIKeyAuth(authService *auth.Service) gin.HandlerFunc {
}
}
func RequireScope(authService *auth.Service, scope string) gin.HandlerFunc {
return func(c *gin.Context) {
apiKey, exists := c.Get(ApiKeyCtx)
if !exists {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"error": gin.H{
"code": "invalid_api_key",
"message": "Authentication required",
},
})
return
}
key := apiKey.(*db.ApiKey)
if !authService.HasScope(key, scope) {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"error": gin.H{
"code": "insufficient_scope",
"message": "API key lacks required scope: " + scope,
},
})
return
}
c.Next()
}
}
func AdminOnly() gin.HandlerFunc {
return func(c *gin.Context) {
apiKey, exists := c.Get(ApiKeyCtx)
if !exists {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"error": gin.H{
"code": "unauthorized",
"message": "Admin access required",
},
})
return
}
key := apiKey.(*db.ApiKey)
if !key.IsAdmin {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"error": gin.H{
"code": "unauthorized",
"message": "Admin access required",
},
})
return
}
c.Next()
}
}
func AdminTokenAuth(token string) gin.HandlerFunc {
return func(c *gin.Context) {
adminToken := c.GetHeader("X-Admin-Token")
if adminToken == "" {
adminToken = c.GetHeader("Authorization")
adminToken = strings.TrimPrefix(adminToken, "Bearer ")
}
if adminToken != token {
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
"error": gin.H{
"code": "unauthorized",
"message": "Invalid admin token",
},
})
return
}
c.Next()
}
}
func AdminSessionAuth(jwtService *auth.AdminJWTService) gin.HandlerFunc {
return func(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
-1
View File
@@ -104,7 +104,6 @@ func New(cfg *config.Config, db *gorm.DB, llamaManager *llama.Manager) *gin.Engi
// Admin API v1 (JWT session auth)
adminV1 := v1.Group("/admin")
adminV1.POST("/login", adminLoginHandler.Login)
adminV1.POST("/logout", adminLoginHandler.Logout)
adminSession := adminV1.Group("")
adminSession.Use(middleware.AdminSessionAuth(adminJWTService))
adminSession.GET("/me", adminMeHandler.Me)
+7 -4
View File
@@ -16,7 +16,7 @@ func generateRandomPassword(length int) (string, error) {
if _, err := rand.Read(bytes); err != nil {
return "", err
}
return hex.EncodeToString(bytes)[:length], nil
return hex.EncodeToString(bytes), nil
}
func SeedAdminUser(db *gorm.DB, username, password string) error {
@@ -28,13 +28,14 @@ func SeedAdminUser(db *gorm.DB, username, password string) error {
}
pwd := password
autoGenerated := false
if pwd == "" {
var err error
pwd, err = generateRandomPassword(24)
pwd, err = generateRandomPassword(12)
if err != nil {
return err
}
slog.Warn("no ADMIN_PASSWORD set — generated random password (save this, it won't be shown again)")
autoGenerated = true
}
hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost)
@@ -54,6 +55,8 @@ func SeedAdminUser(db *gorm.DB, username, password string) error {
}
slog.Info("admin user seeded", "username", admin.Username)
slog.Warn("ADMIN USER: username=" + username + " password=" + pwd + " (save this, it won't be shown again)")
if autoGenerated {
slog.Warn("ADMIN USER: username=" + admin.Username + " password=" + pwd + " (save this, it won't be shown again)")
}
return nil
}