shiori/internal/http/middleware/auth_test.go
Felipe Martin 73a5239753
refactor(apiv1): accounts api (#825)
* list account and create account

* deleteaccount (wip)

* remove old accounts code

* fix from merge

* remove serve method from makefile

* ListAccounts, password hash on domain

* make lint

* more permissive assertion

* rename test

* update account

* Authorization

* updated api calls

* apis, pointers, auth

* swagger

* stylecheck

* domain validation

* tests

* swagger

* error handling

* fix system account changes

* Cleanup database interface

* test cleanup

* fixed nil references

* feat: Add logout endpoint to auth routes

* feat: Add logoutHandler for stateless JWT token logout

* fixed some bug catched in tests

* auth/account patch

* prettier

* remove test logs

* fixed incorrect number of parameters

* fixed swagger docs

* enable swagger in dev environment

* errors.Wrap -> fmt.Errorf

* test: Add comprehensive test cases for accounts API handlers

* fix: Resolve test failures in accounts_test.go

* test: Add tests for duplicate username handling in account creation and update

* feat: Add username uniqueness checks for account creation and update

refactor: Improve username existence checks in SQLite account methods

* linted

* test: Add comprehensive tests for auth domain token and credential validation

* test: Add comprehensive test cases for auth domain token creation and validation

* test: Add comprehensive error handling test cases for accounts domain

* refactor: Remove `SaveAccountSettings` method from database implementations

* test: Add test cases for password update functionality

* test(e2e): auth login

* lint

* send regular context to domain

* fixed e2e auth tests

* test: Add auth_test.go for end-to-end authentication testing

* feat: Add comprehensive authentication tests using Playwright and testcontainers

* fix: Handle multiple return values in Playwright test methods

* error message

* e2e playwrigth tests

* ci: setup playwrigth

* refactor: Update Playwright tests to use locator-based API

* refactor: Remove unnecessary alias for playwright-go expect import

* refactor: Replace deprecated expect package with WaitFor() method in Playwright tests

* fix: Resolve linting issues in e2e Playwright tests

* remove npm ci from e2e ci

* make playwright available in path

* typo

* re enabled ci

* base e2e accounts test

* more account e2e

* feat: Add HTML test reporter with screenshots and detailed results

* feat: Embed screenshots as base64 in HTML test report

* refactor: Remove GitHub step summary functionality from test helper

* refactor: Make reporter global to share test results across test helpers

* refactor: Add HandleSuccess method to TestHelper for consistent test result reporting

* feat: Add descriptive messages to all test assertions in TestHelper

* test: Add descriptive messages to assertions in accounts_test.go

* test: Add descriptive error messages to assertions in accounts_test.go

* feat: Add descriptive messages to assertions in accounts_test.go

* refactor: Update assertion functions to receive *testing.T as first argument

* refactor: Update accounts_test.go assertions to pass *testing.T argument

* refactor: Update accounts_test.go assertions to use *testing.T argument

* refactor: Update `accounts_test.go` to use `*testing.T` argument in `Require()` calls

* refactor: Update `th.Require()` calls with `t *testing.T` argument in accounts_test.go

* assert helper

* refactor: Refactor `False` test helper to use `Assert` function consistently

* refactor: Refactor `Equal` test helper to use `Assert` function

* refactor: Simplify Error test helper to use Assert function

* refactor: Refactor `NoError` to use `Assert` function for consistent error handling

* typo

* refactor: Differentiate between test cases and assertions in reporter

* refactor: Simplify AddResult method signature and use error message for assertion

* refactor: Simplify test report with focused failure details and screenshots

* refactor: Ensure assertions are always called in PlaywrightRequire helper methods

* refactor: Update test error messages to be action-oriented

* refactor: Update error messages to be more action-oriented in accounts_test.go

* refactor: Update error messages to be action-oriented in accounts_test.go

* refactor: Improve error messages in auth_test.go for better test readability

* refactor: Improve screenshot handling and test result reporting in Playwright test helper

* fix: Improve test reporting with detailed error messages and logging

* refactor: Remove unused runningInCI field from TestHelper struct

* fix: Improve message formatting in Assert method for better reporting

* assertions

* test: Add `Require()` calls to 007 test for improved error handling

* refactor: Update test reporter to include error details and improve HTML rendering

* fix: Properly escape and render base64 screenshot in HTML report

* fix: Correct base64 screenshot rendering in test reporter

* fixed tests + html report

* feat: Add artifact upload for e2e test report

* make lint

* chore: use correct version in user agent

* ci: run e2e after other checks

* chore: remove pre-commit
2025-02-22 20:38:36 +01:00

138 lines
4.2 KiB
Go

package middleware
import (
"context"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/go-shiori/shiori/internal/http/response"
"github.com/go-shiori/shiori/internal/model"
"github.com/go-shiori/shiori/internal/testutil"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/require"
)
func TestAuthenticationRequiredMiddleware(t *testing.T) {
t.Run("test unauthorized", func(t *testing.T) {
g := testutil.NewGin()
g.Use(AuthenticationRequired())
g.Handle("GET", "/", func(c *gin.Context) {
response.Send(c, http.StatusOK, nil)
})
w := testutil.PerformRequest(g, "GET", "/")
require.Equal(t, http.StatusUnauthorized, w.Code)
// This ensures we are aborting the request and not sending more data
require.Equal(t, `{"ok":false,"message":null}`, w.Body.String())
})
t.Run("test authorized", func(t *testing.T) {
g := testutil.NewGin()
// Fake a logged in user in the context, which is the way the AuthMiddleware works.
g.Use(func(ctx *gin.Context) {
ctx.Set(model.ContextAccountKey, "test")
})
g.Use(AuthenticationRequired())
g.GET("/", func(c *gin.Context) {
c.Status(http.StatusOK)
})
w := testutil.PerformRequest(g, "GET", "/")
require.Equal(t, http.StatusOK, w.Code)
})
}
func TestAuthMiddleware(t *testing.T) {
ctx := context.TODO()
logger := logrus.New()
_, deps := testutil.GetTestConfigurationAndDependencies(t, ctx, logger)
middleware := AuthMiddleware(deps)
t.Run("test no authorization method", func(t *testing.T) {
w := httptest.NewRecorder()
c, router := gin.CreateTestContext(w)
req := httptest.NewRequest(http.MethodGet, "/", nil)
router.Use(middleware)
router.ServeHTTP(w, req)
_, exists := c.Get("account")
require.False(t, exists)
})
t.Run("test authorization header", func(t *testing.T) {
account := testutil.GetValidAccount().ToDTO()
token, err := deps.Domains.Auth.CreateTokenForAccount(&account, time.Now().Add(time.Minute))
require.NoError(t, err)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request, _ = http.NewRequest("GET", "/", nil)
c.Request.Header.Set(model.AuthorizationHeader, model.AuthorizationTokenType+" "+token)
middleware(c)
_, exists := c.Get(model.ContextAccountKey)
require.True(t, exists)
})
t.Run("test authorization cookie", func(t *testing.T) {
account := model.AccountDTO{Username: "shiori"}
token, err := deps.Domains.Auth.CreateTokenForAccount(&account, time.Now().Add(time.Minute))
require.NoError(t, err)
w := httptest.NewRecorder()
c, _ := gin.CreateTestContext(w)
c.Request, _ = http.NewRequest("GET", "/", nil)
c.Request.AddCookie(&http.Cookie{
Name: "token",
Value: token,
MaxAge: int(time.Now().Add(time.Minute).Unix()),
})
middleware(c)
_, exists := c.Get(model.ContextAccountKey)
require.True(t, exists)
})
}
func TestAdminRequiredMiddleware(t *testing.T) {
t.Run("test unauthorized", func(t *testing.T) {
g := testutil.NewGin()
g.Use(AdminRequired())
g.Handle("GET", "/", func(c *gin.Context) {
response.Send(c, http.StatusOK, nil)
})
w := testutil.PerformRequest(g, "GET", "/")
require.Equal(t, http.StatusForbidden, w.Code)
// This ensures we are aborting the request and not sending more data
require.Equal(t, `{"ok":false,"message":null}`, w.Body.String())
})
t.Run("test user but not admin", func(t *testing.T) {
g := testutil.NewGin()
// Fake a logged in admin in the context, which is the way the AuthMiddleware works.
g.Use(func(ctx *gin.Context) {
ctx.Set(model.ContextAccountKey, &model.AccountDTO{
Owner: model.Ptr(false),
})
})
g.Use(AdminRequired())
g.GET("/", func(c *gin.Context) {
c.Status(http.StatusOK)
})
w := testutil.PerformRequest(g, "GET", "/")
require.Equal(t, http.StatusForbidden, w.Code)
})
t.Run("test authorized", func(t *testing.T) {
g := testutil.NewGin()
// Fake a logged in admin in the context, which is the way the AuthMiddleware works.
g.Use(func(ctx *gin.Context) {
ctx.Set(model.ContextAccountKey, &model.AccountDTO{
Owner: model.Ptr(true),
})
})
g.Use(AdminRequired())
g.GET("/", func(c *gin.Context) {
c.Status(http.StatusOK)
})
w := testutil.PerformRequest(g, "GET", "/")
require.Equal(t, http.StatusOK, w.Code)
})
}