Dateien nach "/" hochladen
This commit is contained in:
+161
@@ -0,0 +1,161 @@
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mailarchive/internal/auth"
|
||||
"github.com/mailarchive/internal/userstore"
|
||||
)
|
||||
|
||||
func newTestAuth(t *testing.T) (*auth.Manager, *userstore.Store) {
|
||||
t.Helper()
|
||||
store, err := userstore.New(filepath.Join(t.TempDir(), "users.db"))
|
||||
if err != nil {
|
||||
t.Fatalf("userstore.New: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { store.Close() })
|
||||
|
||||
// Seed a test user
|
||||
store.Create(userstore.CreateUserRequest{
|
||||
Username: "testadmin",
|
||||
Email: "admin@example.com",
|
||||
Password: "adminpass",
|
||||
Role: userstore.RoleAdmin,
|
||||
})
|
||||
store.Create(userstore.CreateUserRequest{
|
||||
Username: "regularuser",
|
||||
Email: "user@example.com",
|
||||
Password: "userpass",
|
||||
Role: userstore.RoleUser,
|
||||
})
|
||||
|
||||
mgr := auth.New(store, nil, "test-jwt-secret-32chars-long-enough")
|
||||
return mgr, store
|
||||
}
|
||||
|
||||
func TestLoginSuccess(t *testing.T) {
|
||||
mgr, _ := newTestAuth(t)
|
||||
|
||||
token, user, err := mgr.Login("testadmin", "adminpass")
|
||||
if err != nil {
|
||||
t.Fatalf("Login: %v", err)
|
||||
}
|
||||
if token == "" {
|
||||
t.Error("expected non-empty token")
|
||||
}
|
||||
if user.Username != "testadmin" {
|
||||
t.Errorf("Username = %q", user.Username)
|
||||
}
|
||||
if user.Role != userstore.RoleAdmin {
|
||||
t.Errorf("Role = %q", user.Role)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginWrongPassword(t *testing.T) {
|
||||
mgr, _ := newTestAuth(t)
|
||||
|
||||
if _, _, err := mgr.Login("testadmin", "wrongpass"); err == nil {
|
||||
t.Error("expected error for wrong password")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoginUnknownUser(t *testing.T) {
|
||||
mgr, _ := newTestAuth(t)
|
||||
|
||||
if _, _, err := mgr.Login("nobody", "pw"); err == nil {
|
||||
t.Error("expected error for unknown user")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenValidation(t *testing.T) {
|
||||
mgr, _ := newTestAuth(t)
|
||||
|
||||
token, _, _ := mgr.Login("testadmin", "adminpass")
|
||||
sess, err := mgr.ValidateToken(token)
|
||||
if err != nil {
|
||||
t.Fatalf("ValidateToken: %v", err)
|
||||
}
|
||||
if sess.Username != "testadmin" {
|
||||
t.Errorf("Session Username = %q", sess.Username)
|
||||
}
|
||||
if sess.Role != userstore.RoleAdmin {
|
||||
t.Errorf("Session Role = %q", sess.Role)
|
||||
}
|
||||
if sess.JTI == "" {
|
||||
t.Error("Session JTI should not be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenTampering(t *testing.T) {
|
||||
mgr, _ := newTestAuth(t)
|
||||
|
||||
token, _, _ := mgr.Login("testadmin", "adminpass")
|
||||
tampered := token + "x"
|
||||
|
||||
if _, err := mgr.ValidateToken(tampered); err == nil {
|
||||
t.Error("tampered token should fail validation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogout(t *testing.T) {
|
||||
mgr, _ := newTestAuth(t)
|
||||
|
||||
token, _, _ := mgr.Login("testadmin", "adminpass")
|
||||
|
||||
// Token valid before logout
|
||||
if _, err := mgr.ValidateToken(token); err != nil {
|
||||
t.Fatalf("token should be valid before logout: %v", err)
|
||||
}
|
||||
|
||||
if err := mgr.Logout(token); err != nil {
|
||||
t.Fatalf("Logout: %v", err)
|
||||
}
|
||||
|
||||
// Token invalid after logout
|
||||
if _, err := mgr.ValidateToken(token); err == nil {
|
||||
t.Error("token should be invalid after logout")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasRole(t *testing.T) {
|
||||
tests := []struct {
|
||||
userRole string
|
||||
required string
|
||||
want bool
|
||||
}{
|
||||
{userstore.RoleAdmin, userstore.RoleAdmin, true},
|
||||
{userstore.RoleAdmin, userstore.RoleAuditor, true},
|
||||
{userstore.RoleAdmin, userstore.RoleUser, true},
|
||||
{userstore.RoleAuditor, userstore.RoleAdmin, false},
|
||||
{userstore.RoleAuditor, userstore.RoleAuditor, true},
|
||||
{userstore.RoleAuditor, userstore.RoleUser, true},
|
||||
{userstore.RoleUser, userstore.RoleAdmin, false},
|
||||
{userstore.RoleUser, userstore.RoleAuditor, false},
|
||||
{userstore.RoleUser, userstore.RoleUser, true},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
got := auth.HasRole(tt.userRole, tt.required)
|
||||
if got != tt.want {
|
||||
t.Errorf("HasRole(%q, %q) = %v, want %v", tt.userRole, tt.required, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleSessionsIndependent(t *testing.T) {
|
||||
mgr, _ := newTestAuth(t)
|
||||
|
||||
token1, _, _ := mgr.Login("testadmin", "adminpass")
|
||||
token2, _, _ := mgr.Login("testadmin", "adminpass")
|
||||
|
||||
if token1 == token2 {
|
||||
t.Error("two logins should produce different tokens (different JTIs)")
|
||||
}
|
||||
|
||||
// Logout session 1, session 2 should still work
|
||||
mgr.Logout(token1)
|
||||
if _, err := mgr.ValidateToken(token2); err != nil {
|
||||
t.Errorf("session 2 should still be valid after session 1 logout: %v", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user