pypomes-iam 0.3.0__py3-none-any.whl → 0.3.2__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 pypomes-iam might be problematic. Click here for more details.

@@ -0,0 +1,243 @@
1
+ import json
2
+ from flask import Request, Response, request, jsonify
3
+ from logging import Logger
4
+ from typing import Any
5
+
6
+ from .iam_common import IamServer, _get_logger, _get_iam_server
7
+ from .iam_pomes import user_login, user_logout, user_token, token_exchange, login_callback
8
+
9
+
10
+ # @flask_app.route(rule=<login_endpoint>, # JUSBR_LOGIN_ENDPOINT: /iam/jusbr:login
11
+ # methods=["GET"])
12
+ # @flask_app.route(rule=<login_endpoint>, # KEYCLOAK_LOGIN_ENDPOINT: /iam/keycloak:logout
13
+ # methods=["GET"])
14
+ def service_login() -> Response:
15
+ """
16
+ Entry point for the IAM server's login service.
17
+
18
+ Return the URL for the IAM server's authentication page, with the appropriate parameters.
19
+
20
+ :return: the response from the operation
21
+ """
22
+ # declare the return variable
23
+ result: Response | None = None
24
+
25
+ # retrieve the operations's logger
26
+ logger: Logger = _get_logger()
27
+ if logger:
28
+ # log the request
29
+ logger.debug(msg=_log_init(request=request))
30
+
31
+ # retrieve the IAM server
32
+ errors: list[str] = []
33
+ iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
34
+ errors=errors,
35
+ logger=logger)
36
+ if iam_server:
37
+ # obtain the login URL
38
+ login_data: dict[str, str] = user_login(iam_server=iam_server,
39
+ args=request.args,
40
+ errors=errors,
41
+ logger=logger)
42
+ if login_data:
43
+ result = jsonify(login_data)
44
+
45
+ if errors:
46
+ result = Response("; ".join(errors))
47
+ result.status_code = 400
48
+
49
+ # log the response
50
+ if logger:
51
+ logger.debug(msg=f"Response {result}")
52
+
53
+ return result
54
+
55
+
56
+ # @flask_app.route(rule=<logout_endpoint>, # JUSBR_LOGOUT_ENDPOINT
57
+ # methods=["GET"])
58
+ # @flask_app.route(rule=<login_endpoint>, # KEYCLOAK_LOGOUT_ENDPOINT
59
+ # methods=["GET"])
60
+ def service_logout() -> Response:
61
+ """
62
+ Entry point for the JusBR logout service.
63
+
64
+ Remove all data associating the user from the *IAM* server's registry.
65
+
66
+ :return: response *OK*, or response *BAD REQUEST* if error
67
+ """
68
+ # declare the return variable
69
+ result: Response | None
70
+
71
+ # retrieve the operations's logger
72
+ logger: Logger = _get_logger()
73
+ if logger:
74
+ # log the request
75
+ logger.debug(msg=_log_init(request=request))
76
+
77
+ # retrieve the IAM server
78
+ errors: list[str] = []
79
+ iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
80
+ errors=errors,
81
+ logger=logger)
82
+ if iam_server:
83
+ # logout the user
84
+ user_logout(iam_server=iam_server,
85
+ args=request.args,
86
+ errors=errors,
87
+ logger=logger)
88
+ if errors:
89
+ result = Response("; ".join(errors))
90
+ result.status_code = 400
91
+ else:
92
+ result = Response(status=200)
93
+
94
+ # log the response
95
+ if logger:
96
+ logger.debug(msg=f"Response {result}")
97
+
98
+ return result
99
+
100
+
101
+ # @flask_app.route(rule=<callback_endpoint>, # JUSBR_CALLBACK_ENDPOINT
102
+ # methods=["GET", "POST"])
103
+ # @flask_app.route(rule=<callback_endpoint>, # KEYCLOAK_CALLBACK_ENDPOINT
104
+ # methods=["POST"])
105
+ def service_callback() -> Response:
106
+ """
107
+ Entry point for the callback from JusBR on authentication operation.
108
+
109
+ This callback is typically invoked from a front-end application after a successful login at the
110
+ JusBR login page, forwarding the data received.
111
+
112
+ :return: the response containing the token, or *BAD REQUEST*
113
+ """
114
+ # retrieve the operations's logger
115
+ logger: Logger = _get_logger()
116
+ if logger:
117
+ # log the request
118
+ logger.debug(msg=_log_init(request=request))
119
+
120
+ # retrieve the IAM server
121
+ errors: list[str] = []
122
+ token_data: tuple[str, str] | None = None
123
+ iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
124
+ errors=errors,
125
+ logger=logger)
126
+ if iam_server:
127
+ # process the callback operation
128
+ token_data = login_callback(iam_server=iam_server,
129
+ args=request.args,
130
+ errors=errors,
131
+ logger=logger)
132
+ result: Response
133
+ if errors:
134
+ result = jsonify({"errors": "; ".join(errors)})
135
+ result.status_code = 400
136
+ if logger:
137
+ logger.error(msg=json.dumps(obj=result))
138
+ else:
139
+ result = jsonify({
140
+ "user-id": token_data[0],
141
+ "access-token": token_data[1]})
142
+
143
+ # log the response
144
+ if logger:
145
+ logger.debug(msg=f"Response {result}")
146
+
147
+ return result
148
+
149
+
150
+ # @flask_app.route(rule=<token_endpoint>, # JUSBR_ENDPOINT_TOKEN
151
+ # @flask_app.route(rule=<token_endpoint>, # KEYCLOAK_ENDPOINT_TOKEN
152
+ # methods=["GET"])
153
+ # methods=["GET"])
154
+ def service_token() -> Response:
155
+ """
156
+ Entry point for retrieving token from the *IAM* server.
157
+
158
+ :return: the response containing the token, or *UNAUTHORIZED*
159
+ """
160
+ # retrieve the operations's logger
161
+ logger: Logger = _get_logger()
162
+ if logger:
163
+ # log the request
164
+ logger.debug(msg=_log_init(request=request))
165
+
166
+ # retrieve the IAM server
167
+ errors: list[str] = []
168
+ iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
169
+ errors=errors,
170
+ logger=logger)
171
+ # retrieve the token
172
+ token: str | None = None
173
+ if iam_server:
174
+ errors: list[str] = []
175
+ token: str = user_token(iam_server=iam_server,
176
+ args=request.args,
177
+ errors=errors,
178
+ logger=logger)
179
+ result: Response
180
+ if errors:
181
+ result = Response("; ".join(errors))
182
+ result.status_code = 400
183
+ else:
184
+ result = jsonify({"token": token})
185
+
186
+ # log the response
187
+ if logger:
188
+ logger.debug(msg=f"Response {result}")
189
+
190
+ return result
191
+
192
+
193
+ # @flask_app.route(rule=<callback_endpoint>, # KEYCLOAK_ENDPOINT_EXCHANGE
194
+ # methods=["POST"])
195
+ def service_exchange() -> Response:
196
+ """
197
+ Entry point for requesting the *IAM* server to exchange the token.
198
+
199
+ This is currently limit to the *Keycloak* server
200
+
201
+ :return: the response containing the token, or *UNAUTHORIZED*
202
+ """
203
+ # retrieve the operations's logger
204
+ logger: Logger = _get_logger()
205
+
206
+ # retrieve the IAM server (currently, only 'Keycloak' is supported)
207
+ errors: list[str] = []
208
+ iam_server: IamServer = _get_iam_server(endpoint=request.endpoint,
209
+ errors=errors,
210
+ logger=logger)
211
+ # exchange the token
212
+ token_data: dict[str, Any] | None = None
213
+ if iam_server:
214
+ errors: list[str] = []
215
+ token_data = token_exchange(iam_server=iam_server,
216
+ args=request.args,
217
+ errors=errors,
218
+ logger=logger)
219
+ result: Response
220
+ if errors:
221
+ result = Response("; ".join(errors))
222
+ result.status_code = 400
223
+ else:
224
+ result = jsonify(token_data)
225
+
226
+ # log the response
227
+ if logger:
228
+ logger.debug(msg=f"Response {result}")
229
+
230
+ return result
231
+
232
+
233
+ def _log_init(request: Request) -> str:
234
+ """
235
+ Build the messages for logging the request entry.
236
+
237
+ :param request: the Request object
238
+ :return: the log message
239
+ """
240
+
241
+ params: str = json.dumps(obj=request.args,
242
+ ensure_ascii=False)
243
+ return f"Request {request.method}:{request.path}, params {params}"
@@ -1,13 +1,14 @@
1
+ import sys
1
2
  from cachetools import Cache, FIFOCache
