pypomes-iam 0.3.4__py3-none-any.whl → 0.3.5__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.
pypomes_iam/iam_common.py CHANGED
@@ -1,7 +1,5 @@
1
- import json
2
1
  import requests
3
2
  import sys
4
- from cachetools import Cache
5
3
  from datetime import datetime
6
4
  from enum import StrEnum
7
5
  from logging import Logger
@@ -175,11 +173,10 @@ def _get_user_data(iam_server: IamServer,
175
173
  # initialize the return variable
176
174
  result: dict[str, Any] | None = None
177
175
 
178
- cache: Cache = _get_iam_cache(iam_server=iam_server,
179
- errors=errors,
180
- logger=logger)
181
- if cache:
182
- users: dict[str, dict[str, Any]] = cache.get("users")
176
+ users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
177
+ errors=errors,
178
+ logger=logger)
179
+ if users:
183
180
  result = users.get(user_id)
184
181
  if not result:
185
182
  result = {
@@ -256,9 +253,9 @@ def _get_iam_registry(iam_server: IamServer,
256
253
  return result
257
254
 
258
255
 
259
- def _get_iam_cache(iam_server: IamServer,
256
+ def _get_iam_users(iam_server: IamServer,
260
257
  errors: list[str] | None,
261
- logger: Logger | None) -> Cache:
258
+ logger: Logger | None) -> dict[str, dict[str, Any]]:
262
259
  """
263
260
  Retrieve the cache storage in *iam_server*'s registry.
264
261
 
@@ -270,97 +267,4 @@ def _get_iam_cache(iam_server: IamServer,
270
267
  registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
271
268
  errors=errors,
272
269
  logger=logger)
273
- return registry["cache"] if registry else None
274
-
275
-
276
- def _post_for_token(iam_server: IamServer,
277
- body_data: dict[str, Any],
278
- errors: list[str] | None,
279
- logger: Logger | None) -> dict[str, Any] | None:
280
- """
281
- Send a POST request to obtain the authentication token data, and return the data received.
282
-
283
- For token acquisition, *body_data* will have the attributes:
284
- - "grant_type": "authorization_code"
285
- - "code": <16-character-random-code>
286
- - "redirect_uri": <redirect-uri>
287
-
288
- For token refresh, *body_data* will have the attributes:
289
- - "grant_type": "refresh_token"
290
- - "refresh_token": <current-refresh-token>
291
-
292
- For token exchange, *body_data* will have the attributes:
293
- - "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
294
- - "subject_token": <token-to-be-exchanged>,
295
- - "subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
296
- - "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
297
- - "audience": <client-id>,
298
- - "subject_issuer": "oidc"
299
-
300
- These attributes are then added to *body_data*:
301
- - "client_id": <client-id>,
302
- - "client_secret": <client-secret>,
303
-
304
- If the operation is successful, the token data is stored in the registry.
305
- Otherwise, *errors* will contain the appropriate error message.
306
-
307
- :param iam_server: the reference registered *IAM* server
308
- :param body_data: the data to send in the body of the request
309
- :param errors: incidental errors
310
- :param logger: optional logger
311
- :return: the access token obtained, or *None* if error
312
- """
313
- # initialize the return variable
314
- result: dict[str, Any] | None = None
315
-
316
- # PBTAIN THE iam SERVER'S REGISTRY
317
- registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
318
- errors=errors,
319
- logger=logger)
320
- err_msg: str | None = None
321
- if registry:
322
- # complete the data to send in body of request
323
- body_data["client_id"] = registry["client-id"]
324
- client_secret: str = registry["client-secret"]
325
- if client_secret:
326
- body_data["client_secret"] = client_secret
327
-
328
- # obtain the token
329
- url: str = registry["base-url"] + "/protocol/openid-connect/token"
330
- if logger:
331
- logger.debug(msg=f"POST '{url}', data {json.dumps(obj=body_data,
332
- ensure_ascii=False)}")
333
- try:
334
- # typical return on a token request:
335
- # {
336
- # "token_type": "Bearer",
337
- # "access_token": <str>,
338
- # "expires_in": <number-of-seconds>,
339
- # "refresh_token": <str>,
340
- # "refesh_expires_in": <number-of-seconds>
341
- # }
342
- response: requests.Response = requests.post(url=url,
343
- data=body_data)
344
- if response.status_code == 200:
345
- # request succeeded
346
- if logger:
347
- logger.debug(msg=f"POST success, status {response.status_code}")
348
- result = response.json()
349
- else:
350
- # request resulted in error
351
- err_msg = f"POST failure, status {response.status_code}, reason '{response.reason}'"
352
- if hasattr(response, "content") and response.content:
353
- err_msg += f", content '{response.content}'"
354
- if logger:
355
- logger.error(msg=err_msg)
356
- except Exception as e:
357
- # the operation raised an exception
358
- err_msg = exc_format(exc=e,
359
- exc_info=sys.exc_info())
360
- if logger:
361
- logger.error(msg=err_msg)
362
-
363
- if err_msg and isinstance(errors, list):
364
- errors.append(err_msg)
365
-
366
- return result
270
+ return registry["cache"]["users"] if registry else None
pypomes_iam/iam_pomes.py CHANGED
@@ -1,18 +1,20 @@
1
+ import json
2
+ import requests
1
3
  import secrets
2
4
  import string
3
5
  import sys
4
6
  from cachetools import Cache
5
7
  from datetime import datetime
6
8
  from logging import Logger
7
- from pypomes_core import TZ_LOCAL
9
+ from pypomes_core import TZ_LOCAL, exc_format
8
10
  from typing import Any
9
11
 
10
12
  from .iam_common import (
11
13
  IamServer,
12
- _register_logger, _post_for_token,
13
- _get_iam_cache, _get_iam_registry,
14
+ _register_logger, _get_iam_users, _get_iam_registry,
14
15
  _get_login_timeout, _get_user_data, _get_public_key
15
16
  )
17
+ from .token_pomes import token_validate
16
18
 
17
19
 
18
20
  def register_logger(logger: Logger) -> None:
@@ -93,15 +95,13 @@ def user_logout(iam_server: IamServer,
93
95
 
94
96
  if user_id:
95
97
  # retrieve the IAM server's cache storage
96
- cache: Cache = _get_iam_cache(iam_server=iam_server,
97
- errors=errors,
98
- logger=logger)
99
- if cache:
100
- users: dict[str, dict[str, Any]] = cache.get("users") or {}
101
- if user_id in users:
102
- users.pop(user_id)
103
- if logger:
104
- logger.debug(msg=f"User '{user_id}' removed from {iam_server}'s registry")
98
+ users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
99
+ errors=errors,
100
+ logger=logger) or {}
101
+ if user_id in users:
102
+ users.pop(user_id)
103
+ if logger:
104
+ logger.debug(msg=f"User '{user_id}' removed from {iam_server}'s registry")
105
105
 
106
106
 
107
107
  def user_token(iam_server: IamServer,
@@ -147,20 +147,20 @@ def user_token(iam_server: IamServer,
147
147
  "grant_type": "refresh_token",
148
148
  "refresh_token": refresh_token
149
149
  }
150
- token_data: dict[str, Any] = _post_for_token(iam_server=iam_server,
151
- body_data=body_data,
152
- errors=errors,
153
- logger=logger)
150
+ now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
151
+ token_data: dict[str, Any] = __post_for_token(iam_server=iam_server,
152
+ body_data=body_data,
153
+ errors=errors,
154
+ logger=logger)
155
+ # validate and store the token data
154
156
  if token_data:
155
- result = token_data.get("access_token")
156
- user_data["access-token"] = result
157
- # keep current refresh token if a new one is not provided
158
- user_data["refresh-token"] = (token_data.get("refresh_token") or
159
- body_data.get("refresh_token"))
160
- user_data["access-expiration"] = now + token_data.get("expires_in")
161
- refresh_expiration: int = user_data.get("refresh_expires_in")
162
- user_data["refresh-expiration"] = (now + refresh_expiration) \
163
- if refresh_expiration else sys.maxsize
157
+ token_info: tuple[str, str] = __validate_and_store(iam_server=iam_server,
158
+ user_data=user_data,
159
+ token_data=token_data,
160
+ now=now,
161
+ errors=errors,
162
+ logger=logger)
163
+ result = token_info[1]
164
164
  else:
165
165
  # refresh token is no longer valid
166
166
  user_data["refresh-token"] = None
@@ -201,8 +201,6 @@ def login_callback(iam_server: IamServer,
201
201
  :param logger: optional logger
202
202
  :return: a tuple containing the reference user identification and the token obtained, or *None* if error
203
203
  """
204
- from .token_pomes import token_validate
205
-
206
204
  # initialize the return variable
207
205
  result: tuple[str, str] | None = None
208
206
 
@@ -237,35 +235,18 @@ def login_callback(iam_server: IamServer,
237
235
  "redirect_uri": registry["redirect-uri"]
238
236
  }
239
237
  now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
240
- token_data: dict[str, Any] = _post_for_token(iam_server=iam_server,
241
- body_data=body_data,
242
- errors=errors,
243
- logger=logger)
244
- # process the token data
238
+ token_data: dict[str, Any] = __post_for_token(iam_server=iam_server,
239
+ body_data=body_data,
240
+ errors=errors,
241
+ logger=logger)
242
+ # validate and store the token data
245
243
  if token_data:
246
- token: str = token_data.get("access_token")
247
- user_data["access-token"] = token
248
- # keep current refresh token if a new one is not provided
249
- user_data["refresh-token"] = token_data.get("refresh_token") or body_data.get("refresh_token")
250
- user_data["access-expiration"] = now + token_data.get("expires_in")
251
- refresh_exp: int = user_data.get("refresh_expires_in")
252
- user_data["refresh-expiration"] = (now + refresh_exp) if refresh_exp else sys.maxsize
253
- public_key: str = _get_public_key(iam_server=iam_server,
254
- errors=errors,
255
- logger=logger)
256
- if public_key:
257
- recipient_attr = registry["recipient_attr"]
258
- login_id = user_data.pop("login-id", None)
259
- token_claims: dict[str, dict[str, Any]] = token_validate(token=token,
260
- issuer=registry["base-url"],
261
- recipient_id=login_id,
262
- recipient_attr=recipient_attr,
263
- public_key=public_key,
264
- errors=errors,
265
- logger=logger)
266
- if token_claims:
267
- token_user: str = token_claims["payload"].get(recipient_attr)
268
- result = (token_user, token)
244
+ result = __validate_and_store(iam_server=iam_server,
245
+ user_data=user_data,
246
+ token_data=token_data,
247
+ now=now,
248
+ errors=errors,
249
+ logger=logger)
269
250
  else:
270
251
  msg: str = "Unknown state received"
271
252
  if logger:
@@ -281,7 +262,11 @@ def token_exchange(iam_server: IamServer,
281
262
  errors: list[str] = None,
282
263
  logger: Logger = None) -> dict[str, Any]:
283
264
  """
284
- Requst *iam_server* to issue a token in exchange for the token obtained from another *IAM* server.
265
+ Request *iam_server* to issue a token in exchange for the token obtained from another *IAM* server.
266
+
267
+ The expected parameters in *args* are:
268
+ - client-id: identification for the reference user (aliases: 'client_id', 'login')
269
+ - token: the token to be exchanged
285
270
 
286
271
  :param iam_server: the reference registered *IAM* server
287
272
  :param args: the arguments passed when requesting the service
@@ -312,10 +297,21 @@ def token_exchange(iam_server: IamServer,
312
297
  "audience": registry["client-id"],
313
298
  "subject_issuer": "oidc"
314
299
  }
315
- result = _post_for_token(iam_server=IamServer.IAM_KEYCLOAK,
316
- body_data=body_data,
317
- errors=errors,
318
- logger=logger)
300
+ now: int = int(datetime.now(tz=TZ_LOCAL).timestamp())
301
+ token_data: dict[str, Any] = __post_for_token(iam_server=IamServer.IAM_KEYCLOAK,
302
+ body_data=body_data,
303
+ errors=errors,
304
+ logger=logger)
305
+ # validate and store the token data
306
+ if token_data:
307
+ user_data: dict[str, Any] = {}
308
+ result = __validate_and_store(iam_server=iam_server,
309
+ user_data=user_data,
310
+ token_data=token_data,
311
+ now=now,
312
+ errors=errors,
313
+ logger=logger)
314
+
319
315
  else:
320
316
  msg: str = "User identification and token must be provided"
321
317
  if logger:
@@ -324,3 +320,170 @@ def token_exchange(iam_server: IamServer,
324
320
  errors.append(msg)
325
321
 
326
322
  return result
323
+
324
+
325
+ def __post_for_token(iam_server: IamServer,
326
+ body_data: dict[str, Any],
327
+ errors: list[str] | None,
328
+ logger: Logger | None) -> dict[str, Any] | None:
329
+ """
330
+ Send a POST request to obtain the authentication token data, and return the data received.
331
+
332
+ For token acquisition, *body_data* will have the attributes:
333
+ - "grant_type": "authorization_code"
334
+ - "code": <16-character-random-code>
335
+ - "redirect_uri": <redirect-uri>
336
+
337
+ For token refresh, *body_data* will have the attributes:
338
+ - "grant_type": "refresh_token"
339
+ - "refresh_token": <current-refresh-token>
340
+
341
+ For token exchange, *body_data* will have the attributes:
342
+ - "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
343
+ - "subject_token": <token-to-be-exchanged>,
344
+ - "subject_token_type": "urn:ietf:params:oauth:token-type:access_token",
345
+ - "requested_token_type": "urn:ietf:params:oauth:token-type:access_token",
346
+ - "audience": <client-id>,
347
+ - "subject_issuer": "oidc"
348
+
349
+ These attributes are then added to *body_data*:
350
+ - "client_id": <client-id>,
351
+ - "client_secret": <client-secret>,
352
+
353
+ If the operation is successful, the token data is stored in the *IAM* server's registry, and returned.
354
+ Otherwise, *errors* will contain the appropriate error message.
355
+
356
+ The typical data returned contains the following attributes:
357
+ {
358
+ "token_type": "Bearer",
359
+ "access_token": <str>,
360
+ "expires_in": <number-of-seconds>,
361
+ "refresh_token": <str>,
362
+ "refesh_expires_in": <number-of-seconds>
363
+ }
364
+
365
+ :param iam_server: the reference registered *IAM* server
366
+ :param body_data: the data to send in the body of the request
367
+ :param errors: incidental errors
368
+ :param logger: optional logger
369
+ :return: the token data, or *None* if error
370
+ """
371
+ # initialize the return variable
372
+ result: dict[str, Any] | None = None
373
+
374
+ # PBTAIN THE iam SERVER'S REGISTRY
375
+ registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
376
+ errors=errors,
377
+ logger=logger)
378
+ err_msg: str | None = None
379
+ if registry:
380
+ # complete the data to send in body of request
381
+ body_data["client_id"] = registry["client-id"]
382
+ client_secret: str = registry["client-secret"]
383
+ if client_secret:
384
+ body_data["client_secret"] = client_secret
385
+
386
+ # obtain the token
387
+ url: str = registry["base-url"] + "/protocol/openid-connect/token"
388
+ if logger:
389
+ logger.debug(msg=f"POST '{url}', data {json.dumps(obj=body_data,
390
+ ensure_ascii=False)}")
391
+ try:
392
+ # typical return on a token request:
393
+ # {
394
+ # "token_type": "Bearer",
395
+ # "access_token": <str>,
396
+ # "expires_in": <number-of-seconds>,
397
+ # "refresh_token": <str>,
398
+ # "refesh_expires_in": <number-of-seconds>
399
+ # }
400
+ response: requests.Response = requests.post(url=url,
401
+ data=body_data)
402
+ if response.status_code == 200:
403
+ # request succeeded
404
+ if logger:
405
+ logger.debug(msg=f"POST success, status {response.status_code}")
406
+ result = response.json()
407
+ else:
408
+ # request resulted in error
409
+ err_msg = f"POST failure, status {response.status_code}, reason '{response.reason}'"
410
+ if hasattr(response, "content") and response.content:
411
+ err_msg += f", content '{response.content}'"
412
+ if logger:
413
+ logger.error(msg=err_msg)
414
+ except Exception as e:
415
+ # the operation raised an exception
416
+ err_msg = exc_format(exc=e,
417
+ exc_info=sys.exc_info())
418
+ if logger:
419
+ logger.error(msg=err_msg)
420
+
421
+ if err_msg and isinstance(errors, list):
422
+ errors.append(err_msg)
423
+
424
+ return result
425
+
426
+
427
+ def __validate_and_store(iam_server: IamServer,
428
+ user_data: dict[str, Any],
429
+ token_data: dict[str, Any],
430
+ now: int,
431
+ errors: list[str] | None,
432
+ logger: Logger) -> tuple[str, str] | None:
433
+ """
434
+ Validate and store the token data.
435
+
436
+ The typical *token_data* contains the following attributes:
437
+ {
438
+ "token_type": "Bearer",
439
+ "access_token": <str>,
440
+ "expires_in": <number-of-seconds>,
441
+ "refresh_token": <str>,
442
+ "refesh_expires_in": <number-of-seconds>
443
+ }
444
+
445
+ :param iam_server: the reference registered *IAM* server
446
+ :param user_data: the aurthentication data kepth in *iam_server*'s registry
447
+ :param token_data: the token data
448
+ :param errors: incidental errors
449
+ :param logger: optional logger
450
+ :return: tuple containing the user identification and the validated and stored token, or *None* if error
451
+ """
452
+ # initialize the return variable
453
+ result: tuple[str, str] | None = None
454
+
455
+ # retrieve the IAM server's registry
456
+ registry: dict[str, Any] = _get_iam_registry(iam_server=iam_server,
457
+ errors=errors,
458
+ logger=logger)
459
+ if registry:
460
+ token: str = token_data.get("access_token")
461
+ user_data["access-token"] = token
462
+ # keep current refresh token if a new one is not provided
463
+ if token_data.get("refresh_token"):
464
+ user_data["refresh-token"] = token_data.get("refresh_token")
465
+ user_data["access-expiration"] = now + token_data.get("expires_in")
466
+ refresh_exp: int = user_data.get("refresh_expires_in")
467
+ user_data["refresh-expiration"] = (now + refresh_exp) if refresh_exp else sys.maxsize
468
+ public_key: str = _get_public_key(iam_server=iam_server,
469
+ errors=errors,
470
+ logger=logger)
471
+ if public_key:
472
+ recipient_attr = registry["recipient_attr"]
473
+ login_id = user_data.pop("login-id", None)
474
+ claims: dict[str, dict[str, Any]] = token_validate(token=token,
475
+ issuer=registry["base-url"],
476
+ recipient_id=login_id,
477
+ recipient_attr=recipient_attr,
478
+ public_key=public_key,
479
+ errors=errors,
480
+ logger=logger)
481
+ if claims:
482
+ users: dict[str, dict[str, Any]] = _get_iam_users(iam_server=iam_server,
483
+ errors=errors,
484
+ logger=logger)
485
+ if users:
486
+ user_id: str = login_id if login_id else claims["payload"][recipient_attr]
487
+ users[user_id] = user_data
488
+ result = (user_id, token)
489
+ return result
@@ -196,9 +196,24 @@ def service_exchange() -> Response:
196
196
  """
197
197
  Entry point for requesting the *IAM* server to exchange the token.
198
198
 
199
- This is currently limit to the *Keycloak* server
200
-
201
- :return: the response containing the token, or *UNAUTHORIZED*
199
+ This is currently limited to the *KEYCLOAK* server. The token itself is stored in *KEYCLOAK*'s registry.
200
+ The expected parameters in the request are:
201
+ - client-id: identification for the reference user (aliases: 'client_id', 'login')
202
+ - token: the token to be exchanged
203
+
204
+ If the exchange is successful, the token data is stored in the *IAM* server's registry, and returned.
205
+ Otherwise, *errors* will contain the appropriate error message.
206
+
207
+ The typical *Response* returned contains the following attributes:
208
+ {
209
+ "token_type": "Bearer",
210
+ "access_token": <str>,
211
+ "expires_in": <number-of-seconds>,
212
+ "refresh_token": <str>,
213
+ "refesh_expires_in": <number-of-seconds>
214
+ }
215
+
216
+ :return: the response containing the token data, or *UNAUTHORIZED*
202
217
  """
203
218
  # retrieve the operations's logger
204
219
  logger: Logger = _get_logger()
@@ -40,7 +40,7 @@ def token_validate(token: str,
40
40
  :param recipient_attr: attribute in the token's payload holding the expected subject's identification
41
41
  :param errors: incidental error messages
42
42
  :param logger: optional logger
43
- :return: The token's claims (*header* and *payload*) if it is valid, *None* otherwise
43
+ :return: The token's claims (*header* and *payload*), or *None* if error
44
44
  """
45
45
  # initialize the return variable
46
46
  result: dict[str, dict[str, Any]] | None = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypomes_iam
3
- Version: 0.3.4
3
+ Version: 0.3.5
4
4
  Summary: A collection of Python pomes, penyeach (IAM modules)
5
5
  Project-URL: Homepage, https://github.com/TheWiseCoder/PyPomes-IAM
6
6
  Project-URL: Bug Tracker, https://github.com/TheWiseCoder/PyPomes-IAM/issues
@@ -0,0 +1,12 @@
1
+ pypomes_iam/__init__.py,sha256=H7rUCaUEJBLNJv2rtdmBxwcAB28OItdEPenpv_UEOVw,965
2
+ pypomes_iam/iam_common.py,sha256=1NgXFTiD4qpbVqLfYsCfHrE0khEaczp-nR3AYXmzmvU,9608
3
+ pypomes_iam/iam_pomes.py,sha256=qmnHX88iaiMGaGeZfbs4VT-G_XMTpRT6wqRZeCOOKbQ,22294
4
+ pypomes_iam/iam_services.py,sha256=qdPPfwR9jIdGak-wr4t2NkdfhVaMqauBdvmVJvmFqyg,8914
5
+ pypomes_iam/jusbr_pomes.py,sha256=M47h_PUUgbCmFQyKz2sN1H9T00BC5v_oPgwl5ATWMSA,5625
6
+ pypomes_iam/keycloak_pomes.py,sha256=GtXJb4TZb-a_5b9ExYdJGetBcU1pEP96ONO6prA_vDo,6638
7
+ pypomes_iam/provider_pomes.py,sha256=eP8XzjTUEpwejTkO0wmDiqKjqbIEOzRNCR2ju5E15og,5856
8
+ pypomes_iam/token_pomes.py,sha256=1g6PMNNMbmdwLrsvSXvpO8-zdRhso1IFnwAyndNmV4Q,5332
9
+ pypomes_iam-0.3.5.dist-info/METADATA,sha256=fGRhn3H98wOkQSrxMh9FFTiheHez3TMIpX6R91wysoU,694
10
+ pypomes_iam-0.3.5.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
+ pypomes_iam-0.3.5.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
12
+ pypomes_iam-0.3.5.dist-info/RECORD,,
@@ -1,12 +0,0 @@
1
- pypomes_iam/__init__.py,sha256=H7rUCaUEJBLNJv2rtdmBxwcAB28OItdEPenpv_UEOVw,965
2
- pypomes_iam/iam_common.py,sha256=IWH9DVykF7K-Z9Sn3oP7To9_I2TkO2AzjVod238zUWc,13645
3
- pypomes_iam/iam_pomes.py,sha256=g06NSz3r1qv4LzDpjQ9iozdVyabidt7qLEocQRv1yns,15230
4
- pypomes_iam/iam_services.py,sha256=osqDptxCqL9eZPCRecBwtlS35YiMRvO7EIgdcyovSU4,8182
5
- pypomes_iam/jusbr_pomes.py,sha256=M47h_PUUgbCmFQyKz2sN1H9T00BC5v_oPgwl5ATWMSA,5625
6
- pypomes_iam/keycloak_pomes.py,sha256=GtXJb4TZb-a_5b9ExYdJGetBcU1pEP96ONO6prA_vDo,6638
7
- pypomes_iam/provider_pomes.py,sha256=eP8XzjTUEpwejTkO0wmDiqKjqbIEOzRNCR2ju5E15og,5856
8
- pypomes_iam/token_pomes.py,sha256=cfHdv2qYbsciY-3aEuDYUwCM479uMRSm2uwr4-hCaBQ,5345
9
- pypomes_iam-0.3.4.dist-info/METADATA,sha256=wt98InTB4_MY_-JQHDs9ZTZ1hb2T5MbJtAkduCUopNo,694
10
- pypomes_iam-0.3.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
- pypomes_iam-0.3.4.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
12
- pypomes_iam-0.3.4.dist-info/RECORD,,