oidcauthlib 3.0.3__tar.gz → 3.0.5__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.3/oidcauthlib.egg-info → oidcauthlib-3.0.5}/PKG-INFO +1 -1
- oidcauthlib-3.0.5/VERSION +1 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/dcr/dcr_client.py +30 -2
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/dcr/dcr_manager.py +65 -3
- oidcauthlib-3.0.5/oidcauthlib/auth/well_known_configuration/auth_server_metadata.py +18 -0
- oidcauthlib-3.0.5/oidcauthlib/auth/well_known_configuration/auth_server_metadata_discovery.py +112 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5/oidcauthlib.egg-info}/PKG-INFO +1 -1
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib.egg-info/SOURCES.txt +3 -0
- oidcauthlib-3.0.5/tests/auth/well_known_configuration/test_auth_server_metadata_discovery.py +184 -0
- oidcauthlib-3.0.3/VERSION +0 -1
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/LICENSE +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/MANIFEST.in +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/Makefile +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/README.md +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/auth_helper.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/auth_manager.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/cache/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/cache/oauth_cache.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/cache/oauth_memory_cache.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/cache/oauth_mongo_cache.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/config/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/config/auth_config.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/config/auth_config_reader.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/dcr/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/dcr/dcr_registration.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/exceptions/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/exceptions/authorization_bearer_token_expired_exception.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/exceptions/authorization_bearer_token_invalid_exception.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/exceptions/authorization_bearer_token_missing_exception.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/exceptions/authorization_needed_exception.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/fastapi_auth_manager.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/middleware/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/middleware/request_scope_middleware.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/middleware/token_reader_middleware.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/models/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/models/auth.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/models/base_db_model.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/models/cache_item.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/models/client_key_set.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/models/token.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/base_repository.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/memory/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/memory/memory_repository.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/mongo/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/mongo/mongo_repository.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/repository_factory.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/routers/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/routers/auth_router.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/token_reader.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/well_known_configuration/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/well_known_configuration/well_known_configuration_cache.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/well_known_configuration/well_known_configuration_cache_result.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/well_known_configuration/well_known_configuration_manager.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/container/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/container/oidc_authlib_container_factory.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/open_telemetry/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/open_telemetry/attribute_names.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/open_telemetry/span_names.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/py.typed +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/cache_to_collection_mapper.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/memory_storage_factory.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/mongo_gridfs_db.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/mongo_gridfs_exception.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/mongo_storage_factory.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/storage_factory.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/storage/storage_factory_creator.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/cached.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/environment/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/environment/abstract_environment_variables.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/environment/oidc_environment_variables.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/logger/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/logger/log_levels.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/logger/logging_response.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/logger/logging_transport.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/mongo_url_utils.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/utilities/url_validator.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib.egg-info/dependency_links.txt +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib.egg-info/not-zip-safe +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib.egg-info/requires.txt +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib.egg-info/top_level.txt +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/setup.cfg +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/setup.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/cache/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/cache/test_oauth_memory_cache.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/config/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/config/test_auth_config.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/config/test_auth_config_reader.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/config/test_auth_config_reader_register.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/config/test_auth_config_reader_thread_safety.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/conftest.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/dcr/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/dcr/test_dcr_client.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/dcr/test_dcr_manager.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/middleware/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/middleware/test_request_scope_middleware.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/middleware/test_token_reader_middleware.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/models/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/models/test_auth.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/models/test_base_db_model.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/models/test_cache_item.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/models/test_token.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/memory/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/memory/test_memory_repository.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/mongo/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/mongo/test_mongo_repository.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/mongo/test_mongo_repository_real.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/test_auth_helper.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/test_auth_helper2.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/test_auth_manager.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/test_register_dynamic_provider.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/well_known_configuration/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/well_known_configuration/test_well_known_configuration_cache.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/well_known_configuration/test_well_known_configuration_manager.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/conftest.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/storage/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/storage/test_mongo_gridfs_db.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/storage/test_mongo_gridfs_race_setup.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/storage/test_mongo_store_factory.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/storage/test_storage_factory_security.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/test_mongo_url_utils.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/test_simple.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/utilities/__init__.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/utilities/test_cached.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/utilities/test_mongo_url_utils.py +0 -0
- {oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/utilities/test_url_validator.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.0.5
|
|
@@ -46,7 +46,16 @@ class DcrClient:
|
|
|
46
46
|
if contacts:
|
|
47
47
|
payload["contacts"] = contacts
|
|
48
48
|
|
|
49
|
-
logger.info(
|
|
49
|
+
logger.info(
|
|
50
|
+
"DCR: Sending registration request to '%s' with payload keys: %s",
|
|
51
|
+
registration_url,
|
|
52
|
+
sorted(payload.keys()),
|
|
53
|
+
)
|
|
54
|
+
logger.debug(
|
|
55
|
+
"DCR: Full registration payload for '%s': %s",
|
|
56
|
+
registration_url,
|
|
57
|
+
payload,
|
|
58
|
+
)
|
|
50
59
|
|
|
51
60
|
async with httpx.AsyncClient(timeout=self._timeout_seconds) as client:
|
|
52
61
|
response = await client.post(
|
|
@@ -57,6 +66,12 @@ class DcrClient:
|
|
|
57
66
|
try:
|
|
58
67
|
response.raise_for_status()
|
|
59
68
|
except httpx.HTTPStatusError as e:
|
|
69
|
+
logger.error(
|
|
70
|
+
"DCR: Registration failed at '%s' — HTTP %s. Response body: %s",
|
|
71
|
+
registration_url,
|
|
72
|
+
e.response.status_code,
|
|
73
|
+
e.response.text[:500],
|
|
74
|
+
)
|
|
60
75
|
raise ValueError(
|
|
61
76
|
f"DCR registration failed at '{registration_url}' "
|
|
62
77
|
f"with status {e.response.status_code}"
|
|
@@ -65,14 +80,27 @@ class DcrClient:
|
|
|
65
80
|
|
|
66
81
|
if "client_id" not in dcr_response:
|
|
67
82
|
response_keys: list[str] = sorted(dcr_response.keys())
|
|
83
|
+
logger.error(
|
|
84
|
+
"DCR: Response from '%s' missing 'client_id'. Keys present: %s",
|
|
85
|
+
registration_url,
|
|
86
|
+
response_keys,
|
|
87
|
+
)
|
|
68
88
|
raise ValueError(
|
|
69
89
|
f"DCR response from '{registration_url}' missing 'client_id'. "
|
|
70
90
|
f"Response keys: {response_keys}"
|
|
71
91
|
)
|
|
72
92
|
|
|
73
93
|
logger.info(
|
|
74
|
-
"DCR successful at '%s'
|
|
94
|
+
"DCR: Registration successful at '%s' — client_id=%s, "
|
|
95
|
+
"has_secret=%s, expires_at=%s",
|
|
75
96
|
registration_url,
|
|
76
97
|
dcr_response["client_id"],
|
|
98
|
+
"client_secret" in dcr_response,
|
|
99
|
+
dcr_response.get("client_secret_expires_at", "not_set"),
|
|
100
|
+
)
|
|
101
|
+
logger.debug(
|
|
102
|
+
"DCR: Full response from '%s': %s",
|
|
103
|
+
registration_url,
|
|
104
|
+
{k: v for k, v in dcr_response.items() if k != "client_secret"},
|
|
77
105
|
)
|
|
78
106
|
return dcr_response
|
|
@@ -52,9 +52,20 @@ class DcrManager:
|
|
|
52
52
|
contacts: list[str] | None = None,
|
|
53
53
|
) -> DcrRegistration | None:
|
|
54
54
|
if client_id:
|
|
55
|
+
logger.info(
|
|
56
|
+
"DCR: Skipping registration for '%s' — client_id already "
|
|
57
|
+
"provided (client_id=%s)",
|
|
58
|
+
auth_provider,
|
|
59
|
+
client_id,
|
|
60
|
+
)
|
|
55
61
|
return None
|
|
56
62
|
|
|
57
63
|
if not registration_url:
|
|
64
|
+
logger.error(
|
|
65
|
+
"DCR: No registration_url and no client_id for '%s' — "
|
|
66
|
+
"cannot resolve credentials",
|
|
67
|
+
auth_provider,
|
|
68
|
+
)
|
|
58
69
|
raise ValueError(
|
|
59
70
|
f"registration_url is required for DCR when client_id is not "
|
|
60
71
|
f"provided (auth_provider='{auth_provider}')"
|
|
@@ -62,19 +73,43 @@ class DcrManager:
|
|
|
62
73
|
|
|
63
74
|
validate_url(registration_url)
|
|
64
75
|
|
|
76
|
+
logger.info(
|
|
77
|
+
"DCR: Resolving credentials for '%s' via registration_url='%s'",
|
|
78
|
+
auth_provider,
|
|
79
|
+
registration_url,
|
|
80
|
+
)
|
|
81
|
+
|
|
65
82
|
cached = await self._find_cached(
|
|
66
83
|
auth_provider=auth_provider,
|
|
67
84
|
registration_url=registration_url,
|
|
68
85
|
)
|
|
69
86
|
|
|
70
87
|
if cached and not self._is_expired(cached):
|
|
71
|
-
logger.
|
|
72
|
-
"Using cached
|
|
88
|
+
logger.info(
|
|
89
|
+
"DCR: Using cached credentials for '%s' — client_id=%s, "
|
|
90
|
+
"expires_at=%s",
|
|
73
91
|
auth_provider,
|
|
74
92
|
cached.client_id,
|
|
93
|
+
cached.client_secret_expires_at or "never",
|
|
75
94
|
)
|
|
76
95
|
return cached
|
|
77
96
|
|
|
97
|
+
if cached and self._is_expired(cached):
|
|
98
|
+
logger.info(
|
|
99
|
+
"DCR: Cached credentials for '%s' are expired "
|
|
100
|
+
"(client_id=%s, expired_at=%s) — re-registering",
|
|
101
|
+
auth_provider,
|
|
102
|
+
cached.client_id,
|
|
103
|
+
cached.client_secret_expires_at,
|
|
104
|
+
)
|
|
105
|
+
else:
|
|
106
|
+
logger.info(
|
|
107
|
+
"DCR: No cached credentials found for '%s' — performing "
|
|
108
|
+
"new registration at '%s'",
|
|
109
|
+
auth_provider,
|
|
110
|
+
registration_url,
|
|
111
|
+
)
|
|
112
|
+
|
|
78
113
|
dcr_response = await self._dcr_client.register(
|
|
79
114
|
registration_url=registration_url,
|
|
80
115
|
redirect_uri=self._redirect_uri,
|
|
@@ -84,11 +119,17 @@ class DcrManager:
|
|
|
84
119
|
contacts=contacts,
|
|
85
120
|
)
|
|
86
121
|
|
|
87
|
-
|
|
122
|
+
registration = await self._persist(
|
|
88
123
|
auth_provider=auth_provider,
|
|
89
124
|
registration_url=registration_url,
|
|
90
125
|
dcr_response=dcr_response,
|
|
91
126
|
)
|
|
127
|
+
logger.info(
|
|
128
|
+
"DCR: Persisted credentials for '%s' — client_id=%s",
|
|
129
|
+
auth_provider,
|
|
130
|
+
registration.client_id,
|
|
131
|
+
)
|
|
132
|
+
return registration
|
|
92
133
|
|
|
93
134
|
async def _find_cached(
|
|
94
135
|
self,
|
|
@@ -96,6 +137,13 @@ class DcrManager:
|
|
|
96
137
|
auth_provider: str,
|
|
97
138
|
registration_url: str,
|
|
98
139
|
) -> DcrRegistration | None:
|
|
140
|
+
logger.debug(
|
|
141
|
+
"DCR: Querying cache for auth_provider='%s', "
|
|
142
|
+
"registration_url='%s', collection='%s'",
|
|
143
|
+
auth_provider,
|
|
144
|
+
registration_url,
|
|
145
|
+
self._collection_name,
|
|
146
|
+
)
|
|
99
147
|
results = await self._repository.find_many(
|
|
100
148
|
collection_name=self._collection_name,
|
|
101
149
|
model_class=DcrRegistration,
|
|
@@ -104,6 +152,20 @@ class DcrManager:
|
|
|
104
152
|
"registration_url": registration_url,
|
|
105
153
|
},
|
|
106
154
|
)
|
|
155
|
+
if results:
|
|
156
|
+
logger.debug(
|
|
157
|
+
"DCR: Cache hit for '%s' — found %d result(s), "
|
|
158
|
+
"client_id=%s",
|
|
159
|
+
auth_provider,
|
|
160
|
+
len(results),
|
|
161
|
+
results[0].client_id,
|
|
162
|
+
)
|
|
163
|
+
else:
|
|
164
|
+
logger.debug(
|
|
165
|
+
"DCR: Cache miss for '%s' at '%s'",
|
|
166
|
+
auth_provider,
|
|
167
|
+
registration_url,
|
|
168
|
+
)
|
|
107
169
|
return results[0] if results else None
|
|
108
170
|
|
|
109
171
|
@staticmethod
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@dataclass(frozen=True)
|
|
5
|
+
class AuthServerMetadata:
|
|
6
|
+
"""Parsed OAuth 2.0 Authorization Server Metadata (RFC 8414) or
|
|
7
|
+
OpenID Connect Discovery metadata.
|
|
8
|
+
|
|
9
|
+
Contains the subset of fields needed to configure an OAuth client:
|
|
10
|
+
authorization and token endpoints (required), plus optional registration
|
|
11
|
+
endpoint, issuer, and supported scopes.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
authorization_endpoint: str
|
|
15
|
+
token_endpoint: str
|
|
16
|
+
registration_endpoint: str | None = None
|
|
17
|
+
issuer: str | None = None
|
|
18
|
+
scopes_supported: list[str] | None = None
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Protocol, Any
|
|
3
|
+
from urllib.parse import urlparse
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from oidcauthlib.auth.well_known_configuration.auth_server_metadata import (
|
|
8
|
+
AuthServerMetadata,
|
|
9
|
+
)
|
|
10
|
+
from oidcauthlib.utilities.logger.log_levels import SRC_LOG_LEVELS
|
|
11
|
+
|
|
12
|
+
logger = logging.getLogger(__name__)
|
|
13
|
+
logger.setLevel(SRC_LOG_LEVELS["AUTH"])
|
|
14
|
+
|
|
15
|
+
_DISCOVERY_TIMEOUT = httpx.Timeout(10.0)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AuthServerMetadataDiscoveryProtocol(Protocol):
|
|
19
|
+
"""Protocol for discovering OAuth authorization server metadata from a resource URL."""
|
|
20
|
+
|
|
21
|
+
async def discover(self, *, resource_url: str) -> AuthServerMetadata | None: ...
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AuthServerMetadataDiscovery:
|
|
25
|
+
"""Discovers OAuth authorization server metadata from a resource server URL.
|
|
26
|
+
|
|
27
|
+
Implements RFC 8414 (OAuth 2.0 Authorization Server Metadata) with a
|
|
28
|
+
fallback to OpenID Connect Discovery. Given a resource URL, extracts
|
|
29
|
+
the origin (scheme + host + port) and attempts to fetch:
|
|
30
|
+
|
|
31
|
+
1. ``{origin}/.well-known/oauth-authorization-server`` (RFC 8414)
|
|
32
|
+
2. ``{origin}/.well-known/openid-configuration`` (OIDC Discovery)
|
|
33
|
+
|
|
34
|
+
Returns an ``AuthServerMetadata`` with the discovered endpoints, or
|
|
35
|
+
``None`` if neither well-known URL returns valid metadata.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def _extract_base_url(url: str) -> str:
|
|
40
|
+
parsed = urlparse(url)
|
|
41
|
+
port_suffix = f":{parsed.port}" if parsed.port else ""
|
|
42
|
+
return f"{parsed.scheme}://{parsed.hostname}{port_suffix}"
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _parse_metadata(metadata: dict[str, Any]) -> AuthServerMetadata | None:
|
|
46
|
+
authorization_endpoint = metadata.get("authorization_endpoint")
|
|
47
|
+
token_endpoint = metadata.get("token_endpoint")
|
|
48
|
+
if not authorization_endpoint or not token_endpoint:
|
|
49
|
+
logger.warning(
|
|
50
|
+
"Discovered metadata missing required endpoints "
|
|
51
|
+
"(authorization_endpoint=%s, token_endpoint=%s)",
|
|
52
|
+
authorization_endpoint,
|
|
53
|
+
token_endpoint,
|
|
54
|
+
)
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
scopes: list[str] | None = None
|
|
58
|
+
scopes_supported = metadata.get("scopes_supported")
|
|
59
|
+
if isinstance(scopes_supported, list):
|
|
60
|
+
scopes = [s for s in scopes_supported if isinstance(s, str)]
|
|
61
|
+
|
|
62
|
+
return AuthServerMetadata(
|
|
63
|
+
authorization_endpoint=authorization_endpoint,
|
|
64
|
+
token_endpoint=token_endpoint,
|
|
65
|
+
registration_endpoint=metadata.get("registration_endpoint"),
|
|
66
|
+
issuer=metadata.get("issuer"),
|
|
67
|
+
scopes_supported=scopes,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
async def discover(self, *, resource_url: str) -> AuthServerMetadata | None:
|
|
71
|
+
"""Discover OAuth authorization server metadata for a resource URL.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
resource_url: The URL of the resource server (e.g. an MCP server).
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
AuthServerMetadata if discovery succeeds, None otherwise.
|
|
78
|
+
"""
|
|
79
|
+
base_url = self._extract_base_url(resource_url)
|
|
80
|
+
|
|
81
|
+
well_known_urls = [
|
|
82
|
+
f"{base_url}/.well-known/oauth-authorization-server",
|
|
83
|
+
f"{base_url}/.well-known/openid-configuration",
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
async with httpx.AsyncClient(timeout=_DISCOVERY_TIMEOUT) as client:
|
|
87
|
+
for url in well_known_urls:
|
|
88
|
+
try:
|
|
89
|
+
response = await client.get(url)
|
|
90
|
+
if response.status_code != 200:
|
|
91
|
+
logger.debug(
|
|
92
|
+
"Discovery fetch %s returned status %s, skipping",
|
|
93
|
+
url,
|
|
94
|
+
response.status_code,
|
|
95
|
+
)
|
|
96
|
+
continue
|
|
97
|
+
metadata = response.json()
|
|
98
|
+
result = self._parse_metadata(metadata)
|
|
99
|
+
if result is not None:
|
|
100
|
+
logger.info(
|
|
101
|
+
"Discovered auth server metadata from %s for resource %s",
|
|
102
|
+
url,
|
|
103
|
+
resource_url,
|
|
104
|
+
)
|
|
105
|
+
return result
|
|
106
|
+
except httpx.TimeoutException:
|
|
107
|
+
logger.debug("Discovery fetch %s timed out", url)
|
|
108
|
+
except (httpx.HTTPError, ValueError) as e:
|
|
109
|
+
logger.debug("Discovery fetch %s failed: %s", url, e)
|
|
110
|
+
|
|
111
|
+
logger.info("No auth server metadata discovered for resource %s", resource_url)
|
|
112
|
+
return None
|
|
@@ -53,6 +53,8 @@ oidcauthlib/auth/repository/mongo/mongo_repository.py
|
|
|
53
53
|
oidcauthlib/auth/routers/__init__.py
|
|
54
54
|
oidcauthlib/auth/routers/auth_router.py
|
|
55
55
|
oidcauthlib/auth/well_known_configuration/__init__.py
|
|
56
|
+
oidcauthlib/auth/well_known_configuration/auth_server_metadata.py
|
|
57
|
+
oidcauthlib/auth/well_known_configuration/auth_server_metadata_discovery.py
|
|
56
58
|
oidcauthlib/auth/well_known_configuration/well_known_configuration_cache.py
|
|
57
59
|
oidcauthlib/auth/well_known_configuration/well_known_configuration_cache_result.py
|
|
58
60
|
oidcauthlib/auth/well_known_configuration/well_known_configuration_manager.py
|
|
@@ -115,6 +117,7 @@ tests/auth/repository/mongo/__init__.py
|
|
|
115
117
|
tests/auth/repository/mongo/test_mongo_repository.py
|
|
116
118
|
tests/auth/repository/mongo/test_mongo_repository_real.py
|
|
117
119
|
tests/auth/well_known_configuration/__init__.py
|
|
120
|
+
tests/auth/well_known_configuration/test_auth_server_metadata_discovery.py
|
|
118
121
|
tests/auth/well_known_configuration/test_well_known_configuration_cache.py
|
|
119
122
|
tests/auth/well_known_configuration/test_well_known_configuration_manager.py
|
|
120
123
|
tests/storage/__init__.py
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"""Tests for AuthServerMetadataDiscovery — RFC 8414 and OIDC Discovery."""
|
|
2
|
+
|
|
3
|
+
import httpx
|
|
4
|
+
import pytest
|
|
5
|
+
import respx
|
|
6
|
+
|
|
7
|
+
from oidcauthlib.auth.well_known_configuration.auth_server_metadata_discovery import (
|
|
8
|
+
AuthServerMetadataDiscovery,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
_BASE = "https://mcp.example.com"
|
|
12
|
+
_RESOURCE_URL = f"{_BASE}/v1/mcp"
|
|
13
|
+
_RFC8414_URL = f"{_BASE}/.well-known/oauth-authorization-server"
|
|
14
|
+
_OIDC_URL = f"{_BASE}/.well-known/openid-configuration"
|
|
15
|
+
|
|
16
|
+
_VALID_METADATA = {
|
|
17
|
+
"issuer": "https://auth.example.com",
|
|
18
|
+
"authorization_endpoint": "https://auth.example.com/authorize",
|
|
19
|
+
"token_endpoint": "https://auth.example.com/token",
|
|
20
|
+
"registration_endpoint": "https://auth.example.com/register",
|
|
21
|
+
"scopes_supported": ["openid", "profile", "email"],
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@pytest.mark.asyncio
|
|
26
|
+
@respx.mock
|
|
27
|
+
async def test_rfc8414_success() -> None:
|
|
28
|
+
"""RFC 8414 endpoint returns valid metadata."""
|
|
29
|
+
respx.get(_RFC8414_URL).mock(return_value=httpx.Response(200, json=_VALID_METADATA))
|
|
30
|
+
|
|
31
|
+
discovery = AuthServerMetadataDiscovery()
|
|
32
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
33
|
+
|
|
34
|
+
assert result is not None
|
|
35
|
+
assert result.authorization_endpoint == "https://auth.example.com/authorize"
|
|
36
|
+
assert result.token_endpoint == "https://auth.example.com/token"
|
|
37
|
+
assert result.registration_endpoint == "https://auth.example.com/register"
|
|
38
|
+
assert result.issuer == "https://auth.example.com"
|
|
39
|
+
assert result.scopes_supported == ["openid", "profile", "email"]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@pytest.mark.asyncio
|
|
43
|
+
@respx.mock
|
|
44
|
+
async def test_rfc8414_fails_oidc_succeeds() -> None:
|
|
45
|
+
"""RFC 8414 returns 404, falls back to OIDC Discovery."""
|
|
46
|
+
respx.get(_RFC8414_URL).mock(return_value=httpx.Response(404))
|
|
47
|
+
respx.get(_OIDC_URL).mock(return_value=httpx.Response(200, json=_VALID_METADATA))
|
|
48
|
+
|
|
49
|
+
discovery = AuthServerMetadataDiscovery()
|
|
50
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
51
|
+
|
|
52
|
+
assert result is not None
|
|
53
|
+
assert result.authorization_endpoint == "https://auth.example.com/authorize"
|
|
54
|
+
assert result.token_endpoint == "https://auth.example.com/token"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.mark.asyncio
|
|
58
|
+
@respx.mock
|
|
59
|
+
async def test_both_endpoints_fail() -> None:
|
|
60
|
+
"""Both well-known endpoints return errors — returns None."""
|
|
61
|
+
respx.get(_RFC8414_URL).mock(return_value=httpx.Response(404))
|
|
62
|
+
respx.get(_OIDC_URL).mock(return_value=httpx.Response(500))
|
|
63
|
+
|
|
64
|
+
discovery = AuthServerMetadataDiscovery()
|
|
65
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
66
|
+
|
|
67
|
+
assert result is None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@pytest.mark.asyncio
|
|
71
|
+
@respx.mock
|
|
72
|
+
async def test_malformed_json() -> None:
|
|
73
|
+
"""Endpoint returns non-JSON — returns None."""
|
|
74
|
+
respx.get(_RFC8414_URL).mock(return_value=httpx.Response(200, text="not json"))
|
|
75
|
+
respx.get(_OIDC_URL).mock(return_value=httpx.Response(200, text="also not json"))
|
|
76
|
+
|
|
77
|
+
discovery = AuthServerMetadataDiscovery()
|
|
78
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
79
|
+
|
|
80
|
+
assert result is None
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@pytest.mark.asyncio
|
|
84
|
+
@respx.mock
|
|
85
|
+
async def test_missing_required_endpoints() -> None:
|
|
86
|
+
"""Metadata without authorization_endpoint or token_endpoint — returns None."""
|
|
87
|
+
respx.get(_RFC8414_URL).mock(
|
|
88
|
+
return_value=httpx.Response(200, json={"issuer": "https://auth.example.com"})
|
|
89
|
+
)
|
|
90
|
+
respx.get(_OIDC_URL).mock(return_value=httpx.Response(404))
|
|
91
|
+
|
|
92
|
+
discovery = AuthServerMetadataDiscovery()
|
|
93
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
94
|
+
|
|
95
|
+
assert result is None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@pytest.mark.asyncio
|
|
99
|
+
@respx.mock
|
|
100
|
+
async def test_network_timeout() -> None:
|
|
101
|
+
"""Network timeout — returns None."""
|
|
102
|
+
respx.get(_RFC8414_URL).mock(side_effect=httpx.ConnectTimeout("timeout"))
|
|
103
|
+
respx.get(_OIDC_URL).mock(side_effect=httpx.ConnectTimeout("timeout"))
|
|
104
|
+
|
|
105
|
+
discovery = AuthServerMetadataDiscovery()
|
|
106
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
107
|
+
|
|
108
|
+
assert result is None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@pytest.mark.asyncio
|
|
112
|
+
@respx.mock
|
|
113
|
+
async def test_no_scopes_in_metadata() -> None:
|
|
114
|
+
"""Metadata without scopes_supported — scopes_supported is None."""
|
|
115
|
+
metadata = {
|
|
116
|
+
"authorization_endpoint": "https://auth.example.com/authorize",
|
|
117
|
+
"token_endpoint": "https://auth.example.com/token",
|
|
118
|
+
}
|
|
119
|
+
respx.get(_RFC8414_URL).mock(return_value=httpx.Response(200, json=metadata))
|
|
120
|
+
|
|
121
|
+
discovery = AuthServerMetadataDiscovery()
|
|
122
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
123
|
+
|
|
124
|
+
assert result is not None
|
|
125
|
+
assert result.scopes_supported is None
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@pytest.mark.asyncio
|
|
129
|
+
@respx.mock
|
|
130
|
+
async def test_url_with_port() -> None:
|
|
131
|
+
"""Resource URL with custom port — base URL preserves port."""
|
|
132
|
+
url = "https://mcp.example.com:8443/v1/mcp"
|
|
133
|
+
respx.get(
|
|
134
|
+
"https://mcp.example.com:8443/.well-known/oauth-authorization-server"
|
|
135
|
+
).mock(return_value=httpx.Response(200, json=_VALID_METADATA))
|
|
136
|
+
|
|
137
|
+
discovery = AuthServerMetadataDiscovery()
|
|
138
|
+
result = await discovery.discover(resource_url=url)
|
|
139
|
+
|
|
140
|
+
assert result is not None
|
|
141
|
+
assert result.authorization_endpoint == "https://auth.example.com/authorize"
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class TestExtractBaseUrl:
|
|
145
|
+
def test_strips_path(self) -> None:
|
|
146
|
+
assert (
|
|
147
|
+
AuthServerMetadataDiscovery._extract_base_url(
|
|
148
|
+
"https://mcp.example.com/v1/mcp"
|
|
149
|
+
)
|
|
150
|
+
== "https://mcp.example.com"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
def test_preserves_port(self) -> None:
|
|
154
|
+
assert (
|
|
155
|
+
AuthServerMetadataDiscovery._extract_base_url(
|
|
156
|
+
"https://mcp.example.com:8443/v1/mcp"
|
|
157
|
+
)
|
|
158
|
+
== "https://mcp.example.com:8443"
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
def test_no_path(self) -> None:
|
|
162
|
+
assert (
|
|
163
|
+
AuthServerMetadataDiscovery._extract_base_url("https://mcp.example.com")
|
|
164
|
+
== "https://mcp.example.com"
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@pytest.mark.asyncio
|
|
169
|
+
@respx.mock
|
|
170
|
+
async def test_no_registration_endpoint() -> None:
|
|
171
|
+
"""Metadata without registration_endpoint — registration_endpoint is None."""
|
|
172
|
+
metadata = {
|
|
173
|
+
"authorization_endpoint": "https://auth.example.com/authorize",
|
|
174
|
+
"token_endpoint": "https://auth.example.com/token",
|
|
175
|
+
"issuer": "https://auth.example.com",
|
|
176
|
+
}
|
|
177
|
+
respx.get(_RFC8414_URL).mock(return_value=httpx.Response(200, json=metadata))
|
|
178
|
+
|
|
179
|
+
discovery = AuthServerMetadataDiscovery()
|
|
180
|
+
result = await discovery.discover(resource_url=_RESOURCE_URL)
|
|
181
|
+
|
|
182
|
+
assert result is not None
|
|
183
|
+
assert result.registration_endpoint is None
|
|
184
|
+
assert result.issuer == "https://auth.example.com"
|
oidcauthlib-3.0.3/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
3.0.3
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/middleware/request_scope_middleware.py
RENAMED
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/middleware/token_reader_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/memory/memory_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/repository/mongo/mongo_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/auth/well_known_configuration/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/oidcauthlib/container/oidc_authlib_container_factory.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/config/test_auth_config_reader_register.py
RENAMED
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/config/test_auth_config_reader_thread_safety.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/middleware/test_request_scope_middleware.py
RENAMED
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/middleware/test_token_reader_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/memory/test_memory_repository.py
RENAMED
|
File without changes
|
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/mongo/test_mongo_repository.py
RENAMED
|
File without changes
|
{oidcauthlib-3.0.3 → oidcauthlib-3.0.5}/tests/auth/repository/mongo/test_mongo_repository_real.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|