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") }