digitalhub 0.13.0b4__py3-none-any.whl → 0.14.0b1__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 digitalhub might be problematic. Click here for more details.
- digitalhub/__init__.py +3 -8
- digitalhub/entities/_base/_base/entity.py +0 -11
- digitalhub/entities/_base/entity/builder.py +5 -5
- digitalhub/entities/_base/executable/entity.py +1 -1
- digitalhub/entities/_base/runtime_entity/builder.py +53 -18
- digitalhub/entities/_commons/utils.py +64 -21
- digitalhub/entities/_processors/base.py +11 -3
- digitalhub/entities/_processors/context.py +71 -22
- digitalhub/entities/_processors/utils.py +3 -3
- digitalhub/entities/artifact/crud.py +20 -4
- digitalhub/entities/artifact/utils.py +1 -1
- digitalhub/entities/dataitem/crud.py +20 -4
- digitalhub/entities/dataitem/table/entity.py +0 -21
- digitalhub/entities/dataitem/utils.py +1 -1
- digitalhub/entities/function/_base/entity.py +1 -1
- digitalhub/entities/function/crud.py +15 -4
- digitalhub/entities/model/_base/entity.py +21 -1
- digitalhub/entities/model/crud.py +21 -5
- digitalhub/entities/model/utils.py +1 -1
- digitalhub/entities/project/_base/entity.py +65 -33
- digitalhub/entities/project/crud.py +8 -1
- digitalhub/entities/run/_base/entity.py +21 -1
- digitalhub/entities/run/crud.py +22 -5
- digitalhub/entities/secret/crud.py +22 -5
- digitalhub/entities/task/crud.py +22 -5
- digitalhub/entities/trigger/crud.py +20 -4
- digitalhub/entities/workflow/_base/entity.py +1 -1
- digitalhub/entities/workflow/crud.py +15 -4
- digitalhub/factory/enums.py +18 -0
- digitalhub/factory/factory.py +136 -57
- digitalhub/factory/utils.py +3 -54
- digitalhub/stores/client/api.py +6 -10
- digitalhub/stores/client/builder.py +3 -3
- digitalhub/stores/client/dhcore/client.py +105 -163
- digitalhub/stores/client/dhcore/configurator.py +92 -289
- digitalhub/stores/client/dhcore/enums.py +0 -16
- digitalhub/stores/client/dhcore/params_builder.py +41 -83
- digitalhub/stores/client/dhcore/utils.py +14 -22
- digitalhub/stores/client/local/client.py +77 -45
- digitalhub/stores/credentials/ini_module.py +0 -16
- digitalhub/stores/data/local/store.py +0 -103
- digitalhub/stores/data/s3/configurator.py +60 -6
- digitalhub/stores/data/s3/store.py +44 -2
- digitalhub/stores/data/sql/store.py +15 -0
- digitalhub/utils/file_utils.py +0 -17
- digitalhub/utils/generic_utils.py +1 -2
- digitalhub/utils/store_utils.py +44 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/METADATA +3 -2
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/RECORD +58 -59
- digitalhub/entities/task/_base/utils.py +0 -22
- digitalhub/stores/client/dhcore/models.py +0 -40
- digitalhub/stores/data/s3/utils.py +0 -78
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/__init__.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/metadata.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/name.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/spec.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/status.py +0 -0
- /digitalhub/entities/{_base/entity/_constructors → _constructors}/uuid.py +0 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/WHEEL +0 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/licenses/AUTHORS +0 -0
- {digitalhub-0.13.0b4.dist-info → digitalhub-0.14.0b1.dist-info}/licenses/LICENSE +0 -0
|
@@ -22,38 +22,22 @@ if typing.TYPE_CHECKING:
|
|
|
22
22
|
|
|
23
23
|
class ClientDHCoreConfigurator(Configurator):
|
|
24
24
|
"""
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Once the credentials are read, the configurator check the current profile
|
|
37
|
-
name from the ini file, and set it. The default one is __default. The
|
|
38
|
-
profile is used to discriminate a set of credentials inside the ini file.
|
|
39
|
-
|
|
40
|
-
The configurator finally set the authentication type based on the credentials.
|
|
41
|
-
The logic is the following:
|
|
42
|
-
|
|
43
|
-
1. Check for a personal access token. Use it immediately to
|
|
44
|
-
require a timed access token in an exchange endpoint.
|
|
45
|
-
Switche then the origin to file and .
|
|
46
|
-
Set the auth type to EXCHANGE.
|
|
47
|
-
2. Check for an access token and a refresh token.
|
|
48
|
-
Set the auth type to OAUTH2.
|
|
49
|
-
3. Check for username and password.
|
|
50
|
-
Set the auth type to BASIC.
|
|
51
|
-
4. If none of the above is true, leave the auth type to None.
|
|
25
|
+
DHCore client configurator for credential management and authentication.
|
|
26
|
+
|
|
27
|
+
Handles loading credentials from environment variables and configuration files,
|
|
28
|
+
evaluates authentication types, and manages token refresh operations. Supports
|
|
29
|
+
multiple authentication methods: EXCHANGE (personal access token), OAUTH2
|
|
30
|
+
(access + refresh tokens), ACCESS_TOKEN (access token only), and BASIC
|
|
31
|
+
(username + password).
|
|
32
|
+
|
|
33
|
+
The configurator automatically determines the best authentication method and
|
|
34
|
+
handles token exchange for personal access tokens by switching to file-based
|
|
35
|
+
credential storage.
|
|
52
36
|
"""
|
|
53
37
|
|
|
54
38
|
keys = [*list_enum(CredsEnvVar)]
|
|
55
39
|
required_keys = [CredsEnvVar.DHCORE_ENDPOINT.value]
|
|
56
|
-
|
|
40
|
+
keys_to_prefix = [
|
|
57
41
|
CredsEnvVar.DHCORE_REFRESH_TOKEN.value,
|
|
58
42
|
CredsEnvVar.DHCORE_ACCESS_TOKEN.value,
|
|
59
43
|
CredsEnvVar.DHCORE_ISSUER.value,
|
|
@@ -62,10 +46,7 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
62
46
|
|
|
63
47
|
def __init__(self) -> None:
|
|
64
48
|
"""
|
|
65
|
-
Initialize
|
|
66
|
-
|
|
67
|
-
Sets up the configurator by calling the parent constructor and
|
|
68
|
-
initializing the authentication type evaluation process.
|
|
49
|
+
Initialize DHCore configurator and evaluate authentication type.
|
|
69
50
|
|
|
70
51
|
Returns
|
|
71
52
|
-------
|
|
@@ -81,20 +62,14 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
81
62
|
|
|
82
63
|
def load_env_vars(self) -> None:
|
|
83
64
|
"""
|
|
84
|
-
Load credentials from environment variables.
|
|
65
|
+
Load and sanitize credentials from environment variables.
|
|
85
66
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
handler for the environment origin.
|
|
67
|
+
Sanitizes endpoint and issuer URLs to ensure proper HTTP/HTTPS schemes
|
|
68
|
+
and removes trailing slashes.
|
|
89
69
|
|
|
90
70
|
Returns
|
|
91
71
|
-------
|
|
92
72
|
None
|
|
93
|
-
|
|
94
|
-
Notes
|
|
95
|
-
-----
|
|
96
|
-
This method sanitizes endpoint and issuer URLs to ensure they have
|
|
97
|
-
proper schemes and removes trailing slashes.
|
|
98
73
|
"""
|
|
99
74
|
env_creds = self._creds_handler.load_from_env(self.keys)
|
|
100
75
|
env_creds = self._sanitize_env_vars(env_creds)
|
|
@@ -102,30 +77,25 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
102
77
|
|
|
103
78
|
def _sanitize_env_vars(self, creds: dict) -> dict:
|
|
104
79
|
"""
|
|
105
|
-
Sanitize
|
|
80
|
+
Sanitize environment variable credentials.
|
|
106
81
|
|
|
107
|
-
Validates and normalizes endpoint and issuer URLs
|
|
108
|
-
|
|
82
|
+
Validates and normalizes endpoint and issuer URLs. Environment variables
|
|
83
|
+
use full "DHCORE_" prefixes.
|
|
109
84
|
|
|
110
85
|
Parameters
|
|
111
86
|
----------
|
|
112
87
|
creds : dict
|
|
113
|
-
Raw credentials
|
|
88
|
+
Raw credentials from environment variables.
|
|
114
89
|
|
|
115
90
|
Returns
|
|
116
91
|
-------
|
|
117
92
|
dict
|
|
118
|
-
Sanitized credentials
|
|
93
|
+
Sanitized credentials with normalized URLs.
|
|
119
94
|
|
|
120
95
|
Raises
|
|
121
96
|
------
|
|
122
97
|
ClientError
|
|
123
98
|
If endpoint or issuer URLs have invalid schemes.
|
|
124
|
-
|
|
125
|
-
Notes
|
|
126
|
-
-----
|
|
127
|
-
Environment variables are expected to have the full "DHCORE_" prefix
|
|
128
|
-
for issuer endpoints.
|
|
129
99
|
"""
|
|
130
100
|
creds[CredsEnvVar.DHCORE_ENDPOINT.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ENDPOINT.value])
|
|
131
101
|
creds[CredsEnvVar.DHCORE_ISSUER.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ISSUER.value])
|
|
@@ -133,112 +103,73 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
133
103
|
|
|
134
104
|
def load_file_vars(self) -> None:
|
|
135
105
|
"""
|
|
136
|
-
Load credentials from configuration file.
|
|
106
|
+
Load credentials from configuration file with CLI compatibility.
|
|
137
107
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
falls back to environment variables for missing endpoint and
|
|
141
|
-
personal access token values.
|
|
108
|
+
Handles keys without "DHCORE_" prefix for CLI compatibility. Falls back
|
|
109
|
+
to environment variables for missing endpoint and personal access token values.
|
|
142
110
|
|
|
143
111
|
Returns
|
|
144
112
|
-------
|
|
145
113
|
None
|
|
146
|
-
|
|
147
|
-
Notes
|
|
148
|
-
-----
|
|
149
|
-
This method handles the case where:
|
|
150
|
-
- Endpoint might not be present in file response, falls back to env
|
|
151
|
-
- Personal access token might not be present, falls back to env
|
|
152
|
-
- File format uses keys without "DHCORE_" prefix for compatibility
|
|
153
114
|
"""
|
|
154
|
-
|
|
155
|
-
file_creds = self._creds_handler.load_from_file(keys)
|
|
156
|
-
env_creds = self._creds_handler.load_from_env(self.keys)
|
|
157
|
-
|
|
158
|
-
# Because in the response there is no endpoint
|
|
159
|
-
if file_creds[CredsEnvVar.DHCORE_ENDPOINT.value] is None:
|
|
160
|
-
file_creds[CredsEnvVar.DHCORE_ENDPOINT.value] = env_creds.get(CredsEnvVar.DHCORE_ENDPOINT.value)
|
|
115
|
+
file_creds = self._creds_handler.load_from_file(self.keys)
|
|
161
116
|
|
|
162
117
|
# Because in the response there is no personal access token
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
)
|
|
118
|
+
pat = CredsEnvVar.DHCORE_PERSONAL_ACCESS_TOKEN.value
|
|
119
|
+
if file_creds[pat] is None:
|
|
120
|
+
file_creds[pat] = self._creds_handler.load_from_env([pat]).get(pat)
|
|
167
121
|
|
|
168
122
|
file_creds = self._sanitize_file_vars(file_creds)
|
|
169
123
|
self._creds_handler.set_credentials(self._file, file_creds)
|
|
170
124
|
|
|
171
125
|
def _sanitize_file_vars(self, creds: dict) -> dict:
|
|
172
126
|
"""
|
|
173
|
-
Sanitize
|
|
127
|
+
Sanitize configuration file credentials.
|
|
174
128
|
|
|
175
|
-
Handles
|
|
176
|
-
|
|
177
|
-
|
|
129
|
+
Handles different key formats between file and environment variables.
|
|
130
|
+
File format omits "DHCORE_" prefix for: issuer, client_id, access_token,
|
|
131
|
+
refresh_token. Full names used for: endpoint, user, password, personal_access_token.
|
|
178
132
|
|
|
179
133
|
Parameters
|
|
180
134
|
----------
|
|
181
135
|
creds : dict
|
|
182
|
-
Raw credentials
|
|
136
|
+
Raw credentials from configuration file.
|
|
183
137
|
|
|
184
138
|
Returns
|
|
185
139
|
-------
|
|
186
140
|
dict
|
|
187
|
-
Sanitized credentials
|
|
188
|
-
and normalized URLs, filtered to include only valid keys.
|
|
141
|
+
Sanitized credentials with standardized keys and normalized URLs.
|
|
189
142
|
|
|
190
143
|
Raises
|
|
191
144
|
------
|
|
192
145
|
ClientError
|
|
193
146
|
If endpoint or issuer URLs have invalid schemes.
|
|
194
|
-
|
|
195
|
-
Notes
|
|
196
|
-
-----
|
|
197
|
-
File format expects these keys without "DHCORE_" prefix:
|
|
198
|
-
- issuer, client_id, access_token, refresh_token
|
|
199
|
-
But uses full names for: endpoint, user, password, personal_access_token
|
|
200
147
|
"""
|
|
201
148
|
creds[CredsEnvVar.DHCORE_ENDPOINT.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ENDPOINT.value])
|
|
202
|
-
creds[CredsEnvVar.DHCORE_ISSUER.value] = self._sanitize_endpoint(
|
|
203
|
-
creds[CredsEnvVar.DHCORE_ISSUER.value.removeprefix("DHCORE_")]
|
|
204
|
-
)
|
|
205
|
-
creds[CredsEnvVar.DHCORE_REFRESH_TOKEN.value] = creds[
|
|
206
|
-
CredsEnvVar.DHCORE_REFRESH_TOKEN.value.removeprefix("DHCORE_")
|
|
207
|
-
]
|
|
208
|
-
creds[CredsEnvVar.DHCORE_ACCESS_TOKEN.value] = creds[
|
|
209
|
-
CredsEnvVar.DHCORE_ACCESS_TOKEN.value.removeprefix("DHCORE_")
|
|
210
|
-
]
|
|
211
|
-
creds[CredsEnvVar.DHCORE_CLIENT_ID.value] = creds[CredsEnvVar.DHCORE_CLIENT_ID.value.removeprefix("DHCORE_")]
|
|
149
|
+
creds[CredsEnvVar.DHCORE_ISSUER.value] = self._sanitize_endpoint(creds[CredsEnvVar.DHCORE_ISSUER.value])
|
|
212
150
|
return {k: v for k, v in creds.items() if k in self.keys}
|
|
213
151
|
|
|
214
152
|
@staticmethod
|
|
215
153
|
def _sanitize_endpoint(endpoint: str | None = None) -> str | None:
|
|
216
154
|
"""
|
|
217
|
-
|
|
155
|
+
Validate and normalize endpoint URL.
|
|
218
156
|
|
|
219
|
-
|
|
220
|
-
trims whitespace, and removes trailing slashes for consistency.
|
|
157
|
+
Ensures proper HTTP/HTTPS scheme, trims whitespace, and removes trailing slashes.
|
|
221
158
|
|
|
222
159
|
Parameters
|
|
223
160
|
----------
|
|
224
161
|
endpoint : str, optional
|
|
225
|
-
|
|
162
|
+
Endpoint URL to sanitize.
|
|
226
163
|
|
|
227
164
|
Returns
|
|
228
165
|
-------
|
|
229
166
|
str or None
|
|
230
|
-
|
|
231
|
-
or None if input was None.
|
|
167
|
+
Sanitized URL or None if input was None.
|
|
232
168
|
|
|
233
169
|
Raises
|
|
234
170
|
------
|
|
235
171
|
ClientError
|
|
236
|
-
If
|
|
237
|
-
|
|
238
|
-
Notes
|
|
239
|
-
-----
|
|
240
|
-
This method ensures endpoint URLs are properly formatted for
|
|
241
|
-
HTTP requests and prevents common URL formatting issues.
|
|
172
|
+
If endpoint lacks http:// or https:// scheme.
|
|
242
173
|
"""
|
|
243
174
|
if endpoint is None:
|
|
244
175
|
return
|
|
@@ -252,23 +183,17 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
252
183
|
"""
|
|
253
184
|
Get the configured DHCore backend endpoint.
|
|
254
185
|
|
|
255
|
-
|
|
256
|
-
(environment or file based on current origin).
|
|
186
|
+
Returns the sanitized and validated endpoint URL from current credential source.
|
|
257
187
|
|
|
258
188
|
Returns
|
|
259
189
|
-------
|
|
260
190
|
str
|
|
261
|
-
|
|
191
|
+
DHCore backend endpoint URL.
|
|
262
192
|
|
|
263
193
|
Raises
|
|
264
194
|
------
|
|
265
195
|
KeyError
|
|
266
|
-
If
|
|
267
|
-
|
|
268
|
-
Notes
|
|
269
|
-
-----
|
|
270
|
-
The endpoint returned is already sanitized and validated during
|
|
271
|
-
the credential loading process.
|
|
196
|
+
If endpoint not configured in current credential source.
|
|
272
197
|
"""
|
|
273
198
|
creds = self._creds_handler.get_credentials(self._origin)
|
|
274
199
|
return creds[CredsEnvVar.DHCORE_ENDPOINT.value]
|
|
@@ -279,22 +204,14 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
279
204
|
|
|
280
205
|
def change_origin(self) -> None:
|
|
281
206
|
"""
|
|
282
|
-
|
|
207
|
+
Switch credential source and re-evaluate authentication type.
|
|
283
208
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
This is typically called when the current credential source fails
|
|
287
|
-
or when switching contexts.
|
|
209
|
+
Changes between environment and file credential sources, then re-evaluates
|
|
210
|
+
authentication type based on the new credentials.
|
|
288
211
|
|
|
289
212
|
Returns
|
|
290
213
|
-------
|
|
291
214
|
None
|
|
292
|
-
|
|
293
|
-
Notes
|
|
294
|
-
-----
|
|
295
|
-
This method extends the parent class behavior by also re-evaluating
|
|
296
|
-
the authentication type, which may change based on different
|
|
297
|
-
credentials available in the new source.
|
|
298
215
|
"""
|
|
299
216
|
super().change_origin()
|
|
300
217
|
|
|
@@ -307,29 +224,16 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
307
224
|
|
|
308
225
|
def set_auth_type(self) -> None:
|
|
309
226
|
"""
|
|
310
|
-
|
|
227
|
+
Determine authentication type from available credentials.
|
|
311
228
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
3. ACCESS_TOKEN - Only access token available
|
|
317
|
-
4. BASIC - Username and password available
|
|
318
|
-
5. None - No valid credentials found
|
|
319
|
-
|
|
320
|
-
For EXCHANGE authentication, automatically performs token exchange
|
|
321
|
-
and switches to file-based credential storage.
|
|
229
|
+
Evaluates credentials in priority order: EXCHANGE (personal access token),
|
|
230
|
+
OAUTH2 (access + refresh tokens), ACCESS_TOKEN (access only), BASIC
|
|
231
|
+
(username + password). For EXCHANGE type, automatically exchanges the
|
|
232
|
+
personal access token and switches to file-based credentials storage.
|
|
322
233
|
|
|
323
234
|
Returns
|
|
324
235
|
-------
|
|
325
236
|
None
|
|
326
|
-
|
|
327
|
-
Notes
|
|
328
|
-
-----
|
|
329
|
-
When EXCHANGE authentication is detected, this method automatically:
|
|
330
|
-
- Performs credential refresh to exchange the personal access token
|
|
331
|
-
- Changes origin to file-based storage for the new tokens
|
|
332
|
-
- Updates the authentication type accordingly
|
|
333
237
|
"""
|
|
334
238
|
creds = creds_handler.get_credentials(self._origin)
|
|
335
239
|
self._auth_type = self._eval_auth_type(creds)
|
|
@@ -343,55 +247,34 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
343
247
|
|
|
344
248
|
def refreshable_auth_types(self) -> bool:
|
|
345
249
|
"""
|
|
346
|
-
Check if
|
|
250
|
+
Check if current authentication supports token refresh.
|
|
347
251
|
|
|
348
|
-
|
|
349
|
-
|
|
252
|
+
Returns True for OAUTH2 (refresh token) and EXCHANGE (personal access token),
|
|
253
|
+
False for BASIC and ACCESS_TOKEN.
|
|
350
254
|
|
|
351
255
|
Returns
|
|
352
256
|
-------
|
|
353
257
|
bool
|
|
354
|
-
|
|
355
|
-
False otherwise (BASIC or ACCESS_TOKEN).
|
|
356
|
-
|
|
357
|
-
Notes
|
|
358
|
-
-----
|
|
359
|
-
Only OAUTH2 and EXCHANGE authentication types support refresh:
|
|
360
|
-
- OAUTH2: Uses refresh token to get new access tokens
|
|
361
|
-
- EXCHANGE: Uses personal access token for token exchange
|
|
362
|
-
- BASIC and ACCESS_TOKEN do not support refresh
|
|
258
|
+
Whether authentication type supports refresh.
|
|
363
259
|
"""
|
|
364
260
|
return self._auth_type in [AuthType.OAUTH2.value, AuthType.EXCHANGE.value]
|
|
365
261
|
|
|
366
262
|
def get_auth_parameters(self, kwargs: dict) -> dict:
|
|
367
263
|
"""
|
|
368
|
-
Add authentication parameters to HTTP request
|
|
264
|
+
Add authentication headers/parameters to HTTP request kwargs.
|
|
369
265
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
type and available credentials.
|
|
266
|
+
Adds Authorization Bearer header for token-based auth or auth tuple
|
|
267
|
+
for basic authentication.
|
|
373
268
|
|
|
374
269
|
Parameters
|
|
375
270
|
----------
|
|
376
271
|
kwargs : dict
|
|
377
|
-
HTTP request
|
|
272
|
+
HTTP request arguments to modify.
|
|
378
273
|
|
|
379
274
|
Returns
|
|
380
275
|
-------
|
|
381
276
|
dict
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
Notes
|
|
385
|
-
-----
|
|
386
|
-
Authentication is added based on auth type:
|
|
387
|
-
- OAUTH2/EXCHANGE/ACCESS_TOKEN: Adds Authorization Bearer header
|
|
388
|
-
- BASIC: Adds auth tuple with username/password
|
|
389
|
-
- None: No authentication added
|
|
390
|
-
|
|
391
|
-
The method assumes that:
|
|
392
|
-
- Authentication type has been properly set
|
|
393
|
-
- For EXCHANGE type, refresh token has been obtained
|
|
394
|
-
- Required credentials are available for the current auth type
|
|
277
|
+
Modified kwargs with authentication parameters.
|
|
395
278
|
"""
|
|
396
279
|
creds = creds_handler.get_credentials(self._origin)
|
|
397
280
|
if self._auth_type in (
|
|
@@ -411,18 +294,16 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
411
294
|
|
|
412
295
|
def refresh_credentials(self, change_origin: bool = False) -> None:
|
|
413
296
|
"""
|
|
414
|
-
Refresh authentication
|
|
297
|
+
Refresh authentication tokens using OAuth2 flows.
|
|
415
298
|
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
299
|
+
Uses refresh_token grant for OAUTH2 or token exchange for EXCHANGE authentication.
|
|
300
|
+
On 400/401/403 errors with change_origin=True, attempts to switch credential
|
|
301
|
+
sources and retry. Saves new credentials to configuration file.
|
|
419
302
|
|
|
420
303
|
Parameters
|
|
421
304
|
----------
|
|
422
305
|
change_origin : bool, default False
|
|
423
|
-
Whether to
|
|
424
|
-
If True and refresh fails, attempts to switch credential sources
|
|
425
|
-
and retry once.
|
|
306
|
+
Whether to switch credential sources on auth failure.
|
|
426
307
|
|
|
427
308
|
Returns
|
|
428
309
|
-------
|
|
@@ -431,21 +312,7 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
431
312
|
Raises
|
|
432
313
|
------
|
|
433
314
|
ClientError
|
|
434
|
-
If
|
|
435
|
-
credentials are missing, or if refresh fails and change_origin
|
|
436
|
-
is False.
|
|
437
|
-
|
|
438
|
-
Notes
|
|
439
|
-
-----
|
|
440
|
-
Refresh behavior by authentication type:
|
|
441
|
-
- OAUTH2: Uses refresh_token grant to get new access/refresh tokens
|
|
442
|
-
- EXCHANGE: Uses token exchange with personal access token
|
|
443
|
-
|
|
444
|
-
If refresh fails with 400/401/403 status and change_origin=True,
|
|
445
|
-
attempts to switch credential sources and retry once.
|
|
446
|
-
|
|
447
|
-
New credentials are automatically saved to the configuration file
|
|
448
|
-
and the origin is switched to file-based storage.
|
|
315
|
+
If auth type doesn't support refresh or credentials missing.
|
|
449
316
|
"""
|
|
450
317
|
if not self.refreshable_auth_types():
|
|
451
318
|
raise ClientError(f"Auth type {self._auth_type} does not support refresh.")
|
|
@@ -491,64 +358,26 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
491
358
|
# Read new credentials and propagate to config file
|
|
492
359
|
self._export_new_creds(response.json())
|
|
493
360
|
|
|
494
|
-
def _remove_prefix_dhcore(self) -> list[str]:
|
|
495
|
-
"""
|
|
496
|
-
Remove DHCORE_ prefix from selected credential keys for CLI compatibility.
|
|
497
|
-
|
|
498
|
-
Creates a list of credential key names with "DHCORE_" prefix removed
|
|
499
|
-
from specific keys that are stored without the prefix in configuration
|
|
500
|
-
files for compatibility with CLI tools.
|
|
501
|
-
|
|
502
|
-
Returns
|
|
503
|
-
-------
|
|
504
|
-
list[str]
|
|
505
|
-
List of credential keys with selective prefix removal applied.
|
|
506
|
-
|
|
507
|
-
Notes
|
|
508
|
-
-----
|
|
509
|
-
Keys that have prefix removed (defined in keys_to_unprefix):
|
|
510
|
-
- DHCORE_REFRESH_TOKEN -> refresh_token
|
|
511
|
-
- DHCORE_ACCESS_TOKEN -> access_token
|
|
512
|
-
- DHCORE_ISSUER -> issuer
|
|
513
|
-
- DHCORE_CLIENT_ID -> client_id
|
|
514
|
-
|
|
515
|
-
Other keys retain their full names for consistency.
|
|
516
|
-
"""
|
|
517
|
-
new_list = []
|
|
518
|
-
for key in self.keys:
|
|
519
|
-
if key in self.keys_to_unprefix:
|
|
520
|
-
new_list.append(key.removeprefix("DHCORE_"))
|
|
521
|
-
else:
|
|
522
|
-
new_list.append(key)
|
|
523
|
-
return new_list
|
|
524
|
-
|
|
525
361
|
def _get_refresh_endpoint(self) -> str:
|
|
526
362
|
"""
|
|
527
|
-
Discover
|
|
363
|
+
Discover OAuth2 token endpoint from issuer well-known configuration.
|
|
528
364
|
|
|
529
|
-
Queries
|
|
530
|
-
|
|
365
|
+
Queries /.well-known/openid-configuration to extract token_endpoint for
|
|
366
|
+
credential refresh operations.
|
|
531
367
|
|
|
532
368
|
Returns
|
|
533
369
|
-------
|
|
534
370
|
str
|
|
535
|
-
|
|
371
|
+
Token endpoint URL for credential refresh.
|
|
536
372
|
|
|
537
373
|
Raises
|
|
538
374
|
------
|
|
539
375
|
ClientError
|
|
540
|
-
If
|
|
376
|
+
If issuer endpoint not configured.
|
|
541
377
|
HTTPError
|
|
542
|
-
If
|
|
378
|
+
If well-known configuration endpoint inaccessible.
|
|
543
379
|
KeyError
|
|
544
|
-
If
|
|
545
|
-
|
|
546
|
-
Notes
|
|
547
|
-
-----
|
|
548
|
-
This method follows the OAuth2/OpenID Connect discovery standard by:
|
|
549
|
-
1. Accessing the issuer's /.well-known/openid-configuration endpoint
|
|
550
|
-
2. Extracting the token_endpoint from the configuration
|
|
551
|
-
3. Using this endpoint for subsequent token refresh operations
|
|
380
|
+
If token_endpoint not found in issuer configuration.
|
|
552
381
|
"""
|
|
553
382
|
# Get issuer endpoint
|
|
554
383
|
creds = self._creds_handler.get_credentials(self._origin)
|
|
@@ -570,30 +399,22 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
570
399
|
**kwargs,
|
|
571
400
|
) -> Response:
|
|
572
401
|
"""
|
|
573
|
-
Make
|
|
402
|
+
Make OAuth2 token refresh request.
|
|
574
403
|
|
|
575
|
-
|
|
576
|
-
|
|
404
|
+
Sends POST request with form-encoded payload using required OAuth2
|
|
405
|
+
content type and 60-second timeout.
|
|
577
406
|
|
|
578
407
|
Parameters
|
|
579
408
|
----------
|
|
580
409
|
url : str
|
|
581
|
-
|
|
410
|
+
Token endpoint URL.
|
|
582
411
|
**kwargs : dict
|
|
583
|
-
Token request parameters
|
|
584
|
-
refresh_token, subject_token, etc.
|
|
412
|
+
Token request parameters (grant_type, client_id, etc.).
|
|
585
413
|
|
|
586
414
|
Returns
|
|
587
415
|
-------
|
|
588
416
|
Response
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
Notes
|
|
592
|
-
-----
|
|
593
|
-
This method:
|
|
594
|
-
- Uses application/x-www-form-urlencoded content type as required by OAuth2
|
|
595
|
-
- Sets a 60-second timeout for the request
|
|
596
|
-
- Returns the raw response for caller to handle status and parsing
|
|
417
|
+
Raw HTTP response for caller handling.
|
|
597
418
|
"""
|
|
598
419
|
# Send request to get new access token
|
|
599
420
|
payload = {**kwargs}
|
|
@@ -602,30 +423,20 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
602
423
|
|
|
603
424
|
def _eval_auth_type(self, creds: dict) -> str | None:
|
|
604
425
|
"""
|
|
605
|
-
|
|
426
|
+
Determine authentication type from available credentials.
|
|
606
427
|
|
|
607
|
-
|
|
608
|
-
|
|
428
|
+
Evaluates in priority order: EXCHANGE (personal access token), OAUTH2
|
|
429
|
+
(access + refresh tokens), ACCESS_TOKEN (access only), BASIC (username + password).
|
|
609
430
|
|
|
610
431
|
Parameters
|
|
611
432
|
----------
|
|
612
433
|
creds : dict
|
|
613
|
-
|
|
434
|
+
Available credential values.
|
|
614
435
|
|
|
615
436
|
Returns
|
|
616
437
|
-------
|
|
617
438
|
str or None
|
|
618
|
-
|
|
619
|
-
if no valid authentication method can be determined.
|
|
620
|
-
|
|
621
|
-
Notes
|
|
622
|
-
-----
|
|
623
|
-
Authentication type priority (checked in order):
|
|
624
|
-
1. EXCHANGE - Personal access token is available
|
|
625
|
-
2. OAUTH2 - Both access token and refresh token are available
|
|
626
|
-
3. ACCESS_TOKEN - Only access token is available
|
|
627
|
-
4. BASIC - Both username and password are available
|
|
628
|
-
5. None - No valid credential combination found
|
|
439
|
+
Authentication type from AuthType enum, or None if no valid credentials.
|
|
629
440
|
"""
|
|
630
441
|
if creds[CredsEnvVar.DHCORE_PERSONAL_ACCESS_TOKEN.value] is not None:
|
|
631
442
|
return AuthType.EXCHANGE.value
|
|
@@ -642,32 +453,24 @@ class ClientDHCoreConfigurator(Configurator):
|
|
|
642
453
|
|
|
643
454
|
def _export_new_creds(self, response: dict) -> None:
|
|
644
455
|
"""
|
|
645
|
-
Save
|
|
456
|
+
Save refreshed credentials and switch to file-based storage.
|
|
646
457
|
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
reloads file-based credentials and switches to file origin.
|
|
458
|
+
Persists new tokens (access_token, refresh_token, etc.) to configuration
|
|
459
|
+
file and switches credential origin to file storage.
|
|
650
460
|
|
|
651
461
|
Parameters
|
|
652
462
|
----------
|
|
653
463
|
response : dict
|
|
654
|
-
|
|
655
|
-
and other credential information.
|
|
464
|
+
OAuth2 token response with new credentials.
|
|
656
465
|
|
|
657
466
|
Returns
|
|
658
467
|
-------
|
|
659
468
|
None
|
|
660
|
-
|
|
661
|
-
Notes
|
|
662
|
-
-----
|
|
663
|
-
This method:
|
|
664
|
-
1. Writes new credentials to the configuration file
|
|
665
|
-
2. Reloads file-based credentials to ensure consistency
|
|
666
|
-
3. Changes current origin to file since new tokens are file-based
|
|
667
|
-
|
|
668
|
-
The response typically contains access_token, refresh_token,
|
|
669
|
-
token_type, expires_in, and other OAuth2 standard fields.
|
|
670
469
|
"""
|
|
470
|
+
for key in self.keys_to_prefix:
|
|
471
|
+
key = key.lower()
|
|
472
|
+
if key.removeprefix("dhcore_") in response:
|
|
473
|
+
response[key] = response.pop(key.removeprefix("dhcore_"))
|
|
671
474
|
creds_handler.write_env(response)
|
|
672
475
|
self.load_file_vars()
|
|
673
476
|
|
|
@@ -7,22 +7,6 @@ from __future__ import annotations
|
|
|
7
7
|
from enum import Enum
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class DhcoreEnvVar(Enum):
|
|
11
|
-
"""
|
|
12
|
-
Environment variables.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
ENDPOINT = "DHCORE_ENDPOINT"
|
|
16
|
-
ISSUER = "DHCORE_ISSUER"
|
|
17
|
-
USER = "DHCORE_USER"
|
|
18
|
-
PASSWORD = "DHCORE_PASSWORD"
|
|
19
|
-
CLIENT_ID = "DHCORE_CLIENT_ID"
|
|
20
|
-
ACCESS_TOKEN = "DHCORE_ACCESS_TOKEN"
|
|
21
|
-
REFRESH_TOKEN = "DHCORE_REFRESH_TOKEN"
|
|
22
|
-
PERSONAL_ACCESS_TOKEN = "DHCORE_PERSONAL_ACCESS_TOKEN"
|
|
23
|
-
WORKFLOW_IMAGE = "DHCORE_WORKFLOW_IMAGE"
|
|
24
|
-
|
|
25
|
-
|
|
26
10
|
class AuthType(Enum):
|
|
27
11
|
"""
|
|
28
12
|
Authentication types.
|