Files
fn_registry/functions/infra/rbac_middleware_test.go
egutierrez af2366acb5 feat: rbac_check (pure), jwt_middleware, rbac_middleware
Fase 5 del issue 0010 — RBAC y middlewares de auth.
- rbac_check es pura: solo recorre la matriz roles/permisos
- jwt_middleware extrae token del header Authorization: Bearer, valida e
  inyecta claims en el context con una key privada (jwtCtxKey struct{})
- rbac_middleware requiere jwt_middleware antes; lee role de claims.Custom
- Helper JWTClaimsFromContext para acceder a las claims desde handlers
- 401 claro si RBAC se usa sin JWT antes (code: no_claims)
2026-04-18 17:44:04 +02:00

99 lines
2.8 KiB
Go

package infra
import (
"net/http"
"net/http/httptest"
"testing"
"time"
)
func buildRBACRoles() []Role {
return []Role{
{Name: "admin", Permissions: []Permission{{Resource: "users", Action: "delete"}}},
{Name: "viewer", Permissions: []Permission{{Resource: "users", Action: "read"}}},
}
}
func buildAuthedRequest(t *testing.T, role, secret string) *http.Request {
t.Helper()
claims := JWTClaims{
Subject: "user-1",
ExpiresAt: time.Now().Add(time.Hour).Unix(),
Custom: map[string]any{"role": role},
}
tok, err := JWTGenerate(claims, secret)
if err != nil {
t.Fatalf("JWTGenerate: %v", err)
}
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("Authorization", "Bearer "+tok)
return req
}
func TestRBACMiddleware_PermissionGranted(t *testing.T) {
secret := "s"
chain := HTTPMiddlewareChain(
JWTMiddleware(secret),
RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "delete"}),
)
var called bool
handler := chain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
called = true
w.WriteHeader(200)
}))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, buildAuthedRequest(t, "admin", secret))
if rec.Code != 200 || !called {
t.Errorf("admin deberia pasar: status=%d called=%v", rec.Code, called)
}
}
func TestRBACMiddleware_PermissionDenied(t *testing.T) {
secret := "s"
chain := HTTPMiddlewareChain(
JWTMiddleware(secret),
RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "delete"}),
)
handler := chain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Error("viewer no deberia pasar")
}))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, buildAuthedRequest(t, "viewer", secret))
if rec.Code != 403 {
t.Errorf("status = %d, esperaba 403", rec.Code)
}
}
func TestRBACMiddleware_UnknownRole(t *testing.T) {
secret := "s"
chain := HTTPMiddlewareChain(
JWTMiddleware(secret),
RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "read"}),
)
handler := chain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Error("rol ghost no deberia pasar")
}))
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, buildAuthedRequest(t, "ghost", secret))
if rec.Code != 403 {
t.Errorf("status = %d, esperaba 403", rec.Code)
}
}
func TestRBACMiddleware_NoClaims(t *testing.T) {
// Sin JWTMiddleware delante → no hay claims en context
mw := RBACMiddleware(buildRBACRoles(), Permission{Resource: "users", Action: "read"})
handler := mw(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
t.Error("no deberia ejecutarse")
}))
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != 401 {
t.Errorf("status = %d, esperaba 401", rec.Code)
}
}