mdb-engine 0.1.6__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.
Files changed (75) hide show
  1. mdb_engine/README.md +144 -0
  2. mdb_engine/__init__.py +37 -0
  3. mdb_engine/auth/README.md +631 -0
  4. mdb_engine/auth/__init__.py +128 -0
  5. mdb_engine/auth/casbin_factory.py +199 -0
  6. mdb_engine/auth/casbin_models.py +46 -0
  7. mdb_engine/auth/config_defaults.py +71 -0
  8. mdb_engine/auth/config_helpers.py +213 -0
  9. mdb_engine/auth/cookie_utils.py +158 -0
  10. mdb_engine/auth/decorators.py +350 -0
  11. mdb_engine/auth/dependencies.py +747 -0
  12. mdb_engine/auth/helpers.py +64 -0
  13. mdb_engine/auth/integration.py +578 -0
  14. mdb_engine/auth/jwt.py +225 -0
  15. mdb_engine/auth/middleware.py +241 -0
  16. mdb_engine/auth/oso_factory.py +323 -0
  17. mdb_engine/auth/provider.py +570 -0
  18. mdb_engine/auth/restrictions.py +271 -0
  19. mdb_engine/auth/session_manager.py +477 -0
  20. mdb_engine/auth/token_lifecycle.py +213 -0
  21. mdb_engine/auth/token_store.py +289 -0
  22. mdb_engine/auth/users.py +1516 -0
  23. mdb_engine/auth/utils.py +614 -0
  24. mdb_engine/cli/__init__.py +13 -0
  25. mdb_engine/cli/commands/__init__.py +7 -0
  26. mdb_engine/cli/commands/generate.py +105 -0
  27. mdb_engine/cli/commands/migrate.py +83 -0
  28. mdb_engine/cli/commands/show.py +70 -0
  29. mdb_engine/cli/commands/validate.py +63 -0
  30. mdb_engine/cli/main.py +41 -0
  31. mdb_engine/cli/utils.py +92 -0
  32. mdb_engine/config.py +217 -0
  33. mdb_engine/constants.py +160 -0
  34. mdb_engine/core/README.md +542 -0
  35. mdb_engine/core/__init__.py +42 -0
  36. mdb_engine/core/app_registration.py +392 -0
  37. mdb_engine/core/connection.py +243 -0
  38. mdb_engine/core/engine.py +749 -0
  39. mdb_engine/core/index_management.py +162 -0
  40. mdb_engine/core/manifest.py +2793 -0
  41. mdb_engine/core/seeding.py +179 -0
  42. mdb_engine/core/service_initialization.py +355 -0
  43. mdb_engine/core/types.py +413 -0
  44. mdb_engine/database/README.md +522 -0
  45. mdb_engine/database/__init__.py +31 -0
  46. mdb_engine/database/abstraction.py +635 -0
  47. mdb_engine/database/connection.py +387 -0
  48. mdb_engine/database/scoped_wrapper.py +1721 -0
  49. mdb_engine/embeddings/README.md +184 -0
  50. mdb_engine/embeddings/__init__.py +62 -0
  51. mdb_engine/embeddings/dependencies.py +193 -0
  52. mdb_engine/embeddings/service.py +759 -0
  53. mdb_engine/exceptions.py +167 -0
  54. mdb_engine/indexes/README.md +651 -0
  55. mdb_engine/indexes/__init__.py +21 -0
  56. mdb_engine/indexes/helpers.py +145 -0
  57. mdb_engine/indexes/manager.py +895 -0
  58. mdb_engine/memory/README.md +451 -0
  59. mdb_engine/memory/__init__.py +30 -0
  60. mdb_engine/memory/service.py +1285 -0
  61. mdb_engine/observability/README.md +515 -0
  62. mdb_engine/observability/__init__.py +42 -0
  63. mdb_engine/observability/health.py +296 -0
  64. mdb_engine/observability/logging.py +161 -0
  65. mdb_engine/observability/metrics.py +297 -0
  66. mdb_engine/routing/README.md +462 -0
  67. mdb_engine/routing/__init__.py +73 -0
  68. mdb_engine/routing/websockets.py +813 -0
  69. mdb_engine/utils/__init__.py +7 -0
  70. mdb_engine-0.1.6.dist-info/METADATA +213 -0
  71. mdb_engine-0.1.6.dist-info/RECORD +75 -0
  72. mdb_engine-0.1.6.dist-info/WHEEL +5 -0
  73. mdb_engine-0.1.6.dist-info/entry_points.txt +2 -0
  74. mdb_engine-0.1.6.dist-info/licenses/LICENSE +661 -0
  75. mdb_engine-0.1.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,128 @@
