af2366acb5
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)
95 lines
2.5 KiB
Go
95 lines
2.5 KiB
Go
package infra
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func makeTokenFor(t *testing.T, subject, secret string) string {
|
|
t.Helper()
|
|
tok, err := JWTGenerate(JWTClaims{
|
|
Subject: subject,
|
|
ExpiresAt: time.Now().Add(time.Hour).Unix(),
|
|
}, secret)
|
|
if err != nil {
|
|
t.Fatalf("JWTGenerate: %v", err)
|
|
}
|
|
return tok
|
|
}
|
|
|
|
func TestJWTMiddleware_ValidToken(t *testing.T) {
|
|
secret := "test-sec"
|
|
token := makeTokenFor(t, "alice", secret)
|
|
|
|
var gotSubject string
|
|
handler := JWTMiddleware(secret)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
claims, ok := JWTClaimsFromContext(r.Context())
|
|
if !ok {
|
|
t.Error("JWTClaimsFromContext no encontro claims")
|
|
}
|
|
gotSubject = claims.Subject
|
|
w.WriteHeader(200)
|
|
}))
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.ServeHTTP(rec, req)
|
|
if rec.Code != 200 {
|
|
t.Errorf("status = %d", rec.Code)
|
|
}
|
|
if gotSubject != "alice" {
|
|
t.Errorf("subject = %q", gotSubject)
|
|
}
|
|
}
|
|
|
|
func TestJWTMiddleware_MissingAuthHeader(t *testing.T) {
|
|
handler := JWTMiddleware("s")(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", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestJWTMiddleware_WrongFormat(t *testing.T) {
|
|
handler := JWTMiddleware("s")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
t.Error("no deberia ejecutarse")
|
|
}))
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
req.Header.Set("Authorization", "Basic abcdef")
|
|
rec := httptest.NewRecorder()
|
|
handler.ServeHTTP(rec, req)
|
|
if rec.Code != 401 {
|
|
t.Errorf("status = %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestJWTMiddleware_InvalidToken(t *testing.T) {
|
|
handler := JWTMiddleware("secret-a")(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
t.Error("no deberia ejecutarse")
|
|
}))
|
|
tok := makeTokenFor(t, "x", "secret-b") // firmado con otro secret
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
req.Header.Set("Authorization", "Bearer "+tok)
|
|
rec := httptest.NewRecorder()
|
|
handler.ServeHTTP(rec, req)
|
|
if rec.Code != 401 {
|
|
t.Errorf("status = %d", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestJWTClaimsFromContext_NotPresent(t *testing.T) {
|
|
req := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
_, ok := JWTClaimsFromContext(req.Context())
|
|
if ok {
|
|
t.Fatal("no deberia haber claims en un context nuevo")
|
|
}
|
|
}
|