mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-07-18 16:59:53 +00:00
110 lines
3.7 KiB
Go
110 lines
3.7 KiB
Go
package webauthn
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/danielgtaylor/huma/v2"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/pocket-id/pocket-id/backend/internal/model"
|
|
"github.com/pocket-id/pocket-id/backend/internal/utils/cookie"
|
|
httpapi "github.com/pocket-id/pocket-id/backend/internal/utils/huma"
|
|
testutils "github.com/pocket-id/pocket-id/backend/internal/utils/testing"
|
|
)
|
|
|
|
func TestRequestWithBodyReconstructsUnderlyingRequest(t *testing.T) {
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.New()
|
|
api := httpapi.New(router, router.Group("/"))
|
|
type input struct {
|
|
Body map[string]string
|
|
}
|
|
type output struct {
|
|
Body map[string]string
|
|
}
|
|
httpapi.Register(api, huma.Operation{
|
|
OperationID: "reconstruct-request",
|
|
Method: http.MethodPost,
|
|
Path: "/api/reconstruct",
|
|
}, func(ctx context.Context, _ *input) (*output, error) {
|
|
request := requestWithBody(ctx, []byte(`{"credential":"value"}`))
|
|
body, err := io.ReadAll(request.Body)
|
|
require.NoError(t, err)
|
|
require.True(t, bytes.Equal([]byte(`{"credential":"value"}`), body))
|
|
require.Equal(t, int64(len(body)), request.ContentLength)
|
|
return &output{Body: map[string]string{"status": "ok"}}, nil
|
|
})
|
|
|
|
request := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/api/reconstruct", http.NoBody)
|
|
request.Header.Set("Content-Type", "application/json")
|
|
response := httptest.NewRecorder()
|
|
router.ServeHTTP(response, request)
|
|
require.Equal(t, http.StatusBadRequest, response.Code)
|
|
|
|
request = httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/api/reconstruct", strings.NewReader(`{"input":"present"}`))
|
|
request.Header.Set("Content-Type", "application/json")
|
|
response = httptest.NewRecorder()
|
|
router.ServeHTTP(response, request)
|
|
require.Equal(t, http.StatusOK, response.Code)
|
|
}
|
|
|
|
func TestLogoutClearsAccessTokenCookie(t *testing.T) {
|
|
output, err := (&handler{}).logout(t.Context(), &httpapi.EmptyInput{})
|
|
require.NoError(t, err)
|
|
require.Len(t, output.SetCookie, 1)
|
|
require.Equal(t, -1, output.SetCookie[0].MaxAge)
|
|
require.Contains(t, output.SetCookie[0].String(), "Max-Age=0")
|
|
}
|
|
|
|
func TestReauthenticateFallsBackWithoutSessionCookie(t *testing.T) {
|
|
db := testutils.NewDatabaseForTest(t)
|
|
user := model.User{Base: model.Base{ID: "handler-reauth-user"}, Username: "handler-reauth-user"}
|
|
require.NoError(t, db.Create(&user).Error)
|
|
|
|
signer := newFakeSigner()
|
|
accessToken, err := signer.GenerateAccessToken(user, authenticationMethodPhishingResistant)
|
|
require.NoError(t, err)
|
|
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.New()
|
|
api := httpapi.New(router, router.Group("/"))
|
|
h := &handler{service: &Service{db: db, signer: signer}}
|
|
httpapi.Register(api, huma.Operation{
|
|
OperationID: "test-reauthenticate-fallback",
|
|
Method: http.MethodPost,
|
|
Path: "/api/test-reauthenticate-fallback",
|
|
DefaultStatus: http.StatusNoContent,
|
|
}, h.reauthenticate)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
body io.Reader
|
|
}{
|
|
{name: "empty body"},
|
|
{name: "invalid assertion", body: strings.NewReader(`{"invalid":true}`)},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
request := httptest.NewRequestWithContext(t.Context(), http.MethodPost, "/api/test-reauthenticate-fallback", testCase.body)
|
|
if testCase.body != nil {
|
|
request.Header.Set("Content-Type", "application/json")
|
|
}
|
|
request.AddCookie(cookie.NewAccessTokenCookie(60, accessToken))
|
|
response := httptest.NewRecorder()
|
|
|
|
router.ServeHTTP(response, request)
|
|
|
|
require.Equal(t, http.StatusNoContent, response.Code)
|
|
require.Contains(t, response.Header().Get("Set-Cookie"), cookie.ReauthenticationTokenCookieName+"=")
|
|
})
|
|
}
|
|
}
|