94 lines
2.7 KiB
Go
94 lines
2.7 KiB
Go
package apitest
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/omnex/control-plane/api/internal/auth"
|
|
"github.com/omnex/control-plane/api/internal/session"
|
|
)
|
|
|
|
func TestHashAndVerifyPassword(t *testing.T) {
|
|
hash, err := auth.HashPassword("s3cret-password")
|
|
if err != nil {
|
|
t.Fatalf("hash: %v", err)
|
|
}
|
|
if hash == "s3cret-password" {
|
|
t.Fatal("le mot de passe ne doit pas être stocké en clair")
|
|
}
|
|
ok, err := auth.VerifyPassword("s3cret-password", hash)
|
|
if err != nil || !ok {
|
|
t.Fatalf("verify bon mdp: ok=%v err=%v", ok, err)
|
|
}
|
|
if ok, _ := auth.VerifyPassword("mauvais", hash); ok {
|
|
t.Fatal("un mauvais mot de passe ne doit pas passer")
|
|
}
|
|
}
|
|
|
|
func TestHashUniqueSalt(t *testing.T) {
|
|
h1, _ := auth.HashPassword("same")
|
|
h2, _ := auth.HashPassword("same")
|
|
if h1 == h2 {
|
|
t.Fatal("deux hash du même mdp doivent différer (salt aléatoire)")
|
|
}
|
|
}
|
|
|
|
func TestVerifyRejectsMalformed(t *testing.T) {
|
|
if _, err := auth.VerifyPassword("x", "pas-un-hash"); err == nil {
|
|
t.Fatal("un hash malformé doit être rejeté")
|
|
}
|
|
}
|
|
|
|
func TestJWTIssueVerify(t *testing.T) {
|
|
iss := auth.NewIssuer([]byte(testSecret), time.Minute)
|
|
tok, err := iss.Issue("user-1", auth.RoleClient, "sid-123")
|
|
if err != nil {
|
|
t.Fatalf("issue: %v", err)
|
|
}
|
|
claims, err := iss.Verify(tok)
|
|
if err != nil {
|
|
t.Fatalf("verify: %v", err)
|
|
}
|
|
if claims.Subject != "user-1" || claims.Role != auth.RoleClient || claims.SessionID != "sid-123" {
|
|
t.Fatalf("claims inattendus: %+v", claims)
|
|
}
|
|
}
|
|
|
|
// Sécurité : token signé avec une autre clé rejeté.
|
|
func TestJWTRejectsWrongKey(t *testing.T) {
|
|
a := auth.NewIssuer([]byte(testSecret), time.Minute)
|
|
b := auth.NewIssuer([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), time.Minute)
|
|
tok, _ := a.Issue("u", auth.RoleClient, "sid")
|
|
if _, err := b.Verify(tok); err == nil {
|
|
t.Fatal("un token d'une autre clé ne doit pas être accepté")
|
|
}
|
|
}
|
|
|
|
// Sécurité : token expiré rejeté.
|
|
func TestJWTRejectsExpired(t *testing.T) {
|
|
iss := auth.NewIssuer([]byte(testSecret), -time.Minute)
|
|
tok, _ := iss.Issue("u", auth.RoleClient, "sid")
|
|
if _, err := iss.Verify(tok); err == nil {
|
|
t.Fatal("un token expiré ne doit pas être accepté")
|
|
}
|
|
}
|
|
|
|
// Session Redis(mem) : create → get → delete.
|
|
func TestSessionManagerLifecycle(t *testing.T) {
|
|
mgr := session.NewMemManager(time.Hour)
|
|
sid, err := mgr.Create(context.Background(), session.Session{UserID: "u1", Role: "sales"})
|
|
if err != nil || sid == "" {
|
|
t.Fatalf("create: sid=%q err=%v", sid, err)
|
|
}
|
|
if _, found, _ := mgr.Get(context.Background(), sid); !found {
|
|
t.Fatal("session attendue présente")
|
|
}
|
|
if err := mgr.Delete(context.Background(), sid); err != nil {
|
|
t.Fatalf("delete: %v", err)
|
|
}
|
|
if _, found, _ := mgr.Get(context.Background(), sid); found {
|
|
t.Fatal("session ne doit plus exister après delete")
|
|
}
|
|
}
|