PYTHON-3906 & PYTHON-2867 Implement GSSAPI ServiceHost support and expand canonicalization options (#1983)
This commit is contained in:
parent
ad3292e39b
commit
92d6a732c5
@ -77,7 +77,7 @@ MongoCredential = namedtuple(
|
||||
|
||||
|
||||
GSSAPIProperties = namedtuple(
|
||||
"GSSAPIProperties", ["service_name", "canonicalize_host_name", "service_realm"]
|
||||
"GSSAPIProperties", ["service_name", "canonicalize_host_name", "service_realm", "service_host"]
|
||||
)
|
||||
"""Mechanism properties for GSSAPI authentication."""
|
||||
|
||||
@ -86,6 +86,16 @@ _AWSProperties = namedtuple("_AWSProperties", ["aws_session_token"])
|
||||
"""Mechanism properties for MONGODB-AWS authentication."""
|
||||
|
||||
|
||||
def _validate_canonicalize_host_name(value: str | bool) -> str | bool:
|
||||
valid_names = [False, True, "none", "forward", "forwardAndReverse"]
|
||||
if value in ["true", "false", True, False]:
|
||||
return value in ["true", True]
|
||||
|
||||
if value not in valid_names:
|
||||
raise ValueError(f"CANONICALIZE_HOST_NAME '{value}' not in valid options: {valid_names}")
|
||||
return value
|
||||
|
||||
|
||||
def _build_credentials_tuple(
|
||||
mech: str,
|
||||
source: Optional[str],
|
||||
@ -102,12 +112,15 @@ def _build_credentials_tuple(
|
||||
raise ValueError("authentication source must be $external or None for GSSAPI")
|
||||
properties = extra.get("authmechanismproperties", {})
|
||||
service_name = properties.get("SERVICE_NAME", "mongodb")
|
||||
canonicalize = bool(properties.get("CANONICALIZE_HOST_NAME", False))
|
||||
service_host = properties.get("SERVICE_HOST", None)
|
||||
canonicalize = properties.get("CANONICALIZE_HOST_NAME", "false")
|
||||
canonicalize = _validate_canonicalize_host_name(canonicalize)
|
||||
service_realm = properties.get("SERVICE_REALM")
|
||||
props = GSSAPIProperties(
|
||||
service_name=service_name,
|
||||
canonicalize_host_name=canonicalize,
|
||||
service_realm=service_realm,
|
||||
service_host=service_host,
|
||||
)
|
||||
# Source is always $external.
|
||||
return MongoCredential(mech, "$external", user, passwd, props, None)
|
||||
|
||||
@ -139,6 +139,9 @@ SRV_SERVICE_NAME = "mongodb"
|
||||
# Default value for serverMonitoringMode
|
||||
SERVER_MONITORING_MODE = "auto" # poll/stream/auto
|
||||
|
||||
# Auth mechanism properties that must raise an error instead of warning if they invalidate.
|
||||
_MECH_PROP_MUST_RAISE = ["CANONICALIZE_HOST_NAME"]
|
||||
|
||||
|
||||
def partition_node(node: str) -> tuple[str, int]:
|
||||
"""Split a host:port string into (host, int(port)) pair."""
|
||||
@ -423,6 +426,7 @@ def validate_read_preference_tags(name: str, value: Any) -> list[dict[str, str]]
|
||||
_MECHANISM_PROPS = frozenset(
|
||||
[
|
||||
"SERVICE_NAME",
|
||||
"SERVICE_HOST",
|
||||
"CANONICALIZE_HOST_NAME",
|
||||
"SERVICE_REALM",
|
||||
"AWS_SESSION_TOKEN",
|
||||
@ -476,7 +480,9 @@ def validate_auth_mechanism_properties(option: str, value: Any) -> dict[str, Uni
|
||||
)
|
||||
|
||||
if key == "CANONICALIZE_HOST_NAME":
|
||||
props[key] = validate_boolean_or_string(key, val)
|
||||
from pymongo.auth_shared import _validate_canonicalize_host_name
|
||||
|
||||
props[key] = _validate_canonicalize_host_name(val)
|
||||
else:
|
||||
props[key] = val
|
||||
|
||||
@ -867,6 +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
|
||||
):
|
||||
raise
|
||||
if warn:
|
||||
warnings.warn(str(exc), stacklevel=2)
|
||||
else:
|
||||
|
||||
@ -80,7 +80,7 @@
|
||||
},
|
||||
{
|
||||
"description": "should accept generic mechanism property (GSSAPI)",
|
||||
"uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true",
|
||||
"uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com",
|
||||
"valid": true,
|
||||
"credential": {
|
||||
"username": "user@DOMAIN.COM",
|
||||
@ -89,10 +89,46 @@
|
||||
"mechanism": "GSSAPI",
|
||||
"mechanism_properties": {
|
||||
"SERVICE_NAME": "other",
|
||||
"CANONICALIZE_HOST_NAME": true
|
||||
"SERVICE_HOST": "example.com",
|
||||
"CANONICALIZE_HOST_NAME": "forward"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "should accept forwardAndReverse hostname canonicalization (GSSAPI)",
|
||||
"uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forwardAndReverse",
|
||||
"valid": true,
|
||||
"credential": {
|
||||
"username": "user@DOMAIN.COM",
|
||||
"password": null,
|
||||
"source": "$external",
|
||||
"mechanism": "GSSAPI",
|
||||
"mechanism_properties": {
|
||||
"SERVICE_NAME": "other",
|
||||
"CANONICALIZE_HOST_NAME": "forwardAndReverse"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "should accept no hostname canonicalization (GSSAPI)",
|
||||
"uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:none",
|
||||
"valid": true,
|
||||
"credential": {
|
||||
"username": "user@DOMAIN.COM",
|
||||
"password": null,
|
||||
"source": "$external",
|
||||
"mechanism": "GSSAPI",
|
||||
"mechanism_properties": {
|
||||
"SERVICE_NAME": "other",
|
||||
"CANONICALIZE_HOST_NAME": "none"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "must raise an error when the hostname canonicalization is invalid",
|
||||
"uri": "mongodb://user%40DOMAIN.COM@localhost/?authMechanism=GSSAPI&authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:invalid",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "should accept the password (GSSAPI)",
|
||||
"uri": "mongodb://user%40DOMAIN.COM:password@localhost/?authMechanism=GSSAPI&authSource=$external",
|
||||
@ -433,14 +469,14 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"description": "should throw an exception if username and password is specified for test environment (MONGODB-OIDC)",
|
||||
"description": "should throw an exception if supplied a password (MONGODB-OIDC)",
|
||||
"uri": "mongodb://user:pass@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test",
|
||||
"valid": false,
|
||||
"credential": null
|
||||
},
|
||||
{
|
||||
"description": "should throw an exception if username is specified for test environment (MONGODB-OIDC)",
|
||||
"uri": "mongodb://principalName@localhost/?authMechanism=MONGODB-OIDC&ENVIRONMENT:test",
|
||||
"description": "should throw an exception if username is specified for test (MONGODB-OIDC)",
|
||||
"uri": "mongodb://principalName@localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:test",
|
||||
"valid": false,
|
||||
"credential": null
|
||||
},
|
||||
@ -451,11 +487,17 @@
|
||||
"credential": null
|
||||
},
|
||||
{
|
||||
"description": "should throw an exception if neither provider nor callbacks specified (MONGODB-OIDC)",
|
||||
"description": "should throw an exception if neither environment nor callbacks specified (MONGODB-OIDC)",
|
||||
"uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC",
|
||||
"valid": false,
|
||||
"credential": null
|
||||
},
|
||||
{
|
||||
"description": "should throw an exception when unsupported auth property is specified (MONGODB-OIDC)",
|
||||
"uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=UnsupportedProperty:unexisted",
|
||||
"valid": false,
|
||||
"credential": null
|
||||
},
|
||||
{
|
||||
"description": "should recognise the mechanism with azure provider (MONGODB-OIDC)",
|
||||
"uri": "mongodb://localhost/?authMechanism=MONGODB-OIDC&authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE:foo",
|
||||
@ -586,4 +628,4 @@
|
||||
"credential": null
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,7 +263,7 @@
|
||||
},
|
||||
{
|
||||
"description": "Escaped username (GSSAPI)",
|
||||
"uri": "mongodb://user%40EXAMPLE.COM:secret@localhost/?authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:true&authMechanism=GSSAPI",
|
||||
"uri": "mongodb://user%40EXAMPLE.COM:secret@localhost/?authMechanismProperties=SERVICE_NAME:other,CANONICALIZE_HOST_NAME:forward,SERVICE_HOST:example.com&authMechanism=GSSAPI",
|
||||
"valid": true,
|
||||
"warning": false,
|
||||
"hosts": [
|
||||
@ -282,7 +282,8 @@
|
||||
"authmechanism": "GSSAPI",
|
||||
"authmechanismproperties": {
|
||||
"SERVICE_NAME": "other",
|
||||
"CANONICALIZE_HOST_NAME": true
|
||||
"SERVICE_HOST": "example.com",
|
||||
"CANONICALIZE_HOST_NAME": "forward"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Loading…
Reference in New Issue
Block a user