Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/jwt/api_jwk.py: 25%

92 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1from __future__ import annotations 

2 

3import json 

4import time 

5 

6from .algorithms import get_default_algorithms 

7from .exceptions import InvalidKeyError, PyJWKError, PyJWKSetError 

8 

9 

10class PyJWK: 

11 def __init__(self, jwk_data, algorithm=None): 

12 self._algorithms = get_default_algorithms() 

13 self._jwk_data = jwk_data 

14 

15 kty = self._jwk_data.get("kty", None) 

16 if not kty: 

17 raise InvalidKeyError(f"kty is not found: {self._jwk_data}") 

18 

19 if not algorithm and isinstance(self._jwk_data, dict): 

20 algorithm = self._jwk_data.get("alg", None) 

21 

22 if not algorithm: 

23 # Determine alg with kty (and crv). 

24 crv = self._jwk_data.get("crv", None) 

25 if kty == "EC": 

26 if crv == "P-256" or not crv: 

27 algorithm = "ES256" 

28 elif crv == "P-384": 

29 algorithm = "ES384" 

30 elif crv == "P-521": 

31 algorithm = "ES512" 

32 elif crv == "secp256k1": 

33 algorithm = "ES256K" 

34 else: 

35 raise InvalidKeyError(f"Unsupported crv: {crv}") 

36 elif kty == "RSA": 

37 algorithm = "RS256" 

38 elif kty == "oct": 

39 algorithm = "HS256" 

40 elif kty == "OKP": 

41 if not crv: 

42 raise InvalidKeyError(f"crv is not found: {self._jwk_data}") 

43 if crv == "Ed25519": 

44 algorithm = "EdDSA" 

45 else: 

46 raise InvalidKeyError(f"Unsupported crv: {crv}") 

47 else: 

48 raise InvalidKeyError(f"Unsupported kty: {kty}") 

49 

50 self.Algorithm = self._algorithms.get(algorithm) 

51 

52 if not self.Algorithm: 

53 raise PyJWKError(f"Unable to find a algorithm for key: {self._jwk_data}") 

54 

55 self.key = self.Algorithm.from_jwk(self._jwk_data) 

56 

57 @staticmethod 

58 def from_dict(obj, algorithm=None): 

59 return PyJWK(obj, algorithm) 

60 

61 @staticmethod 

62 def from_json(data, algorithm=None): 

63 obj = json.loads(data) 

64 return PyJWK.from_dict(obj, algorithm) 

65 

66 @property 

67 def key_type(self): 

68 return self._jwk_data.get("kty", None) 

69 

70 @property 

71 def key_id(self): 

72 return self._jwk_data.get("kid", None) 

73 

74 @property 

75 def public_key_use(self): 

76 return self._jwk_data.get("use", None) 

77 

78 

79class PyJWKSet: 

80 def __init__(self, keys: list[dict]) -> None: 

81 self.keys = [] 

82 

83 if not keys: 

84 raise PyJWKSetError("The JWK Set did not contain any keys") 

85 

86 if not isinstance(keys, list): 

87 raise PyJWKSetError("Invalid JWK Set value") 

88 

89 for key in keys: 

90 try: 

91 self.keys.append(PyJWK(key)) 

92 except PyJWKError: 

93 # skip unusable keys 

94 continue 

95 

96 if len(self.keys) == 0: 

97 raise PyJWKSetError("The JWK Set did not contain any usable keys") 

98 

99 @staticmethod 

100 def from_dict(obj): 

101 keys = obj.get("keys", []) 

102 return PyJWKSet(keys) 

103 

104 @staticmethod 

105 def from_json(data): 

106 obj = json.loads(data) 

107 return PyJWKSet.from_dict(obj) 

108 

109 def __getitem__(self, kid): 

110 for key in self.keys: 

111 if key.key_id == kid: 

112 return key 

113 raise KeyError(f"keyset has no key for kid: {kid}") 

114 

115 

116class PyJWTSetWithTimestamp: 

117 def __init__(self, jwk_set: PyJWKSet): 

118 self.jwk_set = jwk_set 

119 self.timestamp = time.monotonic() 

120 

121 def get_jwk_set(self): 

122 return self.jwk_set 

123 

124 def get_timestamp(self): 

125 return self.timestamp