2
- from datetime import datetime
3
3
  from flask import Flask
4
4
  from logging import Logger
5
5
  from pypomes_core import (
6
- APP_PREFIX, TZ_LOCAL, env_get_int, env_get_str
6
+ APP_PREFIX, env_get_int, env_get_str
7
7
  )
8
8
  from typing import Any, Final
9
9
 
10
- from .iam_common import IAM_SERVERS, IamServer, _service_token
10
+ from .iam_common import _IAM_SERVERS, IamServer
11
+ from .iam_pomes import user_token
11
12
 
12
13
  JUSBR_CLIENT_ID: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_CLIENT_ID")
13
14
  JUSBR_CLIENT_SECRET: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_CLIENT_SECRET")
@@ -24,6 +25,8 @@ JUSBR_ENDPOINT_TOKEN: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_ENDPOINT
24
25
 
25
26
  JUSBR_PUBLIC_KEY_LIFETIME: Final[int] = env_get_int(key=f"{APP_PREFIX}_JUSBR_PUBLIC_KEY_LIFETIME",
26
27
  def_value=86400) # 24 hours
28
+ JUSBR_RECIPIENT_ATTR: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_RECIPIENT_ATTR",
29
+ def_value="preferred_username")
27
30
  JUSBR_URL_AUTH_BASE: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_URL_AUTH_BASE")
