From 09ce694f3fbd9d349b679fe4016ceee81b5ad0bb Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 29 Oct 2024 06:14:23 -0500 Subject: [PATCH 01/31] PYTHON-4845 Ensure ALLOWED_HOSTS is optional for Workload Usage --- pymongo/asynchronous/auth_oidc.py | 2 +- pymongo/synchronous/auth_oidc.py | 2 +- test/auth_oidc/test_auth_oidc.py | 47 +++++++++++++++++++++++++------ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index f5801b85d4..f1c15045de 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -55,7 +55,7 @@ def _get_authenticator( properties = credentials.mechanism_properties # Validate that the address is allowed. - if not properties.environment: + if properties.human_callback is not None: found = False allowed_hosts = properties.allowed_hosts for patt in allowed_hosts: diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index 6381a408ab..5a8967d96b 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -55,7 +55,7 @@ def _get_authenticator( properties = credentials.mechanism_properties # Validate that the address is allowed. - if not properties.environment: + if properties.human_callback is not None: found = False allowed_hosts = properties.allowed_hosts for patt in allowed_hosts: diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 6526391daf..23bc063eba 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -37,11 +37,17 @@ from pymongo import MongoClient from pymongo._azure_helpers import _get_azure_response from pymongo._gcp_helpers import _get_gcp_response +from pymongo.auth_shared import _build_credentials_tuple from pymongo.cursor_shared import CursorType from pymongo.errors import AutoReconnect, ConfigurationError, OperationFailure from pymongo.hello import HelloCompat from pymongo.operations import InsertOne -from pymongo.synchronous.auth_oidc import OIDCCallback, OIDCCallbackContext, OIDCCallbackResult +from pymongo.synchronous.auth_oidc import ( + OIDCCallback, + OIDCCallbackContext, + OIDCCallbackResult, + _get_authenticator, +) from pymongo.uri_parser import parse_uri ROOT = Path(__file__).parent.parent.resolve() @@ -98,16 +104,15 @@ def fail_point(self, command_args): client.close() -@pytest.mark.auth_oidc class TestAuthOIDCHuman(OIDCTestBase): uri: str @classmethod def setUpClass(cls): - if ENVIRON != "test": - raise unittest.SkipTest("Human workflows are only tested with the test environment") - if DOMAIN is None: - raise ValueError("Missing OIDC_DOMAIN") + # if ENVIRON != "test": + # raise unittest.SkipTest("Human workflows are only tested with the test environment") + # if DOMAIN is None: + # raise ValueError("Missing OIDC_DOMAIN") super().setUpClass() def setUp(self): @@ -253,6 +258,15 @@ def test_1_8_machine_idp_human_callback(self): # Close the client. client.close() + def test_1_9_non_default_allowed_host_errors(self): + # Create a MongoCredential for OIDC with a human callback. + props = {"OIDC_HUMAN_CALLBACK": self.create_request_cb()} + extra = dict(authmechanismproperties=props) + mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, "", None, extra, "test") + # Assert that creating an authenticator for example.com results in a client error. + with self.assertRaises(ConfigurationError): + _get_authenticator(mongo_creds, ("example.com", 30)) + def test_2_1_valid_callback_inputs(self): # Create a MongoClient with a human callback that validates its inputs and returns a valid access token. client = self.create_client() @@ -841,12 +855,29 @@ def test_2_4_invalid_client_configuration_with_callback(self): self.create_client(authmechanismproperties=props) def test_2_5_invalid_use_of_ALLOWED_HOSTS(self): - # Create an OIDC configured client with auth mechanism properties `{"ENVIRONMENT": "azure", "ALLOWED_HOSTS": []}`. - props: Dict = {"ENVIRONMENT": "azure", "ALLOWED_HOSTS": []} + # Create an OIDC configured client with auth mechanism properties `{"ENVIRONMENT": "test", "ALLOWED_HOSTS": []}`. + props: Dict = {"ENVIRONMENT": "test", "ALLOWED_HOSTS": []} # Assert it returns a client configuration error. with self.assertRaises(ConfigurationError): self.create_client(authmechanismproperties=props) + def test_2_6_ALLOWED_HOSTS_defaults_ignored(self): + # Create a MongoCredential for OIDC with a machine callback. + props = {"OIDC_CALLBACK": self.create_request_cb()} + extra = dict(authmechanismproperties=props) + mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, "foo", None, extra, "test") + # Assert that creating an authenticator for example.com does not result in an error. + authenticator = _get_authenticator(mongo_creds, ("example.com", 30)) + assert authenticator.properties.username == "foo" + + # Create a MongoCredential for OIDC with an ENVIRONMENT. + props = {"ENVIRONMENT": "test"} + extra = dict(authmechanismproperties=props) + mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, None, None, extra, "test") + # Assert that creating an authenticator for example.com does not result in an error. + authenticator = _get_authenticator(mongo_creds, ("example.com", 30)) + assert authenticator.properties.username is None + def test_3_1_authentication_failure_with_cached_tokens_fetch_a_new_token_and_retry(self): # Create a MongoClient and an OIDC callback that implements the provider logic. client = self.create_client() From 5577beb063fdd1dc312b5f2300e40a5d9295810e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 5 Nov 2024 07:55:07 -0600 Subject: [PATCH 02/31] PYTHON-4845 Ensure ALLOWED_HOSTS is optional for Workload Usage --- pymongo/auth_shared.py | 2 ++ pymongo/common.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pymongo/auth_shared.py b/pymongo/auth_shared.py index 1e1ce7b4d8..8c7176bf6f 100644 --- a/pymongo/auth_shared.py +++ b/pymongo/auth_shared.py @@ -161,6 +161,8 @@ def _build_credentials_tuple( "::1", ] allowed_hosts = properties.get("ALLOWED_HOSTS", default_allowed) + if properties.get("ALLOWED_HOSTS", None) is not None and human_callback is None: + raise ConfigurationError("ALLOWED_HOSTS is only valid with OIDC_HUMAN_CALLBACK") msg = ( "authentication with MONGODB-OIDC requires providing either a callback or a environment" ) diff --git a/pymongo/common.py b/pymongo/common.py index d4601a0eb5..5661de011c 100644 --- a/pymongo/common.py +++ b/pymongo/common.py @@ -873,8 +873,10 @@ def get_setter_key(x: str) -> str: validator = _get_validator(opt, URI_OPTIONS_VALIDATOR_MAP, normed_key=normed_key) validated = validator(opt, value) except (ValueError, TypeError, ConfigurationError) as exc: - if normed_key == "authmechanismproperties" and any( - p in str(exc) for p in _MECH_PROP_MUST_RAISE + if ( + normed_key == "authmechanismproperties" + and any(p in str(exc) for p in _MECH_PROP_MUST_RAISE) + and "is not a supported auth mechanism property" not in str(exc) ): raise if warn: From d287f7640ea7c0a1cd730ac5055d50c0c37094bf Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 5 Nov 2024 09:24:44 -0600 Subject: [PATCH 03/31] fix test skips --- test/auth_oidc/test_auth_oidc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 0c28731efe..f624b0ef70 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -114,10 +114,10 @@ class TestAuthOIDCHuman(OIDCTestBase): @classmethod def setUpClass(cls): - # if ENVIRON != "test": - # raise unittest.SkipTest("Human workflows are only tested with the test environment") - # if DOMAIN is None: - # raise ValueError("Missing OIDC_DOMAIN") + if ENVIRON != "test": + raise unittest.SkipTest("Human workflows are only tested with the test environment") + if DOMAIN is None: + raise ValueError("Missing OIDC_DOMAIN") super().setUpClass() def setUp(self): From 3366b1d3351a154fbe7a66dd4d27cdabd21a3bca Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 5 Nov 2024 11:22:08 -0600 Subject: [PATCH 04/31] fix test --- test/auth_oidc/test_auth_oidc.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index f624b0ef70..6b461a17a9 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -940,11 +940,14 @@ def test_3_3_unexpected_error_code_does_not_clear_cache(self): # Assert that the callback has been called once. self.assertEqual(self.request_called, 1) - def test_4_1_reauthentication_succeds(self): + def test_4_1_reauthentication_succeeds(self): # Create a ``MongoClient`` configured with a custom OIDC callback that # implements the provider logic. client = self.create_client() + # Perform a ``find`` operation that succeeds. + client.test.test.find_one() + # Set a fail point for the find command. with self.fail_point( { From 0f7dc274b2e3f67cd845ef6da14ee7a4f6502b52 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 5 Nov 2024 13:08:55 -0600 Subject: [PATCH 05/31] debug --- pymongo/asynchronous/auth_oidc.py | 5 +++++ pymongo/synchronous/auth_oidc.py | 5 +++++ test/auth_oidc/test_auth_oidc.py | 1 + 3 files changed, 11 insertions(+) diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index f1c15045de..c64425235f 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -87,6 +87,7 @@ class _OIDCAuthenticator: async def reauthenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. + print("reauthenticating") # noqa: T201 self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -97,12 +98,16 @@ async def authenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any """Handle an initial authenticate request.""" # First handle speculative auth. # If it succeeded, we are done. + print("authenticating") # noqa: T201 ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): + print("speculative auth succeeded") # noqa: T201 resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp + else: + print("speculative auth failed") # noqa: T201 # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index 5a8967d96b..96e9ad4d52 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -87,6 +87,7 @@ class _OIDCAuthenticator: def reauthenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. + print("reauthenticating") # noqa: T201 self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -97,12 +98,16 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle an initial authenticate request.""" # First handle speculative auth. # If it succeeded, we are done. + print("authenticating") # noqa: T201 ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): + print("speculative auth succeeded") # noqa: T201 resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp + else: + print("speculative auth failed") # noqa: T201 # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 6b461a17a9..81329c6b07 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -756,6 +756,7 @@ def setUp(self): def create_request_cb(self, username=None, sleep=0): def request_token(context): + print("got a request") assert isinstance(context.timeout_seconds, int) assert context.version == 1 assert context.refresh_token is None From 564607a6a1399617ca645498f6147843af2b8aec Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 5 Nov 2024 17:57:47 -0600 Subject: [PATCH 06/31] debug again --- pymongo/asynchronous/auth_oidc.py | 12 ++++++++---- pymongo/synchronous/auth_oidc.py | 12 ++++++++---- test/auth_oidc/test_auth_oidc.py | 3 ++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index c64425235f..371c193133 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -87,7 +87,8 @@ class _OIDCAuthenticator: async def reauthenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. - print("reauthenticating") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"reauthenticating\n") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -98,16 +99,19 @@ async def authenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any """Handle an initial authenticate request.""" # First handle speculative auth. # If it succeeded, we are done. - print("authenticating") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"authenticating\n") ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): - print("speculative auth succeeded") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"speculative auth succeeded\n") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp else: - print("speculative auth failed") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"speculative auth failed\n") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index 96e9ad4d52..d408931ff2 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -87,7 +87,8 @@ class _OIDCAuthenticator: def reauthenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. - print("reauthenticating") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"reauthenticating\n") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -98,16 +99,19 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle an initial authenticate request.""" # First handle speculative auth. # If it succeeded, we are done. - print("authenticating") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"authenticating\n") ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): - print("speculative auth succeeded") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"speculative auth succeeded\n") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp else: - print("speculative auth failed") # noqa: T201 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"speculative auth failed\n") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 81329c6b07..9a31a5f440 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -756,7 +756,8 @@ def setUp(self): def create_request_cb(self, username=None, sleep=0): def request_token(context): - print("got a request") + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(b"got a request\n") assert isinstance(context.timeout_seconds, int) assert context.version == 1 assert context.refresh_token is None From e0f25052585cde6e9575fb41478e8c084dc0054e Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 5 Nov 2024 21:29:18 -0600 Subject: [PATCH 07/31] debug --- .evergreen/config.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index fc1713a88e..6ac3ca44e7 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -874,12 +874,16 @@ task_groups: GCPOIDC_VMNAME_PREFIX: "PYTHON_DRIVER" args: - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/gcp/setup.sh - teardown_task: + teardown_group: - command: subprocess.exec params: binary: bash args: - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/gcp/teardown.sh + - command: shell.exec + params: + shell: bash + script: cat src/temp.txt setup_group_can_fail_task: true setup_group_timeout_secs: 1800 tasks: From 104efca2c9b4cb5a6add3068476e5d72643a8796 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Tue, 5 Nov 2024 22:04:43 -0600 Subject: [PATCH 08/31] debug --- .evergreen/run-mongodb-oidc-test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.evergreen/run-mongodb-oidc-test.sh b/.evergreen/run-mongodb-oidc-test.sh index 22864528c0..857ee0a5b5 100755 --- a/.evergreen/run-mongodb-oidc-test.sh +++ b/.evergreen/run-mongodb-oidc-test.sh @@ -32,4 +32,4 @@ fi export TEST_AUTH_OIDC=1 export COVERAGE=1 export AUTH="auth" -bash ./.evergreen/hatch.sh test:test-eg -- "${@:1}" +bash ./.evergreen/hatch.sh test:test-eg -- "${@:1}" || cat temp.txt From 4436ed956e7dde901e7cd399fe556456def8e27c Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Wed, 6 Nov 2024 07:51:39 -0600 Subject: [PATCH 09/31] debug --- .evergreen/run-mongodb-oidc-test.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.evergreen/run-mongodb-oidc-test.sh b/.evergreen/run-mongodb-oidc-test.sh index 857ee0a5b5..4892e834b4 100755 --- a/.evergreen/run-mongodb-oidc-test.sh +++ b/.evergreen/run-mongodb-oidc-test.sh @@ -32,4 +32,7 @@ fi export TEST_AUTH_OIDC=1 export COVERAGE=1 export AUTH="auth" -bash ./.evergreen/hatch.sh test:test-eg -- "${@:1}" || cat temp.txt +bash ./.evergreen/hatch.sh test:test-eg -- "${@:1}" || { + echo "Test failed!" + cat temp.txt +} From 0ab85b2d82caac51b89e7f237e338f1c361ad788 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Wed, 6 Nov 2024 16:11:30 -0600 Subject: [PATCH 10/31] debug --- .evergreen/run-mongodb-oidc-test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.evergreen/run-mongodb-oidc-test.sh b/.evergreen/run-mongodb-oidc-test.sh index 4892e834b4..7eb1cefe9d 100755 --- a/.evergreen/run-mongodb-oidc-test.sh +++ b/.evergreen/run-mongodb-oidc-test.sh @@ -35,4 +35,5 @@ export AUTH="auth" bash ./.evergreen/hatch.sh test:test-eg -- "${@:1}" || { echo "Test failed!" cat temp.txt + exit 1 } From b4c007ba3d7c64001769f3b46ce3218ba81584a9 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Wed, 6 Nov 2024 17:52:02 -0600 Subject: [PATCH 11/31] debug --- pymongo/asynchronous/auth_oidc.py | 8 ++++---- test/auth_oidc/test_auth_oidc.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index 371c193133..28180d7c9a 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -88,7 +88,7 @@ async def reauthenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, A """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"reauthenticating\n") + fid.write("reauthenticating\n") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -100,18 +100,18 @@ async def authenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any # First handle speculative auth. # If it succeeded, we are done. with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"authenticating\n") + fid.write("authenticating\n") ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"speculative auth succeeded\n") + fid.write("speculative auth succeeded\n") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp else: with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"speculative auth failed\n") + fid.write("speculative auth failed\n") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 9a31a5f440..aae0fcfe10 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -757,7 +757,7 @@ def setUp(self): def create_request_cb(self, username=None, sleep=0): def request_token(context): with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"got a request\n") + fid.write("got a request\n") assert isinstance(context.timeout_seconds, int) assert context.version == 1 assert context.refresh_token is None From 3b4748cc58f8f5f3ae5fbcaf49cf49a2922e1e17 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Wed, 6 Nov 2024 18:18:45 -0600 Subject: [PATCH 12/31] debug --- pymongo/synchronous/auth_oidc.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index d408931ff2..a1ad876798 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -88,7 +88,7 @@ def reauthenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"reauthenticating\n") + fid.write("reauthenticating\n") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -100,18 +100,18 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: # First handle speculative auth. # If it succeeded, we are done. with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"authenticating\n") + fid.write("authenticating\n") ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"speculative auth succeeded\n") + fid.write("speculative auth succeeded\n") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp else: with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(b"speculative auth failed\n") + fid.write("speculative auth failed\n") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been From 3a57e9868ecd9a19d312c45c1892f0d6a63aa518 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Wed, 6 Nov 2024 20:49:16 -0600 Subject: [PATCH 13/31] debug --- test/auth_oidc/test_auth_oidc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index aae0fcfe10..ff7010418e 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -753,6 +753,8 @@ class TestAuthOIDCMachine(OIDCTestBase): def setUp(self): self.request_called = 0 + with open("temp.txt", "a") as fid: # noqa: ASYNC101 + fid.write(f"****\n{self.id()}\n") def create_request_cb(self, username=None, sleep=0): def request_token(context): From 6276d7886e1e71e91ad0c40bed58c47b503e120b Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 7 Nov 2024 06:43:07 -0600 Subject: [PATCH 14/31] debug --- test/unified_format.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unified_format.py b/test/unified_format.py index 80c37470e3..fd41c61e71 100644 --- a/test/unified_format.py +++ b/test/unified_format.py @@ -536,6 +536,8 @@ def setUp(self): def maybe_skip_test(self, spec): # add any special-casing for skipping tests here + with open("temp.txt", "a") as fid: + fid.write(f"****\n{spec['description']}\n") if client_context.storage_engine == "mmapv1": if ( "Dirty explicit session is discarded" in spec["description"] From 35ea201708b927990f7e1749d5f0a472517cc1b5 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 7 Nov 2024 19:01:21 -0600 Subject: [PATCH 15/31] debug again --- .evergreen/config.yml | 4 ---- .evergreen/run-mongodb-oidc-test.sh | 6 +----- pymongo/asynchronous/auth_oidc.py | 9 --------- pymongo/synchronous/auth_oidc.py | 9 --------- test/auth_oidc/test_auth_oidc.py | 4 ---- test/unified_format.py | 2 -- 6 files changed, 1 insertion(+), 33 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 6ac3ca44e7..34375cd407 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -880,10 +880,6 @@ task_groups: binary: bash args: - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/gcp/teardown.sh - - command: shell.exec - params: - shell: bash - script: cat src/temp.txt setup_group_can_fail_task: true setup_group_timeout_secs: 1800 tasks: diff --git a/.evergreen/run-mongodb-oidc-test.sh b/.evergreen/run-mongodb-oidc-test.sh index 7eb1cefe9d..22864528c0 100755 --- a/.evergreen/run-mongodb-oidc-test.sh +++ b/.evergreen/run-mongodb-oidc-test.sh @@ -32,8 +32,4 @@ fi export TEST_AUTH_OIDC=1 export COVERAGE=1 export AUTH="auth" -bash ./.evergreen/hatch.sh test:test-eg -- "${@:1}" || { - echo "Test failed!" - cat temp.txt - exit 1 -} +bash ./.evergreen/hatch.sh test:test-eg -- "${@:1}" diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index 28180d7c9a..f1c15045de 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -87,8 +87,6 @@ class _OIDCAuthenticator: async def reauthenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("reauthenticating\n") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -99,19 +97,12 @@ async def authenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any """Handle an initial authenticate request.""" # First handle speculative auth. # If it succeeded, we are done. - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("authenticating\n") ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("speculative auth succeeded\n") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp - else: - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("speculative auth failed\n") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index a1ad876798..5a8967d96b 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -87,8 +87,6 @@ class _OIDCAuthenticator: def reauthenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("reauthenticating\n") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -99,19 +97,12 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle an initial authenticate request.""" # First handle speculative auth. # If it succeeded, we are done. - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("authenticating\n") ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("speculative auth succeeded\n") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp - else: - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("speculative auth failed\n") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index ff7010418e..6b461a17a9 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -753,13 +753,9 @@ class TestAuthOIDCMachine(OIDCTestBase): def setUp(self): self.request_called = 0 - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write(f"****\n{self.id()}\n") def create_request_cb(self, username=None, sleep=0): def request_token(context): - with open("temp.txt", "a") as fid: # noqa: ASYNC101 - fid.write("got a request\n") assert isinstance(context.timeout_seconds, int) assert context.version == 1 assert context.refresh_token is None diff --git a/test/unified_format.py b/test/unified_format.py index fd41c61e71..80c37470e3 100644 --- a/test/unified_format.py +++ b/test/unified_format.py @@ -536,8 +536,6 @@ def setUp(self): def maybe_skip_test(self, spec): # add any special-casing for skipping tests here - with open("temp.txt", "a") as fid: - fid.write(f"****\n{spec['description']}\n") if client_context.storage_engine == "mmapv1": if ( "Dirty explicit session is discarded" in spec["description"] From 3791012562b32f2fed5cacb3570b2862d344dd88 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 7 Nov 2024 19:02:20 -0600 Subject: [PATCH 16/31] add files --- test.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 test.sh diff --git a/test.sh b/test.sh new file mode 100644 index 0000000000..844ecb0346 --- /dev/null +++ b/test.sh @@ -0,0 +1,4 @@ +set -e +for i in {1..10}; do + bash .evergreen/run-mongodb-oidc-remote-test.sh +done From ff573efd524d110eec35b4975fc0f737aa80ab23 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 7 Nov 2024 19:10:25 -0600 Subject: [PATCH 17/31] debug --- pymongo/synchronous/auth_oidc.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index 5a8967d96b..0ef3e64041 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -87,6 +87,7 @@ class _OIDCAuthenticator: def reauthenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. + print("reauthenticating") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -99,10 +100,15 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: # If it succeeded, we are done. ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): + print("spec auth succeeded") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp + elif ctx: + print("spec auth failed") + else: + print("no spec auth") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been From 5a6c7b2cce72dfafaedddce24ce28791ce895f05 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Thu, 7 Nov 2024 19:47:06 -0600 Subject: [PATCH 18/31] add files --- pymongo/synchronous/auth_oidc.py | 6 ------ test.sh | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index 0ef3e64041..5a8967d96b 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -87,7 +87,6 @@ class _OIDCAuthenticator: def reauthenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: """Handle a reauthenticate from the server.""" # Invalidate the token for the connection. - print("reauthenticating") self._invalidate(conn) # Call the appropriate auth logic for the callback type. if self.properties.callback: @@ -100,15 +99,10 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: # If it succeeded, we are done. ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): - print("spec auth succeeded") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp - elif ctx: - print("spec auth failed") - else: - print("no spec auth") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/test.sh b/test.sh index 844ecb0346..c76f9f4a63 100644 --- a/test.sh +++ b/test.sh @@ -1,4 +1,4 @@ set -e -for i in {1..10}; do +for i in {1..30}; do bash .evergreen/run-mongodb-oidc-remote-test.sh done From 6962ad05b35a6ba7d6492ccfa6ed1ac7dd7bed75 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 06:44:00 -0600 Subject: [PATCH 19/31] debug --- pymongo/asynchronous/auth_oidc.py | 5 +++++ pymongo/asynchronous/helpers.py | 4 ++++ pymongo/synchronous/auth_oidc.py | 5 +++++ pymongo/synchronous/helpers.py | 4 ++++ pyproject.toml | 1 + 5 files changed, 19 insertions(+) diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index f1c15045de..1af4f3fcac 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -99,10 +99,15 @@ async def authenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any # If it succeeded, we are done. ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): + print("speculative auth succeeded") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp + elif ctx: + print("speculative auth failed") + else: + print("no speculative auth") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/pymongo/asynchronous/helpers.py b/pymongo/asynchronous/helpers.py index 1ac8b6630f..e91c5b2c3a 100644 --- a/pymongo/asynchronous/helpers.py +++ b/pymongo/asynchronous/helpers.py @@ -45,11 +45,13 @@ async def inner(*args: Any, **kwargs: Any) -> Any: return await func(*args, **kwargs) except OperationFailure as exc: if no_reauth: + print("failure with no reauth") raise if exc.code == _REAUTHENTICATION_REQUIRED_CODE: # Look for an argument that either is a AsyncConnection # or has a connection attribute, so we can trigger # a reauth. + print("got reauth") conn = None for arg in args: if isinstance(arg, AsyncConnection): @@ -59,8 +61,10 @@ async def inner(*args: Any, **kwargs: Any) -> Any: conn = arg.conn # type: ignore[assignment] break if conn: + print("running reauth") await conn.authenticate(reauthenticate=True) else: + print("not running reauth, no conn") raise return func(*args, **kwargs) raise diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index 5a8967d96b..f1775c93cc 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -99,10 +99,15 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: # If it succeeded, we are done. ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): + print("speculative auth succeeded") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp + elif ctx: + print("speculative auth failed") + else: + print("no speculative auth") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/pymongo/synchronous/helpers.py b/pymongo/synchronous/helpers.py index 064583dad3..dbbf461b4e 100644 --- a/pymongo/synchronous/helpers.py +++ b/pymongo/synchronous/helpers.py @@ -45,11 +45,13 @@ def inner(*args: Any, **kwargs: Any) -> Any: return func(*args, **kwargs) except OperationFailure as exc: if no_reauth: + print("failure with no reauth") raise if exc.code == _REAUTHENTICATION_REQUIRED_CODE: # Look for an argument that either is a Connection # or has a connection attribute, so we can trigger # a reauth. + print("got reauth") conn = None for arg in args: if isinstance(arg, Connection): @@ -59,8 +61,10 @@ def inner(*args: Any, **kwargs: Any) -> Any: conn = arg.conn # type: ignore[assignment] break if conn: + print("running reauth") conn.authenticate(reauthenticate=True) else: + print("not running reauth, no conn") raise return func(*args, **kwargs) raise diff --git a/pyproject.toml b/pyproject.toml index 9a29a777fc..671aaf69fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -193,6 +193,7 @@ ignore = [ "EM103", # Exception must not use a `.format()` string directly, assign to variable first "C408", # Unnecessary `dict` call (rewrite as a literal) "SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements + "T20", ] unfixable = [ "RUF100", # Unused noqa From ba8aea94e4469f9404680b933bc27262c36d0ec4 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 07:04:30 -0600 Subject: [PATCH 20/31] add files --- test/auth_oidc/test_auth_oidc.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 6b461a17a9..2a0e42a253 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -858,6 +858,12 @@ def test_2_5_invalid_use_of_ALLOWED_HOSTS(self): with self.assertRaises(ConfigurationError): self.create_client(authmechanismproperties=props) + # Create an OIDC configured client with auth mechanism properties `{"OIDC_CALLBACK": "", "ALLOWED_HOSTS": []}`. + props: Dict = {"OIDC_CALLBACK": self.create_request_cb(), "ALLOWED_HOSTS": []} + # Assert it returns a client configuration error. + with self.assertRaises(ConfigurationError): + self.create_client(authmechanismproperties=props) + def test_2_6_ALLOWED_HOSTS_defaults_ignored(self): # Create a MongoCredential for OIDC with a machine callback. props = {"OIDC_CALLBACK": self.create_request_cb()} From 9cec4385f872f0895c80569d80021719adac8a45 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 09:59:34 -0600 Subject: [PATCH 21/31] remove debug --- pymongo/asynchronous/helpers.py | 4 ---- pymongo/synchronous/helpers.py | 4 ---- 2 files changed, 8 deletions(-) diff --git a/pymongo/asynchronous/helpers.py b/pymongo/asynchronous/helpers.py index e91c5b2c3a..1ac8b6630f 100644 --- a/pymongo/asynchronous/helpers.py +++ b/pymongo/asynchronous/helpers.py @@ -45,13 +45,11 @@ async def inner(*args: Any, **kwargs: Any) -> Any: return await func(*args, **kwargs) except OperationFailure as exc: if no_reauth: - print("failure with no reauth") raise if exc.code == _REAUTHENTICATION_REQUIRED_CODE: # Look for an argument that either is a AsyncConnection # or has a connection attribute, so we can trigger # a reauth. - print("got reauth") conn = None for arg in args: if isinstance(arg, AsyncConnection): @@ -61,10 +59,8 @@ async def inner(*args: Any, **kwargs: Any) -> Any: conn = arg.conn # type: ignore[assignment] break if conn: - print("running reauth") await conn.authenticate(reauthenticate=True) else: - print("not running reauth, no conn") raise return func(*args, **kwargs) raise diff --git a/pymongo/synchronous/helpers.py b/pymongo/synchronous/helpers.py index dbbf461b4e..064583dad3 100644 --- a/pymongo/synchronous/helpers.py +++ b/pymongo/synchronous/helpers.py @@ -45,13 +45,11 @@ def inner(*args: Any, **kwargs: Any) -> Any: return func(*args, **kwargs) except OperationFailure as exc: if no_reauth: - print("failure with no reauth") raise if exc.code == _REAUTHENTICATION_REQUIRED_CODE: # Look for an argument that either is a Connection # or has a connection attribute, so we can trigger # a reauth. - print("got reauth") conn = None for arg in args: if isinstance(arg, Connection): @@ -61,10 +59,8 @@ def inner(*args: Any, **kwargs: Any) -> Any: conn = arg.conn # type: ignore[assignment] break if conn: - print("running reauth") conn.authenticate(reauthenticate=True) else: - print("not running reauth, no conn") raise return func(*args, **kwargs) raise From e43cb33d3510e54a4e2403becf122528e6a3e819 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:00:37 -0600 Subject: [PATCH 22/31] cleanup --- .evergreen/config.yml | 2 +- pymongo/asynchronous/auth_oidc.py | 5 ----- pymongo/synchronous/auth_oidc.py | 5 ----- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index 34375cd407..fc1713a88e 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -874,7 +874,7 @@ task_groups: GCPOIDC_VMNAME_PREFIX: "PYTHON_DRIVER" args: - ${DRIVERS_TOOLS}/.evergreen/auth_oidc/gcp/setup.sh - teardown_group: + teardown_task: - command: subprocess.exec params: binary: bash diff --git a/pymongo/asynchronous/auth_oidc.py b/pymongo/asynchronous/auth_oidc.py index 1af4f3fcac..f1c15045de 100644 --- a/pymongo/asynchronous/auth_oidc.py +++ b/pymongo/asynchronous/auth_oidc.py @@ -99,15 +99,10 @@ async def authenticate(self, conn: AsyncConnection) -> Optional[Mapping[str, Any # If it succeeded, we are done. ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): - print("speculative auth succeeded") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp - elif ctx: - print("speculative auth failed") - else: - print("no speculative auth") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been diff --git a/pymongo/synchronous/auth_oidc.py b/pymongo/synchronous/auth_oidc.py index f1775c93cc..5a8967d96b 100644 --- a/pymongo/synchronous/auth_oidc.py +++ b/pymongo/synchronous/auth_oidc.py @@ -99,15 +99,10 @@ def authenticate(self, conn: Connection) -> Optional[Mapping[str, Any]]: # If it succeeded, we are done. ctx = conn.auth_ctx if ctx and ctx.speculate_succeeded(): - print("speculative auth succeeded") resp = ctx.speculative_authenticate if resp and resp["done"]: conn.oidc_token_gen_id = self.token_gen_id return resp - elif ctx: - print("speculative auth failed") - else: - print("no speculative auth") # If spec auth failed, call the appropriate auth logic for the callback type. # We cannot assume that the token is invalid, because a proxy may have been From bdea3f33eee34b8b97a590dd7b498b5fbca81857 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:01:20 -0600 Subject: [PATCH 23/31] remove config change --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 671aaf69fb..9a29a777fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -193,7 +193,6 @@ ignore = [ "EM103", # Exception must not use a `.format()` string directly, assign to variable first "C408", # Unnecessary `dict` call (rewrite as a literal) "SIM117", # Use a single `with` statement with multiple contexts instead of nested `with` statements - "T20", ] unfixable = [ "RUF100", # Unused noqa From 96f9b779d33b23d144223f7ade6fc1e601d1f752 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:01:32 -0600 Subject: [PATCH 24/31] remove test file --- test.sh | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 test.sh diff --git a/test.sh b/test.sh deleted file mode 100644 index c76f9f4a63..0000000000 --- a/test.sh +++ /dev/null @@ -1,4 +0,0 @@ -set -e -for i in {1..30}; do - bash .evergreen/run-mongodb-oidc-remote-test.sh -done From 2211972d344070901ae5d8588d84f64ae0e70230 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:02:11 -0600 Subject: [PATCH 25/31] remove extra test --- test/auth_oidc/test_auth_oidc.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 2a0e42a253..4612b4310b 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -263,15 +263,6 @@ def test_1_8_machine_idp_human_callback(self): # Close the client. client.close() - def test_1_9_non_default_allowed_host_errors(self): - # Create a MongoCredential for OIDC with a human callback. - props = {"OIDC_HUMAN_CALLBACK": self.create_request_cb()} - extra = dict(authmechanismproperties=props) - mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, "", None, extra, "test") - # Assert that creating an authenticator for example.com results in a client error. - with self.assertRaises(ConfigurationError): - _get_authenticator(mongo_creds, ("example.com", 30)) - def test_2_1_valid_callback_inputs(self): # Create a MongoClient with a human callback that validates its inputs and returns a valid access token. client = self.create_client() From d8820a51e420e5bfd4e29f7cdbbbe8c7eeb3b4b6 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:02:40 -0600 Subject: [PATCH 26/31] undo test change --- test/auth_oidc/test_auth_oidc.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 4612b4310b..576a674472 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -942,9 +942,6 @@ def test_4_1_reauthentication_succeeds(self): # implements the provider logic. client = self.create_client() - # Perform a ``find`` operation that succeeds. - client.test.test.find_one() - # Set a fail point for the find command. with self.fail_point( { From b632bad14b1dc98b112693e57e1def7268050d18 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:05:54 -0600 Subject: [PATCH 27/31] type errors --- test/auth_oidc/test_auth_oidc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 576a674472..a32262bc4c 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -859,7 +859,7 @@ def test_2_6_ALLOWED_HOSTS_defaults_ignored(self): # Create a MongoCredential for OIDC with a machine callback. props = {"OIDC_CALLBACK": self.create_request_cb()} extra = dict(authmechanismproperties=props) - mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, "foo", None, extra, "test") + mongo_creds = _build_credentials_tuple("MONGODB-OIDC", "", "foo", "", extra, "test") # Assert that creating an authenticator for example.com does not result in an error. authenticator = _get_authenticator(mongo_creds, ("example.com", 30)) assert authenticator.properties.username == "foo" @@ -867,7 +867,7 @@ def test_2_6_ALLOWED_HOSTS_defaults_ignored(self): # Create a MongoCredential for OIDC with an ENVIRONMENT. props = {"ENVIRONMENT": "test"} extra = dict(authmechanismproperties=props) - mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, None, None, extra, "test") + mongo_creds = _build_credentials_tuple("MONGODB-OIDC", "", "", "", extra, "test") # Assert that creating an authenticator for example.com does not result in an error. authenticator = _get_authenticator(mongo_creds, ("example.com", 30)) assert authenticator.properties.username is None From aa6343d824e30e1ff28eebcedd060d39b8df5ca5 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:19:43 -0600 Subject: [PATCH 28/31] fix signature --- pymongo/auth_shared.py | 4 ++-- test/auth_oidc/test_auth_oidc.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pymongo/auth_shared.py b/pymongo/auth_shared.py index 8c7176bf6f..27b828d3f8 100644 --- a/pymongo/auth_shared.py +++ b/pymongo/auth_shared.py @@ -100,8 +100,8 @@ def _validate_canonicalize_host_name(value: str | bool) -> str | bool: def _build_credentials_tuple( mech: str, source: Optional[str], - user: str, - passwd: str, + user: Optional[str], + passwd: Optional[str], extra: Mapping[str, Any], database: Optional[str], ) -> MongoCredential: diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index a32262bc4c..576a674472 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -859,7 +859,7 @@ def test_2_6_ALLOWED_HOSTS_defaults_ignored(self): # Create a MongoCredential for OIDC with a machine callback. props = {"OIDC_CALLBACK": self.create_request_cb()} extra = dict(authmechanismproperties=props) - mongo_creds = _build_credentials_tuple("MONGODB-OIDC", "", "foo", "", extra, "test") + mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, "foo", None, extra, "test") # Assert that creating an authenticator for example.com does not result in an error. authenticator = _get_authenticator(mongo_creds, ("example.com", 30)) assert authenticator.properties.username == "foo" @@ -867,7 +867,7 @@ def test_2_6_ALLOWED_HOSTS_defaults_ignored(self): # Create a MongoCredential for OIDC with an ENVIRONMENT. props = {"ENVIRONMENT": "test"} extra = dict(authmechanismproperties=props) - mongo_creds = _build_credentials_tuple("MONGODB-OIDC", "", "", "", extra, "test") + mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, None, None, extra, "test") # Assert that creating an authenticator for example.com does not result in an error. authenticator = _get_authenticator(mongo_creds, ("example.com", 30)) assert authenticator.properties.username is None From 4f3da0987e071001c6ef57d090ee33286246ff89 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:22:34 -0600 Subject: [PATCH 29/31] fix signature --- pymongo/auth_oidc_shared.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pymongo/auth_oidc_shared.py b/pymongo/auth_oidc_shared.py index 9e0acaf6c8..11774917c1 100644 --- a/pymongo/auth_oidc_shared.py +++ b/pymongo/auth_oidc_shared.py @@ -64,7 +64,7 @@ class _OIDCProperties: environment: Optional[str] = field(default=None) allowed_hosts: list[str] = field(default_factory=list) token_resource: Optional[str] = field(default=None) - username: str = "" + username: Optional[str] = "" """Mechanism properties for MONGODB-OIDC authentication.""" From 0a6c0640e7008c75c0b71734424c14b5fda2bbb5 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 10:46:06 -0600 Subject: [PATCH 30/31] fix signatures --- pymongo/auth_oidc_shared.py | 2 +- pymongo/auth_shared.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pymongo/auth_oidc_shared.py b/pymongo/auth_oidc_shared.py index 11774917c1..9e0acaf6c8 100644 --- a/pymongo/auth_oidc_shared.py +++ b/pymongo/auth_oidc_shared.py @@ -64,7 +64,7 @@ class _OIDCProperties: environment: Optional[str] = field(default=None) allowed_hosts: list[str] = field(default_factory=list) token_resource: Optional[str] = field(default=None) - username: Optional[str] = "" + username: str = "" """Mechanism properties for MONGODB-OIDC authentication.""" diff --git a/pymongo/auth_shared.py b/pymongo/auth_shared.py index 27b828d3f8..9534bd74ad 100644 --- a/pymongo/auth_shared.py +++ b/pymongo/auth_shared.py @@ -209,7 +209,7 @@ def _build_credentials_tuple( environment=environ, allowed_hosts=allowed_hosts, token_resource=token_resource, - username=user, + username=user or "", ) return MongoCredential(mech, "$external", user, passwd, oidc_props, _Cache()) From 8f32628c1ddbc6d1410fa9846681df269e7064a1 Mon Sep 17 00:00:00 2001 From: Steven Silvester Date: Fri, 8 Nov 2024 11:00:45 -0600 Subject: [PATCH 31/31] fix test --- test/auth_oidc/test_auth_oidc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/auth_oidc/test_auth_oidc.py b/test/auth_oidc/test_auth_oidc.py index 576a674472..7a78f3d2f6 100644 --- a/test/auth_oidc/test_auth_oidc.py +++ b/test/auth_oidc/test_auth_oidc.py @@ -870,7 +870,7 @@ def test_2_6_ALLOWED_HOSTS_defaults_ignored(self): mongo_creds = _build_credentials_tuple("MONGODB-OIDC", None, None, None, extra, "test") # Assert that creating an authenticator for example.com does not result in an error. authenticator = _get_authenticator(mongo_creds, ("example.com", 30)) - assert authenticator.properties.username is None + assert authenticator.properties.username == "" def test_3_1_authentication_failure_with_cached_tokens_fetch_a_new_token_and_retry(self): # Create a MongoClient and an OIDC callback that implements the provider logic.