Skip to content

Commit

Permalink
ajustes broken acess control
Browse files Browse the repository at this point in the history
  • Loading branch information
meiryleneavelino committed Nov 27, 2024
1 parent de62854 commit 2bf96f2
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 69 deletions.
4 changes: 2 additions & 2 deletions owasp-top10-2021-apps/a1/ecommerce-api/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ lint:

## Runs project using docker-compose
compose: compose-down
docker-compose -f deployments/docker-compose.yml -p secdevlabs up -d --build --force-recreate
podman-compose -f deployments/docker-compose.yml -p secdevlabs up -d --build --force-recreate

## Down project using docker-compose
compose-down:
docker-compose -f deployments/docker-compose.yml -p secdevlabs down -v --remove-orphans
podman-compose -f deployments/docker-compose.yml -p secdevlabs down -v --remove-orphans

## Generates passwords and set them as environment variables
generate-passwords:
Expand Down
92 changes: 52 additions & 40 deletions owasp-top10-2021-apps/a1/ecommerce-api/app/handlers/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,61 @@ import (
"github.com/labstack/echo"
)

// HealthCheck is the heath check function.
// HealthCheck is the health check function.
func HealthCheck(c echo.Context) error {
return c.String(http.StatusOK, "WORKING\n")
}

// GetTicket returns the userID ticket.
func GetTicket(c echo.Context) error {
// Obter o userID do contexto (definido por um middleware de autenticação)
userIDFromContext := c.Get("userID").(string) // Assumindo que o middleware adiciona userID no contexto

// Obter o userID da URL
id := c.Param("id")

// Verificar se o userID autenticado corresponde ao userID fornecido
if userIDFromContext != id {
return c.JSON(http.StatusForbidden, map[string]string{
"result": "error",
"details": "Access denied. You are not authorized to view this ticket.",
})
}

// Consultar o banco de dados com base no userID
userDataQuery := map[string]interface{}{"userID": id}
userDataResult, err := db.GetUserData(userDataQuery)
if err != nil {
// Erro ao buscar dados do usuário no MongoDB
return c.JSON(http.StatusBadRequest, map[string]string{
"result": "error",
"details": "Error finding this UserID.",
})
}

// Verificar o formato da resposta (JSON ou texto)
format := c.QueryParam("format")
if format == "json" {
return c.JSON(http.StatusOK, map[string]string{
"result": "success",
"username": userDataResult.Username,
"ticket": userDataResult.Ticket,
})
}

// Resposta em texto simples
msgTicket := fmt.Sprintf("Hey, %s! This is your ticket: %s\n", userDataResult.Username, userDataResult.Ticket)
return c.String(http.StatusOK, msgTicket)
}
// Obter o userID do contexto
userIDFromContext, ok := c.Get("userID").(string)
if !ok {
return c.JSON(http.StatusUnauthorized, map[string]string{
"result": "error",
"details": "Invalid user authentication data.",
})
}

// Obter o userID da URL
id := c.Param("id")
if id == "" {
return c.JSON(http.StatusBadRequest, map[string]string{
"result": "error",
"details": "User ID is required.",
})
}

// Verificar se o userID autenticado corresponde ao userID fornecido
if userIDFromContext != id {
return c.JSON(http.StatusForbidden, map[string]string{
"result": "error",
"details": "Access denied. You are not authorized to view this ticket.",
})
}

// Consultar o banco de dados com base no userID
userDataQuery := map[string]interface{}{"userID": id}
userDataResult, err := db.GetUserData(userDataQuery)
if err != nil {
c.Logger().Errorf("Error querying user data: %v", err)
return c.JSON(http.StatusInternalServerError, map[string]string{
"result": "error",
"details": "An internal error occurred. Please try again later.",
})
}

// Verificar o formato da resposta
format := c.QueryParam("format")
if format == "json" {
return c.JSON(http.StatusOK, map[string]interface{}{
"result": "success",
"username": userDataResult.Username,
"ticket": userDataResult.Ticket,
})
}

// Resposta em texto simples
msgTicket := fmt.Sprintf("Hey, %s! This is your ticket: %s\n", userDataResult.Username, userDataResult.Ticket)
return c.String(http.StatusOK, msgTicket)
}
87 changes: 60 additions & 27 deletions owasp-top10-2021-apps/a1/ecommerce-api/app/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net/http"
"os"
"strings"