28
31
 
29
32
 
@@ -32,6 +35,7 @@ def jusbr_setup(flask_app: Flask,
32
35
  client_secret: str = JUSBR_CLIENT_SECRET,
33
36
  client_timeout: int = JUSBR_CLIENT_TIMEOUT,
34
37
  public_key_lifetime: int = JUSBR_PUBLIC_KEY_LIFETIME,
38
+ recipient_attribute: str = JUSBR_RECIPIENT_ATTR,
35
39
  callback_endpoint: str = JUSBR_ENDPOINT_CALLBACK,
36
40
  token_endpoint: str = JUSBR_ENDPOINT_TOKEN,
37
41
  login_endpoint: str = JUSBR_ENDPOINT_LOGIN,
@@ -48,24 +52,26 @@ def jusbr_setup(flask_app: Flask,
48
52
  :param client_secret: the client's password with JusBR
49
53
  :param client_timeout: timeout for login authentication (in seconds,defaults to no timeout)
50
54
  :param public_key_lifetime: how long to use JusBR's public key, before refreshing it (in seconds)
55
+ :param recipient_attribute: attribute in the token's payload holding the token's subject
51
56
  :param callback_endpoint: endpoint for the callback from JusBR
52
- :param token_endpoint: endpoint for retrieving the JusBR authentication token
53
- :param login_endpoint: endpoint for redirecting user to JusBR login page
57
+ :param token_endpoint: endpoint for retrieving JusBR's authentication token
58
+ :param login_endpoint: endpoint for redirecting user to JusBR's login page
54
59
  :param logout_endpoint: endpoint for terminating user access to JusBR
55
- :param base_url: base URL to request the JusBR services
60
+ :param base_url: base URL to request JusBR services
56
61
  :param logger: optional logger
57
62
  """
58
- from .iam_pomes import service_login, service_logout, service_callback, service_token
63
+ from .iam_services import service_login, service_logout, service_callback, service_token
59
64
 
60
65
  # configure the JusBR registry
61
66
  cache: Cache = FIFOCache(maxsize=1048576)
62
67
  cache["users"] = {}
63
- IAM_SERVERS[IamServer.IAM_JUSRBR] = {
68
+ _IAM_SERVERS[IamServer.IAM_JUSRBR] = {
64
69
  "client-id": client_id,
65
70
  "client-secret": client_secret,
66
71
  "client-timeout": client_timeout,
72
+ "recipient-attr": recipient_attribute,
67
73
  "base-url": base_url,
68
- "pk-expiration": int(datetime.now(tz=TZ_LOCAL).timestamp()),
74
+ "pk-expiration": sys.maxsize,
69
75
  "pk-lifetime": public_key_lifetime,
70
76
  "cache": cache,
71
77
  "logger": logger,
@@ -87,7 +93,7 @@ def jusbr_setup(flask_app: Flask,
87
93
  flask_app.add_url_rule(rule=callback_endpoint,
88
94
  endpoint="jusbr-callback",
89
95
  view_func=service_callback,
90
- methods=["GET", "POST"])
96
+ methods=["GET"])
91
97
  if token_endpoint:
92
98
  flask_app.add_url_rule(rule=token_endpoint,
93
99
  endpoint="jusbr-token",
@@ -108,7 +114,7 @@ def jusbr_get_token(user_id: str,
108
114
  """
109
115
  # retrieve the token
110
116
  args: dict[str, Any] = {"user-id": user_id}
111
- return _service_token(registry=IAM_SERVERS[IamServer.IAM_JUSRBR],
112
- args=args,
113
- errors=errors,
114
- logger=logger)
117
+ return user_token(iam_server=IamServer.IAM_JUSRBR,
118
+ args=args,
119
+ errors=errors,
120
+ logger=logger)
@@ -1,30 +1,35 @@
1
+ import sys
1
2
  from cachetools import Cache, FIFOCache
2
- from datetime import datetime
3
3
  from flask import Flask
4
4
  from logging import Logger
5
5
  from pypomes_core import (
6
- APP_PREFIX, TZ_LOCAL, env_get_int, env_get_str
6
+ APP_PREFIX, env_get_int, env_get_str
7
7
  )
8
8
  from typing import Any, Final
9
9
 
10
- from .iam_common import IAM_SERVERS, IamServer, _service_token
10
+ from .iam_common import _IAM_SERVERS, IamServer
11
+ from .iam_pomes import user_token
11
12
 
12
13
  KEYCLOAK_CLIENT_ID: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_CLIENT_ID")
13
14
  KEYCLOAK_CLIENT_SECRET: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_CLIENT_SECRET")
14
15
  KEYCLOAK_CLIENT_TIMEOUT: Final[int] = env_get_int(key=f"{APP_PREFIX}_KEYCLOAK_CLIENT_TIMEOUT")
15
16
 
16
17
  KEYCLOAK_ENDPOINT_CALLBACK: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_ENDPOINT_CALLBACK",
17
- def_value="/iam/keycloak:callback")
18
+ def_value="/iam/ijud:callback")
19
+ KEYCLOAK_ENDPOINT_EXCHANGE: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_ENDPOINT_EXCHANGE",
20
+ def_value="/iam/ijud:exchange-token")
18
21
  KEYCLOAK_ENDPOINT_LOGIN: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_ENDPOINT_LOGIN",
