feat: backend core - auth, user, role, permission, device, webhook, monitoring, cache, repository, service, middleware, API handlers
This commit is contained in:
126
internal/auth/jwt_password_test.go
Normal file
126
internal/auth/jwt_password_test.go
Normal file
@@ -0,0 +1,126 @@
|
||||
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())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user