package auth import ( "net/http" "net/http/httptest" "os" "testing" "time" ) func TestUserStore(t *testing.T) { store, _ := NewUserStore("") if _, ok := store.Get("admin"); !ok { t.Fatal("admin should exist") } _, ok := store.Verify("admin", "Admin123!") if !ok { t.Fatal("admin password should verify") } if _, ok := store.Verify("admin", "wrong"); ok { t.Fatal("wrong password should fail") } if _, err := store.Create("bob", "secret123", "viewer"); err != nil { t.Fatalf("create bob: %v", err) } if _, err := store.Create("bob", "secret123", "viewer"); err == nil { t.Fatal("duplicate should fail") } } func TestJWT(t *testing.T) { mgr := NewJWTManager("test-secret", time.Hour) tok, err := mgr.Sign("alice", "admin") if err != nil { t.Fatalf("sign: %v", err) } claims, err := mgr.Verify(tok) if err != nil { t.Fatalf("verify: %v", err) } if claims.Username != "alice" || claims.Role != "admin" { t.Fatalf("claims mismatch: %+v", claims) } if _, err := mgr.Verify(tok + "x"); err == nil { t.Fatal("tampered should fail") } mgr2 := NewJWTManager("test-secret", -time.Hour) tok2, _ := mgr2.Sign("alice", "admin") if _, err := mgr2.Verify(tok2); err == nil { t.Fatal("expired should fail") } } func TestCasbinEnforcer(t *testing.T) { tmpPol := os.TempDir() + "/test_policy.csv" data, _ := os.ReadFile("policy.csv") _ = os.WriteFile(tmpPol, data, 0644) defer os.Remove(tmpPol) store, _ := NewUserStore("") _, _ = store.Create("alice", "pass12345", "viewer") _, _ = store.Create("pub", "pass12345", "publisher") enc, err := NewEnforcer("model.conf", tmpPol, store) if err != nil { t.Fatalf("new enforcer: %v", err) } ok, _ := enc.Enforce("admin", "room", "publish") if !ok { t.Fatal("admin should can publish") } ok, _ = enc.Enforce("viewer", "room", "publish") if ok { t.Fatal("viewer should not publish") } ok, _ = enc.Enforce("viewer", "room", "subscribe") if !ok { t.Fatal("viewer should can subscribe") } ok, _ = enc.Enforce("publisher", "room", "publish") if !ok { t.Fatal("publisher should can publish") } ok, _ = enc.Enforce("guest", "room", "watch") if ok { t.Fatal("guest should not watch") } ok, _ = enc.Enforce("alice", "room", "subscribe") if !ok { t.Fatal("alice (viewer) should can subscribe") } ok, _ = enc.Enforce("alice", "room", "publish") if ok { t.Fatal("alice (viewer) should not publish") } } func TestAuthManagerLogin(t *testing.T) { tmpPol := os.TempDir() + "/test_policy2.csv" data, _ := os.ReadFile("policy.csv") _ = os.WriteFile(tmpPol, data, 0644) defer os.Remove(tmpPol) store, _ := NewUserStore("") enc, _ := NewEnforcer("model.conf", tmpPol, store) mgr := NewManagerWithStore(store, "test-jwt", time.Hour, enc) tok, user, err := mgr.Login("admin", "Admin123!") if err != nil { t.Fatalf("login admin: %v", err) } if tok == "" || user.Username != "admin" { t.Fatalf("login result bad: %v %v", tok, user) } if _, _, err := mgr.Login("admin", "wrong"); err == nil { t.Fatal("wrong pwd should fail") } tok2, u2, err := mgr.Register("newuser", "pass12345", "viewer") if err != nil { t.Fatalf("register: %v", err) } if tok2 == "" || u2.Role != "viewer" { t.Fatalf("register result bad") } claims, _, err := mgr.VerifyToken(tok) if err != nil || claims.Username != "admin" { t.Fatalf("verify token: %v %+v", err, claims) } } func TestHTTPMiddleware(t *testing.T) { tmpPol := os.TempDir() + "/test_policy3.csv" data, _ := os.ReadFile("policy.csv") _ = os.WriteFile(tmpPol, data, 0644) defer os.Remove(tmpPol) store, _ := NewUserStore("") enc, _ := NewEnforcer("model.conf", tmpPol, store) mgr := NewManagerWithStore(store, "test-jwt", time.Hour, enc) protected := mgr.AuthorizeMiddleware("room", "publish", true)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok")) })) req := httptest.NewRequest("GET", "/", nil) rec := httptest.NewRecorder() protected.ServeHTTP(rec, req) if rec.Code != http.StatusUnauthorized { t.Fatalf("expected 401, got %d", rec.Code) } tokViewer, _, _ := mgr.Login("viewer", "Viewer123!") req2 := httptest.NewRequest("GET", "/", nil) req2.Header.Set("Authorization", "Bearer "+tokViewer) rec2 := httptest.NewRecorder() protected.ServeHTTP(rec2, req2) if rec2.Code != http.StatusForbidden { t.Fatalf("viewer should be forbidden, got %d body=%s", rec2.Code, rec2.Body.String()) } tokPub, _, _ := mgr.Login("publisher", "Publisher123!") req3 := httptest.NewRequest("GET", "/", nil) req3.Header.Set("Authorization", "Bearer "+tokPub) rec3 := httptest.NewRecorder() protected.ServeHTTP(rec3, req3) if rec3.Code != http.StatusOK { t.Fatalf("publisher should ok, got %d body=%s", rec3.Code, rec3.Body.String()) } }