19
- def_value="/iam/keycloak:login")
22
+ def_value="/iam/ijud:login")
20
23
  KEYCLOAK_ENDPOINT_LOGOUT: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_ENDPOINT_LOGOUT",
21
- def_value="/iam/keycloak:logout")
24
+ def_value="/iam/ijud:logout")
22
25
  KEYCLOAK_ENDPOINT_TOKEN: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_ENDPOINT_TOKEN",
23
- def_value="/iam/keycloak:get-token")
26
+ def_value="/iam/ijud:get-token")
24
27
 
25
28
  KEYCLOAK_PUBLIC_KEY_LIFETIME: Final[int] = env_get_int(key=f"{APP_PREFIX}_KEYCLOAK_PUBLIC_KEY_LIFETIME",
26
29
  def_value=86400) # 24 hours
27
30
  KEYCLOAK_REALM: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_REALM")
31
+ KEYCLOAK_RECIPIENT_ATTR: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_RECIPIENT_ATTR",
32
+ def_value="preferred_username")
28
33
  KEYCLOAK_URL_AUTH_BASE: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_URL_AUTH_BASE")
29
34
 
30
35
 
@@ -33,11 +38,13 @@ def keycloak_setup(flask_app: Flask,
33
38
  client_secret: str = KEYCLOAK_CLIENT_SECRET,
34
39
  client_timeout: int = KEYCLOAK_CLIENT_TIMEOUT,
35
40
  public_key_lifetime: int = KEYCLOAK_PUBLIC_KEY_LIFETIME,
41
+ recipient_attribute: str = KEYCLOAK_RECIPIENT_ATTR,
36
42
  realm: str = KEYCLOAK_REALM,
37
43
  callback_endpoint: str = KEYCLOAK_ENDPOINT_CALLBACK,
38
- token_endpoint: str = KEYCLOAK_ENDPOINT_TOKEN,
44
+ exchange_endpoint: str = KEYCLOAK_ENDPOINT_EXCHANGE,
39
45
  login_endpoint: str = KEYCLOAK_ENDPOINT_LOGIN,
40
46
  logout_endpoint: str = KEYCLOAK_ENDPOINT_LOGOUT,
47
+ token_endpoint: str = KEYCLOAK_ENDPOINT_TOKEN,
41
48
  base_url: str = KEYCLOAK_URL_AUTH_BASE,
42
49
  logger: Logger = None) -> None:
