245 lines
6.1 KiB
Go
245 lines
6.1 KiB
Go
package auth_test
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/99designs/gqlgen/graphql/handler/transport"
|
|
"github.com/photoview/photoview/api/dataloader"
|
|
"github.com/photoview/photoview/api/graphql/auth"
|
|
"github.com/photoview/photoview/api/graphql/models"
|
|
"github.com/photoview/photoview/api/test_utils"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestMain(m *testing.M) {
|
|
test_utils.UnitTestRun(m)
|
|
}
|
|
|
|
func TestTokenFromBearer(t *testing.T) {
|
|
|
|
testsValues := []struct {
|
|
name string
|
|
bearer string
|
|
out string
|
|
valid bool
|
|
}{
|
|
{"Valid bearer", "Bearer ZY9YfxFa3TapSAD37XUBFryo", "ZY9YfxFa3TapSAD37XUBFryo", true},
|
|
{"Case insensitive bearer", "bEaReR ZY9YfxFa3TapSAD37XUBFryo", "ZY9YfxFa3TapSAD37XUBFryo", true},
|
|
{"Missing bearer start", "ZY9YfxFa3TapSAD37XUBFryo", "", false},
|
|
{"Empty input", "", "", false},
|
|
{"Invalid token value", "Bearer THIS_IS_INVALID", "", false},
|
|
}
|
|
|
|
for _, test := range testsValues {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
token, err := auth.TokenFromBearer(&test.bearer)
|
|
if test.valid {
|
|
assert.NoError(t, err)
|
|
assert.NotNil(t, token)
|
|
assert.Equal(t, test.out, *token)
|
|
} else {
|
|
assert.Error(t, err)
|
|
assert.Nil(t, token)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuthWebsocketInit(t *testing.T) {
|
|
db := test_utils.DatabaseTest(t)
|
|
|
|
// Create test user and token
|
|
password := "test_password"
|
|
user, err := models.RegisterUser(db, "testuser", &password, false)
|
|
assert.NoError(t, err)
|
|
|
|
token, err := user.GenerateAccessToken(db)
|
|
assert.NoError(t, err)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
initPayload transport.InitPayload
|
|
expectError bool
|
|
expectUser bool
|
|
expectNilCtx bool
|
|
}{
|
|
{
|
|
name: "Valid authorization",
|
|
initPayload: transport.InitPayload{"Authorization": "Bearer " + token.Value},
|
|
expectError: false,
|
|
expectUser: true,
|
|
},
|
|
{
|
|
name: "Missing authorization",
|
|
initPayload: transport.InitPayload{},
|
|
expectError: false,
|
|
expectUser: false,
|
|
},
|
|
{
|
|
name: "Invalid bearer format",
|
|
initPayload: transport.InitPayload{"Authorization": "InvalidFormat"},
|
|
expectError: true,
|
|
expectNilCtx: true,
|
|
},
|
|
{
|
|
name: "Invalid token",
|
|
initPayload: transport.InitPayload{"Authorization": "Bearer INVALID_TOKEN_123456"},
|
|
expectError: true,
|
|
expectNilCtx: true,
|
|
},
|
|
{
|
|
name: "Empty token",
|
|
initPayload: transport.InitPayload{"Authorization": "Bearer "},
|
|
expectError: true,
|
|
expectNilCtx: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
initFunc := auth.AuthWebsocketInit()
|
|
ctx := context.Background()
|
|
req := httptest.NewRequest("GET", "/", nil)
|
|
req = req.WithContext(ctx)
|
|
|
|
var contextWithLoaders context.Context
|
|
handler := dataloader.Middleware(db)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
contextWithLoaders = r.Context()
|
|
}))
|
|
recorder := httptest.NewRecorder()
|
|
handler.ServeHTTP(recorder, req)
|
|
|
|
resultCtx, ackPayload, err := initFunc(contextWithLoaders, tc.initPayload)
|
|
|
|
if tc.expectError {
|
|
assert.Error(t, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
if tc.expectNilCtx {
|
|
assert.Nil(t, resultCtx)
|
|
} else {
|
|
assert.NotNil(t, resultCtx)
|
|
}
|
|
|
|
// Verify InitPayload acknowledgment is always nil (as per PR implementation)
|
|
assert.Nil(t, ackPayload)
|
|
|
|
if tc.expectUser {
|
|
retrievedUser := auth.UserFromContext(resultCtx)
|
|
assert.NotNil(t, retrievedUser)
|
|
assert.Equal(t, user.ID, retrievedUser.ID)
|
|
assert.Equal(t, "testuser", retrievedUser.Username)
|
|
} else if !tc.expectNilCtx {
|
|
retrievedUser := auth.UserFromContext(resultCtx)
|
|
assert.Nil(t, retrievedUser)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMiddleware(t *testing.T) {
|
|
db := test_utils.DatabaseTest(t)
|
|
|
|
// Create test user and token
|
|
password := "test_password"
|
|
user, err := models.RegisterUser(db, "testuser", &password, false)
|
|
assert.NoError(t, err)
|
|
|
|
token, err := user.GenerateAccessToken(db)
|
|
assert.NoError(t, err)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
cookieValue string
|
|
setCookie bool
|
|
expectStatus int
|
|
expectUser bool
|
|
}{
|
|
{
|
|
name: "Valid token cookie",
|
|
cookieValue: token.Value,
|
|
setCookie: true,
|
|
expectStatus: 200,
|
|
expectUser: true,
|
|
},
|
|
{
|
|
name: "No cookie",
|
|
setCookie: false,
|
|
expectStatus: 200,
|
|
expectUser: false,
|
|
},
|
|
{
|
|
name: "Invalid token",
|
|
cookieValue: "INVALID_TOKEN",
|
|
setCookie: true,
|
|
expectStatus: 401,
|
|
expectUser: false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/graphql", nil)
|
|
if tc.setCookie {
|
|
req.AddCookie(&http.Cookie{
|
|
Name: "auth-token",
|
|
Value: tc.cookieValue,
|
|
})
|
|
}
|
|
|
|
var capturedContext context.Context
|
|
handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
capturedContext = r.Context()
|
|
})
|
|
|
|
authHandler := auth.Middleware(db)(handler)
|
|
fullHandler := dataloader.Middleware(db)(authHandler)
|
|
|
|
recorder := httptest.NewRecorder()
|
|
fullHandler.ServeHTTP(recorder, req)
|
|
|
|
assert.Equal(t, tc.expectStatus, recorder.Code)
|
|
|
|
if tc.expectUser {
|
|
retrievedUser := auth.UserFromContext(capturedContext)
|
|
assert.NotNil(t, retrievedUser)
|
|
assert.Equal(t, user.ID, retrievedUser.ID)
|
|
} else if recorder.Code == 200 {
|
|
// Handler was called, verify no user in context
|
|
retrievedUser := auth.UserFromContext(capturedContext)
|
|
assert.Nil(t, retrievedUser)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestContextUserOperations(t *testing.T) {
|
|
db := test_utils.DatabaseTest(t)
|
|
|
|
password := "test"
|
|
user, err := models.RegisterUser(db, "testuser", &password, false)
|
|
assert.NoError(t, err)
|
|
|
|
t.Run("AddUserToContext and UserFromContext", func(t *testing.T) {
|
|
ctx := context.Background()
|
|
|
|
// Initially no user
|
|
retrieved := auth.UserFromContext(ctx)
|
|
assert.Nil(t, retrieved)
|
|
|
|
// Add user
|
|
ctxWithUser := auth.AddUserToContext(ctx, user)
|
|
|
|
// Retrieve user
|
|
retrieved = auth.UserFromContext(ctxWithUser)
|
|
assert.NotNil(t, retrieved)
|
|
assert.Equal(t, user.ID, retrieved.ID)
|
|
assert.Equal(t, "testuser", retrieved.Username)
|
|
})
|
|
}
|