Files
user-system/internal/auth/jwt_password_test.go

127 lines
3.8 KiB
Go
Raw Permalink Normal View History

package auth
import (
"path/filepath"
"strings"
"testing"
"time"
)
func TestHashPassword_UsesArgon2id(t *testing.T) {
hashed, err := HashPassword("StrongPass1!")
if err != nil {
t.Fatalf("hash password failed: %v", err)
}
if !strings.HasPrefix(hashed, "$argon2id$") {
t.Fatalf("expected argon2id hash, got %q", hashed)
}
if !VerifyPassword(hashed, "StrongPass1!") {
t.Fatal("expected argon2id password verification to succeed")
}
}
func TestVerifyPassword_SupportsLegacyBcrypt(t *testing.T) {
hashed, err := BcryptHash("LegacyPass1!")
if err != nil {
t.Fatalf("hash legacy bcrypt password failed: %v", err)
}
if !VerifyPassword(hashed, "LegacyPass1!") {
t.Fatal("expected bcrypt compatibility verification to succeed")
}
}
func TestNewJWTWithOptions_RS256(t *testing.T) {
dir := t.TempDir()
jwtManager, err := NewJWTWithOptions(JWTOptions{
Algorithm: jwtAlgorithmRS256,
RSAPrivateKeyPath: filepath.Join(dir, "private.pem"),
RSAPublicKeyPath: filepath.Join(dir, "public.pem"),
AccessTokenExpire: 2 * time.Hour,
RefreshTokenExpire: 24 * time.Hour,
})
if err != nil {
t.Fatalf("create rs256 jwt manager failed: %v", err)
}
accessToken, refreshToken, err := jwtManager.GenerateTokenPair(42, "rs256-user")
if err != nil {
t.Fatalf("generate token pair failed: %v", err)
}
if jwtManager.GetAlgorithm() != jwtAlgorithmRS256 {
t.Fatalf("unexpected algorithm: %s", jwtManager.GetAlgorithm())
}
accessClaims, err := jwtManager.ValidateAccessToken(accessToken)
if err != nil {
t.Fatalf("validate access token failed: %v", err)
}
if accessClaims.UserID != 42 || accessClaims.Username != "rs256-user" {
t.Fatalf("unexpected access claims: %+v", accessClaims)
}
refreshClaims, err := jwtManager.ValidateRefreshToken(refreshToken)
if err != nil {
t.Fatalf("validate refresh token failed: %v", err)
}
if refreshClaims.Type != "refresh" {
t.Fatalf("unexpected refresh claims: %+v", refreshClaims)
}
}
func TestNewJWTWithOptions_RS256_RequiresKeyMaterial(t *testing.T) {
_, err := NewJWTWithOptions(JWTOptions{
Algorithm: jwtAlgorithmRS256,
AccessTokenExpire: 2 * time.Hour,
RefreshTokenExpire: 24 * time.Hour,
})
if err == nil {
t.Fatal("expected RS256 without key material to fail")
}
}
func TestNewJWTWithOptions_RS256_RequireExistingKeysRejectsMissingFiles(t *testing.T) {
dir := t.TempDir()
_, err := NewJWTWithOptions(JWTOptions{
Algorithm: jwtAlgorithmRS256,
RSAPrivateKeyPath: filepath.Join(dir, "missing-private.pem"),
RSAPublicKeyPath: filepath.Join(dir, "missing-public.pem"),
RequireExistingRSAKeys: true,
AccessTokenExpire: 2 * time.Hour,
RefreshTokenExpire: 24 * time.Hour,
})
if err == nil {
t.Fatal("expected RS256 strict mode to reject missing key files")
}
}
func TestNewJWTWithOptions_RS256_RequireExistingKeysAllowsExistingFiles(t *testing.T) {
dir := t.TempDir()
privatePath := filepath.Join(dir, "private.pem")
publicPath := filepath.Join(dir, "public.pem")
if _, err := NewJWTWithOptions(JWTOptions{
Algorithm: jwtAlgorithmRS256,
RSAPrivateKeyPath: privatePath,
RSAPublicKeyPath: publicPath,
AccessTokenExpire: 2 * time.Hour,
RefreshTokenExpire: 24 * time.Hour,
}); err != nil {
t.Fatalf("prepare key files failed: %v", err)
}
jwtManager, err := NewJWTWithOptions(JWTOptions{
Algorithm: jwtAlgorithmRS256,
RSAPrivateKeyPath: privatePath,
RSAPublicKeyPath: publicPath,
RequireExistingRSAKeys: true,
AccessTokenExpire: 2 * time.Hour,
RefreshTokenExpire: 24 * time.Hour,
})
if err != nil {
t.Fatalf("expected strict mode to accept existing key files, got: %v", err)
}
if jwtManager.GetAlgorithm() != jwtAlgorithmRS256 {
t.Fatalf("unexpected algorithm: %s", jwtManager.GetAlgorithm())
}
}