122 lines
3.7 KiB
Go
122 lines
3.7 KiB
Go
package middleware
|
|
|
|
import (
|
|
"git.itzana.me/StrafesNET/dev-service/pkg/authz"
|
|
"github.com/gin-gonic/gin"
|
|
log "github.com/sirupsen/logrus"
|
|
"net/http"
|
|
)
|
|
|
|
// UserSession is middleware that handles user session validation and setup.
|
|
func UserSession(authService *authz.Service) gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
cookie, err := ctx.Request.Cookie("session_id")
|
|
if err != nil {
|
|
log.WithError(err).Debug("No session cookie found")
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
sessionId := cookie.Value
|
|
|
|
// Validate session
|
|
valid, err := authService.ValidateSessionID(ctx, sessionId)
|
|
if err != nil || !valid {
|
|
log.WithError(err).WithField("session_id", sessionId).Info("Invalid session")
|
|
ctx.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
// Find or create user using the authz service
|
|
user, err := authService.GetOrCreateUserFromSession(ctx, sessionId)
|
|
if err != nil {
|
|
log.WithError(err).WithField("session_id", sessionId).Error("Failed to get/create user from session")
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "User management failed"})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
// Get user session
|
|
userSession, err := authService.GetUserAuthProfile(ctx, sessionId)
|
|
if err != nil {
|
|
log.WithError(err).WithField("session_id", sessionId).Error("Failed to get user session")
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch user session"})
|
|
}
|
|
|
|
// GetCurrentUser user roles
|
|
userRoles, err := authService.GetUserRoles(ctx, cookie.Value)
|
|
if err != nil {
|
|
log.WithError(err).WithField("session_id", sessionId).Error("Failed to get user roles")
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch user roles"})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
// Attach user and admin status to the context
|
|
ctx.Set(authz.ContextKeyUser, user)
|
|
isAdmin := authService.HasAdminRole(userRoles)
|
|
ctx.Set(authz.ContextKeyIsAdmin, isAdmin)
|
|
ctx.Set(authz.ContextKeyProfile, userSession)
|
|
ctx.Set(authz.ContextKeyRoles, userRoles)
|
|
|
|
log.WithFields(log.Fields{
|
|
"user_id": user.ID,
|
|
"username": user.Username,
|
|
"is_admin": isAdmin,
|
|
"num_roles": len(userRoles),
|
|
}).Debug("User session validated")
|
|
|
|
ctx.Next()
|
|
}
|
|
}
|
|
|
|
// RedirectIfNotLoggedIn is a simpler middleware that redirects to a specified URL
|
|
// if the user is not logged in, instead of returning a JSON error.
|
|
func RedirectIfNotLoggedIn(authService *authz.Service) gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
redirectURL, err := authService.GetLoginUrl(ctx)
|
|
if err != nil {
|
|
log.WithError(err).Error("Failed to get login url")
|
|
ctx.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to fetch login url"})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
cookie, err := ctx.Request.Cookie("session_id")
|
|
if err != nil {
|
|
log.WithError(err).Debug("No session cookie found, redirecting")
|
|
ctx.Redirect(302, redirectURL)
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
sessionId := cookie.Value
|
|
|
|
// Validate session
|
|
valid, err := authService.ValidateSessionID(ctx, sessionId)
|
|
if err != nil || !valid {
|
|
log.WithError(err).WithField("session_id", sessionId).Info("Invalid session, redirecting")
|
|
ctx.Redirect(302, redirectURL)
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
// Session is valid, continue to the next middleware/handler
|
|
ctx.Next()
|
|
}
|
|
}
|
|
|
|
// RequireAdmin is middleware that ensures only admin users can access certain routes
|
|
func RequireAdmin(authService *authz.Service) gin.HandlerFunc {
|
|
return func(ctx *gin.Context) {
|
|
// Use the helper function to check if user is admin
|
|
if !authService.ContextIsAdmin(ctx) {
|
|
ctx.JSON(http.StatusForbidden, gin.H{"error": "Admin access required"})
|
|
ctx.Abort()
|
|
return
|
|
}
|
|
|
|
ctx.Next()
|
|
}
|
|
}
|