Spaces:
Sleeping
Sleeping
| """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 |