clear-skies 1.22.31__py3-none-any.whl → 2.0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of clear-skies might be problematic. Click here for more details.

Files changed (345) hide show
  1. {clear_skies-1.22.31.dist-info → clear_skies-2.0.1.dist-info}/METADATA +12 -14
  2. clear_skies-2.0.1.dist-info/RECORD +249 -0
  3. {clear_skies-1.22.31.dist-info → clear_skies-2.0.1.dist-info}/WHEEL +1 -1
  4. clearskies/__init__.py +42 -25
  5. clearskies/action.py +7 -0
  6. clearskies/authentication/__init__.py +8 -41
  7. clearskies/authentication/authentication.py +46 -0
  8. clearskies/authentication/authorization.py +8 -9
  9. clearskies/authentication/authorization_pass_through.py +11 -9
  10. clearskies/authentication/jwks.py +133 -58
  11. clearskies/authentication/public.py +3 -38
  12. clearskies/authentication/secret_bearer.py +516 -54
  13. clearskies/autodoc/formats/oai3_json/__init__.py +1 -1
  14. clearskies/autodoc/formats/oai3_json/oai3_json.py +9 -7
  15. clearskies/autodoc/formats/oai3_json/parameter.py +6 -3
  16. clearskies/autodoc/formats/oai3_json/request.py +7 -5
  17. clearskies/autodoc/formats/oai3_json/response.py +7 -4
  18. clearskies/autodoc/formats/oai3_json/schema/object.py +4 -1
  19. clearskies/autodoc/request/__init__.py +2 -0
  20. clearskies/autodoc/request/header.py +4 -6
  21. clearskies/autodoc/request/json_body.py +4 -6
  22. clearskies/autodoc/request/parameter.py +8 -0
  23. clearskies/autodoc/request/request.py +7 -4
  24. clearskies/autodoc/request/url_parameter.py +4 -6
  25. clearskies/autodoc/request/url_path.py +4 -6
  26. clearskies/autodoc/schema/__init__.py +4 -2
  27. clearskies/autodoc/schema/array.py +5 -6
  28. clearskies/autodoc/schema/boolean.py +4 -10
  29. clearskies/autodoc/schema/date.py +0 -3
  30. clearskies/autodoc/schema/datetime.py +1 -4
  31. clearskies/autodoc/schema/double.py +0 -3
  32. clearskies/autodoc/schema/enum.py +4 -2
  33. clearskies/autodoc/schema/integer.py +4 -9
  34. clearskies/autodoc/schema/long.py +0 -3
  35. clearskies/autodoc/schema/number.py +4 -9
  36. clearskies/autodoc/schema/object.py +5 -7
  37. clearskies/autodoc/schema/password.py +0 -3
  38. clearskies/autodoc/schema/schema.py +11 -0
  39. clearskies/autodoc/schema/string.py +4 -10
  40. clearskies/backends/__init__.py +55 -20
  41. clearskies/backends/api_backend.py +1100 -284
  42. clearskies/backends/backend.py +53 -84
  43. clearskies/backends/cursor_backend.py +236 -186
  44. clearskies/backends/memory_backend.py +519 -226
  45. clearskies/backends/secrets_backend.py +75 -31
  46. clearskies/column.py +1229 -0
  47. clearskies/columns/__init__.py +71 -0
  48. clearskies/columns/audit.py +205 -0
  49. clearskies/columns/belongs_to_id.py +483 -0
  50. clearskies/columns/belongs_to_model.py +128 -0
  51. clearskies/columns/belongs_to_self.py +105 -0
  52. clearskies/columns/boolean.py +109 -0
  53. clearskies/columns/category_tree.py +275 -0
  54. clearskies/columns/category_tree_ancestors.py +51 -0
  55. clearskies/columns/category_tree_children.py +127 -0
  56. clearskies/columns/category_tree_descendants.py +48 -0
  57. clearskies/columns/created.py +94 -0
  58. clearskies/columns/created_by_authorization_data.py +116 -0
  59. clearskies/columns/created_by_header.py +99 -0
  60. clearskies/columns/created_by_ip.py +92 -0
  61. clearskies/columns/created_by_routing_data.py +96 -0
  62. clearskies/columns/created_by_user_agent.py +92 -0
  63. clearskies/columns/date.py +230 -0
  64. clearskies/columns/datetime.py +278 -0
  65. clearskies/columns/email.py +76 -0
  66. clearskies/columns/float.py +149 -0
  67. clearskies/columns/has_many.py +505 -0
  68. clearskies/columns/has_many_self.py +56 -0
  69. clearskies/columns/has_one.py +14 -0
  70. clearskies/columns/integer.py +156 -0
  71. clearskies/columns/json.py +122 -0
  72. clearskies/columns/many_to_many_ids.py +333 -0
  73. clearskies/columns/many_to_many_ids_with_data.py +270 -0
  74. clearskies/columns/many_to_many_models.py +154 -0
  75. clearskies/columns/many_to_many_pivots.py +133 -0
  76. clearskies/columns/phone.py +158 -0
  77. clearskies/columns/select.py +91 -0
  78. clearskies/columns/string.py +98 -0
  79. clearskies/columns/timestamp.py +160 -0
  80. clearskies/columns/updated.py +110 -0
  81. clearskies/columns/uuid.py +86 -0
  82. clearskies/configs/README.md +105 -0
  83. clearskies/configs/__init__.py +162 -0
  84. clearskies/configs/actions.py +43 -0
  85. clearskies/configs/any.py +13 -0
  86. clearskies/configs/any_dict.py +22 -0
  87. clearskies/configs/any_dict_or_callable.py +23 -0
  88. clearskies/configs/authentication.py +23 -0
  89. clearskies/configs/authorization.py +23 -0
  90. clearskies/configs/boolean.py +16 -0
  91. clearskies/configs/boolean_or_callable.py +18 -0
  92. clearskies/configs/callable_config.py +18 -0
  93. clearskies/configs/columns.py +34 -0
  94. clearskies/configs/conditions.py +30 -0
  95. clearskies/configs/config.py +24 -0
  96. clearskies/configs/datetime.py +18 -0
  97. clearskies/configs/datetime_or_callable.py +19 -0
  98. clearskies/configs/endpoint.py +23 -0
  99. clearskies/configs/endpoint_list.py +28 -0
  100. clearskies/configs/float.py +16 -0
  101. clearskies/configs/float_or_callable.py +18 -0
  102. clearskies/configs/integer.py +16 -0
  103. clearskies/configs/integer_or_callable.py +18 -0
  104. clearskies/configs/joins.py +30 -0
  105. clearskies/configs/list_any_dict.py +30 -0
  106. clearskies/configs/list_any_dict_or_callable.py +31 -0
  107. clearskies/configs/model_class.py +35 -0
  108. clearskies/configs/model_column.py +65 -0
  109. clearskies/configs/model_columns.py +56 -0
  110. clearskies/configs/model_destination_name.py +25 -0
  111. clearskies/configs/model_to_id_column.py +43 -0
  112. clearskies/configs/readable_model_column.py +9 -0
  113. clearskies/configs/readable_model_columns.py +9 -0
  114. clearskies/configs/schema.py +23 -0
  115. clearskies/configs/searchable_model_columns.py +9 -0
  116. clearskies/configs/security_headers.py +39 -0
  117. clearskies/configs/select.py +26 -0
  118. clearskies/configs/select_list.py +47 -0
  119. clearskies/configs/string.py +29 -0
  120. clearskies/configs/string_dict.py +32 -0
  121. clearskies/configs/string_list.py +32 -0
  122. clearskies/configs/string_list_or_callable.py +35 -0
  123. clearskies/configs/string_or_callable.py +18 -0
  124. clearskies/configs/timedelta.py +18 -0
  125. clearskies/configs/timezone.py +18 -0
  126. clearskies/configs/url.py +23 -0
  127. clearskies/configs/validators.py +45 -0
  128. clearskies/configs/writeable_model_column.py +9 -0
  129. clearskies/configs/writeable_model_columns.py +9 -0
  130. clearskies/configurable.py +76 -0
  131. clearskies/contexts/__init__.py +8 -8
  132. clearskies/contexts/cli.py +8 -41
  133. clearskies/contexts/context.py +91 -56
  134. clearskies/contexts/wsgi.py +16 -29
  135. clearskies/contexts/wsgi_ref.py +53 -0
  136. clearskies/di/__init__.py +10 -7
  137. clearskies/di/additional_config.py +115 -4
  138. clearskies/di/additional_config_auto_import.py +12 -0
  139. clearskies/di/di.py +742 -121
  140. clearskies/di/inject/__init__.py +23 -0
  141. clearskies/di/inject/by_class.py +21 -0
  142. clearskies/di/inject/by_name.py +18 -0
  143. clearskies/di/inject/di.py +13 -0
  144. clearskies/di/inject/environment.py +14 -0
  145. clearskies/di/inject/input_output.py +20 -0
  146. clearskies/di/inject/now.py +13 -0
  147. clearskies/di/inject/requests.py +13 -0
  148. clearskies/di/inject/secrets.py +14 -0
  149. clearskies/di/inject/utcnow.py +13 -0
  150. clearskies/di/inject/uuid.py +15 -0
  151. clearskies/di/injectable.py +29 -0
  152. clearskies/di/injectable_properties.py +131 -0
  153. clearskies/end.py +183 -0
  154. clearskies/endpoint.py +1310 -0
  155. clearskies/endpoint_group.py +310 -0
  156. clearskies/endpoints/__init__.py +23 -0
  157. clearskies/endpoints/advanced_search.py +526 -0
  158. clearskies/endpoints/callable.py +388 -0
  159. clearskies/endpoints/create.py +202 -0
  160. clearskies/endpoints/delete.py +139 -0
  161. clearskies/endpoints/get.py +275 -0
  162. clearskies/endpoints/health_check.py +181 -0
  163. clearskies/endpoints/list.py +573 -0
  164. clearskies/endpoints/restful_api.py +427 -0
  165. clearskies/endpoints/simple_search.py +286 -0
  166. clearskies/endpoints/update.py +190 -0
  167. clearskies/environment.py +5 -3
  168. clearskies/exceptions/__init__.py +17 -0
  169. clearskies/{handlers/exceptions/input_error.py → exceptions/input_errors.py} +1 -1
  170. clearskies/exceptions/moved_permanently.py +3 -0
  171. clearskies/exceptions/moved_temporarily.py +3 -0
  172. clearskies/exceptions/not_found.py +2 -0
  173. clearskies/functional/__init__.py +2 -2
  174. clearskies/functional/routing.py +92 -0
  175. clearskies/functional/string.py +19 -11
  176. clearskies/functional/validations.py +61 -9
  177. clearskies/input_outputs/__init__.py +9 -7
  178. clearskies/input_outputs/cli.py +130 -142
  179. clearskies/input_outputs/exceptions/__init__.py +1 -1
  180. clearskies/input_outputs/headers.py +45 -0
  181. clearskies/input_outputs/input_output.py +91 -122
  182. clearskies/input_outputs/programmatic.py +69 -0
  183. clearskies/input_outputs/wsgi.py +23 -38
  184. clearskies/model.py +984 -183
  185. clearskies/parameters_to_properties.py +31 -0
  186. clearskies/query/__init__.py +12 -0
  187. clearskies/query/condition.py +223 -0
  188. clearskies/query/join.py +136 -0
  189. clearskies/query/query.py +196 -0
  190. clearskies/query/sort.py +27 -0
  191. clearskies/schema.py +82 -0
  192. clearskies/secrets/__init__.py +3 -31
  193. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer.py +15 -4
  194. clearskies/secrets/additional_configs/mysql_connection_dynamic_producer_via_ssh_cert_bastion.py +11 -5
  195. clearskies/secrets/akeyless.py +88 -147
  196. clearskies/secrets/secrets.py +8 -8
  197. clearskies/security_header.py +15 -0
  198. clearskies/security_headers/__init__.py +8 -8
  199. clearskies/security_headers/cache_control.py +47 -110
  200. clearskies/security_headers/cors.py +40 -95
  201. clearskies/security_headers/csp.py +76 -151
  202. clearskies/security_headers/hsts.py +14 -16
  203. clearskies/test_base.py +8 -0
  204. clearskies/typing.py +11 -0
  205. clearskies/validator.py +37 -0
  206. clearskies/validators/__init__.py +33 -0
  207. clearskies/validators/after_column.py +62 -0
  208. clearskies/validators/before_column.py +13 -0
  209. clearskies/validators/in_the_future.py +32 -0
  210. clearskies/validators/in_the_future_at_least.py +11 -0
  211. clearskies/validators/in_the_future_at_most.py +10 -0
  212. clearskies/validators/in_the_past.py +32 -0
  213. clearskies/validators/in_the_past_at_least.py +10 -0
  214. clearskies/validators/in_the_past_at_most.py +10 -0
  215. clearskies/validators/maximum_length.py +26 -0
  216. clearskies/validators/maximum_value.py +29 -0
  217. clearskies/validators/minimum_length.py +26 -0
  218. clearskies/validators/minimum_value.py +29 -0
  219. clearskies/validators/required.py +35 -0
  220. clearskies/validators/timedelta.py +59 -0
  221. clearskies/validators/unique.py +31 -0
  222. clear_skies-1.22.31.dist-info/RECORD +0 -214
  223. clearskies/application.py +0 -29
  224. clearskies/authentication/auth0_jwks.py +0 -118
  225. clearskies/authentication/auth_exception.py +0 -2
  226. clearskies/authentication/jwks_jwcrypto.py +0 -51
  227. clearskies/backends/api_get_only_backend.py +0 -48
  228. clearskies/backends/example_backend.py +0 -43
  229. clearskies/backends/file_backend.py +0 -48
  230. clearskies/backends/json_backend.py +0 -7
  231. clearskies/backends/restful_api_advanced_search_backend.py +0 -103
  232. clearskies/binding_config.py +0 -16
  233. clearskies/column_types/__init__.py +0 -203
  234. clearskies/column_types/audit.py +0 -249
  235. clearskies/column_types/belongs_to.py +0 -271
  236. clearskies/column_types/boolean.py +0 -60
  237. clearskies/column_types/category_tree.py +0 -304
  238. clearskies/column_types/column.py +0 -373
  239. clearskies/column_types/created.py +0 -26
  240. clearskies/column_types/created_by_authorization_data.py +0 -26
  241. clearskies/column_types/created_by_header.py +0 -24
  242. clearskies/column_types/created_by_ip.py +0 -17
  243. clearskies/column_types/created_by_routing_data.py +0 -25
  244. clearskies/column_types/created_by_user_agent.py +0 -17
  245. clearskies/column_types/created_micro.py +0 -26
  246. clearskies/column_types/datetime.py +0 -109
  247. clearskies/column_types/datetime_micro.py +0 -12
  248. clearskies/column_types/email.py +0 -18
  249. clearskies/column_types/float.py +0 -43
  250. clearskies/column_types/has_many.py +0 -179
  251. clearskies/column_types/has_one.py +0 -60
  252. clearskies/column_types/integer.py +0 -41
  253. clearskies/column_types/json.py +0 -25
  254. clearskies/column_types/many_to_many.py +0 -278
  255. clearskies/column_types/many_to_many_with_data.py +0 -162
  256. clearskies/column_types/phone.py +0 -48
  257. clearskies/column_types/select.py +0 -11
  258. clearskies/column_types/string.py +0 -24
  259. clearskies/column_types/timestamp.py +0 -73
  260. clearskies/column_types/updated.py +0 -26
  261. clearskies/column_types/updated_micro.py +0 -26
  262. clearskies/column_types/uuid.py +0 -25
  263. clearskies/columns.py +0 -123
  264. clearskies/condition_parser.py +0 -172
  265. clearskies/contexts/build_context.py +0 -54
  266. clearskies/contexts/convert_to_application.py +0 -190
  267. clearskies/contexts/extract_handler.py +0 -37
  268. clearskies/contexts/test.py +0 -94
  269. clearskies/decorators/__init__.py +0 -41
  270. clearskies/decorators/allow_non_json_bodies.py +0 -9
  271. clearskies/decorators/auth0_jwks.py +0 -22
  272. clearskies/decorators/authorization.py +0 -10
  273. clearskies/decorators/binding_classes.py +0 -9
  274. clearskies/decorators/binding_modules.py +0 -9
  275. clearskies/decorators/bindings.py +0 -9
  276. clearskies/decorators/create.py +0 -10
  277. clearskies/decorators/delete.py +0 -10
  278. clearskies/decorators/docs.py +0 -14
  279. clearskies/decorators/get.py +0 -10
  280. clearskies/decorators/jwks.py +0 -26
  281. clearskies/decorators/merge.py +0 -124
  282. clearskies/decorators/patch.py +0 -10
  283. clearskies/decorators/post.py +0 -10
  284. clearskies/decorators/public.py +0 -11
  285. clearskies/decorators/response_headers.py +0 -10
  286. clearskies/decorators/return_raw_response.py +0 -9
  287. clearskies/decorators/schema.py +0 -10
  288. clearskies/decorators/secret_bearer.py +0 -24
  289. clearskies/decorators/security_headers.py +0 -10
  290. clearskies/di/standard_dependencies.py +0 -151
  291. clearskies/handlers/__init__.py +0 -41
  292. clearskies/handlers/advanced_search.py +0 -271
  293. clearskies/handlers/base.py +0 -479
  294. clearskies/handlers/callable.py +0 -192
  295. clearskies/handlers/create.py +0 -35
  296. clearskies/handlers/crud_by_method.py +0 -18
  297. clearskies/handlers/database_connector.py +0 -32
  298. clearskies/handlers/delete.py +0 -61
  299. clearskies/handlers/exceptions/__init__.py +0 -5
  300. clearskies/handlers/exceptions/not_found.py +0 -3
  301. clearskies/handlers/get.py +0 -156
  302. clearskies/handlers/health_check.py +0 -59
  303. clearskies/handlers/input_processing.py +0 -79
  304. clearskies/handlers/list.py +0 -530
  305. clearskies/handlers/mygrations.py +0 -82
  306. clearskies/handlers/request_method_routing.py +0 -47
  307. clearskies/handlers/restful_api.py +0 -218
  308. clearskies/handlers/routing.py +0 -62
  309. clearskies/handlers/schema_helper.py +0 -128
  310. clearskies/handlers/simple_routing.py +0 -206
  311. clearskies/handlers/simple_routing_route.py +0 -197
  312. clearskies/handlers/simple_search.py +0 -136
  313. clearskies/handlers/update.py +0 -102
  314. clearskies/handlers/write.py +0 -193
  315. clearskies/input_requirements/__init__.py +0 -78
  316. clearskies/input_requirements/after.py +0 -36
  317. clearskies/input_requirements/before.py +0 -36
  318. clearskies/input_requirements/in_the_future_at_least.py +0 -19
  319. clearskies/input_requirements/in_the_future_at_most.py +0 -19
  320. clearskies/input_requirements/in_the_past_at_least.py +0 -19
  321. clearskies/input_requirements/in_the_past_at_most.py +0 -19
  322. clearskies/input_requirements/maximum_length.py +0 -19
  323. clearskies/input_requirements/maximum_value.py +0 -19
  324. clearskies/input_requirements/minimum_length.py +0 -22
  325. clearskies/input_requirements/minimum_value.py +0 -19
  326. clearskies/input_requirements/required.py +0 -23
  327. clearskies/input_requirements/requirement.py +0 -25
  328. clearskies/input_requirements/time_delta.py +0 -38
  329. clearskies/input_requirements/unique.py +0 -18
  330. clearskies/mocks/__init__.py +0 -7
  331. clearskies/mocks/input_output.py +0 -124
  332. clearskies/mocks/models.py +0 -142
  333. clearskies/models.py +0 -350
  334. clearskies/security_headers/base.py +0 -12
  335. clearskies/tests/simple_api/models/__init__.py +0 -2
  336. clearskies/tests/simple_api/models/status.py +0 -23
  337. clearskies/tests/simple_api/models/user.py +0 -21
  338. clearskies/tests/simple_api/users_api.py +0 -64
  339. {clear_skies-1.22.31.dist-info → clear_skies-2.0.1.dist-info}/LICENSE +0 -0
  340. /clearskies/{contexts/bash.py → autodoc/py.typed} +0 -0
  341. /clearskies/{handlers/exceptions → exceptions}/authentication.py +0 -0
  342. /clearskies/{handlers/exceptions → exceptions}/authorization.py +0 -0
  343. /clearskies/{handlers/exceptions → exceptions}/client_error.py +0 -0
  344. /clearskies/{tests/__init__.py → input_outputs/py.typed} +0 -0
  345. /clearskies/{tests/simple_api/__init__.py → py.typed} +0 -0
