simple-module-auth 0.0.38__tar.gz → 0.0.39__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.
Files changed (30) hide show
  1. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/PKG-INFO +5 -4
  2. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/middleware.py +9 -12
  3. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/state.py +9 -0
  4. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/package.json +1 -1
  5. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/pyproject.toml +6 -4
  6. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/.gitignore +0 -0
  7. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/LICENSE +0 -0
  8. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/README.md +0 -0
  9. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/__init__.py +0 -0
  10. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/_route_match.py +0 -0
  11. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/contracts/__init__.py +0 -0
  12. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/contracts/provider.py +0 -0
  13. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/contracts/resolver.py +0 -0
  14. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/contracts/schemas.py +0 -0
  15. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/contracts/tokens.py +0 -0
  16. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/deps.py +0 -0
  17. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/locales/de.json +0 -0
  18. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/locales/en.json +0 -0
  19. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/locales/es.json +0 -0
  20. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/module.py +0 -0
  21. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/auth/py.typed +0 -0
  22. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_auth_middleware.py +0 -0
  23. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_auth_next_target.py +0 -0
  24. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_auth_parse_bearer.py +0 -0
  25. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_auth_provider_protocol.py +0 -0
  26. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_auth_unknown_paths.py +0 -0
  27. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_deps.py +0 -0
  28. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_module.py +0 -0
  29. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_resolver_registry.py +0 -0
  30. {simple_module_auth-0.0.38 → simple_module_auth-0.0.39}/tests/test_user_context.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: simple_module_auth
3
- Version: 0.0.38
3
+ Version: 0.0.39
4
4
  Summary: Session-cookie authentication primitives — middleware, login/logout, redirect helpers for simple_module
5
5
  Project-URL: Homepage, https://github.com/antosubash/simple_module_python
6
6
  Project-URL: Repository, https://github.com/antosubash/simple_module_python
@@ -21,9 +21,10 @@ Classifier: Topic :: Internet :: WWW/HTTP
21
21
  Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
22
22
  Classifier: Typing :: Typed
23
23
  Requires-Python: >=3.12
24
- Requires-Dist: itsdangerous>=2.2
25
- Requires-Dist: simple-module-core==0.0.38
26
- Requires-Dist: simple-module-db==0.0.38
24
+ Requires-Dist: itsdangerous<3,>=2.2
25
+ Requires-Dist: simple-module-core==0.0.39
26
+ Requires-Dist: simple-module-db==0.0.39
27
+ Requires-Dist: simple-module-hosting==0.0.39
27
28
  Description-Content-Type: text/markdown
28
29
 
29
30
  # simple_module_auth
@@ -10,9 +10,10 @@ from __future__ import annotations
10
10
 
11
11
  import logging
12
12
 
13
- from simple_module_core.public_routes import legacy_provider_public_paths
13
+ from simple_module_core.app_state import get_openapi_url
14
14
  from simple_module_core.redirect_safety import SESSION_NEXT_KEY, safe_next_or_none
15
15
  from simple_module_db.listeners import current_user_id
16
+ from simple_module_hosting.public_access import is_public as route_is_public
16
17
  from starlette.requests import Request
17
18
  from starlette.responses import JSONResponse, RedirectResponse
18
19
  from starlette.types import ASGIApp, Receive, Scope, Send
@@ -87,19 +88,10 @@ class AuthMiddleware:
87
88
  any(path.startswith(p) for p in _FRAMEWORK_PUBLIC_PREFIXES)
88
89
  or path in _FRAMEWORK_PUBLIC_EXACT
89
90
  # Anonymous exactly when the host serves it (dev, or openapi_public).
90
- or path == getattr(app_state, "openapi_url", None)
91
+ or path == get_openapi_url(scope["app"])
91
92
  )
92
- # Module-contributed public routes (register_public_routes hook). Method
93
- # -aware, so a GET read route can be exempted without opening sibling
94
- # POST/PATCH mutations under the same prefix.
95
93
  if not is_public:
