205a5a36c6
- 8 crypto tests: key derivation, encrypt/decrypt round-trip, wrong key, nonce uniqueness - 6 auth tests: password hash/verify, JWT generate/validate, token revocation - 14 store tests: project CRUD, user CRUD, stage/deploy lifecycle, pagination, cascade deletes - Fix stages CREATE TABLE schema to include notification_url column - Total: 28 tests, all passing
133 lines
3.3 KiB
Go
133 lines
3.3 KiB
Go
package auth
|
|
|
|
import (
|
|
"testing"
|
|
)
|
|
|
|
func TestHashAndCheckPassword(t *testing.T) {
|
|
hash, err := HashPassword("my-password-123")
|
|
if err != nil {
|
|
t.Fatalf("HashPassword failed: %v", err)
|
|
}
|
|
if hash == "my-password-123" {
|
|
t.Fatal("hash equals plaintext")
|
|
}
|
|
|
|
// Correct password
|
|
if err := CheckPassword(hash, "my-password-123"); err != nil {
|
|
t.Fatalf("CheckPassword rejected correct password: %v", err)
|
|
}
|
|
|
|
// Wrong password
|
|
if err := CheckPassword(hash, "wrong-password"); err == nil {
|
|
t.Fatal("CheckPassword accepted wrong password")
|
|
}
|
|
}
|
|
|
|
func TestGenerateAndValidateToken(t *testing.T) {
|
|
key := [32]byte{}
|
|
copy(key[:], "test-jwt-secret-32-bytes-needed!")
|
|
la := NewLocalAuth(key)
|
|
|
|
claims := Claims{UserID: "u1", Username: "admin", Role: "admin"}
|
|
token, err := la.GenerateToken(claims)
|
|
if err != nil {
|
|
t.Fatalf("GenerateToken failed: %v", err)
|
|
}
|
|
if token.Token == "" {
|
|
t.Fatal("generated empty token")
|
|
}
|
|
|
|
// Validate the token
|
|
got, err := la.ValidateToken(token.Token)
|
|
if err != nil {
|
|
t.Fatalf("ValidateToken failed: %v", err)
|
|
}
|
|
if got.UserID != "u1" || got.Username != "admin" || got.Role != "admin" {
|
|
t.Fatalf("claims mismatch: %+v", got)
|
|
}
|
|
}
|
|
|
|
func TestValidateInvalidToken(t *testing.T) {
|
|
key := [32]byte{}
|
|
copy(key[:], "test-jwt-secret-32-bytes-needed!")
|
|
la := NewLocalAuth(key)
|
|
|
|
_, err := la.ValidateToken("invalid-token-string")
|
|
if err == nil {
|
|
t.Fatal("ValidateToken should reject invalid token")
|
|
}
|
|
}
|
|
|
|
func TestValidateTokenFromDifferentKey(t *testing.T) {
|
|
key1 := [32]byte{}
|
|
copy(key1[:], "first-jwt-secret-32-bytes-needed")
|
|
la1 := NewLocalAuth(key1)
|
|
|
|
key2 := [32]byte{}
|
|
copy(key2[:], "other-jwt-secret-32-bytes-needed")
|
|
la2 := NewLocalAuth(key2)
|
|
|
|
claims := Claims{UserID: "u1", Username: "admin", Role: "admin"}
|
|
token, err := la1.GenerateToken(claims)
|
|
if err != nil {
|
|
t.Fatalf("GenerateToken failed: %v", err)
|
|
}
|
|
|
|
// Token signed with key1 should not validate with key2
|
|
_, err = la2.ValidateToken(token.Token)
|
|
if err == nil {
|
|
t.Fatal("ValidateToken should reject token signed with different key")
|
|
}
|
|
}
|
|
|
|
func TestHashPasswordDifferentOutputs(t *testing.T) {
|
|
hash1, err := HashPassword("same-password")
|
|
if err != nil {
|
|
t.Fatalf("HashPassword 1 failed: %v", err)
|
|
}
|
|
|
|
hash2, err := HashPassword("same-password")
|
|
if err != nil {
|
|
t.Fatalf("HashPassword 2 failed: %v", err)
|
|
}
|
|
|
|
if hash1 == hash2 {
|
|
t.Fatal("bcrypt should produce different hashes for same input (random salt)")
|
|
}
|
|
|
|
// Both should still verify
|
|
if err := CheckPassword(hash1, "same-password"); err != nil {
|
|
t.Fatal("hash1 should verify")
|
|
}
|
|
if err := CheckPassword(hash2, "same-password"); err != nil {
|
|
t.Fatal("hash2 should verify")
|
|
}
|
|
}
|
|
|
|
func TestTokenContainsClaims(t *testing.T) {
|
|
key := [32]byte{}
|
|
copy(key[:], "test-jwt-secret-32-bytes-needed!")
|
|
la := NewLocalAuth(key)
|
|
|
|
claims := Claims{UserID: "user-42", Username: "testuser", Role: "viewer"}
|
|
token, err := la.GenerateToken(claims)
|
|
if err != nil {
|
|
t.Fatalf("GenerateToken failed: %v", err)
|
|
}
|
|
|
|
got, err := la.ValidateToken(token.Token)
|
|
if err != nil {
|
|
t.Fatalf("ValidateToken failed: %v", err)
|
|
}
|
|
if got.UserID != "user-42" {
|
|
t.Fatalf("UserID mismatch: got %q, want %q", got.UserID, "user-42")
|
|
}
|
|
if got.Username != "testuser" {
|
|
t.Fatalf("Username mismatch: got %q, want %q", got.Username, "testuser")
|
|
}
|
|
if got.Role != "viewer" {
|
|
t.Fatalf("Role mismatch: got %q, want %q", got.Role, "viewer")
|
|
}
|
|
}
|