mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 07:15:43 +00:00
feat: open API v1 and postman collection
This commit is contained in:
@@ -0,0 +1,239 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/apikeys"
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
sso "gitlab.com/mbugroup/lti-api.git/internal/modules/sso/verifier"
|
||||
userValidation "gitlab.com/mbugroup/lti-api.git/internal/modules/users/validations"
|
||||
)
|
||||
|
||||
type stubUserService struct {
|
||||
user *entity.User
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *stubUserService) GetAll(_ *fiber.Ctx, _ *userValidation.Query) ([]entity.User, int64, error) {
|
||||
return nil, 0, nil
|
||||
}
|
||||
|
||||
func (s *stubUserService) GetOne(_ *fiber.Ctx, _ uint) (*entity.User, error) {
|
||||
return s.user, s.err
|
||||
}
|
||||
|
||||
func (s *stubUserService) CreateOne(_ *fiber.Ctx, _ *userValidation.Create) (*entity.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *stubUserService) UpdateOne(_ *fiber.Ctx, _ *userValidation.Update, _ uint) (*entity.User, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *stubUserService) DeleteOne(_ *fiber.Ctx, _ uint) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stubUserService) GetBySSOUserID(_ *fiber.Ctx, _ uint) (*entity.User, error) {
|
||||
return s.user, s.err
|
||||
}
|
||||
|
||||
type stubAPIKeyAuthenticator struct {
|
||||
principal *apikeys.Principal
|
||||
err error
|
||||
}
|
||||
|
||||
func (s *stubAPIKeyAuthenticator) Authenticate(_ context.Context, _ string, _ string) (*apikeys.Principal, error) {
|
||||
return s.principal, s.err
|
||||
}
|
||||
|
||||
func TestAuthAllowsAPIKeyOnGet(t *testing.T) {
|
||||
SetAPIKeyAuthenticator(&stubAPIKeyAuthenticator{
|
||||
principal: &apikeys.Principal{
|
||||
Name: "dashboard",
|
||||
Permissions: []string{"perm.read"},
|
||||
LocationIDs: []uint{3, 5},
|
||||
},
|
||||
})
|
||||
defer SetAPIKeyAuthenticator(nil)
|
||||
|
||||
app := fiber.New()
|
||||
app.Get("/reports", Auth(&stubUserService{}), RequirePermissions("perm.read"), func(c *fiber.Ctx) error {
|
||||
scope, err := ResolveLocationScope(c, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.JSON(fiber.Map{
|
||||
"principal": c.Locals(authContextLocalsKey).(*AuthContext).PrincipalType,
|
||||
"restrict": scope.Restrict,
|
||||
"ids": scope.IDs,
|
||||
})
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/reports", nil)
|
||||
req.Header.Set("X-API-Key", "lti_dev_prefix_secret")
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthRejectsAPIKeyOnPost(t *testing.T) {
|
||||
SetAPIKeyAuthenticator(&stubAPIKeyAuthenticator{
|
||||
principal: &apikeys.Principal{
|
||||
Name: "dashboard",
|
||||
Permissions: []string{"perm.write"},
|
||||
},
|
||||
})
|
||||
defer SetAPIKeyAuthenticator(nil)
|
||||
|
||||
app := fiber.New()
|
||||
app.Post("/reports", Auth(&stubUserService{}), RequirePermissions("perm.write"), func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(fiber.MethodPost, "/reports", nil)
|
||||
req.Header.Set("X-API-Key", "lti_dev_prefix_secret")
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp.StatusCode != fiber.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthRejectsInvalidAPIKey(t *testing.T) {
|
||||
SetAPIKeyAuthenticator(&stubAPIKeyAuthenticator{err: apikeys.ErrInvalidAPIKey})
|
||||
defer SetAPIKeyAuthenticator(nil)
|
||||
|
||||
app := fiber.New()
|
||||
app.Get("/reports", Auth(&stubUserService{}), func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/reports", nil)
|
||||
req.Header.Set("X-API-Key", "lti_dev_prefix_secret")
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp.StatusCode != fiber.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthRejectsInactiveAPIKey(t *testing.T) {
|
||||
SetAPIKeyAuthenticator(&stubAPIKeyAuthenticator{err: apikeys.ErrInactiveKey})
|
||||
defer SetAPIKeyAuthenticator(nil)
|
||||
|
||||
app := fiber.New()
|
||||
app.Get("/reports", Auth(&stubUserService{}), func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/reports", nil)
|
||||
req.Header.Set("X-API-Key", "lti_dev_prefix_secret")
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp.StatusCode != fiber.StatusUnauthorized {
|
||||
t.Fatalf("expected 401, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthRejectsMissingPermission(t *testing.T) {
|
||||
SetAPIKeyAuthenticator(&stubAPIKeyAuthenticator{
|
||||
principal: &apikeys.Principal{
|
||||
Name: "dashboard",
|
||||
Permissions: []string{"perm.other"},
|
||||
},
|
||||
})
|
||||
defer SetAPIKeyAuthenticator(nil)
|
||||
|
||||
app := fiber.New()
|
||||
app.Get("/reports", Auth(&stubUserService{}), RequirePermissions("perm.read"), func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/reports", nil)
|
||||
req.Header.Set("X-API-Key", "lti_dev_prefix_secret")
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp.StatusCode != fiber.StatusForbidden {
|
||||
t.Fatalf("expected 403, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthAllowsBearerOnGet(t *testing.T) {
|
||||
previousVerify := verifyAccessTokenFunc
|
||||
previousProfile := fetchProfileFunc
|
||||
defer func() {
|
||||
verifyAccessTokenFunc = previousVerify
|
||||
fetchProfileFunc = previousProfile
|
||||
}()
|
||||
|
||||
verifyAccessTokenFunc = func(_ string) (*sso.VerificationResult, error) {
|
||||
return &sso.VerificationResult{
|
||||
UserID: 1,
|
||||
Claims: &sso.AccessTokenClaims{
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
IssuedAt: jwt.NewNumericDate(time.Now().UTC()),
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
fetchProfileFunc = func(_ context.Context, _ string, _ *sso.VerificationResult) (*sso.UserProfile, error) {
|
||||
return &sso.UserProfile{
|
||||
Permissions: []sso.Permission{{Name: "perm.read"}},
|
||||
LocationIDs: []uint{7},
|
||||
}, nil
|
||||
}
|
||||
|
||||
app := fiber.New()
|
||||
app.Get("/reports", Auth(&stubUserService{user: &entity.User{Id: 9, Name: "API User"}}), RequirePermissions("perm.read"), func(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{"principal": c.Locals(authContextLocalsKey).(*AuthContext).PrincipalType})
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/reports", nil)
|
||||
req.Header.Set("Authorization", "Bearer test-token")
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthReturnsServerErrorWhenAPIKeyVerifierFailsUnexpectedly(t *testing.T) {
|
||||
SetAPIKeyAuthenticator(&stubAPIKeyAuthenticator{err: errors.New("boom")})
|
||||
defer SetAPIKeyAuthenticator(nil)
|
||||
|
||||
app := fiber.New()
|
||||
app.Get("/reports", Auth(&stubUserService{}), func(c *fiber.Ctx) error {
|
||||
return c.SendStatus(fiber.StatusOK)
|
||||
})
|
||||
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/reports", nil)
|
||||
req.Header.Set("X-API-Key", "lti_dev_prefix_secret")
|
||||
resp, err := app.Test(req)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if resp.StatusCode != fiber.StatusInternalServerError {
|
||||
t.Fatalf("expected 500, got %d", resp.StatusCode)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user