Files
2024-07-19 17:04:42 +02:00

103 lines
3.0 KiB
Go

package middleware
import (
"context"
"errors"
model2 "mangezmieux-backend/internal/acl/model"
"mangezmieux-backend/internal/jwt"
"mangezmieux-backend/internal/logger"
"mangezmieux-backend/internal/responses"
"mangezmieux-backend/internal/users/model"
"strings"
"github.com/gin-gonic/gin"
)
const CtxUser = "user"
const CtxUserRight = "userRight"
const CtxRole = "role"
const CtxToken = "token"
type IntrospectService interface {
Introspect(token string) (user *model.User, err error)
GetRole(ctx context.Context, user *model.User) (userRight *model2.UserRight, err error)
GetAllRole(ctx context.Context) ([]*model2.Role, error)
}
func GetAuthenticationMiddleware(introspectService IntrospectService, jwtService *jwt.Service) gin.HandlerFunc {
return func(c *gin.Context) {
token, err := getTokenFromGinCtx(c)
c.Set(CtxToken, token)
ctx := c.Request.Context()
ctx = context.WithValue(ctx, CtxToken, token)
if err != nil {
logger.GetLogger().WithError(err).Debug("no token found")
responses.JSONErrorWithMessage(c.Writer, responses.ErrBadRequestFormat, err.Error())
c.Abort()
return
}
_, err = jwtService.ValidateToken(token)
if err != nil {
logger.GetLogger().WithError(err).Debug("error during token validation")
responses.JSONErrorWithMessage(c.Writer, responses.ErrBadRequestFormat, err.Error())
c.Abort()
return
}
user, err := introspectService.Introspect(token)
if err != nil {
logger.GetLogger().WithError(err).Debug("error during introspect")
responses.JSONErrorWithMessage(c.Writer, responses.ErrBadRequestFormat, err.Error())
c.Abort()
return
}
c.Set(CtxUser, user)
userRight, err := introspectService.GetRole(ctx, user)
if err != nil {
logger.GetLogger().WithError(err).Debug("error during getting role for user")
responses.JSONErrorWithMessage(c.Writer, responses.ErrBadRequestFormat, err.Error())
c.Abort()
return
}
c.Set(CtxUserRight, userRight)
roles, err := introspectService.GetAllRole(ctx)
if err != nil {
logger.GetLogger().WithError(err).Debug("error during getting role map")
responses.JSONErrorWithMessage(c.Writer, responses.ErrBadRequestFormat, err.Error())
c.Abort()
return
}
c.Set(CtxRole, roles)
c.Next()
}
}
// getTokenFromGinCtx allow to get the access token of the request in the Authorization request header.
// It will split the header and remove the Bearer part to extract only the token.
func getTokenFromGinCtx(c *gin.Context) (string, error) {
auth := c.GetHeader("Authorization")
if auth != "" {
authSplitted := strings.SplitN(auth, " ", 2)
if len(authSplitted) != 2 {
return "", errors.New("malformed authorization header")
}
if strings.ToUpper(authSplitted[0]) != strings.ToUpper("Bearer") && strings.ToUpper(authSplitted[0]) != strings.ToUpper("JWT") {
return "", errors.New("unsupported authentication scheme")
}
return authSplitted[1], nil
}
if cookie, err := c.Cookie("token"); err == nil {
return cookie, nil
}
return "", errors.New("no token found in the request")
}