dara-core 1.23.0__py3-none-any.whl → 1.23.0a1__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.
- dara/core/auth/definitions.py +0 -4
- dara/core/auth/oidc/config.py +17 -80
- dara/core/auth/oidc/routes.py +1 -6
- dara/core/auth/oidc/settings.py +0 -2
- {dara_core-1.23.0.dist-info → dara_core-1.23.0a1.dist-info}/METADATA +10 -10
- {dara_core-1.23.0.dist-info → dara_core-1.23.0a1.dist-info}/RECORD +9 -9
- {dara_core-1.23.0.dist-info → dara_core-1.23.0a1.dist-info}/LICENSE +0 -0
- {dara_core-1.23.0.dist-info → dara_core-1.23.0a1.dist-info}/WHEEL +0 -0
- {dara_core-1.23.0.dist-info → dara_core-1.23.0a1.dist-info}/entry_points.txt +0 -0
dara/core/auth/definitions.py
CHANGED
|
@@ -18,7 +18,6 @@ limitations under the License.
|
|
|
18
18
|
from contextvars import ContextVar
|
|
19
19
|
from datetime import datetime
|
|
20
20
|
|
|
21
|
-
from pydantic import ConfigDict
|
|
22
21
|
from typing_extensions import TypedDict
|
|
23
22
|
|
|
24
23
|
from dara.core.base_definitions import DaraBaseModel as BaseModel
|
|
@@ -61,9 +60,6 @@ class UserData(BaseModel):
|
|
|
61
60
|
identity_email: str | None = None
|
|
62
61
|
groups: list[str] | None = []
|
|
63
62
|
|
|
64
|
-
# allow extra for more flexibility in custom oidc configs
|
|
65
|
-
model_config = ConfigDict(extra='allow')
|
|
66
|
-
|
|
67
63
|
@classmethod
|
|
68
64
|
def from_token_data(cls, token_data: TokenData):
|
|
69
65
|
return cls(
|
dara/core/auth/oidc/config.py
CHANGED
|
@@ -65,7 +65,6 @@ class OIDCAuthConfig(BaseAuthConfig):
|
|
|
65
65
|
- SSO_EXTRA_AUDIENCE - if set, extra audiences to verify against the ID token in addition to `sso_client_id`
|
|
66
66
|
- SSO_SCOPES - space-separated list of scopes to request from the identity provider, defaults to `openid`
|
|
67
67
|
- SSO_JWT_ALGO - algorithm to use for verifying IDP-provided JWTs, defaults to `ES256`
|
|
68
|
-
- SSO_USE_USERINFO - if set to `true`, fetch additional claims from the userinfo endpoint when an access token is available
|
|
69
68
|
"""
|
|
70
69
|
|
|
71
70
|
# NOTE: the config follows OIDC specification, but makes a few concessions
|
|
@@ -210,84 +209,29 @@ class OIDCAuthConfig(BaseAuthConfig):
|
|
|
210
209
|
state = self.generate_state(redirect_to=body.redirect_to)
|
|
211
210
|
return RedirectResponse(redirect_uri=self.get_authorization_url(state))
|
|
212
211
|
|
|
213
|
-
|
|
212
|
+
def extract_user_data_from_id_token(self, claims: IdTokenClaims) -> UserData:
|
|
214
213
|
"""
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
Per OpenID Connect Core 1.0 Section 5.3, the userinfo endpoint returns claims
|
|
218
|
-
about the authenticated user. This is useful when the ID token doesn't contain
|
|
219
|
-
all required claims.
|
|
220
|
-
|
|
221
|
-
:param access_token: The access token to authenticate the request
|
|
222
|
-
:return: Dictionary of userinfo claims, or None if the request fails
|
|
223
|
-
"""
|
|
224
|
-
userinfo_endpoint = self.discovery.userinfo_endpoint
|
|
225
|
-
if not userinfo_endpoint:
|
|
226
|
-
dev_logger.warning('Userinfo endpoint not available in OIDC discovery')
|
|
227
|
-
return None
|
|
228
|
-
|
|
229
|
-
try:
|
|
230
|
-
response = await self.client.get(
|
|
231
|
-
userinfo_endpoint,
|
|
232
|
-
headers={'Authorization': f'Bearer {access_token}'},
|
|
233
|
-
timeout=10,
|
|
234
|
-
)
|
|
235
|
-
response.raise_for_status()
|
|
236
|
-
return response.json()
|
|
237
|
-
except httpx.HTTPStatusError as e:
|
|
238
|
-
dev_logger.warning(
|
|
239
|
-
f'Failed to fetch userinfo: HTTP {e.response.status_code}',
|
|
240
|
-
)
|
|
241
|
-
return None
|
|
242
|
-
except httpx.RequestError as e:
|
|
243
|
-
dev_logger.warning(f'Failed to fetch userinfo: {e}')
|
|
244
|
-
return None
|
|
245
|
-
|
|
246
|
-
def extract_user_data(self, claims: IdTokenClaims, userinfo: dict | None = None) -> UserData:
|
|
247
|
-
"""
|
|
248
|
-
Extract user data from ID token claims and optional userinfo response.
|
|
214
|
+
Extract user data from ID token claims.
|
|
249
215
|
|
|
250
216
|
Override this method in subclasses to handle provider-specific claim structures.
|
|
251
217
|
The default implementation uses standard OIDC claims, with support for the
|
|
252
|
-
non-standard 'identity' claim.
|
|
253
|
-
is enabled, userinfo claims take precedence over ID token claims.
|
|
218
|
+
non-standard 'identity' claim.
|
|
254
219
|
|
|
255
220
|
:param claims: Decoded ID token claims
|
|
256
|
-
:param userinfo: Optional userinfo response from the userinfo endpoint
|
|
257
221
|
:return: UserData extracted from the claims
|
|
258
222
|
"""
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
identity_email =
|
|
266
|
-
identity_name = (
|
|
267
|
-
userinfo.get('name')
|
|
268
|
-
or userinfo.get('preferred_username')
|
|
269
|
-
or userinfo.get('nickname')
|
|
270
|
-
or (
|
|
271
|
-
f'{userinfo.get("given_name", "")} {userinfo.get("family_name", "")}'.strip()
|
|
272
|
-
if userinfo.get('given_name') or userinfo.get('family_name')
|
|
273
|
-
else None
|
|
274
|
-
)
|
|
275
|
-
)
|
|
276
|
-
groups = userinfo.get('groups') or claims.groups
|
|
223
|
+
# Check for non-standard 'identity' claim (Causalens IDP)
|
|
224
|
+
# This is a nested object with id, name, email fields
|
|
225
|
+
identity_claim = getattr(claims, 'identity', None)
|
|
226
|
+
if isinstance(identity_claim, dict):
|
|
227
|
+
identity_id = identity_claim.get('id') or claims.sub
|
|
228
|
+
identity_name = identity_claim.get('name')
|
|
229
|
+
identity_email = identity_claim.get('email') or claims.email
|
|
277
230
|
else:
|
|
278
|
-
#
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
identity_id = identity_claim.get('id') or claims.sub
|
|
283
|
-
identity_name = identity_claim.get('name')
|
|
284
|
-
identity_email = identity_claim.get('email') or claims.email
|
|
285
|
-
else:
|
|
286
|
-
# Standard OIDC: use 'sub' as the identity ID
|
|
287
|
-
identity_id = claims.sub
|
|
288
|
-
identity_email = claims.email
|
|
289
|
-
identity_name = None
|
|
290
|
-
groups = claims.groups
|
|
231
|
+
# Standard OIDC: use 'sub' as the identity ID
|
|
232
|
+
identity_id = claims.sub
|
|
233
|
+
identity_email = claims.email
|
|
234
|
+
identity_name = None
|
|
291
235
|
|
|
292
236
|
# Fall back to standard claims for name if not set
|
|
293
237
|
if not identity_name:
|
|
@@ -308,7 +252,7 @@ class OIDCAuthConfig(BaseAuthConfig):
|
|
|
308
252
|
identity_id=identity_id,
|
|
309
253
|
identity_name=identity_name,
|
|
310
254
|
identity_email=identity_email,
|
|
311
|
-
groups=groups,
|
|
255
|
+
groups=claims.groups,
|
|
312
256
|
)
|
|
313
257
|
|
|
314
258
|
def verify_token(self, token: str) -> TokenData:
|
|
@@ -347,7 +291,7 @@ class OIDCAuthConfig(BaseAuthConfig):
|
|
|
347
291
|
claims = decode_id_token(token)
|
|
348
292
|
|
|
349
293
|
# Extract user data (can be overridden for provider-specific claim structures)
|
|
350
|
-
user_data = self.
|
|
294
|
+
user_data = self.extract_user_data_from_id_token(claims)
|
|
351
295
|
|
|
352
296
|
# Verify user has access based on groups
|
|
353
297
|
self.verify_user_access(user_data)
|
|
@@ -446,8 +390,6 @@ class OIDCAuthConfig(BaseAuthConfig):
|
|
|
446
390
|
:return: Tuple of (new_session_token, new_refresh_token)
|
|
447
391
|
:raises HTTPException: If the refresh fails
|
|
448
392
|
"""
|
|
449
|
-
oidc_settings = get_oidc_settings()
|
|
450
|
-
|
|
451
393
|
# Request new tokens from the IDP
|
|
452
394
|
oidc_tokens = await get_token_from_idp(
|
|
453
395
|
self,
|
|
@@ -464,13 +406,8 @@ class OIDCAuthConfig(BaseAuthConfig):
|
|
|
464
406
|
# Decode and verify the new ID token
|
|
465
407
|
claims = decode_id_token(oidc_tokens.id_token)
|
|
466
408
|
|
|
467
|
-
# Fetch userinfo if enabled and we have an access token
|
|
468
|
-
userinfo = None
|
|
469
|
-
if oidc_settings.use_userinfo and oidc_tokens.access_token:
|
|
470
|
-
userinfo = await self.fetch_userinfo(oidc_tokens.access_token)
|
|
471
|
-
|
|
472
409
|
# Extract user data from claims
|
|
473
|
-
user_data = self.
|
|
410
|
+
user_data = self.extract_user_data_from_id_token(claims)
|
|
474
411
|
|
|
475
412
|
# Verify user still has access
|
|
476
413
|
self.verify_user_access(user_data)
|
dara/core/auth/oidc/routes.py
CHANGED
|
@@ -100,13 +100,8 @@ async def sso_callback(
|
|
|
100
100
|
# Decode and verify the ID token
|
|
101
101
|
claims = decode_id_token(oidc_tokens.id_token)
|
|
102
102
|
|
|
103
|
-
# Fetch userinfo if enabled and we have an access token
|
|
104
|
-
userinfo = None
|
|
105
|
-
if oidc_settings.use_userinfo and oidc_tokens.access_token:
|
|
106
|
-
userinfo = await auth_config.fetch_userinfo(oidc_tokens.access_token)
|
|
107
|
-
|
|
108
103
|
# Extract user data from claims (handles both standard OIDC and Causalens identity claim)
|
|
109
|
-
user_data = auth_config.
|
|
104
|
+
user_data = auth_config.extract_user_data_from_id_token(claims)
|
|
110
105
|
|
|
111
106
|
# Verify user has access based on groups
|
|
112
107
|
auth_config.verify_user_access(user_data)
|
dara/core/auth/oidc/settings.py
CHANGED
|
@@ -24,8 +24,6 @@ class OIDCSettings(BaseSettings):
|
|
|
24
24
|
verify_audience: bool = False
|
|
25
25
|
extra_audience: list[str] | None = None
|
|
26
26
|
allowed_identity_id: str | None = None
|
|
27
|
-
use_userinfo: bool = False
|
|
28
|
-
"""If True, fetch additional claims from the userinfo endpoint when an access token is available."""
|
|
29
27
|
|
|
30
28
|
model_config = SettingsConfigDict(env_file='.env', extra='allow', env_prefix='sso_')
|
|
31
29
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: dara-core
|
|
3
|
-
Version: 1.23.
|
|
3
|
+
Version: 1.23.0a1
|
|
4
4
|
Summary: Dara Framework Core
|
|
5
5
|
Home-page: https://dara.causalens.com/
|
|
6
6
|
License: Apache-2.0
|
|
@@ -21,10 +21,10 @@ Requires-Dist: cachetools (>=5.0.0)
|
|
|
21
21
|
Requires-Dist: certifi (>=2024.7.4)
|
|
22
22
|
Requires-Dist: click (>=8.1.3,<9.0.0)
|
|
23
23
|
Requires-Dist: colorama (>=0.4.6,<0.5.0)
|
|
24
|
-
Requires-Dist: create-dara-app (==1.23.0)
|
|
24
|
+
Requires-Dist: create-dara-app (==1.23.0-alpha.1)
|
|
25
25
|
Requires-Dist: croniter (>=6.0.0,<7.0.0)
|
|
26
26
|
Requires-Dist: cryptography (>=42.0.4)
|
|
27
|
-
Requires-Dist: dara-components (==1.23.0) ; extra == "all"
|
|
27
|
+
Requires-Dist: dara-components (==1.23.0-alpha.1) ; extra == "all"
|
|
28
28
|
Requires-Dist: exceptiongroup (>=1.1.3,<2.0.0)
|
|
29
29
|
Requires-Dist: fastapi (>=0.115.0,<0.121.0)
|
|
30
30
|
Requires-Dist: fastapi_vite_dara (==0.4.0)
|
|
@@ -55,7 +55,7 @@ Description-Content-Type: text/markdown
|
|
|
55
55
|
|
|
56
56
|
# Dara Application Framework
|
|
57
57
|
|
|
58
|
-
<img src="https://github.com/causalens/dara/blob/v1.23.0/img/dara_light.svg?raw=true">
|
|
58
|
+
<img src="https://github.com/causalens/dara/blob/v1.23.0-alpha.1/img/dara_light.svg?raw=true">
|
|
59
59
|
|
|
60
60
|

|
|
61
61
|
[](https://www.apache.org/licenses/LICENSE-2.0)
|
|
@@ -100,7 +100,7 @@ source .venv/bin/activate
|
|
|
100
100
|
dara start
|
|
101
101
|
```
|
|
102
102
|
|
|
103
|
-

|
|
103
|
+

|
|
104
104
|
|
|
105
105
|
Note: `pip` installation uses [PEP 660](https://peps.python.org/pep-0660/) `pyproject.toml`-based editable installs which require `pip >= 21.3` and `setuptools >= 64.0.0`. You can upgrade both with:
|
|
106
106
|
|
|
@@ -117,9 +117,9 @@ Explore some of our favorite apps - a great way of getting started and getting t
|
|
|
117
117
|
|
|
118
118
|
| Dara App | Description |
|
|
119
119
|
| -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
120
|
-
|  | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
|
|
121
|
-
|  | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
|
|
122
|
-
|  | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
|
|
120
|
+
|  | Demonstrates how to use incorporate a LLM chat box into your decision app to understand model insights |
|
|
121
|
+
|  | Demonstrates how to enable the user to interact with plots, trigger actions based on clicks, mouse movements and other interactions with `Bokeh` or `Plotly` plots |
|
|
122
|
+
|  | Demonstrates how to use the `CausalGraphViewer` component to display your graphs or networks, customising the displayed information through colors and tooltips, and updating the page based on user interaction. |
|
|
123
123
|
|
|
124
124
|
Check out our [App Gallery](https://dara.causalens.com/gallery) for more inspiration!
|
|
125
125
|
|
|
@@ -146,9 +146,9 @@ And the supporting UI packages and tools.
|
|
|
146
146
|
- `ui-utils` - miscellaneous utility functions
|
|
147
147
|
- `ui-widgets` - widget components
|
|
148
148
|
|
|
149
|
-
More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.23.0/CONTRIBUTING.md) file.
|
|
149
|
+
More information on the repository structure can be found in the [CONTRIBUTING.md](https://github.com/causalens/dara/blob/v1.23.0-alpha.1/CONTRIBUTING.md) file.
|
|
150
150
|
|
|
151
151
|
## License
|
|
152
152
|
|
|
153
|
-
Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.23.0/LICENSE).
|
|
153
|
+
Dara is open-source and licensed under the [Apache 2.0 License](https://github.com/causalens/dara/blob/v1.23.0-alpha.1/LICENSE).
|
|
154
154
|
|
|
@@ -12,12 +12,12 @@ dara/core/actions.py,sha256=rC5Tu79AFNWMv0CJuchBnoy6pETIFh_1RTSqxrolArI,947
|
|
|
12
12
|
dara/core/auth/__init__.py,sha256=HJoYIVPzbpwzN_RUHjGpSJj4o5TmHz9yFyZGiRiObCk,906
|
|
13
13
|
dara/core/auth/base.py,sha256=NJmUJqA-W8AVKIQbX_0BoHoZqtU1Iz6cJ16RKdcdIyU,3642
|
|
14
14
|
dara/core/auth/basic.py,sha256=sglIaogCslG2HlDMjFsaaJhOJeXUW-QQLTIYPaUPxAU,4927
|
|
15
|
-
dara/core/auth/definitions.py,sha256=
|
|
15
|
+
dara/core/auth/definitions.py,sha256=OzJshDLuut8MaM_pbfyQFkSlUuMNBWNszA57jRXF0Cg,3848
|
|
16
16
|
dara/core/auth/oidc/__init__.py,sha256=UWdhFvDqLCoILaKVWbmrrJgiMgg9wlVZgCxRvf_HGHM,65
|
|
17
|
-
dara/core/auth/oidc/config.py,sha256=
|
|
17
|
+
dara/core/auth/oidc/config.py,sha256=5rDxbr3wVZdjIz8USYNeUmKwKfeucHtLgfXwM3_weaE,20835
|
|
18
18
|
dara/core/auth/oidc/definitions.py,sha256=KLlUl2Y7n6prX0JSAwPde6J43iMs6uUY07OG7kumRPw,17568
|
|
19
|
-
dara/core/auth/oidc/routes.py,sha256=
|
|
20
|
-
dara/core/auth/oidc/settings.py,sha256=
|
|
19
|
+
dara/core/auth/oidc/routes.py,sha256=uvNHYUieaXy9hu6MYe_5eZvflX5TmFaIv6EGpCRP-dw,5335
|
|
20
|
+
dara/core/auth/oidc/settings.py,sha256=k1CKDTUKSFoCEp1ASI_R5L_lsNkFzjfAymMMIMmI1AE,2097
|
|
21
21
|
dara/core/auth/oidc/utils.py,sha256=IL17tStRNpkAQI3M17nrzGeb4xr47zSLPo4wT7LMwBQ,5145
|
|
22
22
|
dara/core/auth/routes.py,sha256=dtOxpFotnt4XQ4spW3mbyM7ThYRvfIA_oRK5X5lyYHg,7256
|
|
23
23
|
dara/core/auth/utils.py,sha256=_aHZ98qMJ0VLE9Zfvj5biPARhe973_eyTx2qxnufzRE,7290
|
|
@@ -134,8 +134,8 @@ dara/core/visual/themes/__init__.py,sha256=aM4mgoIYo2neBSw5FRzswsht7PUKjLthiHLmF
|
|
|
134
134
|
dara/core/visual/themes/dark.py,sha256=QazCRDqh_SCOyQhdwMkH1wbHf301oL7gCFj91plbLww,2020
|
|
135
135
|
dara/core/visual/themes/definitions.py,sha256=dtET2YUlwXkO6gJ23MqSb8gIq-LxJ343CWsgueWSifM,2787
|
|
136
136
|
dara/core/visual/themes/light.py,sha256=dtHb6Q1HOb5r_AvJfe0vZajikVc-GnBEUrGsTcI5MHA,2022
|
|
137
|
-
dara_core-1.23.
|
|
138
|
-
dara_core-1.23.
|
|
139
|
-
dara_core-1.23.
|
|
140
|
-
dara_core-1.23.
|
|
141
|
-
dara_core-1.23.
|
|
137
|
+
dara_core-1.23.0a1.dist-info/LICENSE,sha256=r9u1w2RvpLMV6YjuXHIKXRBKzia3fx_roPwboGcLqCc,10944
|
|
138
|
+
dara_core-1.23.0a1.dist-info/METADATA,sha256=WH9TER9_ycRXWaU40zxhvD5teCWhUbExsBay21YHW_w,7598
|
|
139
|
+
dara_core-1.23.0a1.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
140
|
+
dara_core-1.23.0a1.dist-info/entry_points.txt,sha256=nAT9o1kJCmTK1saDh29PFGFD6cbxDDDjTj31HDEDwfU,197
|
|
141
|
+
dara_core-1.23.0a1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|