"""Unit tests for JWT validation service.""" import pytest import base64 import json from infrastructure.services.jwt_validation_service import JWTValidationService class TestJWTValidationService: """Test cases for JWT validation service.""" def setup_method(self): """Set up test fixtures.""" self.jwt_service = JWTValidationService() # Create a valid JWT token for testing self.valid_header = {"alg": "HS256", "typ": "JWT"} self.valid_payload = {"sub": "1234567890", "name": "John Doe", "iat": 1516239022} self.valid_signature = "test_signature" # Encode the parts header_b64 = base64.urlsafe_b64encode( json.dumps(self.valid_header).encode() ).decode().rstrip('=') payload_b64 = base64.urlsafe_b64encode( json.dumps(self.valid_payload).encode() ).decode().rstrip('=') self.valid_token = f"{header_b64}.{payload_b64}.{self.valid_signature}" def test_validate_structure_valid_token(self): """Test validation of a valid JWT token structure.""" assert self.jwt_service.validate_structure(self.valid_token) is True def test_validate_structure_empty_token(self): """Test validation fails for empty token.""" assert self.jwt_service.validate_structure("") is False assert self.jwt_service.validate_structure(None) is False def test_validate_structure_invalid_type(self): """Test validation fails for non-string token.""" assert self.jwt_service.validate_structure(123) is False assert self.jwt_service.validate_structure([]) is False def test_validate_structure_wrong_part_count(self): """Test validation fails for wrong number of parts.""" assert self.jwt_service.validate_structure("only.one.part") is False assert self.jwt_service.validate_structure("too.many.parts.here") is False assert self.jwt_service.validate_structure("single_part") is False def test_validate_structure_empty_signature(self): """Test validation fails for empty signature.""" header_b64 = base64.urlsafe_b64encode( json.dumps(self.valid_header).encode() ).decode().rstrip('=') payload_b64 = base64.urlsafe_b64encode( json.dumps(self.valid_payload).encode() ).decode().rstrip('=') invalid_token = f"{header_b64}.{payload_b64}." assert self.jwt_service.validate_structure(invalid_token) is False def test_validate_structure_invalid_base64_header(self): """Test validation fails for invalid base64 in header.""" invalid_token = "invalid_base64.valid_payload.signature" assert self.jwt_service.validate_structure(invalid_token) is False def test_validate_structure_invalid_json_header(self): """Test validation fails for invalid JSON in header.""" invalid_header = base64.urlsafe_b64encode(b"not_json").decode() payload_b64 = base64.urlsafe_b64encode( json.dumps(self.valid_payload).encode() ).decode().rstrip('=') invalid_token = f"{invalid_header}.{payload_b64}.signature" assert self.jwt_service.validate_structure(invalid_token) is False def test_validate_structure_invalid_json_payload(self): """Test validation fails for invalid JSON in payload.""" header_b64 = base64.urlsafe_b64encode( json.dumps(self.valid_header).encode() ).decode().rstrip('=') invalid_payload = base64.urlsafe_b64encode(b"not_json").decode() invalid_token = f"{header_b64}.{invalid_payload}.signature" assert self.jwt_service.validate_structure(invalid_token) is False def test_validate_jwt_part_valid_part(self): """Test validation of valid JWT part.""" header_b64 = base64.urlsafe_b64encode( json.dumps(self.valid_header).encode() ).decode().rstrip('=') result = self.jwt_service._validate_jwt_part(header_b64, "header") assert result == self.valid_header def test_validate_jwt_part_empty_part(self): """Test validation fails for empty part.""" with pytest.raises(ValueError, match="Empty JWT header"): self.jwt_service._validate_jwt_part("", "header") def test_validate_jwt_part_invalid_base64(self): """Test validation fails for invalid base64.""" with pytest.raises(ValueError, match="Invalid JWT header"): self.jwt_service._validate_jwt_part("invalid_base64", "header") def test_validate_jwt_part_non_object_json(self): """Test validation fails for non-object JSON.""" # JSON array instead of object json_array = json.dumps(["not", "an", "object"]) array_b64 = base64.urlsafe_b64encode(json_array.encode()).decode() with pytest.raises(ValueError, match="JWT header is not a JSON object"): self.jwt_service._validate_jwt_part(array_b64, "header") def test_extract_claims_valid_token(self): """Test extracting claims from valid token.""" claims = self.jwt_service.extract_claims(self.valid_token) assert claims == self.valid_payload def test_extract_claims_invalid_token(self): """Test extracting claims from invalid token.""" claims = self.jwt_service.extract_claims("invalid.token") assert claims is None def test_extract_claims_empty_token(self): """Test extracting claims from empty token.""" claims = self.jwt_service.extract_claims("") assert claims is None def test_jwt_with_padding(self): """Test JWT validation with base64 padding.""" # Create JWT parts that need padding header = {"alg": "HS256", "typ": "JWT"} payload = {"sub": "test"} # Shorter payload header_b64 = base64.urlsafe_b64encode( json.dumps(header).encode() ).decode().rstrip('=') payload_b64 = base64.urlsafe_b64encode( json.dumps(payload).encode() ).decode().rstrip('=') token = f"{header_b64}.{payload_b64}.signature" assert self.jwt_service.validate_structure(token) is True claims = self.jwt_service.extract_claims(token) assert claims == payload