43
50
  """
@@ -50,25 +57,30 @@ def keycloak_setup(flask_app: Flask,
50
57
  :param client_secret: the client's password with JusBR
51
58
  :param client_timeout: timeout for login authentication (in seconds,defaults to no timeout)
52
59
  :param public_key_lifetime: how long to use Keycloak's public key, before refreshing it (in seconds)
60
+ :param recipient_attribute: attribute in the token's payload holding the token's subject
53
61
  :param realm: the Keycloak realm
54
- :param callback_endpoint: endpoint for the callback from JusBR
55
- :param token_endpoint: endpoint for retrieving the JusBR authentication token
56
- :param login_endpoint: endpoint for redirecting user to JusBR login page
57
- :param logout_endpoint: endpoint for terminating user access to JusBR
58
- :param base_url: base URL to request the JusBR services
62
+ :param callback_endpoint: endpoint for the callback from the front end
63
+ :param exchange_endpoint: endpoint fro requesting token exchange
64
+ :param token_endpoint: endpoint for retrieving Keycloak's authentication token
65
+ :param login_endpoint: endpoint for redirecting user to Keycloak's login page
66
+ :param logout_endpoint: endpoint for terminating user access to Keycloak
67
+ :param base_url: base URL to request Keycloak services
59
68
  :param logger: optional logger
60
69
  """
61
- from .iam_pomes import service_login, service_logout, service_callback, service_token
70
+ from .iam_services import (
71
+ service_login, service_logout, service_callback, service_exchange, service_token
72
+ )
62
73
 
63
74
  # configure the Keycloak registry
64
75
  cache: Cache = FIFOCache(maxsize=1048576)
65
76
  cache["users"] = {}
