You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
321 lines
9.4 KiB
Go
321 lines
9.4 KiB
Go
package auth
|
|
|
|
import (
|
|
"encoding/json"
|
|
"io"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func setupTestApp() (*fiber.App, *JWTMiddleware, *MockAuthService) {
|
|
app := fiber.New()
|
|
authService, _ := NewMockAuthService("test-service")
|
|
middleware := NewJWTMiddleware(authService)
|
|
return app, middleware, authService
|
|
}
|
|
|
|
func TestJWTMiddleware_Authenticate(t *testing.T) {
|
|
app, middleware, authService := setupTestApp()
|
|
|
|
// Generate a valid token
|
|
validToken, err := authService.GenerateToken("user123", "testuser", "test@example.com", []string{"player"})
|
|
require.NoError(t, err)
|
|
|
|
app.Get("/protected", middleware.Authenticate(), func(c *fiber.Ctx) error {
|
|
user, _ := GetUserFromContext(c)
|
|
return c.JSON(fiber.Map{"user": user.Username})
|
|
})
|
|
|
|
t.Run("Allows request with valid token", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/protected", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer "+validToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, "testuser", response["user"])
|
|
})
|
|
|
|
t.Run("Rejects request without Authorization header", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/protected", nil)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, StatusUnauthorized, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, ErrAuthHeaderRequired, response["error"])
|
|
})
|
|
|
|
t.Run("Rejects request with invalid Authorization header format", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/protected", nil)
|
|
req.Header.Set(AuthorizationHeader, "Token "+validToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, StatusUnauthorized, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, ErrInvalidAuthHeaderFormat, response["error"])
|
|
})
|
|
|
|
t.Run("Rejects request with invalid token", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/protected", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer invalid-token")
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, StatusUnauthorized, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, ErrInvalidToken, response["error"])
|
|
assert.NotNil(t, response["details"])
|
|
})
|
|
}
|
|
|
|
func TestJWTMiddleware_RequireRole(t *testing.T) {
|
|
app, middleware, authService := setupTestApp()
|
|
|
|
// Generate tokens with different roles
|
|
adminToken, err := authService.GenerateToken("admin1", "admin", "admin@test.com", []string{"admin", "player"})
|
|
require.NoError(t, err)
|
|
|
|
playerToken, err := authService.GenerateToken("player1", "player", "player@test.com", []string{"player"})
|
|
require.NoError(t, err)
|
|
|
|
app.Get("/admin", middleware.Authenticate(), middleware.RequireRole("admin"), func(c *fiber.Ctx) error {
|
|
return c.JSON(fiber.Map{"message": "admin access"})
|
|
})
|
|
|
|
t.Run("Allows access when user has required role", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/admin", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer "+adminToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Denies access when user doesn't have required role", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/admin", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer "+playerToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, StatusForbidden, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, ErrInsufficientPermissions, response["error"])
|
|
assert.Equal(t, "admin", response["required_role"])
|
|
assert.Contains(t, response["user_roles"], "player")
|
|
})
|
|
}
|
|
|
|
func TestJWTMiddleware_RequireAnyRole(t *testing.T) {
|
|
app, middleware, authService := setupTestApp()
|
|
|
|
// Generate tokens with different roles
|
|
adminToken, err := authService.GenerateToken("admin1", "admin", "admin@test.com", []string{"admin"})
|
|
require.NoError(t, err)
|
|
|
|
playerToken, err := authService.GenerateToken("player1", "player", "player@test.com", []string{"player"})
|
|
require.NoError(t, err)
|
|
|
|
guestToken, err := authService.GenerateToken("guest1", "guest", "guest@test.com", []string{"guest"})
|
|
require.NoError(t, err)
|
|
|
|
app.Get("/restricted", middleware.Authenticate(), middleware.RequireAnyRole("admin", "player"), func(c *fiber.Ctx) error {
|
|
return c.JSON(fiber.Map{"message": "access granted"})
|
|
})
|
|
|
|
t.Run("Allows access when user has admin role", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/restricted", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer "+adminToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Allows access when user has player role", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/restricted", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer "+playerToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
})
|
|
|
|
t.Run("Denies access when user doesn't have any required role", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/restricted", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer "+guestToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, StatusForbidden, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, ErrInsufficientPermissions, response["error"])
|
|
assert.Contains(t, response["required_roles"], "admin")
|
|
assert.Contains(t, response["required_roles"], "player")
|
|
assert.Contains(t, response["user_roles"], "guest")
|
|
})
|
|
}
|
|
|
|
func TestJWTMiddleware_Optional(t *testing.T) {
|
|
app, middleware, authService := setupTestApp()
|
|
|
|
// Generate a valid token
|
|
validToken, err := authService.GenerateToken("user123", "testuser", "test@example.com", []string{"player"})
|
|
require.NoError(t, err)
|
|
|
|
app.Get("/public", middleware.Optional(), func(c *fiber.Ctx) error {
|
|
if IsAuthenticated(c) {
|
|
user, _ := GetUserFromContext(c)
|
|
return c.JSON(fiber.Map{"authenticated": true, "user": user.Username})
|
|
}
|
|
return c.JSON(fiber.Map{"authenticated": false, "user": "anonymous"})
|
|
})
|
|
|
|
t.Run("Sets user context when valid token is provided", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/public", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer "+validToken)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, true, response["authenticated"])
|
|
assert.Equal(t, "testuser", response["user"])
|
|
})
|
|
|
|
t.Run("Allows request without token", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/public", nil)
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, false, response["authenticated"])
|
|
assert.Equal(t, "anonymous", response["user"])
|
|
})
|
|
|
|
t.Run("Allows request with invalid token format", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/public", nil)
|
|
req.Header.Set(AuthorizationHeader, "Token invalid-format")
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, false, response["authenticated"])
|
|
assert.Equal(t, "anonymous", response["user"])
|
|
})
|
|
|
|
t.Run("Allows request with invalid token", func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/public", nil)
|
|
req.Header.Set(AuthorizationHeader, "Bearer invalid-token")
|
|
|
|
resp, err := app.Test(req)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, 200, resp.StatusCode)
|
|
|
|
body, err := io.ReadAll(resp.Body)
|
|
require.NoError(t, err)
|
|
|
|
var response map[string]interface{}
|
|
err = json.Unmarshal(body, &response)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, false, response["authenticated"])
|
|
assert.Equal(t, "anonymous", response["user"])
|
|
})
|
|
}
|
|
|
|
func TestNewJWTMiddleware(t *testing.T) {
|
|
t.Run("Creates new JWT middleware", func(t *testing.T) {
|
|
authService, err := NewMockAuthService("test-service")
|
|
require.NoError(t, err)
|
|
|
|
middleware := NewJWTMiddleware(authService)
|
|
|
|
assert.NotNil(t, middleware)
|
|
assert.Equal(t, authService, middleware.authService)
|
|
})
|
|
} |