96
- public_routes = getattr(app_state, "public_routes", None)
97
- is_public = public_routes is not None and public_routes.matches(method, path)
98
- # Deprecated provider-declared paths (prefix-only, method-agnostic); honoured
99
- # until 0.1.0 for third-party providers. users/keycloak use the registry.
100
- if not is_public:
101
- prefix_paths, exact_paths = legacy_provider_public_paths(provider)
102
- is_public = any(path.startswith(p) for p in prefix_paths) or path in exact_paths
94
+ is_public = route_is_public(scope["app"], method, path)
103
95
 
104
96
  # Contract with the host's RateLimitMiddleware (plain scope key, no import
105
97
  # between them): whether *this* middleware treats the request as anonymous-
@@ -159,6 +151,11 @@ class AuthMiddleware:
159
151
 
160
152
  if user_ctx is not None:
161
153
  request.state.user = user_ctx
154
+ for guard in auth_state.principal_guards:
155
+ refusal = guard(request)
156
+ if refusal is not None:
157
+ await refusal(scope, receive, send)
158
+ return
162
159
  token = current_user_id.set(user_ctx.id)
163
160
  try:
164
161
  await self.app(scope, receive, send)
@@ -9,12 +9,16 @@ principal-resolver registry. Apps register additional resolvers from their
9
9
 
10
10
  from __future__ import annotations
11
11
 
12
+ from collections.abc import Callable
12
13
  from dataclasses import dataclass, field
13
14
  from typing import TYPE_CHECKING
14
15
 
15
16
  from auth.contracts.resolver import PrincipalResolver
16
17
 
17
18
  if TYPE_CHECKING:
19
+ from starlette.requests import Request
20
+ from starlette.responses import Response
21
+
18
22
  from auth.contracts.provider import AuthProvider
19
23
 
20
24
 
@@ -24,6 +28,11 @@ class AuthState:
24
28
 
25
29
  auth_provider: AuthProvider | None = None
26
30
  principal_resolvers: list[PrincipalResolver] = field(default_factory=list)
31
+ # Run once a principal has resolved (any credential source), before downstream
32
+ # middleware; anonymous requests never reach them.
33
+ # A guard is a sync callable returning a refusal response or None to continue.
34
+ # An exception propagates (a 500), so a broken guard fails closed, never open.
35
+ principal_guards: list[Callable[[Request], Response | None]] = field(default_factory=list)
27
36
 
28
37
 
29
38
  __all__ = ["AuthState"]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simple-module-py/auth",
3
- "version": "0.0.38",
3
+ "version": "0.0.39",
4
4
  "private": true,
5
5
  "description": "Frontend assets for the Auth module",
6
6
  "peerDependencies": {
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "simple_module_auth"
3
- version = "0.0.38"
3
+ version = "0.0.39"
4
4
  description = "Session-cookie authentication primitives — middleware, login/logout, redirect helpers for simple_module"
5
5
  readme = "README.md"
6
6
  license = "MIT"
@@ -21,9 +21,10 @@ classifiers = [
21
21
  "Typing :: Typed",
22
22
  ]
23
23
  dependencies = [
24
- "itsdangerous>=2.2",
25
- "simple_module_core==0.0.38",
26
- "simple_module_db==0.0.38",
24
+ "itsdangerous>=2.2,<3",
25
+ "simple_module_core==0.0.39",
26
+ "simple_module_db==0.0.39",
27
+ "simple_module_hosting==0.0.39",
27
28
  ]
28
29
 
29
30
  [project.entry-points.simple_module]
@@ -50,3 +51,4 @@ packages = ["auth"]
50
51
  [tool.uv.sources]
51
52
  simple_module_core = { workspace = true }
52
53
  simple_module_db = { workspace = true }
54
+ simple_module_hosting = { workspace = true }