66
- IAM_SERVERS[IamServer.IAM_KEYCLOAK] = {
77
+ _IAM_SERVERS[IamServer.IAM_KEYCLOAK] = {
67
78
  "client-id": client_id,
68
79
  "client-secret": client_secret,
69
80
  "client-timeout": client_timeout,
81
+ "recipient-attr": recipient_attribute,
70
82
  "base-url": f"{base_url}/realms/{realm}",
71
- "pk-expiration": int(datetime.now(tz=TZ_LOCAL).timestamp()),
83
+ "pk-expiration": sys.maxsize,
72
84
  "pk-lifetime": public_key_lifetime,
73
85
  "cache": cache,
74
86
  "logger": logger,
@@ -90,12 +102,17 @@ def keycloak_setup(flask_app: Flask,
90
102
  flask_app.add_url_rule(rule=callback_endpoint,
91
103
  endpoint="keycloak-callback",
92
104
  view_func=service_callback,
93
- methods=["POST"])
105
+ methods=["GET"])
94
106
  if token_endpoint:
95
107
  flask_app.add_url_rule(rule=token_endpoint,
96
108
  endpoint="keycloak-token",
97
109
  view_func=service_token,
98
110
  methods=["GET"])
111
+ if exchange_endpoint:
112
+ flask_app.add_url_rule(rule=exchange_endpoint,
113
+ endpoint="keycloak-exchange",
114
+ view_func=service_exchange,
115
+ methods=["POST"])
99
116
 
100
117
 
101
118
  def keycloak_get_token(user_id: str,
@@ -111,7 +128,7 @@ def keycloak_get_token(user_id: str,
111
128
  """
112
129
  # retrieve the token
113
130
  args: dict[str, Any] = {"user-id": user_id}
114
- return _service_token(registry=IAM_SERVERS[IamServer.IAM_KEYCLOAK],
115
- args=args,
116
- errors=errors,
117
- logger=logger)
131
+ return user_token(iam_server=IamServer.IAM_KEYCLOAK,
132
+ args=args,
133
+ errors=errors,
134
+ logger=logger)
@@ -9,6 +9,8 @@ from typing import Any
9
9
 
10
10
  def token_validate(token: str,
11
11
  issuer: str = None,
12
+ recipient_id: str = None,
13
+ recipient_attr: str = None,
12
14
  public_key: str | bytes | PyJWK | RSAPublicKey = None,
13
15
  errors: list[str] = None,
14
16
  logger: Logger = None) -> dict[str, dict[str, Any]] | None:
@@ -24,12 +26,18 @@ def token_validate(token: str,
24
26
  If an asymmetric algorithm was used to sign the token and *public_key* is provided, then
25
27
  the token is validated, by using the data in its *signature* section.
26
28
 
29
+ The parameters *recipient_id* and *recipient_attr* refer the token's expected subject, respectively,
30
+ the subject's identification and the attribute in the token's payload data identifying its subject.
31
+ If both are provided, *recipient_id* is validated.
32
+
27
33
  On failure, *errors* will contain the reason(s) for rejecting *token*.
28
34
  On success, return the token's claims (*header* and *payload*).
29
35
 
30
36
  :param token: the token to be validated
31
37
  :param public_key: optional public key used to sign the token, in *PEM* format
32
38
  :param issuer: optional value to compare with the token's *iss* (issuer) attribute in its *payload*
39
+ :param recipient_id: identification of the expected token subject
40
+ :param recipient_attr: attribute in the token's payload holding the expected subject's identification
33
41
  :param errors: incidental error messages
34
42
  :param logger: optional logger
35
43
  :return: The token's claims (*header* and *payload*) if it is valid, *None* otherwise
@@ -87,10 +95,17 @@ def token_validate(token: str,
87
95
  algorithms=[token_alg],
88
96
  options=options,
89
97
  issuer=issuer)
90
- result = {
91
- "header": token_header,
92
- "payload": payload
93
- }
98
+ if recipient_id and recipient_attr and \
99
+ payload.get(recipient_attr) and recipient_id != payload.get(recipient_attr):
100
+ msg: str = f"Token was issued to '{payload.get(recipient_attr)}', not to '{recipient_id}'"
101
+ if logger:
102
+ logger.error(msg=msg)
103
+ errors.append(msg)
104
+ else:
105
+ result = {
106
+ "header": token_header,
107
+ "payload": payload
108
+ }
94
109
  except Exception as e:
95
110
  exc_err: str = exc_format(exc=e,
96
111
  exc_info=sys.exc_info())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pypomes_iam
3
- Version: 0.3.0
3
+ Version: 0.3.2
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=NB5ALh_kihQhfzl-7x_od4icrRBuSmYCSG5QSJujkuo,887
2
+ pypomes_iam/iam_common.py,sha256=IWH9DVykF7K-Z9Sn3oP7To9_I2TkO2AzjVod238zUWc,13645
3
+ pypomes_iam/iam_pomes.py,sha256=MqPcz39u5yBFGCnDBA8zFLMRZQyH6U4iZvG0q0XL0h8,15216
4
+ pypomes_iam/iam_services.py,sha256=4NQR5agj5zNnFymldHaTURGYDEHMkK0nX8PqkAldFXQ,8221
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.2.dist-info/METADATA,sha256=8E8b97RrTn4eLYueJum1UugCVC-230nEoWBOQK2QkyM,694
10
+ pypomes_iam-0.3.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
11
+ pypomes_iam-0.3.2.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
12
+ pypomes_iam-0.3.2.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- pypomes_iam/__init__.py,sha256=u-gNGbsayMf-2SWTB8VcoTCADoczZuwNEH50BPxTZZ8,682
2
- pypomes_iam/iam_common.py,sha256=_3Fx8kAJCthRTvQtlZg1gx0hWlUn4ko_ASROwsU9dJM,17017
3
- pypomes_iam/iam_pomes.py,sha256=O1acRMyisiZuB9rIkSboxwzGoLU_1hq_gNrg39CE9NQ,7835
4
- pypomes_iam/jusbr_pomes.py,sha256=Zh4nbKiBD2c4slYxgXoricCSScI8SROQproFfZ_55BI,5322
5
- pypomes_iam/keycloak_pomes.py,sha256=zVoLG0yNKGW1CP1bCf3yQiFw-8ZtOG7YG3VGZDq9_3c,5681
6
- pypomes_iam/provider_pomes.py,sha256=eP8XzjTUEpwejTkO0wmDiqKjqbIEOzRNCR2ju5E15og,5856
7
- pypomes_iam/token_pomes.py,sha256=OSllw00XnU-sE9EKXo8jZAto0zfFLBi83dvllLs-Sc0,4402
8
- pypomes_iam-0.3.0.dist-info/METADATA,sha256=-hmCE_h6DbGx97J44czCa2OD2wh4gXQkQ8HQzDmy6E0,694
9
- pypomes_iam-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
10
- pypomes_iam-0.3.0.dist-info/licenses/LICENSE,sha256=YvUELgV8qvXlaYsy9hXG5EW3Bmsrkw-OJmmILZnonAc,1086
11
- pypomes_iam-0.3.0.dist-info/RECORD,,