1
+ """
2
+ Authentication and Authorization Module
3
+
4
+ Provides authentication, authorization, and access control for the MongoDB Engine.
5
+
6
+ This module is part of MDB_ENGINE - MongoDB Engine.
7
+ """
8
+
9
+ # Casbin Factory
10
+ from .casbin_factory import (create_casbin_enforcer, get_casbin_model,
11
+ initialize_casbin_from_manifest)
12
+ # Cookie utilities
13
+ from .cookie_utils import (clear_auth_cookies, get_secure_cookie_settings,
14
+ set_auth_cookies)
15
+ # Decorators
16
+ from .decorators import (auto_token_setup, rate_limit_auth, require_auth,
17
+ token_security)
18
+ from .dependencies import (SECRET_KEY, _validate_next_url, get_authz_provider,
19
+ get_current_user, get_current_user_from_request,
20
+ get_current_user_or_redirect, get_refresh_token,
21
+ get_session_manager, get_token_blacklist,
22
+ refresh_access_token, require_admin,
23
+ require_admin_or_developer, require_permission)
24
+ from .helpers import initialize_token_management
25
+ # Integration
26
+ from .integration import get_auth_config, setup_auth_from_manifest
27
+ from .jwt import (decode_jwt_token, encode_jwt_token, extract_token_metadata,
28
+ generate_token_pair)
29
+ # Middleware
30
+ from .middleware import SecurityMiddleware, create_security_middleware
31
+ from .provider import (AUTHZ_CACHE_TTL, AuthorizationProvider, CasbinAdapter,
32
+ OsoAdapter)
33
+ from .restrictions import block_demo_users, is_demo_user, require_non_demo_user
34
+ from .session_manager import SessionManager
35
+ from .token_lifecycle import (get_time_until_expiry, get_token_age,
36
+ get_token_expiry_time, get_token_info,
37
+ is_token_expiring_soon, should_refresh_token,
38
+ validate_token_version)
39
+ # Token management
40
+ from .token_store import TokenBlacklist
41
+ from .users import (authenticate_app_user, create_app_session, create_app_user,
42
+ ensure_demo_users_exist, ensure_demo_users_for_actor,
43
+ get_app_user, get_app_user_role,
44
+ get_or_create_anonymous_user, get_or_create_demo_user,
45
+ get_or_create_demo_user_for_request,
46
+ sync_app_user_to_casbin)
47
+ # Utilities
48
+ from .utils import (get_device_info, login_user, logout_user, register_user,
49
+ validate_password_strength)
50
+
51
+ __all__ = [
52
+ # Provider
53
+ "AuthorizationProvider",
54
+ "CasbinAdapter",
55
+ "OsoAdapter",
56
+ "AUTHZ_CACHE_TTL",
57
+ # JWT
58
+ "decode_jwt_token",
59
+ "encode_jwt_token",
60
+ "generate_token_pair",
61
+ "extract_token_metadata",
62
+ # Dependencies
63
+ "SECRET_KEY",
64
+ "get_authz_provider",
65
+ "get_current_user",
66
+ "get_current_user_from_request",
67
+ "require_admin",
68
+ "require_admin_or_developer",
69
+ "get_current_user_or_redirect",
70
+ "require_permission",
71
+ "_validate_next_url",
72
+ "get_token_blacklist",
73
+ "get_session_manager",
74
+ "get_refresh_token",
75
+ "refresh_access_token",
76
+ # App-level user management
77
+ "get_app_user",
78
+ "create_app_session",
79
+ "authenticate_app_user",
80
+ "create_app_user",
81
+ "get_or_create_anonymous_user",
82
+ "ensure_demo_users_exist",
83
+ "get_or_create_demo_user_for_request",
84
+ "get_or_create_demo_user",
85
+ "ensure_demo_users_for_actor",
86
+ "sync_app_user_to_casbin",
87
+ "get_app_user_role",
88
+ # Restrictions
89
+ "is_demo_user",
90
+ "require_non_demo_user",
91
+ "block_demo_users",
92
+ # Token Management
93
+ "TokenBlacklist",
94
+ "SessionManager",
95
+ "get_token_expiry_time",
96
+ "is_token_expiring_soon",
97
+ "should_refresh_token",
98
+ "get_token_age",
99
+ "get_time_until_expiry",
100
+ "validate_token_version",
101
+ "get_token_info",
102
+ "initialize_token_management",
103
+ # Utilities
104
+ "login_user",
105
+ "register_user",
106
+ "logout_user",
107
+ "validate_password_strength",
108
+ "get_device_info",
109
+ # Decorators
110
+ "require_auth",
111
+ "token_security",
112
+ "rate_limit_auth",
113
+ "auto_token_setup",
114
+ # Cookie utilities
115
+ "get_secure_cookie_settings",
116
+ "set_auth_cookies",
117
+ "clear_auth_cookies",
118
+ # Middleware
119
+ "SecurityMiddleware",
120
+ "create_security_middleware",
121
+ # Integration
122
+ "get_auth_config",
123
+ "setup_auth_from_manifest",
124
+ # Casbin Factory
125
+ "get_casbin_model",
126
+ "create_casbin_enforcer",
127
+ "initialize_casbin_from_manifest",
128
+ ]
@@ -0,0 +1,199 @@
1
+ """
2
+ Casbin Provider Factory
3
+
4
+ Provides helper functions to auto-initialize Casbin authorization provider
5
+ from manifest configuration.
6
+
7
+ This module is part of MDB_ENGINE - MongoDB Engine.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import logging
13
+ from pathlib import Path
14
+ from typing import TYPE_CHECKING, Any, Dict, Optional
15
+
16
+ from .casbin_models import DEFAULT_RBAC_MODEL, SIMPLE_ACL_MODEL
17
+
18
+ if TYPE_CHECKING:
19
+ import casbin
20
+
21
+ from .provider import CasbinAdapter
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ def get_casbin_model(model_type: str = "rbac") -> str:
27
+ """
28
+ Get Casbin model string by type or path.
29
+
30
+ Args:
31
+ model_type: Model type ("rbac", "acl") or path to model file
32
+
33
+ Returns:
34
+ Casbin model string
35
+ """
36
+ if model_type == "rbac":
37
+ return DEFAULT_RBAC_MODEL
38
+ elif model_type == "acl":
39
+ return SIMPLE_ACL_MODEL
40
+ else:
41
+ # Assume it's a file path
42
+ model_path = Path(model_type)
43
+ if model_path.exists():
44
+ return model_path.read_text()
45
+ else:
46
+ logger.warning(
47
+ f"Casbin model file not found: {model_type}, using default RBAC model"
48
+ )
49
+ return DEFAULT_RBAC_MODEL
50
+
51
+
52
+ async def create_casbin_enforcer(
53
+ db,
54
+ model: str = "rbac",
55
+ policies_collection: str = "casbin_policies",
56
+ default_roles: Optional[list] = None,
57
+ ) -> casbin.AsyncEnforcer:
58
+ """
59
+ Create a Casbin AsyncEnforcer with MongoDB adapter.
60
+
61
+ Args:
62
+ db: MongoDB database instance (Motor AsyncIOMotorDatabase)
63
+ model: Casbin model type ("rbac", "acl") or path to model file
64
+ policies_collection: MongoDB collection name for policies
65
+ default_roles: List of default roles to create (optional)
66
+
67
+ Returns:
68
+ Configured Casbin AsyncEnforcer instance
69
+
70
+ Raises:
71
+ ImportError: If casbin or casbin-motor-adapter is not installed
72
+ """
73
+ try:
74
+ import casbin
75
+ from casbin_motor_adapter import MotorAdapter
76
+ except ImportError as e:
77
+ raise ImportError(
78
+ "Casbin dependencies not installed. Install with: pip install mdb-engine[casbin]"
79
+ ) from e
80
+
81
+ # Get model string
82
+ model_str = get_casbin_model(model)
83
+
84
+ # Create MongoDB adapter
85
+ adapter = MotorAdapter(db, policies_collection)
86
+
87
+ # Create enforcer with model and adapter
88
+ enforcer = casbin.AsyncEnforcer()
89
+ await enforcer.set_model(casbin.new_model_from_string(model_str))
90
+ enforcer.set_adapter(adapter)
91
+
92
+ # Load policies from database
93
+ await enforcer.load_policy()
94
+
95
+ # Create default roles if specified
96
+ if default_roles:
97
+ await _create_default_roles(enforcer, default_roles)
98
+
99
+ logger.info(
100
+ f"Casbin enforcer created with model '{model}' and "
101
+ f"policies collection '{policies_collection}'"
102
+ )
103
+
104
+ return enforcer
105
+
106
+
107
+ async def _create_default_roles(enforcer: "casbin.AsyncEnforcer", roles: list) -> None:
108
+ """
109
+ Create default roles in Casbin (as grouping rules).
110
+
111
+ Args:
112
+ enforcer: Casbin AsyncEnforcer instance
113
+ roles: List of role names to create
114
+ """
115
+ for role in roles:
116
+ # Create a grouping rule: role -> role (self-reference for role existence)
117
+ # This ensures the role exists in the system
118
+ # Actual user-role assignments will be added when users are created
119
+ try:
120
+ # Check if role already exists
121
+ existing = await enforcer.get_roles_for_user(role)
122
+ if not existing:
123
+ # Add role as a self-grouping rule to ensure it exists
124
+ # This is a common pattern to "register" roles
125
+ await enforcer.add_grouping_policy(role, role)
126
+ logger.debug(f"Created default Casbin role: {role}")
127
+ except (AttributeError, TypeError, ValueError, RuntimeError) as e:
128
+ logger.warning(f"Error creating default role '{role}': {e}")
129
+
130
+
131
+ async def initialize_casbin_from_manifest(
132
+ engine, app_slug: str, auth_config: Dict[str, Any]
133
+ ) -> Optional["CasbinAdapter"]:
134
+ """
135
+ Initialize Casbin provider from manifest configuration.
136
+
137
+ Args:
138
+ engine: MongoDBEngine instance
139
+ app_slug: App slug identifier
140
+ auth_config: Auth configuration dict from manifest (contains auth_policy)
141
+
142
+ Returns:
143
+ CasbinAdapter instance if successfully created, None otherwise
144
+ """
145
+ try:
146
+ from .provider import CasbinAdapter
147
+
148
+ auth_policy = auth_config.get("auth_policy", {})
149
+ provider = auth_policy.get("provider", "casbin")
150
+
151
+ # Only proceed if provider is casbin
152
+ if provider != "casbin":
153
+ return None
154
+
155
+ # Get authorization config
156
+ authorization = auth_policy.get("authorization", {})
157
+ model = authorization.get("model", "rbac")
158
+ policies_collection = authorization.get(
159
+ "policies_collection", "casbin_policies"
160
+ )
161
+ default_roles = authorization.get("default_roles", [])
162
+
163
+ # Get database from engine
164
+ db = engine.get_database()
165
+
166
+ # Create enforcer
167
+ enforcer = await create_casbin_enforcer(
168
+ db=db,
169
+ model=model,
170
+ policies_collection=policies_collection,
171
+ default_roles=default_roles,
172
+ )
173
+
174
+ # Create adapter
175
+ adapter = CasbinAdapter(enforcer)
176
+
177
+ logger.info(f"Casbin provider initialized for app '{app_slug}'")
178
+
179
+ return adapter
180
+
181
+ except ImportError as e:
182
+ logger.warning(
183
+ f"Casbin not available for app '{app_slug}': {e}. "
184
+ "Install with: pip install mdb-engine[casbin]"
185
+ )
186
+ return None
187
+ except (
188
+ ImportError,
189
+ AttributeError,
190
+ TypeError,
191
+ ValueError,
192
+ RuntimeError,
193
+ KeyError,
194
+ ) as e:
195
+ logger.error(
196
+ f"Error initializing Casbin provider for app '{app_slug}': {e}",
197
+ exc_info=True,
198
+ )
199
+ return None
@@ -0,0 +1,46 @@
1
+ """
2
+ Default Casbin Models
3
+
4
+ Provides default Casbin model configurations for authorization.
5
+
6
+ This module is part of MDB_ENGINE - MongoDB Engine.
7
+ """
8
+
9
+ # Default RBAC (Role-Based Access Control) model
10
+ # This model supports:
11
+ # - Subject (user/role) -> Object (resource) -> Action (permission)
12
+ # - Role inheritance via g (grouping) rules
13
+ # - Policy effect: allow if any policy matches
14
+
15
+ DEFAULT_RBAC_MODEL = """
16
+ [request_definition]
17
+ r = sub, obj, act
18
+
19
+ [policy_definition]
20
+ p = sub, obj, act
21
+
22
+ [role_definition]
23
+ g = _, _
24
+
25
+ [policy_effect]
26
+ e = some(where (p.eft == allow))
27
+
28
+ [matchers]
29
+ m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
30
+ """
31
+
32
+ # Alternative: Simple ACL model (no roles)
33
+ # Use this if you don't need role-based access control
34
+ SIMPLE_ACL_MODEL = """
35
+ [request_definition]
36
+ r = sub, obj, act
37
+
38
+ [policy_definition]
39
+ p = sub, obj, act
40
+
41
+ [policy_effect]
42
+ e = some(where (p.eft == allow))
43
+
44
+ [matchers]
45
+ m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
46
+ """
@@ -0,0 +1,71 @@
1
+ """
2
+ Authentication Configuration Defaults
3
+
4
+ Centralized default values for all authentication and security configurations.
5
+ This module provides a single source of truth for all config defaults.
6
+
7
+ This module is part of MDB_ENGINE - MongoDB Engine.
8
+ """
9
+
10
+ from typing import Any, Dict
11
+
12
+ SECURITY_CONFIG_DEFAULTS: Dict[str, Any] = {
13
+ "password_policy": {
14
+ "allow_plain_text": False,
15
+ "min_length": 8,
16
+ "require_uppercase": True,
17
+ "require_lowercase": True,
18
+ "require_numbers": True,
19
+ "require_special": False,
20
+ },
21
+ "session_fingerprinting": {
22
+ "enabled": True,
23
+ "validate_on_login": True,
24
+ "validate_on_refresh": True,
25
+ "validate_on_request": False,
26
+ "strict_mode": False,
27
+ },
28
+ "account_lockout": {
29
+ "enabled": True,
30
+ "max_failed_attempts": 5,
31
+ "lockout_duration_seconds": 900,
32
+ "reset_on_success": True,
33
+ },
34
+ "ip_validation": {"enabled": False, "strict": False, "allow_ip_change": True},
35
+ "token_fingerprinting": {"enabled": True, "bind_to_device": True},
36
+ }
37
+
38
+ TOKEN_MANAGEMENT_DEFAULTS: Dict[str, Any] = {
39
+ "enabled": True,
40
+ "access_token_ttl": 900,
41
+ "refresh_token_ttl": 604800,
42
+ "token_rotation": True,
43
+ "max_sessions_per_user": 10,
44
+ "session_inactivity_timeout": 1800,
45
+ "auto_setup": True,
46
+ }
47
+
48
+ CORS_DEFAULTS: Dict[str, Any] = {
49
+ "enabled": False,
50
+ "allow_origins": ["*"],
51
+ "allow_credentials": False,
52
+ "allow_methods": ["GET", "POST", "PUT", "DELETE", "PATCH"],
53
+ "allow_headers": ["*"],
54
+ "max_age": 3600,
55
+ }
56
+
57
+ OBSERVABILITY_DEFAULTS: Dict[str, Any] = {
58
+ "health_checks": {"enabled": True, "endpoint": "/health", "interval_seconds": 30},
59
+ "metrics": {
60
+ "enabled": True,
61
+ "collect_operation_metrics": True,
62
+ "collect_performance_metrics": True,
63
+ "custom_metrics": [],
64
+ },
65
+ "logging": {
66
+ "level": "INFO",
67
+ "format": "json",
68
+ "include_request_id": True,
69
+ "log_sensitive_data": False,
70
+ },
71
+ }
@@ -0,0 +1,213 @@
1
+ """
2
+ Authentication Config Helper Utilities
3
+
4
+ Type-safe utility functions for accessing and merging authentication configurations
5
+ from manifest.json and app.state.
6
+
7
+ This module is part of MDB_ENGINE - MongoDB Engine.
8
+ """
9
+
10
+ import logging
11
+ from typing import Any, Dict
12
+
13
+ from fastapi import Request
14
+
15
+ from .config_defaults import (CORS_DEFAULTS, OBSERVABILITY_DEFAULTS,
16
+ SECURITY_CONFIG_DEFAULTS,
17
+ TOKEN_MANAGEMENT_DEFAULTS)
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ def merge_config_with_defaults(
23
+ user_config: Dict[str, Any], defaults: Dict[str, Any]
24
+ ) -> Dict[str, Any]:
25
+ """
26
+ Deep merge user config with defaults.
27
+
28
+ User config values take precedence over defaults. Nested dictionaries
29
+ are merged recursively.
30
+
31
+ Args:
32
+ user_config: User-provided configuration (from manifest)
33
+ defaults: Default configuration values
34
+
35
+ Returns:
36
+ Merged configuration dictionary
37
+ """
38
+ if not user_config:
39
+ return defaults.copy()
40
+
41
+ if not defaults:
42
+ return user_config.copy()
43
+
44
+ merged = defaults.copy()
45
+
46
+ for key, value in user_config.items():
47
+ if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
48
+ merged[key] = merge_config_with_defaults(value, merged[key])
49
+ else:
50
+ merged[key] = value
51
+
52
+ return merged
53
+
54
+
55
+ def get_security_config(request: Request) -> Dict[str, Any]:
56
+ """
57
+ Get security configuration from app.state with defaults merged.
58
+
59
+ Args:
60
+ request: FastAPI Request object
61
+
62
+ Returns:
63
+ Security configuration dictionary with defaults applied
64
+ """
65
+ try:
66
+ security_config = getattr(request.app.state, "security_config", None)
67
+ if security_config:
68
+ return merge_config_with_defaults(security_config, SECURITY_CONFIG_DEFAULTS)
69
+ return SECURITY_CONFIG_DEFAULTS.copy()
70
+ except (AttributeError, TypeError, KeyError) as e:
71
+ logger.warning(f"Error getting security config: {e}, using defaults")
72
+ return SECURITY_CONFIG_DEFAULTS.copy()
73
+
74
+
75
+ def get_password_policy(request: Request) -> Dict[str, Any]:
76
+ """
77
+ Get password policy configuration with defaults merged.
78
+
79
+ Args:
80
+ request: FastAPI Request object
81
+
82
+ Returns:
83
+ Password policy configuration dictionary
84
+ """
85
+ security_config = get_security_config(request)
86
+ return security_config.get(
87
+ "password_policy", SECURITY_CONFIG_DEFAULTS["password_policy"].copy()
88
+ )
89
+
90
+
91
+ def get_session_fingerprinting_config(request: Request) -> Dict[str, Any]:
92
+ """
93
+ Get session fingerprinting configuration with defaults merged.
94
+
95
+ Args:
96
+ request: FastAPI Request object
97
+
98
+ Returns:
99
+ Session fingerprinting configuration dictionary
100
+ """
101
+ security_config = get_security_config(request)
102
+ return security_config.get(
103
+ "session_fingerprinting",
104
+ SECURITY_CONFIG_DEFAULTS["session_fingerprinting"].copy(),
105
+ )
106
+
107
+
108
+ def get_account_lockout_config(request: Request) -> Dict[str, Any]:
109
+ """
110
+ Get account lockout configuration with defaults merged.
111
+
112
+ Args:
113
+ request: FastAPI Request object
114
+
115
+ Returns:
116
+ Account lockout configuration dictionary
117
+ """
118
+ security_config = get_security_config(request)
119
+ return security_config.get(
120
+ "account_lockout", SECURITY_CONFIG_DEFAULTS["account_lockout"].copy()
121
+ )
122
+
123
+
124
+ def get_ip_validation_config(request: Request) -> Dict[str, Any]:
125
+ """
126
+ Get IP validation configuration with defaults merged.
127
+
128
+ Args:
129
+ request: FastAPI Request object
130
+
131
+ Returns:
132
+ IP validation configuration dictionary
133
+ """
134
+ security_config = get_security_config(request)
135
+ return security_config.get(
136
+ "ip_validation", SECURITY_CONFIG_DEFAULTS["ip_validation"].copy()
137
+ )
138
+
139
+
140
+ def get_token_fingerprinting_config(request: Request) -> Dict[str, Any]:
141
+ """
142
+ Get token fingerprinting configuration with defaults merged.
143
+
144
+ Args:
145
+ request: FastAPI Request object
146
+
147
+ Returns:
148
+ Token fingerprinting configuration dictionary
149
+ """
150
+ security_config = get_security_config(request)
151
+ return security_config.get(
152
+ "token_fingerprinting", SECURITY_CONFIG_DEFAULTS["token_fingerprinting"].copy()
153
+ )
154
+
155
+
156
+ def get_token_management_config(request: Request) -> Dict[str, Any]:
157
+ """
158
+ Get token management configuration from app.state with defaults merged.
159
+
160
+ Args:
161
+ request: FastAPI Request object
162
+
163
+ Returns:
164
+ Token management configuration dictionary with defaults applied
165
+ """
166
+ try:
167
+ token_config = getattr(request.app.state, "token_management_config", None)
168
+ if token_config:
169
+ return merge_config_with_defaults(token_config, TOKEN_MANAGEMENT_DEFAULTS)
170
+ return TOKEN_MANAGEMENT_DEFAULTS.copy()
171
+ except (AttributeError, TypeError, KeyError) as e:
172
+ logger.warning(f"Error getting token management config: {e}, using defaults")
173
+ return TOKEN_MANAGEMENT_DEFAULTS.copy()
174
+
175
+
176
+ def get_cors_config(request: Request) -> Dict[str, Any]:
177
+ """
178
+ Get CORS configuration from app.state with defaults merged.
179
+
180
+ Args:
181
+ request: FastAPI Request object
182
+
183
+ Returns:
184
+ CORS configuration dictionary with defaults applied
185
+ """
186
+ try:
187
+ cors_config = getattr(request.app.state, "cors_config", None)
188
+ if cors_config:
189
+ return merge_config_with_defaults(cors_config, CORS_DEFAULTS)
190
+ return CORS_DEFAULTS.copy()
191
+ except (AttributeError, TypeError, KeyError) as e:
192
+ logger.warning(f"Error getting CORS config: {e}, using defaults")
193
+ return CORS_DEFAULTS.copy()
194
+
195
+
196
+ def get_observability_config(request: Request) -> Dict[str, Any]:
197
+ """
198
+ Get observability configuration from app.state with defaults merged.
199
+
200
+ Args:
201
+ request: FastAPI Request object
202
+
203
+ Returns:
204
+ Observability configuration dictionary with defaults applied
205
+ """
206
+ try:
207
+ obs_config = getattr(request.app.state, "observability_config", None)
208
+ if obs_config:
209
+ return merge_config_with_defaults(obs_config, OBSERVABILITY_DEFAULTS)
210
+ return OBSERVABILITY_DEFAULTS.copy()
211
+ except (AttributeError, TypeError, KeyError) as e:
212
+ logger.warning(f"Error getting observability config: {e}, using defaults")
213
+ return OBSERVABILITY_DEFAULTS.copy()