PYTHON-4845 Ensure ALLOWED_HOSTS is optional for Workload Usage (#1998)
This commit is contained in:
parent
41527f06bb
commit
6a8a805217
@ -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:
|
||||
|
||||
@ -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:
|
||||
@ -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"
|
||||
)
|
||||
@ -207,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())
|
||||
|
||||
|
||||
@ -873,8 +873,10 @@ def get_validated_options(
|
||||
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:
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -38,11 +38,17 @@ from pymongo import MongoClient
|
||||
from pymongo._azure_helpers import _get_azure_response
|
||||
from pymongo._gcp_helpers import _get_gcp_response
|
||||
from pymongo.auth_oidc_shared import _get_k8s_token
|
||||
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()
|
||||
@ -103,7 +109,6 @@ class OIDCTestBase(PyMongoTestCase):
|
||||
client.close()
|
||||
|
||||
|
||||
@pytest.mark.auth_oidc
|
||||
class TestAuthOIDCHuman(OIDCTestBase):
|
||||
uri: str
|
||||
|
||||
@ -838,12 +843,35 @@ class TestAuthOIDCMachine(OIDCTestBase):
|
||||
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)
|
||||
|
||||
# Create an OIDC configured client with auth mechanism properties `{"OIDC_CALLBACK": "<my_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()}
|
||||
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 == ""
|
||||
|
||||
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()
|
||||
@ -909,7 +937,7 @@ class TestAuthOIDCMachine(OIDCTestBase):
|
||||
# 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()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user