@@ -1,88 +1,163 @@
1
- from clearskies.authentication import Auth0JWKS
2
- from clearskies.handlers.exceptions import ClientError
3
- import datetime
1
+ import json
2
+ from typing import Any
4
3
 
4
+ import clearskies.configs
5
+ import clearskies.di
6
+ import clearskies.parameters_to_properties
7
+ from clearskies.authentication.authentication import Authentication
8
+ from clearskies.exceptions import ClientError
9
+ from clearskies.security_headers.cors import Cors
5
10
 
6
- class JWKS(Auth0JWKS):
7
- _audience = None
8
- _jwks_url = None
9
- _jwks_cache_time = None
10
- _authorization_url = None
11
11
 
12
- def __init__(self, environment, requests, jose_jwt):
13
- super().__init__(environment, requests, jose_jwt)
12
+ class Jwks(Authentication, clearskies.di.InjectableProperties):
13
+ """
14
+ Validate a JWT against a JWKS (JSON Web Key Set)
15
+ """
14
16
 
15
- def configure(
17
+ """
18
+ The URL of the JWKS
19
+ """
20
+ jwks_url = clearskies.configs.String(required=True)
21
+
22
+ """
23
+ The audience to accept JWTs for.
24
+ """
25
+ audience = clearskies.configs.StringList(default=[])
26
+
27
+ """
28
+ The expected issuer of the JWTs.
29
+ """
30
+ issuer = clearskies.configs.String(default="")
31
+
32
+ """
33
+ The allowed algorithms
34
+ """
35
+ algorithms = clearskies.configs.StringList(default=["RS256"])
36
+
37
+ """
38
+ The number of seconds for which the JWKS URL contents can be cached
39
+ """
40
+ jwks_cache_time = clearskies.configs.Integer(default=86400)
41
+
42
+ """
43
+ The Authorization URL (used in the auto-generated documentation)
44
+ """
45
+ authorization_url = clearskies.configs.String()
46
+
47
+ """
48
+ The name of the security scheme in the auto-generated documentation.
49
+ """
50
+ documentation_security_name = clearskies.configs.String(default="jwt")
51
+
52
+ """
53
+ The environment helper.
54
+ """
55
+ environment = clearskies.di.inject.Environment()
56
+
57
+ """
58
+ The requests object.
59
+ """
60
+ requests = clearskies.di.inject.Requests()
61
+
62
+ """
63
+ The JoseJwt library
64
+ """
65
+ jose_jwt = clearskies.di.inject.ByName("jose_jwt")
66
+
67
+ """
68
+ The current time
69
+ """
70
+ now = clearskies.di.inject.Now()
71
+
72
+ """
73
+ Local cache of the JWKS
74
+ """
75
+ _jwks = None
76
+
77
+ """
78
+ The time when the JWKS was last fetched
79
+ """
80
+ _jwks_fetched = None
81
+
82
+ @clearskies.parameters_to_properties.parameters_to_properties
83
+ def __init__(
16
84
  self,
17
- jwks_url=None,
18
- algorithms=None,
19
- audience=None,
20
- issuer=None,
21
- documentation_security_name=None,
22
- authorization_url=None,
23
- jwks_cache_time=86400,
85
+ jwks_url: str,
86
+ audience: str = "",
87
+ issuer: str = "",
88
+ algorithms: list[str] = ["RS256"],
89
+ jwks_cache_time: int = 86400,
90
+ authorization_url: str = "",
91
+ documentation_security_name: str = "jwt",
24
92
  ):
25
- self._audience = audience
26
- self._issuer = issuer
27
- self._jwks_url = jwks_url
28
- self._jwks_cache_time = jwks_cache_time
29
- if not self._jwks_url:
30
- raise ValueError("Must provide 'jwks_url' when using JWKS authentication")
31
- self._algorithms = ["RS256"] if algorithms is None else algorithms
32
- self._documentation_security_name = documentation_security_name
33
- self._authorization_url = authorization_url if authorization_url else ""
34
-
35
- def authenticate(self, input_output):
93
+ self.finalize_and_validate_configuration()
94
+
95
+ def authenticate(self, input_output) -> bool:
36
96
  auth_header = input_output.get_request_header("authorization", True)
37
97
  if not auth_header:
38
98
  raise ClientError("Missing 'Authorization' header in request")
39
99
  if auth_header[:7].lower() != "bearer ":
40
100
  raise ClientError("Missing 'Bearer ' prefix in authorization header")
41
101
  self.validate_jwt(auth_header[7:])
42
- input_output.set_authorization_data(self.jwt_claims)
102
+ input_output.authorization_data = self.jwt_claims
43
103
  return True
44
104
 
45
105
  def validate_jwt(self, raw_jwt):
46
106
  try:
47
- unverified_header = self._jose_jwt.get_unverified_header(raw_jwt)
48
- except self._jose_jwt.JWTError as e:
107
+ from jwcrypto import jwk, jws, jwt # type: ignore
108
+ from jwcrypto.common import JWException # type: ignore
109
+ except:
110
+ raise ValueError(
111
+ "The JWKS authentication method requires the jwcrypto libraries to be installed. These are optional dependencies of clearskies, so to include them do a `pip install 'clear-skies[jwcrypto]'`"
112
+ )
113
+
114
+ keys = jwk.JWKSet()
115
+ keys.import_keyset(json.dumps(self._get_jwks()))
116
+
117
+ client_jwt = jwt.JWT()
118
+ try:
119
+ client_jwt.deserialize(raw_jwt)
120
+ except Exception as e:
49
121
  raise ClientError(str(e))
50
- jwks = self._get_jwks()
51
- # find a matching key in the JWKS for the key in the JWT
52
- rsa_key = next((key for key in jwks["keys"] if key["kid"] == unverified_header["kid"]), False)
53
- if not rsa_key:
54
- raise ClientError("No matching keys found")
55
122
 
56
123
  try:
57
- self.jwt_claims = self._jose_jwt.decode(
58
- raw_jwt,
59
- rsa_key,
60
- audience=self._audience,
61
- issuer=self._issuer,
62
- algorithms=self._algorithms,
63
- )
64
- except self._jose_jwt.ExpiredSignatureError:
65
- raise ClientError("JWT is expired")
66
- except self._jose_jwt.JWTClaimsError:
67
- raise ClientError("JWT has incorrect claims: double check the audience and issuer")
68
- except Exception:
69
- raise ClientError("Unable to parse JWT")
124
+ client_jwt.validate(keys)
125
+ self.jwt_claims = json.loads(client_jwt.claims)
126
+ except JWException as e:
127
+ raise ClientError(str(e))
128
+
129
+ if self.issuer and self.jwt_claims.get("iss") != self.issuer:
130
+ raise ClientError("Issuer does not match")
131
+
132
+ if self.audience:
133
+ jwt_audience = self.jwt_claims.get("aud")
134
+ if not jwt_audience:
135
+ raise ClientError("Audience required, but missing in JWT")
136
+ has_match = False
137
+ for audience in jwt_audience:
138
+ if audience == self.audience:
139
+ has_match = True
140
+ if not has_match:
141
+ raise ClientError("Audience does not match")
142
+
70
143
  return True
71
144
 
72
145
  def _get_jwks(self):
73
- now = datetime.datetime.now()
74
- if self._jwks is None or ((now - self._jwks_fetched).total_seconds() > self._jwks_cache_time):
75
- self._jwks = self._requests.get(self._jwks_url).json()
76
- self._jwks_fetched = now
146
+ if self._jwks is None or ((self.now - self._jwks_fetched).total_seconds() > self.jwks_cache_time):
147
+ self._jwks = self.requests.get(self.jwks_url).json()
148
+ self._jwks_fetched = self.now
77
149
 
78
150
  return self._jwks
79
151
 
80
- def documentation_security_scheme(self):
152
+ def documentation_security_scheme(self) -> dict[str, Any]:
81
153
  return {
82
154
  "type": "oauth2",
83
155
  "description": "JWT based authentication",
84
- "flows": {"implicit": {"authorizationUrl": self._authorization_url, "scopes": {}}},
156
+ "flows": {"implicit": {"authorizationUrl": self.authorization_url, "scopes": {}}},
85
157
  }
86
158
 
87
- def documentation_security_scheme_name(self):
88
- return self._documentation_security_name if self._documentation_security_name is not None else "jwt"
159
+ def documentation_security_scheme_name(self) -> str:
160
+ return self.documentation_security_name
161
+
162
+ def set_headers_for_cors(self, cors: Cors):
163
+ cors.add_header("Authorization")
@@ -1,40 +1,5 @@
1
- from requests.auth import AuthBase
2
- from requests.models import PreparedRequest
1
+ from .authentication import Authentication
3
2
 
4
3
 
5
- class Public:
6
- is_public = True
7
- can_authorize = False
8
- has_dynamic_credentials = False
9
-
10
- def headers(self, retry_auth=False):
11
- return {}
12
-
13
- def configure(self):
14
- pass
15
-
16
- def authenticate(self, input_output):
17
- return True
18
-
19
- def authorize(self, authorization):
20
- raise ValueError("Public endpoints do not support authorization")
21
-
22
- def set_headers_for_cors(self, cors):
23
- pass
24
-
25
- def documentation_request_parameters(self):
26
- return []
27
-
28
- def documentation_security_scheme(self):
29
- return {}
30
-
31
- def documentation_security_scheme_name(self):
32
- return ""
33
-
34
-
35
- class PublicAuth(AuthBase, Public):
36
- """Wrapper around SecretBearer to allow for the use of the SecretBearer class as an AuthBase class"""
37
-
38
- def __call__(self, r: PreparedRequest) -> PreparedRequest:
39
- r.headers = {**r.headers, **self.headers()}
40
- return r
4
+ class Public(Authentication):
5
+ pass