File size: 6,428 Bytes
dbe78dd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
"""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 |