Cleanup: remove dead auth middleware and fix security log leak
CI / test (push) Failing after 12m28s
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:
@@ -66,6 +66,4 @@ func (h *LoginHandler) Login(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
func (h *LoginHandler) Logout(c *gin.Context) {
|
||||
c.Status(http.StatusOK)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user