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