@@ -0,0 +1,167 @@
package AccessHandler
import (
"fmt"
"log"
"net/http"
"strings"
"gitea.tecamino.com/paadi/access-handler/models"
"gitea.tecamino.com/paadi/tecamino-logger/logging"
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
)
// SetMiddlewareLogger
//
// Description:
//
// Registers a Gin middleware that attaches a custom logger instance
// to every incoming request via the Gin context. This allows other
// middleware and handlers to access the logger using:
//
// logger := c.MustGet("logger").(*logging.Logger)
//
// Parameters:
// - r: The Gin engine to which the middleware is applied.
// - logger: A pointer to the application's custom logger.
//
// Usage:
//
// SetMiddlewareLogger(router, logger)
func ( aH * AccessHandlerAPI ) SetMiddlewareLogger ( r * gin . Engine , logger * logging . Logger ) {
// Add middleware that injects logger into context
r . Use ( func ( c * gin . Context ) {
c . Set ( "logger" , logger )
c . Next ( )
} )
}
// AuthMiddleware
//
// Description:
//
// A Gin middleware that performs authentication using a JWT token stored
// in a cookie named "access_token". It validates the token and extracts
// the user's role from the claims, storing it in the Gin context.
//
// Behavior:
// - Requires that SetMiddlewareLogger was used earlier to inject the logger.
// - If the JWT cookie is missing or invalid, it aborts the request with
// an appropriate HTTP error (401 or 500).
//
// Returns:
//
// A Gin handler function that can be used as middleware.
//
// Usage:
//
// r.Use(AuthMiddleware())
func ( aH * AccessHandlerAPI ) AuthMiddleware ( ) gin . HandlerFunc {
return func ( c * gin . Context ) {
// Retrieve logger from Gin context
middlewareLogger , ok := c . Get ( "logger" )
if ! ok {
log . Fatal ( "middleware logger not set — use SetMiddlewareLogger first" )
c . AbortWithStatusJSON ( http . StatusInternalServerError , http . StatusInternalServerError )
return
}
logger := middlewareLogger . ( * logging . Logger )
// Read access token from cookie
cookie , err := c . Cookie ( "access_token" )
if err != nil {
logger . Error ( "AuthMiddleware" , err )
c . AbortWithStatusJSON ( http . StatusUnauthorized , gin . H { "message" : "not logged in" } )
return
}
// Parse and validate JWT token
token , err := jwt . Parse ( cookie , func ( t * jwt . Token ) ( any , error ) {
return ACCESS_SECRET , nil
} )
if err != nil || ! token . Valid {
logger . Error ( "AuthMiddleware" , err )
c . AbortWithStatusJSON ( http . StatusUnauthorized , gin . H { "message" : "invalid token" } )
return
}
// Extract custom claims (role)
if claims , ok := token . Claims . ( jwt . MapClaims ) ; ok {
role , _ := claims [ "role" ] . ( string )
c . Set ( "role" , role )
}
c . Next ( )
}
}
// (AccessHandler).AuthorizeRole
//
// Description:
//
// A role-based authorization middleware. It checks whether the authenticated
// user (based on the "role" set in AuthMiddleware) has permission to access
// the given route. The check is performed by comparing the requested URL
// path against the user’ s allowed permissions.
//
// Parameters:
// - suffix: A URL prefix to trim from the request path before matching
// permissions (e.g., "/api/v1").
//
// Behavior:
// - Fetches the user role from Gin context.
// - Uses aH.GetRoleByKey() to retrieve role records and permissions.
// - Grants access (calls c.Next()) if a matching permission is found.
// - Denies access (401 Unauthorized) if no permission matches.
//
// Usage:
//
// router.GET("/secure/:id", aH.AuthorizeRole("/api/v1"))
func ( aH * AccessHandlerAPI ) AuthorizeRole ( suffix string ) gin . HandlerFunc {
return func ( c * gin . Context ) {
aH . logger . Debug ( "AuthorizeRole" , "permission path of url path" )
permissionPath := strings . TrimPrefix ( c . Request . URL . Path , suffix + "/" )
aH . logger . Debug ( "AuthorizeRole" , "get set role" )
role , ok := c . Get ( "role" )
if ! ok {
aH . logger . Error ( "AuthorizeRole" , "no role set" )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "message" : http . StatusInternalServerError } )
return
}
// Fetch roles and associated permissions from the database or store
var roles [ ] models . Role
err := aH . dbHandler . GetByKey ( & roles , "role" , role , false )
if err != nil {
aH . logger . Error ( "AuthorizeRole" , err )
c . AbortWithStatusJSON ( http . StatusInternalServerError , gin . H { "message" : http . StatusInternalServerError } )
return
}
// Validate that a role was found
if len ( roles ) == 0 {
log . Println ( "not logged in" )
aH . logger . Error ( "AuthorizeRole" , "no logged in" )
c . JSON ( http . StatusUnauthorized , http . StatusUnauthorized )
return
} else if len ( roles ) > 1 {
aH . logger . Error ( "AuthorizeRole" , "more than one record found" )
c . JSON ( http . StatusInternalServerError , http . StatusInternalServerError )
return
}
// Check permissions
for _ , permission := range roles [ 0 ] . Permissions {
fmt . Println ( 100 , permissionPath , permission . Name )
if permission . Name == permissionPath {
c . Next ( )
return
}
}
// Access denied
aH . logger . Error ( "AuthorizeRole" , "Forbidden" )
c . AbortWithStatusJSON ( http . StatusUnauthorized , gin . H { "message" : "Forbidden" } )
}
}