359 lines
12 KiB
Go
359 lines
12 KiB
Go
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
archivalDomain "git.nakama.town/fmartingr/hako/internal/archival/domain"
|
|
authDomain "git.nakama.town/fmartingr/hako/internal/auth/domain"
|
|
"git.nakama.town/fmartingr/hako/internal/server/webcontext"
|
|
"git.nakama.town/fmartingr/hako/internal/testutil"
|
|
"github.com/google/uuid"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestAuthMiddleware_ValidToken(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user first
|
|
user, _, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Generate a valid token for the user
|
|
tokenString, _, err := deps.Dependencies.GetJWTService().GenerateToken(user.ID, user.Email)
|
|
require.NoError(t, err)
|
|
|
|
// Create middleware with user store
|
|
middleware := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
|
|
// Create a test handler that checks context
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
c := webcontext.NewWebContext(w, r)
|
|
ctxUserID := c.GetUserID()
|
|
userEmail := c.GetUserEmail()
|
|
userRole := c.GetUserRole()
|
|
|
|
require.Equal(t, user.ID.String(), ctxUserID)
|
|
require.Equal(t, user.Email, userEmail)
|
|
// Role should be "user" by default
|
|
require.Equal(t, "user", userRole)
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
// Wrap handler with middleware
|
|
wrappedHandler := middleware(handler)
|
|
|
|
// Create request with token
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
req.Header.Set("Authorization", "Bearer "+tokenString)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestAuthMiddleware_NoToken(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
middleware := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
|
|
// Create handler
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
c := webcontext.NewWebContext(w, r)
|
|
userID := c.GetUserID()
|
|
|
|
// Should be empty without token
|
|
require.Empty(t, userID)
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
wrappedHandler := middleware(handler)
|
|
|
|
// Request without token
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should still succeed (middleware doesn't block)
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestAuthMiddleware_InvalidToken(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
middleware := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
c := webcontext.NewWebContext(w, r)
|
|
userID := c.GetUserID()
|
|
|
|
// Should be empty with invalid token
|
|
require.Empty(t, userID)
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
wrappedHandler := middleware(handler)
|
|
|
|
// Request with invalid token
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
req.Header.Set("Authorization", "Bearer invalid-token")
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should still succeed (global middleware doesn't block)
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestAuthMiddleware_UserDoesNotExist(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Generate a token for a user that doesn't exist in the database
|
|
nonExistentUserID := uuid.New()
|
|
tokenString, _, err := deps.Dependencies.GetJWTService().GenerateToken(nonExistentUserID, "nonexistent@example.com")
|
|
require.NoError(t, err)
|
|
|
|
// Create middleware
|
|
middleware := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
|
|
// Create a test handler that checks context
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
c := webcontext.NewWebContext(w, r)
|
|
ctxUserID := c.GetUserID()
|
|
userEmail := c.GetUserEmail()
|
|
|
|
// Should be empty because user doesn't exist
|
|
require.Empty(t, ctxUserID)
|
|
require.Empty(t, userEmail)
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
// Wrap handler with middleware
|
|
wrappedHandler := middleware(handler)
|
|
|
|
// Create request with valid token but non-existent user
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
req.Header.Set("Authorization", "Bearer "+tokenString)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should still succeed (middleware doesn't block), but context should be empty
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestRequireAuthMiddleware_Authenticated(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user first
|
|
user, _, err := testutil.NewTestUser(t, deps.Dependencies, "test@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Generate token
|
|
tokenString, _, err := deps.Dependencies.GetJWTService().GenerateToken(user.ID, user.Email)
|
|
require.NoError(t, err)
|
|
|
|
// Create both middlewares
|
|
globalAuth := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuth := RequireAuthMiddleware()
|
|
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
// Apply both middlewares
|
|
wrappedHandler := globalAuth(requireAuth(handler))
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
req.Header.Set("Authorization", "Bearer "+tokenString)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestRequireAuthMiddleware_NotAuthenticated(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
globalAuth := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuth := RequireAuthMiddleware()
|
|
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
wrappedHandler := globalAuth(requireAuth(handler))
|
|
|
|
// Request without token
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should be unauthorized
|
|
require.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestRequireAuthMiddleware_UserDoesNotExist(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Generate a token for a user that doesn't exist in the database
|
|
nonExistentUserID := uuid.New()
|
|
tokenString, _, err := deps.Dependencies.GetJWTService().GenerateToken(nonExistentUserID, "nonexistent@example.com")
|
|
require.NoError(t, err)
|
|
|
|
// Create both middlewares
|
|
globalAuth := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAuth := RequireAuthMiddleware()
|
|
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
// Apply both middlewares
|
|
wrappedHandler := globalAuth(requireAuth(handler))
|
|
|
|
// Request with valid token but non-existent user
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
req.Header.Set("Authorization", "Bearer "+tokenString)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should be unauthorized because user doesn't exist
|
|
require.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|
|
|
|
func TestRequireAdminMiddleware_AdminUser(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user with admin role
|
|
user, _, err := testutil.NewTestUser(t, deps.Dependencies, "admin@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Update user to admin role directly in database
|
|
// Get the write DB connection from dependencies
|
|
writeDB := deps.Dependencies.Database().WriterDB()
|
|
_, err = writeDB.Exec(
|
|
"UPDATE users SET role = 'admin' WHERE id = ?",
|
|
user.ID.String(),
|
|
)
|
|
require.NoError(t, err)
|
|
|
|
// Generate token with admin role
|
|
tokenString, _, err := deps.Dependencies.GetJWTService().GenerateTokenWithRole(user.ID, user.Email, "admin")
|
|
require.NoError(t, err)
|
|
|
|
// Create both middlewares
|
|
globalAuth := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAdmin := RequireAdminMiddleware()
|
|
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
// Apply both middlewares
|
|
wrappedHandler := globalAuth(requireAdmin(handler))
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
req.Header.Set("Authorization", "Bearer "+tokenString)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should succeed for admin user
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
}
|
|
|
|
func TestRequireAdminMiddleware_RegularUser(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
// Initialize domains
|
|
deps.Dependencies.Domains().SetLinks(archivalDomain.NewLinkDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetArchives(archivalDomain.NewArchiveDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetCategories(archivalDomain.NewCategoryDomain(deps.Dependencies))
|
|
deps.Dependencies.Domains().SetAuth(authDomain.NewAuthDomain(deps.Dependencies))
|
|
|
|
// Create a test user (defaults to "user" role)
|
|
user, _, err := testutil.NewTestUser(t, deps.Dependencies, "user@example.com", "testpassword123")
|
|
require.NoError(t, err)
|
|
|
|
// Generate token (defaults to "user" role)
|
|
tokenString, _, err := deps.Dependencies.GetJWTService().GenerateToken(user.ID, user.Email)
|
|
require.NoError(t, err)
|
|
|
|
// Create both middlewares
|
|
globalAuth := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAdmin := RequireAdminMiddleware()
|
|
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
// Apply both middlewares
|
|
wrappedHandler := globalAuth(requireAdmin(handler))
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
req.Header.Set("Authorization", "Bearer "+tokenString)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should be forbidden for regular user
|
|
require.Equal(t, http.StatusForbidden, w.Code)
|
|
}
|
|
|
|
func TestRequireAdminMiddleware_NotAuthenticated(t *testing.T) {
|
|
ctx := context.Background()
|
|
deps := testutil.GetTestConfigurationAndDependencies(t, ctx)
|
|
|
|
globalAuth := AuthMiddleware(deps.Dependencies.GetJWTService(), deps.Dependencies.UserStore)
|
|
requireAdmin := RequireAdminMiddleware()
|
|
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
})
|
|
|
|
wrappedHandler := globalAuth(requireAdmin(handler))
|
|
|
|
// Request without token
|
|
req := httptest.NewRequest(http.MethodGet, "/test", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
wrappedHandler.ServeHTTP(w, req)
|
|
|
|
// Should be unauthorized
|
|
require.Equal(t, http.StatusUnauthorized, w.Code)
|
|
}
|