apiContext "github.com/globocom/secDevLabs/owasp-top10-2021-apps/a1/ecommerce-api/app/context"
"github.com/globocom/secDevLabs/owasp-top10-2021-apps/a1/ecommerce-api/app/handlers"
Expand Down Expand Up @@ -34,27 +35,42 @@ func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c
func isAuthorized(dbInstance *db.DB) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
// Recuperar o token JWT do contexto
user, ok := c.Get("user").(*jwt.Token)
if !ok {
return echo.ErrUnauthorized
return echo.ErrUnauthorized // Retorna 401 se o token estiver ausente ou inválido
}

// Extrair as claims do token
claims, ok := user.Claims.(jwt.MapClaims)
if !ok {
return echo.ErrUnauthorized
return echo.ErrUnauthorized // Retorna 401 se as claims não puderem ser extraídas
}

userID := claims["id"]
// Garantir que a claim "id" exista
userID, ok := claims["id"].(string)
if !ok {
return echo.ErrUnauthorized // Retorna 401 se o campo "id" não existir ou estiver no formato errado
}

// Recuperar o ID do ticket da rota
ticketID := c.Param("id")
if !userHasAccessToTicket(dbInstance, fmt.Sprintf("%v", userID), ticketID) {
return echo.ErrUnauthorized
if ticketID == "" {
return echo.ErrBadRequest // Retorna 400 se o ticket ID não for informado
}

// Verificar permissão no banco de dados
if !userHasAccessToTicket(dbInstance, userID, ticketID) {
return echo.ErrUnauthorized // Retorna 401 se o usuário não tiver permissão
}

// Prosseguir para o próximo handler
return next(c)
}
}
}


// Checks if a user has access to a specific ticket
func userHasAccessToTicket(dbInstance *db.DB, userID, ticketID string) bool {
hasPermission, err := dbInstance.CheckUserPermission(userID, ticketID)
Expand All @@ -66,30 +82,44 @@ func userHasAccessToTicket(dbInstance *db.DB, userID, ticketID string) bool {

// Middleware: Auth checks JWT token
func AuthMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
token := c.Request().Header.Get("Authorization")
if token == "" {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Unauthorized"})
}

_, err := parseToken(token)
if err != nil {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Invalid token"})
}

c.Set("userID", "exampleUserID") // Exemplo simples
return next(c)
}
return func(c echo.Context) error {
tokenHeader := c.Request().Header.Get("Authorization")
if !strings.HasPrefix(tokenHeader, "Bearer ") {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": "Invalid token format"})
}

token := strings.TrimPrefix(tokenHeader, "Bearer ")
userID, err := parseToken(token)
if err != nil {
return c.JSON(http.StatusUnauthorized, map[string]string{"error": err.Error()})
}

c.Set("userID", userID)
return next(c)
}
}

// Simulated token parser
func parseToken(token string) (string, error) {
if token == "valid-token" {
return "user123", nil
}
return "", errors.New("invalid token")
parsedToken, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
return []byte("secretKey"), nil
})
if err != nil || !parsedToken.Valid {
return "", errors.New("invalid token")
}

claims, ok := parsedToken.Claims.(jwt.MapClaims)
if !ok {
return "", errors.New("invalid token claims")
}

userID, ok := claims["id"].(string)
if !ok {
return "", errors.New("invalid user ID in token")
}
return userID, nil
}


func main() {
configAPI := apiContext.GetAPIConfig()

Expand Down Expand Up @@ -121,10 +151,13 @@ func main() {
echoInstance.GET("/healthcheck", handlers.HealthCheck)
echoInstance.POST("/register", handlers.RegisterUser)
echoInstance.POST("/login", handlers.Login)

ticketGroup := echoInstance.Group("/ticket")
ticketGroup.Use(isAuthorized(database))
ticketGroup.GET("/:id", handlers.GetTicket)
ticketGroup.Use(middleware.JWTWithConfig(middleware.JWTConfig{
SigningKey: []byte("secretKey"), // Substitua por uma variável de ambiente
}))
ticketGroup.Use(isAuthorized(database))
ticketGroup.GET("/:id", handlers.GetTicket)

APIport := fmt.Sprintf(":%d", configAPI.APIPort)
echoInstance.Logger.Fatal(echoInstance.Start(APIport))
Expand Down

0 comments on commit 2bf96f2

Please sign in to comment.