pypomes-jwt 0.5.6__tar.gz → 0.5.8__tar.gz

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 pypomes-jwt might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypomes_jwt
3
- Version: 0.5.6
3
+ Version: 0.5.8
4
4
  Summary: A collection of Python pomes, penyeach (JWT module)
5
5
  Project-URL: Homepage, https://github.com/TheWiseCoder/PyPomes-JWT
6
6
  Project-URL: Bug Tracker, https://github.com/TheWiseCoder/PyPomes-JWT/issues
@@ -6,7 +6,7 @@ build-backend = "hatchling.build"
6
6
 
7
7
  [project]
8
8
  name = "pypomes_jwt"
9
- version = "0.5.6"
9
+ version = "0.5.8"
10
10
  authors = [
11
11
  { name="GT Nunes", email="wisecoder01@gmail.com" }
12
12
  ]
@@ -36,8 +36,8 @@ class JwtData:
36
36
  "request-timeout": <float>, # in seconds - defaults to no timeout
37
37
  "access-max-age": <int>, # in seconds - defaults to JWT_ACCESS_MAX_AGE
38
38
  "refresh-exp": <timestamp>, # expiration time for the refresh operation
39
- "service-url": <url>, # URL to obtain and validate the access tokens
40
- "local-provider": <bool>, # whether 'service-url' is a local endpoint
39
+ "reference-url": <url>, # URL to obtain and validate the access tokens
40
+ "remote-provider": <bool>, # whether the JWT provider is a remote server
41
41
  "secret-key": <bytes>, # HS secret key
42
42
  "private-key": <bytes>, # RSA private key
43
43
  "public-key": <bytes>, # RSA public key
@@ -54,7 +54,7 @@ class JwtData:
54
54
  self.access_data: list[dict[str, dict[str, Any]]] = []
55
55
 
56
56
  def add_access_data(self,
57
- service_url: str,
57
+ reference_url: str,
58
58
  claims: dict[str, Any],
59
59
  algorithm: Literal["HS256", "HS512", "RSA256", "RSA512"],
60
60
  access_max_age: int,
@@ -63,15 +63,16 @@ class JwtData:
63
63
  private_key: bytes,
64
64
  public_key: bytes,
65
65
  request_timeout: float,
66
+ remote_provider: bool,
66
67
  logger: Logger = None) -> None:
67
68
  """
68
- Add to storage the parameters needed to obtain and validate JWT tokens.
69
+ Add to storage the parameters needed to obtain and validate JWT tokens for *reference_url*.
69
70
 
70
71
  Presently, the *refresh_max_age* data is not relevant, as the authorization parameters in *claims*
71
72
  (typically, an acess-key/secret-key pair), have been previously validated elsewhere.
72
73
  This situation might change in the future.
73
74
 
74
- :param service_url: the reference URL
75
+ :param reference_url: the reference URL
75
76
  :param claims: the JWT claimset, as key-value pairs
76
77
  :param algorithm: the algorithm used to sign the token with
77
78
  :param access_max_age: token duration
@@ -80,18 +81,18 @@ class JwtData:
80
81
  :param private_key: private key for RSA authentication
81
82
  :param public_key: public key for RSA authentication
82
83
  :param request_timeout: timeout for the requests to the service URL
84
+ :param remote_provider: whether the JWT provider is a remote server
83
85
  :param logger: optional logger
84
86
  """
85
- # obtain the item in storage
86
- item_data: dict[str, dict[str, Any]] = self.retrieve_access_data(service_url=service_url,
87
- logger=logger)
88
- if not item_data:
89
- # build control data
87
+ # Do the access data already exist ?
88
+ if not self.assert_access_data(reference_url=reference_url):
89
+ # no, build control data
90
90
  control_data: dict[str, Any] = {
91
- "service-url": service_url,
91
+ "reference-url": reference_url,
92
92
  "algorithm": algorithm,
93
93
  "access-max-age": access_max_age,
94
94
  "request-timeout": request_timeout,
95
+ "remote-provider": remote_provider,
95
96
  "refresh-exp": datetime.now(tz=timezone.utc) + timedelta(seconds=refresh_max_age)
96
97
  }
