pypomes-iam 0.1.9__tar.gz → 0.2.1__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-iam might be problematic. Click here for more details.
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/PKG-INFO +1 -1
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/pyproject.toml +1 -1
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/src/pypomes_iam/__init__.py +4 -4
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/src/pypomes_iam/common_pomes.py +2 -28
- pypomes_iam-0.2.1/src/pypomes_iam/iam_pomes.py +176 -0
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/src/pypomes_iam/jusbr_pomes.py +11 -167
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/src/pypomes_iam/keycloak_pomes.py +6 -163
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/.gitignore +0 -0
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/LICENSE +0 -0
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/README.md +0 -0
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/src/pypomes_iam/provider_pomes.py +0 -0
- {pypomes_iam-0.1.9 → pypomes_iam-0.2.1}/src/pypomes_iam/token_pomes.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pypomes_iam
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
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
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from .jusbr_pomes import (
|
|
2
|
-
jusbr_setup, jusbr_get_token
|
|
2
|
+
jusbr_setup, jusbr_get_token
|
|
3
3
|
)
|
|
4
4
|
from .keycloak_pomes import (
|
|
5
|
-
keycloak_setup, keycloak_get_token
|
|
5
|
+
keycloak_setup, keycloak_get_token
|
|
6
6
|
)
|
|
7
7
|
from .provider_pomes import (
|
|
8
8
|
provider_register, provider_get_token
|
|
@@ -13,9 +13,9 @@ from .token_pomes import (
|
|
|
13
13
|
|
|
14
14
|
__all__ = [
|
|
15
15
|
# jusbr_pomes
|
|
16
|
-
"jusbr_setup", "jusbr_get_token",
|
|
16
|
+
"jusbr_setup", "jusbr_get_token",
|
|
17
17
|
# keycloak_pomes
|
|
18
|
-
"keycloak_setup", "keycloak_get_token",
|
|
18
|
+
"keycloak_setup", "keycloak_get_token",
|
|
19
19
|
# provider_pomes
|
|
20
20
|
"provider_register", "provider_get_token",
|
|
21
21
|
# token_pomes
|
|
@@ -31,7 +31,6 @@ from typing import Any
|
|
|
31
31
|
# "access-expiration": <timestamp>,
|
|
32
32
|
# "login-expiration": <timestamp>, <-- transient
|
|
33
33
|
# "login-id": <str>, <-- transient
|
|
34
|
-
# "oauth-scope": <str> <-- optional
|
|
35
34
|
# }
|
|
36
35
|
# }
|
|
37
36
|
# }
|
|
@@ -132,15 +131,11 @@ def _service_login(registry: dict[str, Any],
|
|
|
132
131
|
user_data["login-expiration"] = int(datetime.now(tz=TZ_LOCAL).timestamp()) + timeout if timeout else None
|
|
133
132
|
|
|
134
133
|
# build the redirect url
|
|
135
|
-
result: str = (f"{registry["base-url"]}/protocol/openid-connect/auth
|
|
134
|
+
result: str = (f"{registry["base-url"]}/protocol/openid-connect/auth"
|
|
135
|
+
f"?response_type=code&scope=openid"
|
|
136
136
|
f"&client_id={registry["client-id"]}"
|
|
137
137
|
f"&redirect_uri={registry["callback-url"]}"
|
|
138
138
|
f"&state={oauth_state}")
|
|
139
|
-
scope: str = _get_user_scope(registry=registry,
|
|
140
|
-
user_id=user_id)
|
|
141
|
-
if scope:
|
|
142
|
-
user_data["oauth-scope"] = scope
|
|
143
|
-
result += f"&scope={scope}"
|
|
144
139
|
|
|
145
140
|
# logout the user
|
|
146
141
|
_service_logout(registry=registry,
|
|
@@ -304,27 +299,6 @@ def _get_user_data(registry: dict[str, Any],
|
|
|
304
299
|
return result
|
|
305
300
|
|
|
306
301
|
|
|
307
|
-
def _get_user_scope(registry: dict[str, Any],
|
|
308
|
-
user_id: str) -> str | None:
|
|
309
|
-
"""
|
|
310
|
-
Retrieve the OAuth2 scope associated with *user_id*.
|
|
311
|
-
|
|
312
|
-
:param registry: the registry holding the authentication data
|
|
313
|
-
:param user_id:
|
|
314
|
-
:return: the OAuth2 scope associated with *user_id*, or *None* if it does not exist
|
|
315
|
-
"""
|
|
316
|
-
# initialize the return variable
|
|
317
|
-
result: str | None = None
|
|
318
|
-
|
|
319
|
-
if user_id:
|
|
320
|
-
cache: Cache = registry["safe-cache"]
|
|
321
|
-
users: dict[str, dict[str, Any]] = cache.get("users")
|
|
322
|
-
if user_id in users:
|
|
323
|
-
result = users[user_id].get("oauth2-scope")
|
|
324
|
-
|
|
325
|
-
return result
|
|
326
|
-
|
|
327
|
-
|
|
328
302
|
def _post_for_token(registry: dict[str, Any],
|
|
329
303
|
user_data: dict[str, Any],
|
|
330
304
|
body_data: dict[str, Any],
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
from flask import Response, redirect, request, jsonify
|
|
2
|
+
from logging import Logger
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from .common_pomes import (
|
|
6
|
+
_service_login, _service_logout,
|
|
7
|
+
_service_callback, _service_token, _log_init
|
|
8
|
+
)
|
|
9
|
+
from .jusbr_pomes import _jusbr_logger, _jusbr_registry
|
|
10
|
+
from .keycloak_pomes import _keycloak_logger, _keycloak_registry
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# @flask_app.route(rule=<login_endpoint>, # JUSBR_LOGIN_ENDPOINT: /iam/jusbr:login
|
|
14
|
+
# methods=["GET"])
|
|
15
|
+
# @flask_app.route(rule=<login_endpoint>, # KEYCLOAK_LOGIN_ENDPOINT: /iam/keycloak:logout
|
|
16
|
+
# methods=["GET"])
|
|
17
|
+
def service_login() -> Response:
|
|
18
|
+
"""
|
|
19
|
+
Entry point for the JusBR login service.
|
|
20
|
+
|
|
21
|
+
Redirect the request to the JusBR authentication page, with the appropriate parameters.
|
|
22
|
+
|
|
23
|
+
:return: the response from the redirect operation
|
|
24
|
+
"""
|
|
25
|
+
logger: Logger
|
|
26
|
+
registry: dict[str, Any]
|
|
27
|
+
if request.endpoint == "jusbr-login":
|
|
28
|
+
logger = _jusbr_logger
|
|
29
|
+
registry = _jusbr_registry
|
|
30
|
+
else:
|
|
31
|
+
logger = _keycloak_logger
|
|
32
|
+
registry = _keycloak_registry
|
|
33
|
+
|
|
34
|
+
# log the request
|
|
35
|
+
if logger:
|
|
36
|
+
logger.debug(msg=_log_init(request=request))
|
|
37
|
+
|
|
38
|
+
# obtain the redirect URL
|
|
39
|
+
auth_url: str = _service_login(registry=registry,
|
|
40
|
+
args=request.args,
|
|
41
|
+
logger=logger)
|
|
42
|
+
# redirect the request
|
|
43
|
+
result: Response = redirect(location=auth_url)
|
|
44
|
+
|
|
45
|
+
# log the response
|
|
46
|
+
if logger:
|
|
47
|
+
logger.debug(msg=f"Response {result}")
|
|
48
|
+
|
|
49
|
+
return result
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# @flask_app.route(rule=<logout_endpoint>, # JUSBR_LOGOUT_ENDPOINT: /iam/jusbr:logout
|
|
53
|
+
# methods=["GET"])
|
|
54
|
+
# @flask_app.route(rule=<login_endpoint>, # KEYCLOAK_LOGOUT_ENDPOINT: /iam/keycloak:logout
|
|
55
|
+
# methods=["GET"])
|
|
56
|
+
def service_logout() -> Response:
|
|
57
|
+
"""
|
|
58
|
+
Entry point for the JusBR logout service.
|
|
59
|
+
|
|
60
|
+
Remove all data associating the user with JusBR from the registry.
|
|
61
|
+
|
|
62
|
+
:return: response *OK*
|
|
63
|
+
"""
|
|
64
|
+
logger: Logger
|
|
65
|
+
registry: dict[str, Any]
|
|
66
|
+
if request.endpoint == "jusbr-logout":
|
|
67
|
+
logger = _jusbr_logger
|
|
68
|
+
registry = _jusbr_registry
|
|
69
|
+
else:
|
|
70
|
+
logger = _keycloak_logger
|
|
71
|
+
registry = _keycloak_registry
|
|
72
|
+
|
|
73
|
+
# log the request
|
|
74
|
+
if logger:
|
|
75
|
+
logger.debug(msg=_log_init(request=request))
|
|
76
|
+
|
|
77
|
+
# logout the user
|
|
78
|
+
_service_logout(registry=registry,
|
|
79
|
+
args=request.args,
|
|
80
|
+
logger=logger)
|
|
81
|
+
|
|
82
|
+
result: Response = Response(status=200)
|
|
83
|
+
|
|
84
|
+
# log the response
|
|
85
|
+
if logger:
|
|
86
|
+
logger.debug(msg=f"Response {result}")
|
|
87
|
+
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
# @flask_app.route(rule=<callback_endpoint>, # JUSBR_CALLBACK_ENDPOINT: /iam/jusbr:callback
|
|
92
|
+
# methods=["GET", "POST"])
|
|
93
|
+
# @flask_app.route(rule=<callback_endpoint>, # KEYCLOAK_CALLBACK_ENDPOINT: /iam/keycloak:callback
|
|
94
|
+
# methods=["POST"])
|
|
95
|
+
def service_callback() -> Response:
|
|
96
|
+
"""
|
|
97
|
+
Entry point for the callback from JusBR on authentication operation.
|
|
98
|
+
|
|
99
|
+
:return: the response containing the token, or *BAD REQUEST*
|
|
100
|
+
"""
|
|
101
|
+
logger: Logger
|
|
102
|
+
registry: dict[str, Any]
|
|
103
|
+
if request.endpoint == "jusbr-callback":
|
|
104
|
+
logger = _jusbr_logger
|
|
105
|
+
registry = _jusbr_registry
|
|
106
|
+
else:
|
|
107
|
+
logger = _keycloak_logger
|
|
108
|
+
registry = _keycloak_registry
|
|
109
|
+
|
|
110
|
+
# log the request
|
|
111
|
+
if logger:
|
|
112
|
+
logger.debug(msg=_log_init(request=request))
|
|
113
|
+
|
|
114
|
+
# process the callback operation
|
|
115
|
+
errors: list[str] = []
|
|
116
|
+
token_data: tuple[str, str] = _service_callback(registry=registry,
|
|
117
|
+
args=request.args,
|
|
118
|
+
errors=errors,
|
|
119
|
+
logger=logger)
|
|
120
|
+
result: Response
|
|
121
|
+
if errors:
|
|
122
|
+
result = jsonify({"errors": "; ".join(errors)})
|
|
123
|
+
result.status_code = 400
|
|
124
|
+
else:
|
|
125
|
+
result = jsonify({
|
|
126
|
+
"user_id": token_data[0],
|
|
127
|
+
"access_token": token_data[1]})
|
|
128
|
+
|
|
129
|
+
# log the response
|
|
130
|
+
if logger:
|
|
131
|
+
logger.debug(msg=f"Response {result}")
|
|
132
|
+
|
|
133
|
+
return result
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
# @flask_app.route(rule=<token_endpoint>, # JUSBR_TOKEN_ENDPOINT: /iam/jusbr:get-token
|
|
137
|
+
# methods=["GET"])
|
|
138
|
+
# @flask_app.route(rule=<token_endpoint>, # JUSBR_TOKEN_ENDPOINT: /iam/jusbr:get-token
|
|
139
|
+
# methods=["GET"])
|
|
140
|
+
def service_token() -> Response:
|
|
141
|
+
"""
|
|
142
|
+
Entry point for retrieving the JusBR token.
|
|
143
|
+
|
|
144
|
+
:return: the response containing the token, or *UNAUTHORIZED*
|
|
145
|
+
"""
|
|
146
|
+
logger: Logger
|
|
147
|
+
registry: dict[str, Any]
|
|
148
|
+
if request.endpoint == "jusbr-token":
|
|
149
|
+
logger = _jusbr_logger
|
|
150
|
+
registry = _jusbr_registry
|
|
151
|
+
else:
|
|
152
|
+
logger = _keycloak_logger
|
|
153
|
+
registry = _keycloak_registry
|
|
154
|
+
|
|
155
|
+
# log the request
|
|
156
|
+
if logger:
|
|
157
|
+
logger.debug(msg=_log_init(request=request))
|
|
158
|
+
|
|
159
|
+
# retrieve the token
|
|
160
|
+
errors: list[str] = []
|
|
161
|
+
token: str = _service_token(registry=registry,
|
|
162
|
+
args=request.args,
|
|
163
|
+
errors=errors,
|
|
164
|
+
logger=logger)
|
|
165
|
+
result: Response
|
|
166
|
+
if token:
|
|
167
|
+
result = jsonify({"token": token})
|
|
168
|
+
else:
|
|
169
|
+
result = Response("; ".join(errors))
|
|
170
|
+
result.status_code = 401
|
|
171
|
+
|
|
172
|
+
# log the response
|
|
173
|
+
if logger:
|
|
174
|
+
logger.debug(msg=f"Response {result}")
|
|
175
|
+
|
|
176
|
+
return result
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
from cachetools import FIFOCache
|
|
2
2
|
from datetime import datetime
|
|
3
|
-
from flask import Flask
|
|
3
|
+
from flask import Flask
|
|
4
4
|
from logging import Logger
|
|
5
5
|
from pypomes_core import (
|
|
6
6
|
APP_PREFIX, TZ_LOCAL, env_get_int, env_get_str
|
|
7
7
|
)
|
|
8
8
|
from typing import Any, Final
|
|
9
9
|
|
|
10
|
-
from .common_pomes import
|
|
11
|
-
_service_login, _service_logout,
|
|
12
|
-
_service_callback, _service_token,
|
|
13
|
-
_get_user_data, _log_init
|
|
14
|
-
)
|
|
10
|
+
from .common_pomes import _service_token
|
|
15
11
|
|
|
16
12
|
JUSBR_CLIENT_ID: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_CLIENT_ID")
|
|
17
13
|
JUSBR_CLIENT_SECRET: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_CLIENT_SECRET")
|
|
@@ -52,14 +48,13 @@ JUSBR_URL_AUTH_CALLBACK: Final[str] = env_get_str(key=f"{APP_PREFIX}_JUSBR_URL_A
|
|
|
52
48
|
# "access-expiration": <timestamp>,
|
|
53
49
|
# "login-expiration": <timestamp>, <-- transient
|
|
54
50
|
# "login-id": <str>, <-- transient
|
|
55
|
-
# "oauth-scope": <str> <-- optional
|
|
56
51
|
# }
|
|
57
52
|
# }
|
|
58
53
|
# }
|
|
59
54
|
_jusbr_registry: dict[str, Any] | None = None
|
|
60
55
|
|
|
61
56
|
# dafault logger
|
|
62
|
-
|
|
57
|
+
_jusbr_logger: Logger | None = None
|
|
63
58
|
|
|
64
59
|
|
|
65
60
|
def jusbr_setup(flask_app: Flask,
|
|
@@ -92,12 +87,13 @@ def jusbr_setup(flask_app: Flask,
|
|
|
92
87
|
:param callback_url: URL for JusBR to callback on login
|
|
93
88
|
:param logger: optional logger
|
|
94
89
|
"""
|
|
90
|
+
from .iam_pomes import service_login, service_logout, service_callback, service_token
|
|
91
|
+
global _jusbr_logger, _jusbr_registry
|
|
92
|
+
|
|
95
93
|
# establish the logger
|
|
96
|
-
global _logger
|
|
97
94
|
_logger = logger
|
|
98
95
|
|
|
99
96
|
# configure the JusBR registry
|
|
100
|
-
global _jusbr_registry
|
|
101
97
|
_jusbr_registry = {
|
|
102
98
|
"client-id": client_id,
|
|
103
99
|
"client-secret": client_secret,
|
|
@@ -110,11 +106,6 @@ def jusbr_setup(flask_app: Flask,
|
|
|
110
106
|
}
|
|
111
107
|
|
|
112
108
|
# establish the endpoints
|
|
113
|
-
if token_endpoint:
|
|
114
|
-
flask_app.add_url_rule(rule=token_endpoint,
|
|
115
|
-
endpoint="jusbr-token",
|
|
116
|
-
view_func=service_token,
|
|
117
|
-
methods=["GET"])
|
|
118
109
|
if login_endpoint:
|
|
119
110
|
flask_app.add_url_rule(rule=login_endpoint,
|
|
120
111
|
endpoint="jusbr-login",
|
|
@@ -130,136 +121,11 @@ def jusbr_setup(flask_app: Flask,
|
|
|
130
121
|
endpoint="jusbr-callback",
|
|
131
122
|
view_func=service_callback,
|
|
132
123
|
methods=["GET", "POST"])
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
"""
|
|
139
|
-
Entry point for the JusBR login service.
|
|
140
|
-
|
|
141
|
-
Redirect the request to the JusBR authentication page, with the appropriate parameters.
|
|
142
|
-
|
|
143
|
-
:return: the response from the redirect operation
|
|
144
|
-
"""
|
|
145
|
-
global _jusbr_registry
|
|
146
|
-
|
|
147
|
-
# log the request
|
|
148
|
-
if _logger:
|
|
149
|
-
_logger.debug(msg=_log_init(request=request))
|
|
150
|
-
|
|
151
|
-
# obtain the redirect URL
|
|
152
|
-
auth_url: str = _service_login(registry=_jusbr_registry,
|
|
153
|
-
args=request.args,
|
|
154
|
-
logger=_logger)
|
|
155
|
-
# redirect the request
|
|
156
|
-
result: Response = redirect(location=auth_url)
|
|
157
|
-
|
|
158
|
-
# log the response
|
|
159
|
-
if _logger:
|
|
160
|
-
_logger.debug(msg=f"Response {result}")
|
|
161
|
-
|
|
162
|
-
return result
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
# @flask_app.route(rule=<login_endpoint>, # JUSBR_LOGIN_ENDPOINT: /iam/jusbr:logout
|
|
166
|
-
# methods=["GET"])
|
|
167
|
-
def service_logout() -> Response:
|
|
168
|
-
"""
|
|
169
|
-
Entry point for the JusBR logout service.
|
|
170
|
-
|
|
171
|
-
Remove all data associating the user with JusBR from the registry.
|
|
172
|
-
|
|
173
|
-
:return: response *OK*
|
|
174
|
-
"""
|
|
175
|
-
global _jusbr_registry
|
|
176
|
-
|
|
177
|
-
# log the request
|
|
178
|
-
if _logger:
|
|
179
|
-
_logger.debug(msg=_log_init(request=request))
|
|
180
|
-
|
|
181
|
-
# logout the user
|
|
182
|
-
_service_logout(registry=_jusbr_registry,
|
|
183
|
-
args=request.args,
|
|
184
|
-
logger=_logger)
|
|
185
|
-
|
|
186
|
-
result: Response = Response(status=200)
|
|
187
|
-
|
|
188
|
-
# log the response
|
|
189
|
-
if _logger:
|
|
190
|
-
_logger.debug(msg=f"Response {result}")
|
|
191
|
-
|
|
192
|
-
return result
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
# @flask_app.route(rule=<callback_endpoint>, # JUSBR_CALLBACK_ENDPOINT: /iam/jusbr:callback
|
|
196
|
-
# methods=["GET", "POST"])
|
|
197
|
-
def service_callback() -> Response:
|
|
198
|
-
"""
|
|
199
|
-
Entry point for the callback from JusBR on authentication operation.
|
|
200
|
-
|
|
201
|
-
:return: the response containing the token, or *BAD REQUEST*
|
|
202
|
-
"""
|
|
203
|
-
global _jusbr_registry
|
|
204
|
-
|
|
205
|
-
# log the request
|
|
206
|
-
if _logger:
|
|
207
|
-
_logger.debug(msg=_log_init(request=request))
|
|
208
|
-
|
|
209
|
-
# process the callback operation
|
|
210
|
-
errors: list[str] = []
|
|
211
|
-
token_data: tuple[str, str] = _service_callback(registry=_jusbr_registry,
|
|
212
|
-
args=request.args,
|
|
213
|
-
errors=errors,
|
|
214
|
-
logger=_logger)
|
|
215
|
-
result: Response
|
|
216
|
-
if errors:
|
|
217
|
-
result = jsonify({"errors": "; ".join(errors)})
|
|
218
|
-
result.status_code = 400
|
|
219
|
-
else:
|
|
220
|
-
result = jsonify({
|
|
221
|
-
"user_id": token_data[0],
|
|
222
|
-
"access_token": token_data[1]})
|
|
223
|
-
|
|
224
|
-
# log the response
|
|
225
|
-
if _logger:
|
|
226
|
-
_logger.debug(msg=f"Response {result}")
|
|
227
|
-
|
|
228
|
-
return result
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
# @flask_app.route(rule=<token_endpoint>, # JUSBR_TOKEN_ENDPOINT: /iam/jusbr:get-token
|
|
232
|
-
# methods=["GET"])
|
|
233
|
-
def service_token() -> Response:
|
|
234
|
-
"""
|
|
235
|
-
Entry point for retrieving the JusBR token.
|
|
236
|
-
|
|
237
|
-
:return: the response containing the token, or *UNAUTHORIZED*
|
|
238
|
-
"""
|
|
239
|
-
global _jusbr_registry
|
|
240
|
-
|
|
241
|
-
# log the request
|
|
242
|
-
if _logger:
|
|
243
|
-
_logger.debug(msg=_log_init(request=request))
|
|
244
|
-
|
|
245
|
-
# retrieve the token
|
|
246
|
-
errors: list[str] = []
|
|
247
|
-
token: str = _service_token(registry=_jusbr_registry,
|
|
248
|
-
args=request.args,
|
|
249
|
-
errors=errors,
|
|
250
|
-
logger=_logger)
|
|
251
|
-
result: Response
|
|
252
|
-
if token:
|
|
253
|
-
result = jsonify({"token": token})
|
|
254
|
-
else:
|
|
255
|
-
result = Response("; ".join(errors))
|
|
256
|
-
result.status_code = 401
|
|
257
|
-
|
|
258
|
-
# log the response
|
|
259
|
-
if _logger:
|
|
260
|
-
_logger.debug(msg=f"Response {result}")
|
|
261
|
-
|
|
262
|
-
return result
|
|
124
|
+
if token_endpoint:
|
|
125
|
+
flask_app.add_url_rule(rule=token_endpoint,
|
|
126
|
+
endpoint="jusbr-token",
|
|
127
|
+
view_func=service_token,
|
|
128
|
+
methods=["GET"])
|
|
263
129
|
|
|
264
130
|
|
|
265
131
|
def jusbr_get_token(user_id: str,
|
|
@@ -281,25 +147,3 @@ def jusbr_get_token(user_id: str,
|
|
|
281
147
|
args=args,
|
|
282
148
|
errors=errors,
|
|
283
149
|
logger=logger)
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
def jusbr_set_scope(user_id: str,
|
|
287
|
-
scope: str,
|
|
288
|
-
logger: Logger = None) -> None:
|
|
289
|
-
"""
|
|
290
|
-
Set the OAuth2 scope of *user_id* to *scope*.
|
|
291
|
-
|
|
292
|
-
:param user_id: the user's identification
|
|
293
|
-
:param scope: the OAuth2 scope to set to the user
|
|
294
|
-
:param logger: optional logger
|
|
295
|
-
"""
|
|
296
|
-
global _jusbr_registry
|
|
297
|
-
|
|
298
|
-
# retrieve user data
|
|
299
|
-
user_data: dict[str, Any] = _get_user_data(registry=_jusbr_registry,
|
|
300
|
-
user_id=user_id,
|
|
301
|
-
logger=logger)
|
|
302
|
-
# set the OAuth2 scope
|
|
303
|
-
user_data["oauth-scope"] = scope
|
|
304
|
-
if logger:
|
|
305
|
-
logger.debug(msg=f"Scope for user '{user_id}' set to '{scope}'")
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
from cachetools import FIFOCache
|
|
2
2
|
from datetime import datetime
|
|
3
|
-
from flask import Flask
|
|
3
|
+
from flask import Flask
|
|
4
4
|
from logging import Logger
|
|
5
5
|
from pypomes_core import (
|
|
6
6
|
APP_PREFIX, TZ_LOCAL, env_get_int, env_get_str
|
|
7
7
|
)
|
|
8
8
|
from typing import Any, Final
|
|
9
9
|
|
|
10
|
-
from .common_pomes import
|
|
11
|
-
_service_login, _service_logout,
|
|
12
|
-
_service_callback, _service_token,
|
|
13
|
-
_get_user_data, _log_init
|
|
14
|
-
)
|
|
10
|
+
from .common_pomes import _service_token
|
|
15
11
|
|
|
16
12
|
KEYCLOAK_CLIENT_ID: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_CLIENT_ID")
|
|
17
13
|
KEYCLOAK_CLIENT_SECRET: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK_CLIENT_SECRET")
|
|
@@ -53,14 +49,13 @@ KEYCLOAK_URL_AUTH_CALLBACK: Final[str] = env_get_str(key=f"{APP_PREFIX}_KEYCLOAK
|
|
|
53
49
|
# "access-expiration": <timestamp>,
|
|
54
50
|
# "login-expiration": <timestamp>, <-- transient
|
|
55
51
|
# "login-id": <str>, <-- transient
|
|
56
|
-
# "oauth-scope": <str> <-- optional
|
|
57
52
|
# }
|
|
58
53
|
# }
|
|
59
54
|
# }
|
|
60
55
|
_keycloak_registry: dict[str, Any] = {}
|
|
61
56
|
|
|
62
57
|
# dafault logger
|
|
63
|
-
|
|
58
|
+
_keycloak_logger: Logger | None = None
|
|
64
59
|
|
|
65
60
|
|
|
66
61
|
def keycloak_setup(flask_app: Flask,
|
|
@@ -95,11 +90,11 @@ def keycloak_setup(flask_app: Flask,
|
|
|
95
90
|
:param callback_url: URL for Keycloak to callback on login
|
|
96
91
|
:param logger: optional logger
|
|
97
92
|
"""
|
|
98
|
-
|
|
93
|
+
from .iam_pomes import service_login, service_logout, service_callback, service_token
|
|
94
|
+
global _keycloak_logger, _keycloak_registry
|
|
99
95
|
|
|
100
96
|
# establish the logger
|
|
101
|
-
|
|
102
|
-
_logger = logger
|
|
97
|
+
_keycloak_logger = logger
|
|
103
98
|
|
|
104
99
|
# configure the JusBR registry
|
|
105
100
|
_keycloak_registry = {
|
|
@@ -136,136 +131,6 @@ def keycloak_setup(flask_app: Flask,
|
|
|
136
131
|
methods=["POST"])
|
|
137
132
|
|
|
138
133
|
|
|
139
|
-
# @flask_app.route(rule=<login_endpoint>, # KEYCLOAK_LOGIN_ENDPOINT: /iam/keycloak:login
|
|
140
|
-
# methods=["GET"])
|
|
141
|
-
def service_login() -> Response:
|
|
142
|
-
"""
|
|
143
|
-
Entry point for the Keycloak login service.
|
|
144
|
-
|
|
145
|
-
Redirect the request to the Keycloak authentication page, with the appropriate parameters.
|
|
146
|
-
|
|
147
|
-
:return: the response from the redirect operation
|
|
148
|
-
"""
|
|
149
|
-
global _keycloak_registry
|
|
150
|
-
|
|
151
|
-
# log the request
|
|
152
|
-
if _logger:
|
|
153
|
-
_logger.debug(msg=_log_init(request=request))
|
|
154
|
-
|
|
155
|
-
# obtain the redirect URL
|
|
156
|
-
auth_url: str = _service_login(registry=_keycloak_registry,
|
|
157
|
-
args=request.args,
|
|
158
|
-
logger=_logger)
|
|
159
|
-
# redirect the request
|
|
160
|
-
result: Response = redirect(location=auth_url)
|
|
161
|
-
|
|
162
|
-
# log the response
|
|
163
|
-
if _logger:
|
|
164
|
-
_logger.debug(msg=f"Response {result}")
|
|
165
|
-
|
|
166
|
-
return result
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
# @flask_app.route(rule=<login_endpoint>, # KEYCLOAK_LOGIN_ENDPOINT: /iam/keycloak:logout
|
|
170
|
-
# methods=["GET"])
|
|
171
|
-
def service_logout() -> Response:
|
|
172
|
-
"""
|
|
173
|
-
Entry point for the Keycloak logout service.
|
|
174
|
-
|
|
175
|
-
Remove all data associating the user with Keycloak from the registry.
|
|
176
|
-
|
|
177
|
-
:return: response *OK*
|
|
178
|
-
"""
|
|
179
|
-
global _keycloak_registry
|
|
180
|
-
|
|
181
|
-
# log the request
|
|
182
|
-
if _logger:
|
|
183
|
-
_logger.debug(msg=_log_init(request=request))
|
|
184
|
-
|
|
185
|
-
# logout the user
|
|
186
|
-
_service_logout(registry=_keycloak_registry,
|
|
187
|
-
args=request.args,
|
|
188
|
-
logger=_logger)
|
|
189
|
-
|
|
190
|
-
result: Response = Response(status=200)
|
|
191
|
-
|
|
192
|
-
# log the response
|
|
193
|
-
if _logger:
|
|
194
|
-
_logger.debug(msg=f"Response {result}")
|
|
195
|
-
|
|
196
|
-
return result
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
# @flask_app.route(rule=<callback_endpoint>, # KEYCLOAK_CALLBACK_ENDPOINT: /iam/keycloak:callback
|
|
200
|
-
# methods=["POST"])
|
|
201
|
-
def service_callback() -> Response:
|
|
202
|
-
"""
|
|
203
|
-
Entry point for the callback from Keycloak on authentication operation.
|
|
204
|
-
|
|
205
|
-
:return: the response containing the token, or *NOT AUTHORIZED*
|
|
206
|
-
"""
|
|
207
|
-
global _keycloak_registry
|
|
208
|
-
|
|
209
|
-
# log the request
|
|
210
|
-
if _logger:
|
|
211
|
-
_logger.debug(msg=_log_init(request=request))
|
|
212
|
-
|
|
213
|
-
# process the callback operation
|
|
214
|
-
errors: list[str] = []
|
|
215
|
-
token_data: tuple[str, str] = _service_callback(registry=_keycloak_registry,
|
|
216
|
-
args=request.args,
|
|
217
|
-
errors=errors,
|
|
218
|
-
logger=_logger)
|
|
219
|
-
result: Response
|
|
220
|
-
if errors:
|
|
221
|
-
result = jsonify({"errors": "; ".join(errors)})
|
|
222
|
-
result.status_code = 400
|
|
223
|
-
else:
|
|
224
|
-
result = jsonify({
|
|
225
|
-
"user_id": token_data[0],
|
|
226
|
-
"access_token": token_data[1]})
|
|
227
|
-
|
|
228
|
-
# log the response
|
|
229
|
-
if _logger:
|
|
230
|
-
_logger.debug(msg=f"Response {result}")
|
|
231
|
-
|
|
232
|
-
return result
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
# @flask_app.route(rule=<token_endpoint>, # JUSBR_TOKEN_ENDPOINT: /iam/jusbr:get-token
|
|
236
|
-
# methods=["GET"])
|
|
237
|
-
def service_token() -> Response:
|
|
238
|
-
"""
|
|
239
|
-
Entry point for retrieving the Keycloak token.
|
|
240
|
-
|
|
241
|
-
:return: the response containing the token, or *UNAUTHORIZED*
|
|
242
|
-
"""
|
|
243
|
-
global _keycloak_registry
|
|
244
|
-
|
|
245
|
-
# log the request
|
|
246
|
-
if _logger:
|
|
247
|
-
_logger.debug(msg=_log_init(request=request))
|
|
248
|
-
|
|
249
|
-
# retrieve the token
|
|
250
|
-
errors: list[str] = []
|
|
251
|
-
token: str = _service_token(registry=_keycloak_registry,
|
|
252
|
-
args=request.args,
|
|
253
|
-
errors=errors,
|
|
254
|
-
logger=_logger)
|
|
255
|
-
result: Response
|
|
256
|
-
if token:
|
|
257
|
-
result = jsonify({"token": token})
|
|
258
|
-
else:
|
|
259
|
-
result = Response("; ".join(errors))
|
|
260
|
-
result.status_code = 401
|
|
261
|
-
|
|
262
|
-
# log the response
|
|
263
|
-
if _logger:
|
|
264
|
-
_logger.debug(msg=f"Response {result}")
|
|
265
|
-
|
|
266
|
-
return result
|
|
267
|
-
|
|
268
|
-
|
|
269
134
|
def keycloak_get_token(user_id: str,
|
|
270
135
|
errors: list[str] = None,
|
|
271
136
|
logger: Logger = None) -> str:
|
|
@@ -285,25 +150,3 @@ def keycloak_get_token(user_id: str,
|
|
|
285
150
|
args=args,
|
|
286
151
|
errors=errors,
|
|
287
152
|
logger=logger)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
def keycloak_set_scope(user_id: str,
|
|
291
|
-
scope: str,
|
|
292
|
-
logger: Logger | None) -> None:
|
|
293
|
-
"""
|
|
294
|
-
Set the OAuth2 scope of *user_id* to *scope*.
|
|
295
|
-
|
|
296
|
-
:param user_id: the user's identification
|
|
297
|
-
:param scope: the OAuth2 scope to set to the user
|
|
298
|
-
:param logger: optional logger
|
|
299
|
-
"""
|
|
300
|
-
global _keycloak_registry
|
|
301
|
-
|
|
302
|
-
# retrieve user data
|
|
303
|
-
user_data: dict[str, Any] = _get_user_data(registry=_keycloak_registry,
|
|
304
|
-
user_id=user_id,
|
|
305
|
-
logger=logger)
|
|
306
|
-
# set the OAuth2 scope
|
|
307
|
-
user_data["oauth-scope"] = scope
|
|
308
|
-
if logger:
|
|
309
|
-
logger.debug(msg=f"Scope for user '{user_id}' set to '{scope}'")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|