- Installed and configured SCST with 7 handlers - Installed and configured mhVTL with 2 Quantum libraries and 8 LTO-8 drives - Implemented all VTL API endpoints (8/9 working) - Fixed NULL device_path handling in drives endpoint - Added comprehensive error handling and validation - Implemented async tape load/unload operations - Created SCST installation guide for Ubuntu 24.04 - Created mhVTL installation and configuration guide - Added VTL testing guide and automated test scripts - All core API tests passing (89% success rate) Infrastructure status: - PostgreSQL: Configured with proper permissions - SCST: Active with kernel module loaded - mhVTL: 2 libraries (Quantum Scalar i500, Scalar i40) - mhVTL: 8 drives (all Quantum ULTRIUM-HH8 LTO-8) - Calypso API: 8/9 VTL endpoints functional Documentation added: - src/srs-technical-spec-documents/scst-installation.md - src/srs-technical-spec-documents/mhvtl-installation.md - VTL-TESTING-GUIDE.md - scripts/test-vtl.sh Co-Authored-By: Warp <agent@warp.dev>
156 lines
3.6 KiB
Go
156 lines
3.6 KiB
Go
package router
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/atlasos/calypso/internal/auth"
|
|
"github.com/atlasos/calypso/internal/common/database"
|
|
"github.com/atlasos/calypso/internal/iam"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// authMiddleware validates JWT tokens and sets user context
|
|
func authMiddleware(authHandler *auth.Handler) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
// Extract token from Authorization header
|
|
authHeader := c.GetHeader("Authorization")
|
|
if authHeader == "" {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "missing authorization header"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
// Parse Bearer token
|
|
parts := strings.SplitN(authHeader, " ", 2)
|
|
if len(parts) != 2 || parts[0] != "Bearer" {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid authorization header format"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
token := parts[1]
|
|
|
|
// Validate token and get user
|
|
user, err := authHandler.ValidateToken(token)
|
|
if err != nil {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid or expired token"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
// Load user roles and permissions from database
|
|
// We need to get the DB from the auth handler's context
|
|
// For now, we'll load them in the permission middleware instead
|
|
|
|
// Set user in context
|
|
c.Set("user", user)
|
|
c.Set("user_id", user.ID)
|
|
c.Set("username", user.Username)
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// requireRole creates middleware that requires a specific role
|
|
func requireRole(roleName string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
user, exists := c.Get("user")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
authUser, ok := user.(*iam.User)
|
|
if !ok {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user context"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
// Load roles if not already loaded
|
|
if len(authUser.Roles) == 0 {
|
|
// Get DB from context (set by router)
|
|
db, exists := c.Get("db")
|
|
if exists {
|
|
if dbConn, ok := db.(*database.DB); ok {
|
|
roles, err := iam.GetUserRoles(dbConn, authUser.ID)
|
|
if err == nil {
|
|
authUser.Roles = roles
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if user has the required role
|
|
hasRole := false
|
|
for _, role := range authUser.Roles {
|
|
if role == roleName {
|
|
hasRole = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasRole {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|
|
// requirePermission creates middleware that requires a specific permission
|
|
func requirePermission(resource, action string) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
user, exists := c.Get("user")
|
|
if !exists {
|
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "authentication required"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
authUser, ok := user.(*iam.User)
|
|
if !ok {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": "invalid user context"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
// Load permissions if not already loaded
|
|
if len(authUser.Permissions) == 0 {
|
|
// Get DB from context (set by router)
|
|
db, exists := c.Get("db")
|
|
if exists {
|
|
if dbConn, ok := db.(*database.DB); ok {
|
|
permissions, err := iam.GetUserPermissions(dbConn, authUser.ID)
|
|
if err == nil {
|
|
authUser.Permissions = permissions
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if user has the required permission
|
|
permissionName := resource + ":" + action
|
|
hasPermission := false
|
|
for _, perm := range authUser.Permissions {
|
|
if perm == permissionName {
|
|
hasPermission = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !hasPermission {
|
|
c.JSON(http.StatusForbidden, gin.H{"error": "insufficient permissions"})
|
|
c.Abort()
|
|
return
|
|
}
|
|
|
|
c.Next()
|
|
}
|
|
}
|
|
|