97
98
  if algorithm in ["HS256", "HS512"]:
@@ -121,35 +122,35 @@ class JwtData:
121
122
  with self.access_lock:
122
123
  self.access_data.append(item_data)
123
124
  if logger:
124
- logger.debug(f"JWT data added for '{service_url}': {item_data}")
125
+ logger.debug(f"JWT data added for '{reference_url}': {item_data}")
125
126
  elif logger:
126
- logger.warning(f"JWT data already exists for '{service_url}'")
127
+ logger.warning(f"JWT data already exists for '{reference_url}'")
127
128
 
128
129
  def remove_access_data(self,
129
- service_url: str,
130
+ reference_url: str,
130
131
  logger: Logger) -> None:
131
132
  """
132
- Remove from storage the access data associated with the given parameters.
133
+ Remove from storage the access data for *reference_url*.
133
134
 
134
- :param service_url: the reference URL
135
+ :param reference_url: the reference URL
135
136
  :param logger: optional logger
136
137
  """
137
- # obtain the item in storage
138
- item_data: dict[str, dict[str, Any]] = self.retrieve_access_data(service_url=service_url,
138
+ # obtain the access data item in storage
139
+ item_data: dict[str, dict[str, Any]] = self.retrieve_access_data(reference_url=reference_url,
139
140
  logger=logger)
140
141
  if item_data:
141
142
  with self.access_lock:
142
143
  self.access_data.remove(item_data)
143
144
  if logger:
144
- logger.debug(f"Removed JWT data for '{service_url}'")
145
+ logger.debug(f"Removed JWT data for '{reference_url}'")
145
146
  elif logger:
146
- logger.warning(f"No JWT data found for '{service_url}'")
147
+ logger.warning(f"No JWT data found for '{reference_url}'")
147
148
 
148
149
  def get_token_data(self,
149
- service_url: str,
150
+ reference_url: str,
150
151
  logger: Logger = None) -> dict[str, Any]:
151
152
  """
152
- Obtain and return the JWT token associated with *service_url*, along with its duration.
153
+ Obtain and return the JWT token for *reference_url*, along with its duration.
153
154
 
154
155
  Structure of the return data:
155
156
  {
@@ -157,7 +158,7 @@ class JwtData:
157
158
  "expires_in": <seconds-to-expiration>
158
159
  }
159
160
 
160
- :param service_url: the reference URL for obtaining JWT tokens
161
+ :param reference_url: the reference URL for obtaining JWT tokens
161
162
  :param logger: optional logger
162
163
  :return: the JWT token data, or 'None' if error
163
164
  :raises InvalidTokenError: token is invalid
@@ -170,14 +171,14 @@ class JwtData:
170
171
  :raises InvalidIssuerError: 'iss' claim does not match the expected issuer
171
172
  :raises InvalidIssuedAtError: 'iat' claim is non-numeric
172
173
  :raises MissingRequiredClaimError: a required claim is not contained in the claimset
173
- :raises RuntimeError: access data not found for the given *service_url*, or
174
+ :raises RuntimeError: access data not found for the given *reference_url*, or
174
175
  the remote JWT provider failed to return a token
175
176
  """
176
177
  # declare the return variable
177
178
  result: dict[str, Any]
178
179
 
179
180
  # obtain the item in storage
180
- item_data: dict[str, Any] = self.retrieve_access_data(service_url=service_url,
181
+ item_data: dict[str, Any] = self.retrieve_access_data(reference_url=reference_url,
181
182
  logger=logger)
182
183
  # was the JWT data obtained ?
183
184
  if item_data:
@@ -190,29 +191,19 @@ class JwtData:
190
191
  # is the current token still valid ?
191
192
  if just_now > standard_claims.get("exp"):
192
193
  # no, obtain a new token
193
- service_url: str = control_data.get("service-url")
194
+ reference_url: str = control_data.get("reference-url")
194
195
  claims: dict[str, Any] = standard_claims.copy()
195
196
  claims.update(custom_claims)
196
197
 
197
- # where is the locus of the JWT service ?
198
- if control_data.get("local-provider"):
199
- # JWT service is local
200
- claims["exp"] = just_now + timedelta(seconds=control_data.get("access-max-age") + 10)
201
- # may raise an exception
202
- token: str = jwt.encode(payload=claims,
203
- key=control_data.get("secret-key") or control_data.get("private-key"),
204
- algorithm=control_data.get("algorithm"))
205
- with self.access_lock:
206
- control_data["access-token"] = token
207
- standard_claims["exp"] = claims.get("exp")
208
- else:
209
- # JWT service is remote
210
- if service_url.find("?") > 0:
211
- service_url = service_url[:service_url.index("?")]
198
+ # where is the locus of the JWT service provider ?
199
+ if control_data.get("remote-provider"):
200
+ # JWT service is being provided by a remote server
201
+ if reference_url.find("?") > 0:
202
+ reference_url = reference_url[:reference_url.index("?")]
212
203
  claims.pop("exp", None)
213
204
  errors: list[str] = []
214
205
  result = jwt_request_token(errors=errors,
215
- service_url=service_url,
206
+ reference_url=reference_url,
216
207
  claims=claims,
217
208
  timeout=control_data.get("request-timeout"),
218
209
  logger=logger)
@@ -223,6 +214,16 @@ class JwtData:
223
214
  standard_claims["exp"] = just_now + timedelta(seconds=duration)
224
215
  else:
225
216
  raise RuntimeError(" - ".join(errors))
217
+ else:
218
+ # JWT service is being provided locally
219
+ claims["exp"] = just_now + timedelta(seconds=control_data.get("access-max-age") + 10)
220
+ # may raise an exception
221
+ token: str = jwt.encode(payload=claims,
222
+ key=control_data.get("secret-key") or control_data.get("private-key"),
223
+ algorithm=control_data.get("algorithm"))
224
+ with self.access_lock:
225
+ control_data["access-token"] = token
226
+ standard_claims["exp"] = claims.get("exp")
226
227
 
227
228
  # return the token
228
229
  diff: timedelta = standard_claims.get("exp") - just_now - timedelta(seconds=10)
@@ -231,8 +232,8 @@ class JwtData:
231
232
  "expires_in": math.trunc(diff.total_seconds())
232
233
  }
233
234
  else:
234
- # JWT data not found
235
- err_msg: str = f"No JWT data found for {service_url}"
235
+ # JWT access data not found
236
+ err_msg: str = f"No JWT access data found for '{reference_url}'"
236
237
  if logger:
237
238
  logger.error(err_msg)
238
239
  raise RuntimeError(err_msg)
@@ -274,49 +275,85 @@ class JwtData:
274
275
 
275
276
  return result
276
277
 
278
+ def assert_access_data(self,
279
+ reference_url: str) -> bool:
280
+ # noinspection HttpUrlsUsage
281
+ """
282
+ Assert whether access data exists for *reference_url*.
283
+
284
+ For the purpose of locating access data, Protocol indication in *reference_url*
285
+ (typically, *http://* or *https://*), is disregarded. This guarantees
286
+ that processing herein will not be affected by in-transit protocol changes.
287
+
288
+ :param reference_url: the reference URL for obtaining JWT tokens
289
+ :return: *True" is access data is in storage, *False* otherwise
290
+ """
291
+ # initialize the return variable
292
+ result: bool = False
293
+
294
+ # disregard protocol
295
+ if reference_url.find("://") > 0:
296
+ reference_url = reference_url[reference_url.index("://")+3:]
297
+
298
+ # assert the data
299
+ with self.access_lock:
300
+ for item_data in self.access_data:
301
+ item_url: str = item_data.get("control-data").get("reference-url")
302
+ if item_url.find("://") > 0:
303
+ item_url = item_url[item_url.index("://")+3:]
304
+ if reference_url == item_url:
305
+ result = True
306
+ break
307
+
308
+ return result
309
+
277
310
  def retrieve_access_data(self,
278
- service_url: str,
311
+ reference_url: str,
279
312
  logger: Logger = None) -> dict[str, dict[str, Any]]:
280
313
  # noinspection HttpUrlsUsage
281
314
  """
282
- Retrieve and return the access data in storage corresponding to *service_url*.
315
+ Retrieve and return the access data in storage for *reference_url*.
283
316
 
284
- For the purpose of retrieving access data, Protocol indication in *service_url*
285
- (typically, *http://* or *https://*), is disregarded. This guarantees
286
- that processing herein will not be affected by in-transit protocol changes.
317
+ For the purpose of locating access data, Protocol indication in *reference_url*
318
+ (typically, *http://* or *https://*), is disregarded. This guarantees
319
+ that processing herein will not be affected by in-transit protocol changes.
287
320
 
288
- :param service_url: the reference URL for obtaining JWT tokens
289
- :param logger: optional logger
290
- :return: the corresponding item in storage, or *None* if not found
291
- """
321
+ :param reference_url: the reference URL for obtaining JWT tokens
322
+ :param logger: optional logger
323
+ :return: the corresponding item in storage, or *None* if not found
324
+ """
292
325
  # initialize the return variable
293
326
  result: dict[str, dict[str, Any]] | None = None
327
+
328
+ if logger:
329
+ logger.debug(f"Retrieve access data for reference URL '{reference_url}'")
294
330
 
295
331
  # disregard protocol
296
- if service_url.find("://") > 0:
297
- service_url = service_url[service_url.index("://")+3:]
332
+ if reference_url.find("://") > 0:
333
+ reference_url = reference_url[reference_url.index("://")+3:]
298
334
 
335
+ # retrieve the data
299
336
  with self.access_lock:
300
337
  for item_data in self.access_data:
301
- item_url: str = item_data.get("control-data").get("service-url")
338
+ item_url: str = item_data.get("control-data").get("reference-url")
302
339
  if item_url.find("://") > 0:
303
340
  item_url = item_url[item_url.index("://")+3:]
304
- if service_url == item_url:
341
+ if reference_url == item_url:
305
342
  result = item_data
306
343
  break
307
344
  if logger:
308
- logger.debug(f"JWT data for '{service_url}': {result}")
345
+ logger.debug(f"Data is '{result}'")
309
346
 
310
347
  return result
311
348
 
312
349
 
313
350
  def jwt_request_token(errors: list[str],
314
- service_url: str,
351
+ reference_url: str,
315
352
  claims: dict[str, Any],
316
353
  timeout: float = None,
317
354
  logger: Logger = None) -> dict[str, Any]:
318
355
  """
319
- Obtain and return the JWT token associated with *service_url*, along with its duration.
356
+ Obtain and return the JWT token associated with *reference_url*, along with its duration.
320
357
 
321
358
  Expected structure of the return data:
322
359
  {
@@ -327,7 +364,7 @@ def jwt_request_token(errors: list[str],
327
364
  of the provider issuing the JWT token.
328
365
 
329
366
  :param errors: incidental errors
330
- :param service_url: the reference URL for obtaining JWT tokens
367
+ :param reference_url: the reference URL for obtaining JWT tokens
331
368
  :param claims: the JWT claimset, as expected by the issuing server
332
369
  :param timeout: request timeout, in seconds (defaults to *None*)
333
370
  :param logger: optional logger
@@ -337,9 +374,9 @@ def jwt_request_token(errors: list[str],
337
374
 
338
375
  # request the JWT token
339
376
  if logger:
340
- logger.debug(f"POST request JWT token to '{service_url}'")
377
+ logger.debug(f"POST request JWT token to '{reference_url}'")
341
378
  response: Response = requests.post(
342
- url=service_url,
379
+ url=reference_url,
343
380
  json=claims,
344
381
  timeout=timeout
345
382
  )
@@ -352,7 +389,7 @@ def jwt_request_token(errors: list[str],
352
389
  logger.debug(f"JWT token obtained: {result}")
353
390
  else:
354
391
  # no, report the problem
355
- err_msg: str = f"POST request of '{service_url}' failed: {response.reason}"
392
+ err_msg: str = f"POST request of '{reference_url}' failed: {response.reason}"
356
393
  if response.text:
357
394
  err_msg += f" - {response.text}"
358
395
  if logger:
@@ -16,7 +16,7 @@ JWT_REFRESH_MAX_AGE: Final[int] = env_get_int(key=f"{APP_PREFIX}_JWT_REFRESH_MAX
16
16
  def_value=43200)
17
17
  JWT_HS_SECRET_KEY: Final[bytes] = env_get_bytes(key=f"{APP_PREFIX}_JWT_HS_SECRET_KEY",
18
18
  def_value=token_bytes(32))
19
- # must point to 'jwt_service()' below
19
+ # must invoke 'jwt_service()' below
20
20
  JWT_ENDPOINT_URL: Final[str] = env_get_str(key=f"{APP_PREFIX}_JWT_ENDPOINT_URL")
21
21
 
22
22
  __priv_key: bytes = env_get_bytes(key=f"{APP_PREFIX}_JWT_RSA_PRIVATE_KEY")
@@ -49,7 +49,7 @@ def jwt_needed(func: callable) -> callable:
49
49
  return wrapper
50
50
 
51
51
 
52
- def jwt_set_service_access(service_url: str,
52
+ def jwt_set_service_access(reference_url: str,
53
53
  claims: dict[str, Any],
54
54
  algorithm: Literal["HS256", "HS512", "RSA256", "RSA512"] = JWT_DEFAULT_ALGORITHM,
55
55
  access_max_age: int = JWT_ACCESS_MAX_AGE,
@@ -58,11 +58,12 @@ def jwt_set_service_access(service_url: str,
58
58
  private_key: bytes = JWT_RSA_PRIVATE_KEY,
59
59
  public_key: bytes = JWT_RSA_PUBLIC_KEY,
60
60
  request_timeout: int = None,
61
+ remote_provider: bool = True,
61
62
  logger: Logger = None) -> None:
62
63
  """
63
- Set the data needed to obtain JWT tokens from *service_url*.
64
+ Set the data needed to obtain JWT tokens from *reference_url*.
64
65
 
65
- :param service_url: the reference URL
66
+ :param reference_url: the reference URL
66
67
  :param claims: the JWT claimset, as key-value pairs
67
68
  :param algorithm: the authentication type
68
69
  :param access_max_age: token duration, in seconds
@@ -71,18 +72,22 @@ def jwt_set_service_access(service_url: str,
71
72
  :param private_key: private key for RSA authentication
72
73
  :param public_key: public key for RSA authentication
73
74
  :param request_timeout: timeout for the requests to the service URL
75
+ :param remote_provider: whether the JWT provider is a remote server
74
76
  :param logger: optional logger
75
77
  """
78
+ if logger:
79
+ logger.debug(msg=f"Register access data for reference URL '{reference_url}'")
76
80
  # extract the extra claims
77
- pos: int = service_url.find("?")
81
+ pos: int = reference_url.find("?")
78
82
  if pos > 0:
79
- params: list[str] = service_url[pos+1:].split(sep="&")
80
- for param in params:
81
- claims[param.split("=")[0]] = param.split("=")[1]
82
- service_url = service_url[:pos]
83
+ if remote_provider:
84
+ params: list[str] = reference_url[pos+1:].split(sep="&")
85
+ for param in params:
86
+ claims[param.split("=")[0]] = param.split("=")[1]
87
+ reference_url = reference_url[:pos]
83
88
 
84
89
  # register the JWT service
85
- __jwt_data.add_access_data(service_url=service_url,
90
+ __jwt_data.add_access_data(reference_url=reference_url,
86
91
  claims=claims,
87
92
  algorithm=algorithm,
88
93
  access_max_age=access_max_age,
@@ -91,39 +96,48 @@ def jwt_set_service_access(service_url: str,
91
96
  private_key=private_key,
92
97
  public_key=public_key,
93
98
  request_timeout=request_timeout,
99
+ remote_provider=remote_provider,
94
100
  logger=logger)
95
101
 
96
102
 
97
- def jwt_remove_service_access(service_url: str,
103
+ def jwt_remove_service_access(reference_url: str,
98
104
  logger: Logger = None) -> None:
99
105
  """
100
- Remove from storage the JWT access data for *service_url*.
106
+ Remove from storage the JWT access data for *reference_url*.
101
107
 
102
- :param service_url: the reference URL
108
+ :param reference_url: the reference URL
103
109
  :param logger: optional logger
104
110
  """
105
- __jwt_data.remove_access_data(service_url=service_url,
111
+ if logger:
112
+ logger.debug(msg=f"Remove access data for reference URL '{reference_url}'")
113
+
114
+ __jwt_data.remove_access_data(reference_url=reference_url,
106
115
  logger=logger)
107
116
 
108
117
 
109
118
  def jwt_get_token(errors: list[str],
110
- service_url: str,
119
+ reference_url: str,
111
120
  logger: Logger = None) -> str:
112
121
  """
113
- Obtain and return a JWT token from *service_url*.
122
+ Obtain and return a JWT token from *reference_url*.
114
123
 
115
124
  :param errors: incidental error messages
116
- :param service_url: the reference URL
125
+ :param reference_url: the reference URL
117
126
  :param logger: optional logger
118
127
  :return: the JWT token, or 'None' if an error ocurred
119
128
  """
120
129
  # inicialize the return variable
121
130
  result: str | None = None
122
131
 
132
+ if logger:
133
+ logger.debug(msg=f"Obtain a JWT token for reference URL '{reference_url}'")
134
+
123
135
  try:
124
- token_data: dict[str, Any] = __jwt_data.get_token_data(service_url=service_url,
136
+ token_data: dict[str, Any] = __jwt_data.get_token_data(reference_url=reference_url,
125
137
  logger=logger)
126
138
  result = token_data.get("access_token")
139
+ if logger:
140
+ logger.debug(f"Token is '{result}'")
127
141
  except Exception as e:
128
142
  if logger:
129
143
  logger.error(msg=str(e))
@@ -133,10 +147,10 @@ def jwt_get_token(errors: list[str],
133
147
 
134
148
 
135
149
  def jwt_get_token_data(errors: list[str],
136
- service_url: str,
150
+ reference_url: str,
137
151
  logger: Logger = None) -> dict[str, Any]:
138
152
  """
139
- Obtain and return the JWT token associated with *service_url*, along with its duration.
153
+ Obtain and return the JWT token associated with *reference_url*, along with its duration.
140
154
 
141
155
  Structure of the return data:
142
156
  {
@@ -145,16 +159,20 @@ def jwt_get_token_data(errors: list[str],
145
159
  }
146
160
 
147
161
  :param errors: incidental error messages
148
- :param service_url: the reference URL for obtaining JWT tokens
162
+ :param reference_url: the reference URL for obtaining JWT tokens
149
163
  :param logger: optional logger
150
164
  :return: the JWT token data, or 'None' if error
151
165
  """
152
166
  # inicialize the return variable
153
167
  result: dict[str, Any] | None = None
154
168
 
169
+ if logger:
170
+ logger.debug(msg=f"Retrieve JWT token data for reference URL '{reference_url}'")
155
171
  try:
156
- result = __jwt_data.get_token_data(service_url=service_url,
172
+ result = __jwt_data.get_token_data(reference_url=reference_url,
157
173
  logger=logger)
174
+ if logger:
175
+ logger.debug(msg=f"Data is '{result}'")
158
176
  except Exception as e:
159
177
  if logger:
160
178
  logger.error(msg=str(e))
@@ -177,6 +195,9 @@ def jwt_get_claims(errors: list[str],
177
195
  # initialize the return variable
178
196
  result: dict[str, Any] | None = None
179
197
 
198
+ if logger:
199
+ logger.debug(msg=f"Retrieve claims for token '{token}'")
200
+
180
201
  try:
181
202
  result = __jwt_data.get_token_claims(token=token)
182
203
  except Exception as e:
@@ -198,6 +219,9 @@ def jwt_verify_request(request: Request,
198
219
  """
199
220
  # initialize the return variable
200
221
  result: Response | None = None
222
+
223
+ if logger:
224
+ logger.debug(msg="Validate a JWT token")
201
225
 
202
226
  # retrieve the authorization from the request header
203
227
  auth_header: str = request.headers.get("Authorization")
@@ -206,6 +230,8 @@ def jwt_verify_request(request: Request,
206
230
  if auth_header and auth_header.startswith("Bearer "):
207
231
  # yes, extract and validate the JWT token
208
232
  token: str = auth_header.split(" ")[1]
233
+ if logger:
234
+ logger.debug(msg=f"Token is '{token}'")
209
235
  try:
210
236
  jwt_validate_token(token=token,
211
237
  key=JWT_HS_SECRET_KEY or JWT_RSA_PUBLIC_KEY,
@@ -218,23 +244,24 @@ def jwt_verify_request(request: Request,
218
244
  status=401)
219
245
  else:
220
246
  # no, report the error
247
+ if logger:
248
+ logger.error(msg="Request header has no 'Bearer' data")
221
249
  result = Response(response="Authorization failed",
222
250
  status=401)
223
251
 
224
252
  return result
225
253
 
226
254
 
227
- # @flask_app.route(rule="/jwt-service",
228
- # methods=["POST"])
229
- def jwt_service(service_url: str = None,
230
- service_params: dict[str, Any] = None) -> Response:
255
+ def jwt_service(reference_url: str = None,
256
+ service_params: dict[str, Any] = None,
257
+ logger: Logger = None) -> Response:
231
258
  """
232
259
  Entry point for obtaining JWT tokens.
233
260
 
234
261
  In order to be serviced, the invoker must send, as parameter *service_params* or in the body of the request,
235
262
  a JSON containing:
236
263
  {
237
- "service-url": "<url>", - the JWT reference URL (if not as parameter)
264
+ "reference-url": "<url>", - the JWT reference URL (if not as parameter)
238
265
  "<custom-claim-key-1>": "<custom-claim-value-1>", - the registered custom claims
239
266
  ...
240
267
  "<custom-claim-key-n>": "<custom-claim-value-n>"
@@ -246,13 +273,20 @@ def jwt_service(service_url: str = None,
246
273
  "expires_in": <seconds-to-expiration>
247
274
  }
248
275
 
249
- :param service_url: the JWT reference URL, alternatively passed in JSON
276
+ :param reference_url: the JWT reference URL, alternatively passed in JSON
250
277
  :param service_params: the optional JSON containing the request parameters (defaults to JSON in body)
278
+ :param logger: optional logger
251
279
  :return: the requested JWT token, along with its duration.
252
280
  """
253
281
  # declare the return variable
254
282
  result: Response
255
283
 
284
+ if logger:
285
+ msg: str = "Service a JWT request"
286
+ if request:
287
+ msg += f" from '{request.base_url}'"
288
+ logger.debug(msg=msg)
289
+
256
290
  # obtain the parameters
257
291
  # noinspection PyUnusedLocal
258
292
  params: dict[str, Any] = service_params or {}
@@ -262,10 +296,13 @@ def jwt_service(service_url: str = None,
262
296
 
263
297
  # validate the parameters
264
298
  valid: bool = False
265
- if not service_url:
266
- service_url = params.get("service-url")
267
- if service_url:
268
- item_data: dict[str, dict[str, Any]] = __jwt_data.retrieve_access_data(service_url=service_url)
299
+ if not reference_url:
300
+ reference_url = params.get("reference-url")
301
+ if reference_url:
302
+ if logger:
303
+ logger.debug(msg=f"Reference URL is '{reference_url}'")
304
+ item_data: dict[str, dict[str, Any]] = __jwt_data.retrieve_access_data(reference_url=reference_url,
305
+ logger=logger)
269
306
  if item_data:
270
307
  valid = True
271
308
  custom_claims: dict[str, Any] = item_data.get("custom-claims")
@@ -277,12 +314,18 @@ def jwt_service(service_url: str = None,
277
314
  # obtain the token data
278
315
  if valid:
279
316
  try:
280
- token_data: dict[str, Any] = __jwt_data.get_token_data(service_url=service_url)
317
+ token_data: dict[str, Any] = __jwt_data.get_token_data(reference_url=reference_url,
318
+ logger=logger)
281
319
  result = jsonify(token_data)
282
320
  except Exception as e:
321
+ # validation failed
322
+ if logger:
323
+ logger.error(msg=str(e))
283
324
  result = Response(response=str(e),
284
325
  status=401)
285
326
  else:
327
+ if logger:
328
+ logger.debug(msg=f"Invalid parameters {service_params}")
286
329
  result = Response(response="Invalid parameters",
287
330
  status=401)
288
331
 
File without changes
File without changes
File without changes
File without changes