oidcauthlib 3.0.6__tar.gz → 3.0.7__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.
- oidcauthlib-3.0.7/MANIFEST.in +1 -0
- {oidcauthlib-3.0.6/oidcauthlib.egg-info → oidcauthlib-3.0.7}/PKG-INFO +4 -14
- oidcauthlib-3.0.7/VERSION +1 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/auth_helper.py +2 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/auth_manager.py +30 -53
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/cache/oauth_mongo_cache.py +13 -35
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/config/auth_config.py +1 -2
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/config/auth_config_reader.py +24 -72
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/dcr/dcr_client.py +3 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/dcr/dcr_manager.py +9 -17
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/dcr/dcr_registration.py +3 -9
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/fastapi_auth_manager.py +83 -34
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/middleware/request_scope_middleware.py +4 -11
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/middleware/token_reader_middleware.py +7 -21
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/models/auth.py +2 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/models/cache_item.py +1 -3
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/models/client_key_set.py +2 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/models/token.py +6 -26
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/repository/base_repository.py +2 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/repository/memory/memory_repository.py +2 -8
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/repository/mongo/mongo_repository.py +14 -42
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/repository/repository_factory.py +2 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/routers/auth_router.py +9 -29
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/token_reader.py +8 -26
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/well_known_configuration/auth_server_metadata_discovery.py +1 -2
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/well_known_configuration/well_known_configuration_cache.py +32 -92
- oidcauthlib-3.0.7/oidcauthlib/auth/well_known_configuration/well_known_configuration_cache_result.py +9 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/well_known_configuration/well_known_configuration_manager.py +2 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/container/oidc_authlib_container_factory.py +5 -15
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/mongo_gridfs_db.py +26 -77
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/mongo_storage_factory.py +5 -13
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/storage_factory_creator.py +2 -5
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/environment/oidc_environment_variables.py +8 -24
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/logger/logging_response.py +2 -6
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/mongo_url_utils.py +1 -3
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7/oidcauthlib.egg-info}/PKG-INFO +4 -14
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib.egg-info/SOURCES.txt +2 -50
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib.egg-info/top_level.txt +0 -1
- oidcauthlib-3.0.7/pyproject.toml +107 -0
- oidcauthlib-3.0.7/setup.cfg +4 -0
- oidcauthlib-3.0.6/MANIFEST.in +0 -6
- oidcauthlib-3.0.6/Makefile +0 -85
- oidcauthlib-3.0.6/VERSION +0 -1
- oidcauthlib-3.0.6/oidcauthlib/auth/well_known_configuration/well_known_configuration_cache_result.py +0 -15
- oidcauthlib-3.0.6/oidcauthlib.egg-info/not-zip-safe +0 -1
- oidcauthlib-3.0.6/setup.cfg +0 -29
- oidcauthlib-3.0.6/setup.py +0 -82
- oidcauthlib-3.0.6/tests/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/cache/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/cache/test_oauth_memory_cache.py +0 -26
- oidcauthlib-3.0.6/tests/auth/config/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/config/test_auth_config.py +0 -72
- oidcauthlib-3.0.6/tests/auth/config/test_auth_config_reader.py +0 -91
- oidcauthlib-3.0.6/tests/auth/config/test_auth_config_reader_register.py +0 -200
- oidcauthlib-3.0.6/tests/auth/config/test_auth_config_reader_thread_safety.py +0 -127
- oidcauthlib-3.0.6/tests/auth/conftest.py +0 -14
- oidcauthlib-3.0.6/tests/auth/dcr/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/dcr/test_dcr_client.py +0 -129
- oidcauthlib-3.0.6/tests/auth/dcr/test_dcr_manager.py +0 -198
- oidcauthlib-3.0.6/tests/auth/middleware/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/middleware/test_request_scope_middleware.py +0 -188
- oidcauthlib-3.0.6/tests/auth/middleware/test_token_reader_middleware.py +0 -671
- oidcauthlib-3.0.6/tests/auth/models/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/models/test_auth.py +0 -43
- oidcauthlib-3.0.6/tests/auth/models/test_base_db_model.py +0 -70
- oidcauthlib-3.0.6/tests/auth/models/test_cache_item.py +0 -17
- oidcauthlib-3.0.6/tests/auth/models/test_token.py +0 -48
- oidcauthlib-3.0.6/tests/auth/repository/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/repository/memory/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/repository/memory/test_memory_repository.py +0 -156
- oidcauthlib-3.0.6/tests/auth/repository/mongo/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/repository/mongo/test_mongo_repository.py +0 -912
- oidcauthlib-3.0.6/tests/auth/repository/mongo/test_mongo_repository_real.py +0 -178
- oidcauthlib-3.0.6/tests/auth/test_auth_helper.py +0 -26
- oidcauthlib-3.0.6/tests/auth/test_auth_helper2.py +0 -33
- oidcauthlib-3.0.6/tests/auth/test_auth_manager.py +0 -523
- oidcauthlib-3.0.6/tests/auth/test_register_dynamic_provider.py +0 -357
- oidcauthlib-3.0.6/tests/auth/well_known_configuration/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/auth/well_known_configuration/test_auth_server_metadata_discovery.py +0 -184
- oidcauthlib-3.0.6/tests/auth/well_known_configuration/test_well_known_configuration_cache.py +0 -405
- oidcauthlib-3.0.6/tests/auth/well_known_configuration/test_well_known_configuration_manager.py +0 -174
- oidcauthlib-3.0.6/tests/conftest.py +0 -130
- oidcauthlib-3.0.6/tests/storage/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/storage/test_mongo_gridfs_db.py +0 -378
- oidcauthlib-3.0.6/tests/storage/test_mongo_gridfs_race_setup.py +0 -70
- oidcauthlib-3.0.6/tests/storage/test_mongo_store_factory.py +0 -516
- oidcauthlib-3.0.6/tests/storage/test_storage_factory_security.py +0 -498
- oidcauthlib-3.0.6/tests/utilities/__init__.py +0 -0
- oidcauthlib-3.0.6/tests/utilities/test_cached.py +0 -52
- oidcauthlib-3.0.6/tests/utilities/test_mongo_url_utils.py +0 -30
- oidcauthlib-3.0.6/tests/utilities/test_url_validator.py +0 -182
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/LICENSE +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/README.md +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/cache/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/cache/oauth_cache.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/cache/oauth_memory_cache.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/config/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/dcr/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/exceptions/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/exceptions/authorization_bearer_token_expired_exception.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/exceptions/authorization_bearer_token_invalid_exception.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/exceptions/authorization_bearer_token_missing_exception.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/exceptions/authorization_needed_exception.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/middleware/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/models/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/models/base_db_model.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/repository/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/repository/memory/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/repository/mongo/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/routers/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/well_known_configuration/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/auth/well_known_configuration/auth_server_metadata.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/container/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/open_telemetry/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/open_telemetry/attribute_names.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/open_telemetry/span_names.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/py.typed +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/cache_to_collection_mapper.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/memory_storage_factory.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/mongo_gridfs_exception.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/storage/storage_factory.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/cached.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/environment/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/environment/abstract_environment_variables.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/logger/__init__.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/logger/log_levels.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/logger/logging_transport.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib/utilities/url_validator.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib.egg-info/dependency_links.txt +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/oidcauthlib.egg-info/requires.txt +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/tests/test_mongo_url_utils.py +0 -0
- {oidcauthlib-3.0.6 → oidcauthlib-3.0.7}/tests/test_simple.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
include VERSION
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oidcauthlib
|
|
3
|
-
Version: 3.0.
|
|
3
|
+
Version: 3.0.7
|
|
4
4
|
Summary: oidcauthlib
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Author-email: Imran Qureshi <imran.qureshi@bwell.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/icanbwell/oidc-auth-lib
|
|
8
8
|
Classifier: Development Status :: 4 - Beta
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: Apache Software License
|
|
11
10
|
Classifier: Operating System :: OS Independent
|
|
12
11
|
Requires-Python: >=3.12
|
|
13
12
|
Description-Content-Type: text/markdown
|
|
@@ -23,15 +22,6 @@ Requires-Dist: starlette>=0.49.1
|
|
|
23
22
|
Requires-Dist: py-key-value-aio[memory,mongodb,pydantic,redis]>=0.4.4
|
|
24
23
|
Requires-Dist: opentelemetry-api>=1.39.1
|
|
25
24
|
Requires-Dist: simple-container>=1.0.2
|
|
26
|
-
Dynamic: author
|
|
27
|
-
Dynamic: author-email
|
|
28
|
-
Dynamic: classifier
|
|
29
|
-
Dynamic: description
|
|
30
|
-
Dynamic: description-content-type
|
|
31
|
-
Dynamic: home-page
|
|
32
25
|
Dynamic: license-file
|
|
33
|
-
Dynamic: requires-dist
|
|
34
|
-
Dynamic: requires-python
|
|
35
|
-
Dynamic: summary
|
|
36
26
|
|
|
37
27
|
# oidcauthlib
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.0.7
|
|
@@ -21,9 +21,7 @@ class AuthHelper:
|
|
|
21
21
|
A base64url encoded string of the content.
|
|
22
22
|
"""
|
|
23
23
|
json_content = json.dumps(content)
|
|
24
|
-
encoded_content = base64.urlsafe_b64encode(json_content.encode("utf-8")).decode(
|
|
25
|
-
"utf-8"
|
|
26
|
-
)
|
|
24
|
+
encoded_content = base64.urlsafe_b64encode(json_content.encode("utf-8")).decode("utf-8")
|
|
27
25
|
return encoded_content.rstrip("=")
|
|
28
26
|
|
|
29
27
|
@staticmethod
|
|
@@ -56,9 +54,7 @@ class AuthHelper:
|
|
|
56
54
|
logger.error(f"Failed to decode state (JSON error): {e}")
|
|
57
55
|
raise ValueError("Invalid JSON in decoded state") from e
|
|
58
56
|
if not isinstance(result, dict):
|
|
59
|
-
logger.error(
|
|
60
|
-
"Failed to decode state: Decoded state is not a dictionary"
|
|
61
|
-
)
|
|
57
|
+
logger.error("Failed to decode state: Decoded state is not a dictionary")
|
|
62
58
|
raise ValueError("Decoded state is not a dictionary")
|
|
63
59
|
return result
|
|
64
60
|
except Exception:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import json
|
|
1
2
|
import logging
|
|
2
3
|
import os
|
|
3
4
|
import time
|
|
@@ -70,17 +71,13 @@ class AuthManager:
|
|
|
70
71
|
if self.environment_variables is None:
|
|
71
72
|
raise ValueError("environment_variables must not be None")
|
|
72
73
|
if not isinstance(self.environment_variables, AbstractEnvironmentVariables):
|
|
73
|
-
raise TypeError(
|
|
74
|
-
"environment_variables must be an instance of EnvironmentVariables"
|
|
75
|
-
)
|
|
74
|
+
raise TypeError("environment_variables must be an instance of EnvironmentVariables")
|
|
76
75
|
|
|
77
76
|
self.auth_config_reader: AuthConfigReader = auth_config_reader
|
|
78
77
|
if self.auth_config_reader is None:
|
|
79
78
|
raise ValueError("auth_config_reader must not be None")
|
|
80
79
|
if not isinstance(self.auth_config_reader, AuthConfigReader):
|
|
81
|
-
raise TypeError(
|
|
82
|
-
"auth_config_reader must be an instance of AuthConfigReader"
|
|
83
|
-
)
|
|
80
|
+
raise TypeError("auth_config_reader must be an instance of AuthConfigReader")
|
|
84
81
|
|
|
85
82
|
self.token_reader: TokenReader = token_reader
|
|
86
83
|
if self.token_reader is None:
|
|
@@ -88,17 +85,11 @@ class AuthManager:
|
|
|
88
85
|
if not isinstance(self.token_reader, TokenReader):
|
|
89
86
|
raise TypeError("token_reader must be an instance of TokenReader")
|
|
90
87
|
|
|
91
|
-
self.well_known_configuration_manager: WellKnownConfigurationManager =
|
|
92
|
-
well_known_configuration_manager
|
|
93
|
-
)
|
|
88
|
+
self.well_known_configuration_manager: WellKnownConfigurationManager = well_known_configuration_manager
|
|
94
89
|
if self.well_known_configuration_manager is None:
|
|
95
90
|
raise ValueError("well_known_configuration_manager must not be None")
|
|
96
|
-
if not isinstance(
|
|
97
|
-
|
|
98
|
-
):
|
|
99
|
-
raise TypeError(
|
|
100
|
-
"well_known_configuration_manager must be an instance of WellKnownConfigurationManager"
|
|
101
|
-
)
|
|
91
|
+
if not isinstance(self.well_known_configuration_manager, WellKnownConfigurationManager):
|
|
92
|
+
raise TypeError("well_known_configuration_manager must be an instance of WellKnownConfigurationManager")
|
|
102
93
|
|
|
103
94
|
self._dcr_manager: DcrManager | None = dcr_manager
|
|
104
95
|
|
|
@@ -109,9 +100,7 @@ class AuthManager:
|
|
|
109
100
|
else OAuthMongoCache(environment_variables=environment_variables)
|
|
110
101
|
)
|
|
111
102
|
|
|
112
|
-
logger.debug(
|
|
113
|
-
f"Initializing AuthManager with cache type {type(self.cache)} cache id: {self.cache.id}"
|
|
114
|
-
)
|
|
103
|
+
logger.debug(f"Initializing AuthManager with cache type {type(self.cache)} cache id: {self.cache.id}")
|
|
115
104
|
# OIDC PKCE setup
|
|
116
105
|
self.redirect_uri = os.getenv("AUTH_REDIRECT_URI")
|
|
117
106
|
if self.redirect_uri is None:
|
|
@@ -119,17 +108,13 @@ class AuthManager:
|
|
|
119
108
|
# https://docs.authlib.org/en/latest/client/frameworks.html#frameworks-clients
|
|
120
109
|
self._oauth: OAuth = OAuth(cache=self.cache)
|
|
121
110
|
self._registered_dynamic_providers: set[str] = set()
|
|
122
|
-
self.auth_configs: List[AuthConfig] = (
|
|
123
|
-
self.auth_config_reader.get_auth_configs_for_all_auth_providers()
|
|
124
|
-
)
|
|
111
|
+
self.auth_configs: List[AuthConfig] = self.auth_config_reader.get_auth_configs_for_all_auth_providers()
|
|
125
112
|
|
|
126
113
|
async def ensure_initialized_async(self) -> None:
|
|
127
114
|
auth_config: AuthConfig
|
|
128
115
|
for auth_config in self.auth_configs:
|
|
129
116
|
if auth_config.well_known_uri:
|
|
130
|
-
await self.well_known_configuration_manager.get_async(
|
|
131
|
-
auth_config=auth_config
|
|
132
|
-
)
|
|
117
|
+
await self.well_known_configuration_manager.get_async(auth_config=auth_config)
|
|
133
118
|
await self.register_dynamic_provider(auth_config=auth_config)
|
|
134
119
|
|
|
135
120
|
async def register_dynamic_provider(
|
|
@@ -162,9 +147,7 @@ class AuthManager:
|
|
|
162
147
|
registration_url=auth_config.registration_url,
|
|
163
148
|
)
|
|
164
149
|
if dcr_result is None or not dcr_result.client_id:
|
|
165
|
-
raise ValueError(
|
|
166
|
-
f"DCR failed to obtain client_id for '{auth_config.auth_provider}'"
|
|
167
|
-
)
|
|
150
|
+
raise ValueError(f"DCR failed to obtain client_id for '{auth_config.auth_provider}'")
|
|
168
151
|
client_id = dcr_result.client_id
|
|
169
152
|
client_secret = dcr_result.client_secret
|
|
170
153
|
logger.info(
|
|
@@ -278,12 +261,20 @@ class AuthManager:
|
|
|
278
261
|
f" with state {state_content} and encoded state {state}"
|
|
279
262
|
)
|
|
280
263
|
|
|
281
|
-
rv: Dict[str, Any] = await client.create_authorization_url(
|
|
282
|
-
redirect_uri=redirect_uri, state=state
|
|
283
|
-
)
|
|
264
|
+
rv: Dict[str, Any] = await client.create_authorization_url(redirect_uri=redirect_uri, state=state)
|
|
284
265
|
logger.debug(f"Authorization URL created: {rv}")
|
|
285
|
-
#
|
|
286
|
-
|
|
266
|
+
# Save OAuth state data (code_verifier, nonce, redirect_uri) to our
|
|
267
|
+
# own cache rather than relying on authlib's save_authorize_data which
|
|
268
|
+
# requires request.session (SessionMiddleware). This allows the
|
|
269
|
+
# callback to retrieve the data without SessionMiddleware.
|
|
270
|
+
state_data: Dict[str, Any] = {"redirect_uri": redirect_uri}
|
|
271
|
+
if "code_verifier" in rv:
|
|
272
|
+
state_data["code_verifier"] = rv["code_verifier"]
|
|
273
|
+
if "nonce" in rv:
|
|
274
|
+
state_data["nonce"] = rv["nonce"]
|
|
275
|
+
cache_key = f"_state_{auth_provider}_{state}"
|
|
276
|
+
await self.cache.set(cache_key, json.dumps({"data": state_data}))
|
|
277
|
+
logger.debug(f"Saved OAuth state to cache key={cache_key} data={state_data}")
|
|
287
278
|
return cast(str, rv["url"])
|
|
288
279
|
|
|
289
280
|
async def create_oauth_client(self, *, name: str) -> StarletteOAuth2App:
|
|
@@ -327,17 +318,11 @@ class AuthManager:
|
|
|
327
318
|
resp.raise_for_status()
|
|
328
319
|
token_url = resp.json().get("token_endpoint")
|
|
329
320
|
except Exception as e:
|
|
330
|
-
raise AuthorizationNeededException(
|
|
331
|
-
message=f"Failed to discover token endpoint: {e}"
|
|
332
|
-
)
|
|
321
|
+
raise AuthorizationNeededException(message=f"Failed to discover token endpoint: {e}")
|
|
333
322
|
if not token_url and auth_config.issuer:
|
|
334
|
-
token_url = (
|
|
335
|
-
auth_config.issuer.rstrip("/") + "/protocol/openid-connect/token"
|
|
336
|
-
)
|
|
323
|
+
token_url = auth_config.issuer.rstrip("/") + "/protocol/openid-connect/token"
|
|
337
324
|
if not token_url:
|
|
338
|
-
raise AuthorizationNeededException(
|
|
339
|
-
message="No token endpoint found in AuthConfig."
|
|
340
|
-
)
|
|
325
|
+
raise AuthorizationNeededException(message="No token endpoint found in AuthConfig.")
|
|
341
326
|
|
|
342
327
|
# Prepare OAuth2 client
|
|
343
328
|
client_id = auth_config.client_id
|
|
@@ -369,9 +354,7 @@ class AuthManager:
|
|
|
369
354
|
|
|
370
355
|
return access_token
|
|
371
356
|
|
|
372
|
-
def get_auth_config_for_auth_provider(
|
|
373
|
-
self, *, auth_provider: str
|
|
374
|
-
) -> AuthConfig | None:
|
|
357
|
+
def get_auth_config_for_auth_provider(self, *, auth_provider: str) -> AuthConfig | None:
|
|
375
358
|
if not auth_provider:
|
|
376
359
|
raise ValueError("auth_provider must not be empty")
|
|
377
360
|
for auth_config in self.auth_configs:
|
|
@@ -380,9 +363,7 @@ class AuthManager:
|
|
|
380
363
|
return None
|
|
381
364
|
|
|
382
365
|
@staticmethod
|
|
383
|
-
def wait_till_well_known_configuration_available(
|
|
384
|
-
*, auth_config: AuthConfig, timeout_seconds: int = 30
|
|
385
|
-
) -> None:
|
|
366
|
+
def wait_till_well_known_configuration_available(*, auth_config: AuthConfig, timeout_seconds: int = 30) -> None:
|
|
386
367
|
"""
|
|
387
368
|
Wait until the well-known configuration is available for the given AuthConfig.
|
|
388
369
|
|
|
@@ -406,9 +387,7 @@ class AuthManager:
|
|
|
406
387
|
resp = client.get(auth_config.well_known_uri)
|
|
407
388
|
resp.raise_for_status()
|
|
408
389
|
# Successfully fetched the configuration
|
|
409
|
-
logger.info(
|
|
410
|
-
f"Well-known configuration is now available at {auth_config.well_known_uri}"
|
|
411
|
-
)
|
|
390
|
+
logger.info(f"Well-known configuration is now available at {auth_config.well_known_uri}")
|
|
412
391
|
return
|
|
413
392
|
except Exception as e:
|
|
414
393
|
elapsed_time = time.time() - start_time
|
|
@@ -416,7 +395,5 @@ class AuthManager:
|
|
|
416
395
|
raise TimeoutError(
|
|
417
396
|
f"Timed out waiting for well-known configuration at {auth_config.well_known_uri}"
|
|
418
397
|
) from e
|
|
419
|
-
logger.debug(
|
|
420
|
-
f"Well-known configuration not yet available, retrying... ({elapsed_time:.1f}s elapsed)"
|
|
421
|
-
)
|
|
398
|
+
logger.debug(f"Well-known configuration not yet available, retrying... ({elapsed_time:.1f}s elapsed)")
|
|
422
399
|
time.sleep(2) # Wait before retrying
|
|
@@ -43,30 +43,20 @@ class OAuthMongoCache(OAuthCache):
|
|
|
43
43
|
|
|
44
44
|
"""
|
|
45
45
|
self.id_ = uuid.uuid4()
|
|
46
|
-
self.repository: AsyncBaseRepository[CacheItem] = (
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
environment_variables=environment_variables,
|
|
50
|
-
)
|
|
51
|
-
)
|
|
52
|
-
collection_name: str | None = (
|
|
53
|
-
environment_variables.mongo_db_auth_cache_collection_name
|
|
46
|
+
self.repository: AsyncBaseRepository[CacheItem] = RepositoryFactory.get_repository(
|
|
47
|
+
repository_type=environment_variables.oauth_cache,
|
|
48
|
+
environment_variables=environment_variables,
|
|
54
49
|
)
|
|
50
|
+
collection_name: str | None = environment_variables.mongo_db_auth_cache_collection_name
|
|
55
51
|
if collection_name is None:
|
|
56
|
-
raise ValueError(
|
|
57
|
-
"MONGO_DB_AUTH_CACHE_COLLECTION_NAME environment variable must be set"
|
|
58
|
-
)
|
|
52
|
+
raise ValueError("MONGO_DB_AUTH_CACHE_COLLECTION_NAME environment variable must be set")
|
|
59
53
|
self.collection_name: str = collection_name
|
|
60
54
|
|
|
61
55
|
self.environment_variables: AbstractEnvironmentVariables = environment_variables
|
|
62
56
|
if self.environment_variables is None:
|
|
63
|
-
raise ValueError(
|
|
64
|
-
"OAuthMongoCache requires an EnvironmentVariables instance."
|
|
65
|
-
)
|
|
57
|
+
raise ValueError("OAuthMongoCache requires an EnvironmentVariables instance.")
|
|
66
58
|
if not isinstance(self.environment_variables, AbstractEnvironmentVariables):
|
|
67
|
-
raise TypeError(
|
|
68
|
-
"environment_variables must be an instance of EnvironmentVariables"
|
|
69
|
-
)
|
|
59
|
+
raise TypeError("environment_variables must be an instance of EnvironmentVariables")
|
|
70
60
|
|
|
71
61
|
@property
|
|
72
62
|
@override
|
|
@@ -92,9 +82,7 @@ class OAuthMongoCache(OAuthCache):
|
|
|
92
82
|
"key": key,
|
|
93
83
|
},
|
|
94
84
|
)
|
|
95
|
-
disable_delete: bool | None =
|
|
96
|
-
self.environment_variables.mongo_db_cache_disable_delete
|
|
97
|
-
)
|
|
85
|
+
disable_delete: bool | None = self.environment_variables.mongo_db_cache_disable_delete
|
|
98
86
|
if cache_item is not None and cache_item.id is not None:
|
|
99
87
|
# delete the cache item if it exists
|
|
100
88
|
logger.debug(f" ====== Deleting {cache_item.id} =====")
|
|
@@ -131,9 +119,7 @@ class OAuthMongoCache(OAuthCache):
|
|
|
131
119
|
"key": key,
|
|
132
120
|
},
|
|
133
121
|
)
|
|
134
|
-
logger.debug(
|
|
135
|
-
f" ====== For key {key} found {cache_item} default {default} ====="
|
|
136
|
-
)
|
|
122
|
+
logger.debug(f" ====== For key {key} found {cache_item} default {default} =====")
|
|
137
123
|
return cache_item.value if cache_item is not None else default
|
|
138
124
|
|
|
139
125
|
@override
|
|
@@ -166,21 +152,13 @@ class OAuthMongoCache(OAuthCache):
|
|
|
166
152
|
model_class=CacheItem,
|
|
167
153
|
)
|
|
168
154
|
if updated_cache_item is None:
|
|
169
|
-
raise ValueError(
|
|
170
|
-
|
|
171
|
-
)
|
|
172
|
-
logger.debug(
|
|
173
|
-
f"Cache item updated with ID: {updated_cache_item.id} for key: {key} with value: {value}.\n"
|
|
174
|
-
)
|
|
155
|
+
raise ValueError(f"Failed to update cache item with ID: {existing_cache_item_id} for key: {key}")
|
|
156
|
+
logger.debug(f"Cache item updated with ID: {updated_cache_item.id} for key: {key} with value: {value}.\n")
|
|
175
157
|
else:
|
|
176
158
|
logger.debug(f" ====== Creating new cache item {key}: {value} =====")
|
|
177
|
-
cache_item = CacheItem(
|
|
178
|
-
key=key, value=value, created=datetime.now(timezone.utc)
|
|
179
|
-
)
|
|
159
|
+
cache_item = CacheItem(key=key, value=value, created=datetime.now(timezone.utc))
|
|
180
160
|
new_object_id = await self.repository.insert(
|
|
181
161
|
collection_name=self.collection_name,
|
|
182
162
|
model=cache_item,
|
|
183
163
|
)
|
|
184
|
-
logger.debug(
|
|
185
|
-
f"New cache item created with ID: {new_object_id}: {cache_item}"
|
|
186
|
-
)
|
|
164
|
+
logger.debug(f"New cache item created with ID: {new_object_id}: {cache_item}")
|
|
@@ -77,7 +77,6 @@ class AuthConfig(BaseModel):
|
|
|
77
77
|
def _require_client_id_or_registration_url(self) -> Self:
|
|
78
78
|
if not self.client_id and not self.registration_url:
|
|
79
79
|
raise ValueError(
|
|
80
|
-
f"AuthConfig for '{self.auth_provider}' must have either "
|
|
81
|
-
f"client_id or registration_url (for DCR)"
|
|
80
|
+
f"AuthConfig for '{self.auth_provider}' must have either client_id or registration_url (for DCR)"
|
|
82
81
|
)
|
|
83
82
|
return self
|
|
@@ -28,19 +28,13 @@ class AuthConfigReader:
|
|
|
28
28
|
logger.debug("Initializing AuthConfigReader")
|
|
29
29
|
self.environment_variables: AbstractEnvironmentVariables = environment_variables
|
|
30
30
|
if self.environment_variables is None:
|
|
31
|
-
logger.error(
|
|
32
|
-
|
|
33
|
-
)
|
|
34
|
-
raise ValueError(
|
|
35
|
-
"AuthConfigReader requires an EnvironmentVariables instance."
|
|
36
|
-
)
|
|
31
|
+
logger.error("AuthConfigReader initialization failed: environment_variables is None")
|
|
32
|
+
raise ValueError("AuthConfigReader requires an EnvironmentVariables instance.")
|
|
37
33
|
if not isinstance(self.environment_variables, AbstractEnvironmentVariables):
|
|
38
34
|
logger.error(
|
|
39
35
|
f"AuthConfigReader initialization failed: environment_variables is not an instance of AbstractEnvironmentVariables, got {type(environment_variables)}"
|
|
40
36
|
)
|
|
41
|
-
raise TypeError(
|
|
42
|
-
"environment_variables must be an instance of EnvironmentVariables"
|
|
43
|
-
)
|
|
37
|
+
raise TypeError("environment_variables must be an instance of EnvironmentVariables")
|
|
44
38
|
self._auth_configs: list[AuthConfig] | None = None
|
|
45
39
|
# lock to protect first-time initialization of _auth_configs across threads
|
|
46
40
|
self._lock: threading.Lock = threading.Lock()
|
|
@@ -83,9 +77,7 @@ class AuthConfigReader:
|
|
|
83
77
|
)
|
|
84
78
|
if auth_config is not None:
|
|
85
79
|
auth_configs.append(auth_config)
|
|
86
|
-
logger.debug(
|
|
87
|
-
f"Successfully loaded config for provider: {auth_provider}"
|
|
88
|
-
)
|
|
80
|
+
logger.debug(f"Successfully loaded config for provider: {auth_provider}")
|
|
89
81
|
else:
|
|
90
82
|
logger.warning(f"No config found for provider: {auth_provider}")
|
|
91
83
|
# Assign atomically while still under lock
|
|
@@ -124,23 +116,17 @@ class AuthConfigReader:
|
|
|
124
116
|
return
|
|
125
117
|
with self._lock:
|
|
126
118
|
if self._auth_configs is None:
|
|
127
|
-
auth_providers: list[str] | None =
|
|
128
|
-
self.environment_variables.auth_providers
|
|
129
|
-
)
|
|
119
|
+
auth_providers: list[str] | None = self.environment_variables.auth_providers
|
|
130
120
|
if auth_providers is None:
|
|
131
121
|
auth_providers = []
|
|
132
122
|
env_configs: list[AuthConfig] = []
|
|
133
123
|
for auth_provider in auth_providers:
|
|
134
|
-
auth_config = self.read_config_for_auth_provider(
|
|
135
|
-
auth_provider=auth_provider
|
|
136
|
-
)
|
|
124
|
+
auth_config = self.read_config_for_auth_provider(auth_provider=auth_provider)
|
|
137
125
|
if auth_config is not None:
|
|
138
126
|
env_configs.append(auth_config)
|
|
139
127
|
self._auth_configs = env_configs
|
|
140
128
|
|
|
141
|
-
existing_names: set[str] = {
|
|
142
|
-
c.auth_provider.lower() for c in self._auth_configs
|
|
143
|
-
}
|
|
129
|
+
existing_names: set[str] = {c.auth_provider.lower() for c in self._auth_configs}
|
|
144
130
|
for config in configs:
|
|
145
131
|
if config.auth_provider.lower() not in existing_names:
|
|
146
132
|
self._auth_configs.append(config)
|
|
@@ -175,37 +161,23 @@ class AuthConfigReader:
|
|
|
175
161
|
logger.debug(f"Standardized auth provider name to: {auth_provider_upper}")
|
|
176
162
|
# read client_id and client_secret from the environment variables
|
|
177
163
|
auth_client_id: str | None = os.getenv(f"AUTH_CLIENT_ID_{auth_provider_upper}")
|
|
178
|
-
auth_client_secret: str | None = os.getenv(
|
|
179
|
-
f"AUTH_CLIENT_SECRET_{auth_provider_upper}"
|
|
180
|
-
)
|
|
164
|
+
auth_client_secret: str | None = os.getenv(f"AUTH_CLIENT_SECRET_{auth_provider_upper}")
|
|
181
165
|
if auth_client_secret:
|
|
182
166
|
logger.debug(f"Found client secret for provider: {auth_provider_upper}")
|
|
183
167
|
else:
|
|
184
168
|
logger.debug(f"No client secret found for provider: {auth_provider_upper}")
|
|
185
|
-
auth_well_known_uri: str | None = os.getenv(
|
|
186
|
-
f"AUTH_WELL_KNOWN_URI_{auth_provider_upper}"
|
|
187
|
-
)
|
|
169
|
+
auth_well_known_uri: str | None = os.getenv(f"AUTH_WELL_KNOWN_URI_{auth_provider_upper}")
|
|
188
170
|
issuer: str | None = os.getenv(f"AUTH_ISSUER_{auth_provider_upper}")
|
|
189
|
-
logger.debug(
|
|
190
|
-
f"Issuer for {auth_provider_upper}: {issuer if issuer else 'not set'}"
|
|
191
|
-
)
|
|
171
|
+
logger.debug(f"Issuer for {auth_provider_upper}: {issuer if issuer else 'not set'}")
|
|
192
172
|
audience: str | None = os.getenv(f"AUTH_AUDIENCE_{auth_provider_upper}")
|
|
193
173
|
if audience is None:
|
|
194
|
-
logger.error(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
raise ValueError(
|
|
198
|
-
f"AUTH_AUDIENCE_{auth_provider_upper} environment variable must be set"
|
|
199
|
-
)
|
|
200
|
-
friendly_name: str | None = os.getenv(
|
|
201
|
-
f"AUTH_FRIENDLY_NAME_{auth_provider_upper}"
|
|
202
|
-
)
|
|
174
|
+
logger.error(f"AUTH_AUDIENCE_{auth_provider_upper} environment variable is not set")
|
|
175
|
+
raise ValueError(f"AUTH_AUDIENCE_{auth_provider_upper} environment variable must be set")
|
|
176
|
+
friendly_name: str | None = os.getenv(f"AUTH_FRIENDLY_NAME_{auth_provider_upper}")
|
|
203
177
|
if not friendly_name:
|
|
204
178
|
# if no friendly name is set, use the auth_provider as the friendly name
|
|
205
179
|
friendly_name = auth_provider
|
|
206
|
-
logger.debug(
|
|
207
|
-
f"No friendly name set, using auth provider name: {friendly_name}"
|
|
208
|
-
)
|
|
180
|
+
logger.debug(f"No friendly name set, using auth provider name: {friendly_name}")
|
|
209
181
|
else:
|
|
210
182
|
logger.debug(f"Friendly name for {auth_provider}: {friendly_name}")
|
|
211
183
|
|
|
@@ -214,33 +186,21 @@ class AuthConfigReader:
|
|
|
214
186
|
scope = "openid profile email"
|
|
215
187
|
|
|
216
188
|
logger.info(f"Successfully read config for auth provider: {auth_provider}")
|
|
217
|
-
extra_info_text: str | None = os.getenv(
|
|
218
|
-
f"AUTH_EXTRA_INFO_{auth_provider_upper}"
|
|
219
|
-
)
|
|
189
|
+
extra_info_text: str | None = os.getenv(f"AUTH_EXTRA_INFO_{auth_provider_upper}")
|
|
220
190
|
extra_info_dict: dict[str, Any] | None
|
|
221
191
|
if extra_info_text:
|
|
222
192
|
try:
|
|
223
193
|
extra_info_raw: object = json.loads(extra_info_text)
|
|
224
194
|
except json.JSONDecodeError as exc:
|
|
225
|
-
raise ValueError(
|
|
226
|
-
f"Invalid JSON in AUTH_EXTRA_INFO_{auth_provider_upper}: {exc.msg}"
|
|
227
|
-
) from exc
|
|
195
|
+
raise ValueError(f"Invalid JSON in AUTH_EXTRA_INFO_{auth_provider_upper}: {exc.msg}") from exc
|
|
228
196
|
if not isinstance(extra_info_raw, dict):
|
|
229
|
-
raise ValueError(
|
|
230
|
-
f"AUTH_EXTRA_INFO_{auth_provider_upper} must be a JSON object"
|
|
231
|
-
)
|
|
197
|
+
raise ValueError(f"AUTH_EXTRA_INFO_{auth_provider_upper} must be a JSON object")
|
|
232
198
|
extra_info_dict = {str(key): value for key, value in extra_info_raw.items()}
|
|
233
199
|
else:
|
|
234
200
|
extra_info_dict = None
|
|
235
|
-
authorization_endpoint: str | None = os.getenv(
|
|
236
|
-
|
|
237
|
-
)
|
|
238
|
-
token_endpoint: str | None = os.getenv(
|
|
239
|
-
f"AUTH_TOKEN_ENDPOINT_{auth_provider_upper}"
|
|
240
|
-
)
|
|
241
|
-
registration_url: str | None = os.getenv(
|
|
242
|
-
f"AUTH_REGISTRATION_URL_{auth_provider_upper}"
|
|
243
|
-
)
|
|
201
|
+
authorization_endpoint: str | None = os.getenv(f"AUTH_AUTHORIZATION_ENDPOINT_{auth_provider_upper}")
|
|
202
|
+
token_endpoint: str | None = os.getenv(f"AUTH_TOKEN_ENDPOINT_{auth_provider_upper}")
|
|
203
|
+
registration_url: str | None = os.getenv(f"AUTH_REGISTRATION_URL_{auth_provider_upper}")
|
|
244
204
|
|
|
245
205
|
return AuthConfig(
|
|
246
206
|
auth_provider=auth_provider,
|
|
@@ -268,15 +228,11 @@ class AuthConfigReader:
|
|
|
268
228
|
str: The audience for the specified auth provider.
|
|
269
229
|
"""
|
|
270
230
|
logger.debug(f"Getting audience for provider: {auth_provider}")
|
|
271
|
-
auth_config: AuthConfig | None = self.get_config_for_auth_provider(
|
|
272
|
-
auth_provider=auth_provider
|
|
273
|
-
)
|
|
231
|
+
auth_config: AuthConfig | None = self.get_config_for_auth_provider(auth_provider=auth_provider)
|
|
274
232
|
if auth_config is None:
|
|
275
233
|
logger.error(f"AuthConfig for provider {auth_provider} not found")
|
|
276
234
|
raise ValueError(f"AuthConfig for audience {auth_provider} not found.")
|
|
277
|
-
logger.debug(
|
|
278
|
-
f"Found audience for provider {auth_provider}: {auth_config.audience}"
|
|
279
|
-
)
|
|
235
|
+
logger.debug(f"Found audience for provider {auth_provider}: {auth_config.audience}")
|
|
280
236
|
return auth_config.audience
|
|
281
237
|
|
|
282
238
|
def get_provider_for_audience(self, *, audience: str) -> str | None:
|
|
@@ -293,9 +249,7 @@ class AuthConfigReader:
|
|
|
293
249
|
auth_configs: list[AuthConfig] = self.get_auth_configs_for_all_auth_providers()
|
|
294
250
|
for auth_config in auth_configs:
|
|
295
251
|
if auth_config.audience == audience:
|
|
296
|
-
logger.debug(
|
|
297
|
-
f"Found provider for audience {audience}: {auth_config.auth_provider}"
|
|
298
|
-
)
|
|
252
|
+
logger.debug(f"Found provider for audience {audience}: {auth_config.auth_provider}")
|
|
299
253
|
return auth_config.auth_provider
|
|
300
254
|
logger.warning(f"No provider found for audience: {audience}")
|
|
301
255
|
return None
|
|
@@ -314,9 +268,7 @@ class AuthConfigReader:
|
|
|
314
268
|
auth_configs: list[AuthConfig] = self.get_auth_configs_for_all_auth_providers()
|
|
315
269
|
for auth_config in auth_configs:
|
|
316
270
|
if auth_config.client_id == client_id:
|
|
317
|
-
logger.debug(
|
|
318
|
-
f"Found provider for client_id {client_id}: {auth_config.auth_provider}"
|
|
319
|
-
)
|
|
271
|
+
logger.debug(f"Found provider for client_id {client_id}: {auth_config.auth_provider}")
|
|
320
272
|
return auth_config.auth_provider
|
|
321
273
|
logger.warning(f"No provider found for client_id: {client_id}")
|
|
322
274
|
return None
|
|
@@ -73,8 +73,7 @@ class DcrClient:
|
|
|
73
73
|
e.response.text[:500],
|
|
74
74
|
)
|
|
75
75
|
raise ValueError(
|
|
76
|
-
f"DCR registration failed at '{registration_url}' "
|
|
77
|
-
f"with status {e.response.status_code}"
|
|
76
|
+
f"DCR registration failed at '{registration_url}' with status {e.response.status_code}"
|
|
78
77
|
) from e
|
|
79
78
|
dcr_response: dict[str, Any] = response.json()
|
|
80
79
|
|
|
@@ -86,13 +85,11 @@ class DcrClient:
|
|
|
86
85
|
response_keys,
|
|
87
86
|
)
|
|
88
87
|
raise ValueError(
|
|
89
|
-
f"DCR response from '{registration_url}' missing 'client_id'. "
|
|
90
|
-
f"Response keys: {response_keys}"
|
|
88
|
+
f"DCR response from '{registration_url}' missing 'client_id'. Response keys: {response_keys}"
|
|
91
89
|
)
|
|
92
90
|
|
|
93
91
|
logger.info(
|
|
94
|
-
"DCR: Registration successful at '%s' — client_id=%s, "
|
|
95
|
-
"has_secret=%s, expires_at=%s",
|
|
92
|
+
"DCR: Registration successful at '%s' — client_id=%s, has_secret=%s, expires_at=%s",
|
|
96
93
|
registration_url,
|
|
97
94
|
dcr_response["client_id"],
|
|
98
95
|
"client_secret" in dcr_response,
|
|
@@ -32,11 +32,9 @@ class DcrManager:
|
|
|
32
32
|
) -> None:
|
|
33
33
|
self._collection_name = collection_name
|
|
34
34
|
self._redirect_uri = redirect_uri
|
|
35
|
-
self._repository: AsyncBaseRepository[DcrRegistration] = (
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
environment_variables=environment_variables,
|
|
39
|
-
)
|
|
35
|
+
self._repository: AsyncBaseRepository[DcrRegistration] = RepositoryFactory.get_repository(
|
|
36
|
+
repository_type=environment_variables.oauth_cache,
|
|
37
|
+
environment_variables=environment_variables,
|
|
40
38
|
)
|
|
41
39
|
self._dcr_client = dcr_client or DcrClient()
|
|
42
40
|
|
|
@@ -53,8 +51,7 @@ class DcrManager:
|
|
|
53
51
|
) -> DcrRegistration | None:
|
|
54
52
|
if client_id:
|
|
55
53
|
logger.info(
|
|
56
|
-
"DCR: Skipping registration for '%s' — client_id already "
|
|
57
|
-
"provided (client_id=%s)",
|
|
54
|
+
"DCR: Skipping registration for '%s' — client_id already provided (client_id=%s)",
|
|
58
55
|
auth_provider,
|
|
59
56
|
client_id,
|
|
60
57
|
)
|
|
@@ -62,13 +59,11 @@ class DcrManager:
|
|
|
62
59
|
|
|
63
60
|
if not registration_url:
|
|
64
61
|
logger.error(
|
|
65
|
-
"DCR: No registration_url and no client_id for '%s' — "
|
|
66
|
-
"cannot resolve credentials",
|
|
62
|
+
"DCR: No registration_url and no client_id for '%s' — cannot resolve credentials",
|
|
67
63
|
auth_provider,
|
|
68
64
|
)
|
|
69
65
|
raise ValueError(
|
|
70
|
-
f"registration_url is required for DCR when client_id is not "
|
|
71
|
-
f"provided (auth_provider='{auth_provider}')"
|
|
66
|
+
f"registration_url is required for DCR when client_id is not provided (auth_provider='{auth_provider}')"
|
|
72
67
|
)
|
|
73
68
|
|
|
74
69
|
validate_url(registration_url)
|
|
@@ -95,16 +90,14 @@ class DcrManager:
|
|
|
95
90
|
|
|
96
91
|
if cached and self._is_expired(cached):
|
|
97
92
|
logger.info(
|
|
98
|
-
"DCR: Cached credentials for '%s' are expired "
|
|
99
|
-
"(client_id=%s, expired_at=%s) — re-registering",
|
|
93
|
+
"DCR: Cached credentials for '%s' are expired (client_id=%s, expired_at=%s) — re-registering",
|
|
100
94
|
auth_provider,
|
|
101
95
|
cached.client_id,
|
|
102
96
|
cached.client_secret_expires_at,
|
|
103
97
|
)
|
|
104
98
|
else:
|
|
105
99
|
logger.info(
|
|
106
|
-
"DCR: No cached credentials found for '%s' — performing "
|
|
107
|
-
"new registration at '%s'",
|
|
100
|
+
"DCR: No cached credentials found for '%s' — performing new registration at '%s'",
|
|
108
101
|
auth_provider,
|
|
109
102
|
registration_url,
|
|
110
103
|
)
|
|
@@ -137,8 +130,7 @@ class DcrManager:
|
|
|
137
130
|
registration_url: str,
|
|
138
131
|
) -> DcrRegistration | None:
|
|
139
132
|
logger.debug(
|
|
140
|
-
"DCR: Querying cache for auth_provider='%s', "
|
|
141
|
-
"registration_url='%s', collection='%s'",
|
|
133
|
+
"DCR: Querying cache for auth_provider='%s', registration_url='%s', collection='%s'",
|
|
142
134
|
auth_provider,
|
|
143
135
|
registration_url,
|
|
144
136
|
self._collection_name,
|
|
@@ -10,19 +10,13 @@ class DcrRegistration(BaseDbModel):
|
|
|
10
10
|
"""Persisted DCR credentials in MongoDB."""
|
|
11
11
|
|
|
12
12
|
created: datetime = Field(description="When the registration was created.")
|
|
13
|
-
updated: Optional[datetime] = Field(
|
|
14
|
-
default=None, description="When the registration was last updated."
|
|
15
|
-
)
|
|
13
|
+
updated: Optional[datetime] = Field(default=None, description="When the registration was last updated.")
|
|
16
14
|
auth_provider: str = Field(description="The normalized auth provider key.")
|
|
17
15
|
registration_url: str = Field(description="The DCR endpoint URL.")
|
|
18
16
|
client_id: str = Field(description="The client_id from DCR.")
|
|
19
|
-
client_secret: Optional[str] = Field(
|
|
20
|
-
default=None, description="The client_secret from DCR (if any)."
|
|
21
|
-
)
|
|
17
|
+
client_secret: Optional[str] = Field(default=None, description="The client_secret from DCR (if any).")
|
|
22
18
|
client_secret_expires_at: int = Field(
|
|
23
19
|
default=0,
|
|
24
20
|
description="Unix timestamp when client_secret expires. 0 = no expiry.",
|
|
25
21
|
)
|
|
26
|
-
registration_response: dict[str, Any] = Field(
|
|
27
|
-
default_factory=dict, description="The full DCR response."
|
|
28
|
-
)
|
|
22
|
+
registration_response: dict[str, Any] = Field(default_factory=dict, description="The full DCR response.")
|