Skip to content

Commit 85b7090

Browse files
committed
Merge branch 'master' of github.com:mongodb/mongo-python-driver
2 parents a595e39 + 8d27699 commit 85b7090

File tree

11 files changed

+202
-28
lines changed

11 files changed

+202
-28
lines changed

.evergreen/install-dependencies.sh

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#!/bin/bash
2-
set -o xtrace # Write all commands first to stderr
3-
set -o errexit # Exit the script with error if any of the commands fail
2+
set -eu
43

54
# Copy PyMongo's test certificates over driver-evergreen-tools'
65
cp ${PROJECT_DIRECTORY}/test/certificates/* ${DRIVERS_TOOLS}/.evergreen/x509gen/
@@ -9,7 +8,7 @@ cp ${PROJECT_DIRECTORY}/test/certificates/* ${DRIVERS_TOOLS}/.evergreen/x509gen/
98
cp ${PROJECT_DIRECTORY}/test/certificates/client.pem ${MONGO_ORCHESTRATION_HOME}/lib/client.pem
109

1110
# Ensure hatch is installed.
12-
bash ${PROJECT_DIRECTORY}/scripts/ensure-hatch.sh
11+
bash ${PROJECT_DIRECTORY}/.evergreen/scripts/ensure-hatch.sh
1312

1413
if [ -w /etc/hosts ]; then
1514
SUDO=""

.evergreen/scripts/configure-env.sh

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
#!/bin/bash -eux
1+
#!/bin/bash
2+
3+
set -eu
24

35
# Get the current unique version of this checkout
46
# shellcheck disable=SC2154
5-
if [ "$is_patch" = "true" ]; then
7+
if [ "${is_patch:-}" = "true" ]; then
68
# shellcheck disable=SC2154
79
CURRENT_VERSION="$(git describe)-patch-$version_id"
810
else
@@ -14,7 +16,7 @@ DRIVERS_TOOLS="$(dirname $PROJECT_DIRECTORY)/drivers-tools"
1416
CARGO_HOME=${CARGO_HOME:-${DRIVERS_TOOLS}/.cargo}
1517

1618
# Python has cygwin path problems on Windows. Detect prospective mongo-orchestration home directory
17-
if [ "Windows_NT" = "$OS" ]; then # Magic variable in cygwin
19+
if [ "Windows_NT" = "${OS:-}" ]; then # Magic variable in cygwin
1820
DRIVERS_TOOLS=$(cygpath -m $DRIVERS_TOOLS)
1921
PROJECT_DIRECTORY=$(cygpath -m $PROJECT_DIRECTORY)
2022
CARGO_HOME=$(cygpath -m $CARGO_HOME)
@@ -59,7 +61,7 @@ export CARGO_HOME="$CARGO_HOME"
5961
export TMPDIR="$MONGO_ORCHESTRATION_HOME/db"
6062
export PATH="$MONGODB_BINARIES:$PATH"
6163
# shellcheck disable=SC2154
62-
export PROJECT="$project"
64+
export PROJECT="${project:-mongo-python-driver}"
6365
export PIP_QUIET=1
6466
EOT
6567

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#!/bin/bash
2+
set -eu
3+
4+
HERE=$(dirname ${BASH_SOURCE:-$0})
5+
pushd $HERE
6+
. env.sh
27

3-
. src/.evergreen/scripts/env.sh
4-
set -o xtrace
58
rm -rf $DRIVERS_TOOLS
69
if [ "$PROJECT" = "drivers-tools" ]; then
710
# If this was a patch build, doing a fresh clone would not actually test the patch
@@ -10,3 +13,5 @@ else
1013
git clone https://github.com/mongodb-labs/drivers-evergreen-tools.git $DRIVERS_TOOLS
1114
fi
1215
echo "{ \"releases\": { \"default\": \"$MONGODB_BINARIES\" }}" >$MONGO_ORCHESTRATION_HOME/orchestration.config
16+
17+
popd
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#!/bin/bash
2+
set -eu
23

34
# Disable xtrace for security reasons (just in case it was accidentally set).
45
set +x
56
# Use the default python to bootstrap secrets.
6-
PYTHON_BINARY="" bash "${DRIVERS_TOOLS}"/.evergreen/auth_aws/setup_secrets.sh drivers/enterprise_auth
7+
bash "${DRIVERS_TOOLS}"/.evergreen/secrets_handling/setup-secrets.sh drivers/enterprise_auth
78
TEST_ENTERPRISE_AUTH=1 AUTH=auth bash "${PROJECT_DIRECTORY}"/.evergreen/hatch.sh test:test-eg

.evergreen/scripts/setup-system.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
HERE=$(dirname ${BASH_SOURCE:-$0})
6+
pushd "$(dirname "$(dirname $HERE)")"
7+
echo "Setting up system..."
8+
bash .evergreen/scripts/configure-env.sh
9+
source .evergreen/scripts/env.sh
10+
bash .evergreen/scripts/prepare-resources.sh
11+
bash $DRIVERS_TOOLS/.evergreen/setup.sh
12+
bash .evergreen/scripts/install-dependencies.sh
13+
popd
14+
echo "Setting up system... done."

.evergreen/setup-spawn-host.sh

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash
2+
3+
set -eu
4+
5+
if [ -z "$1" ]
6+
then
7+
echo "Must supply a spawn host URL!"
8+
fi
9+
10+
target=$1
11+
12+
echo "Copying files to $target..."
13+
rsync -az -e ssh --exclude '.git' --filter=':- .gitignore' -r . $target:/home/ec2-user/mongo-python-driver
14+
echo "Copying files to $target... done"
15+
16+
ssh $target /home/ec2-user/mongo-python-driver/.evergreen/scripts/setup-system.sh

.evergreen/sync-spawn-host.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/bin/bash
2+
3+
if [ -z "$1" ]
4+
then
5+
echo "Must supply a spawn host URL!"
6+
fi
7+
8+
target=$1
9+
10+
echo "Syncing files to $target..."
11+
# shellcheck disable=SC2034
12+
fswatch -o . | while read f; do rsync -hazv -e ssh --exclude '.git' --filter=':- .gitignore' -r . $target:/home/ec2-user/mongo-python-driver; done
13+
echo "Syncing files to $target... done."

pymongo/asynchronous/auth.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,20 @@ def _auth_key(nonce: str, username: str, password: str) -> str:
177177
return md5hash.hexdigest()
178178

179179

180-
def _canonicalize_hostname(hostname: str) -> str:
180+
def _canonicalize_hostname(hostname: str, option: str | bool) -> str:
181181
"""Canonicalize hostname following MIT-krb5 behavior."""
182182
# https://github.com/krb5/krb5/blob/d406afa363554097ac48646a29249c04f498c88e/src/util/k5test.py#L505-L520
183+
if option in [False, "none"]:
184+
return hostname
185+
183186
af, socktype, proto, canonname, sockaddr = socket.getaddrinfo(
184187
hostname, None, 0, 0, socket.IPPROTO_TCP, socket.AI_CANONNAME
185188
)[0]
186189

190+
# For forward just to resolve the cname as dns.lookup() will not return it.
191+
if option == "forward":
192+
return canonname.lower()
193+
187194
try:
188195
name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
189196
except socket.gaierror:
@@ -205,9 +212,8 @@ async def _authenticate_gssapi(credentials: MongoCredential, conn: AsyncConnecti
205212
props = credentials.mechanism_properties
206213
# Starting here and continuing through the while loop below - establish
207214
# the security context. See RFC 4752, Section 3.1, first paragraph.
208-
host = conn.address[0]
209-
if props.canonicalize_host_name:
210-
host = _canonicalize_hostname(host)
215+
host = props.service_host or conn.address[0]
216+
host = _canonicalize_hostname(host, props.canonicalize_host_name)
211217
service = props.service_name + "@" + host
212218
if props.service_realm is not None:
213219
service = service + "@" + props.service_realm

pymongo/synchronous/auth.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,20 @@ def _auth_key(nonce: str, username: str, password: str) -> str:
174174
return md5hash.hexdigest()
175175

176176

177-
def _canonicalize_hostname(hostname: str) -> str:
177+
def _canonicalize_hostname(hostname: str, option: str | bool) -> str:
178178
"""Canonicalize hostname following MIT-krb5 behavior."""
179179
# https://github.com/krb5/krb5/blob/d406afa363554097ac48646a29249c04f498c88e/src/util/k5test.py#L505-L520
180+
if option in [False, "none"]:
181+
return hostname
182+
180183
af, socktype, proto, canonname, sockaddr = socket.getaddrinfo(
181184
hostname, None, 0, 0, socket.IPPROTO_TCP, socket.AI_CANONNAME
182185
)[0]
183186

187+
# For forward just to resolve the cname as dns.lookup() will not return it.
188+
if option == "forward":
189+
return canonname.lower()
190+
184191
try:
185192
name = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
186193
except socket.gaierror:
@@ -202,9 +209,8 @@ def _authenticate_gssapi(credentials: MongoCredential, conn: Connection) -> None
202209
props = credentials.mechanism_properties
203210
# Starting here and continuing through the while loop below - establish
204211
# the security context. See RFC 4752, Section 3.1, first paragraph.
205-
host = conn.address[0]
206-
if props.canonicalize_host_name:
207-
host = _canonicalize_hostname(host)
212+
host = props.service_host or conn.address[0]
213+
host = _canonicalize_hostname(host, props.canonicalize_host_name)
208214
service = props.service_name + "@" + host
209215
if props.service_realm is not None:
210216
service = service + "@" + props.service_realm

test/asynchronous/test_auth.py

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
import pytest
3636

3737
from pymongo import AsyncMongoClient, monitoring
38-
from pymongo.asynchronous.auth import HAVE_KERBEROS
38+
from pymongo.asynchronous.auth import HAVE_KERBEROS, _canonicalize_hostname
3939
from pymongo.auth_shared import _build_credentials_tuple
4040
from pymongo.errors import OperationFailure
4141
from pymongo.hello import HelloCompat
@@ -96,10 +96,11 @@ def setUpClass(cls):
9696
cls.service_realm_required = (
9797
GSSAPI_SERVICE_REALM is not None and GSSAPI_SERVICE_REALM not in GSSAPI_PRINCIPAL
9898
)
99-
mech_properties = f"SERVICE_NAME:{GSSAPI_SERVICE_NAME}"
100-
mech_properties += f",CANONICALIZE_HOST_NAME:{GSSAPI_CANONICALIZE}"
99+
mech_properties = dict(
100+
SERVICE_NAME=GSSAPI_SERVICE_NAME, CANONICALIZE_HOST_NAME=GSSAPI_CANONICALIZE
101+
)
101102
if GSSAPI_SERVICE_REALM is not None:
102-
mech_properties += f",SERVICE_REALM:{GSSAPI_SERVICE_REALM}"
103+
mech_properties["SERVICE_REALM"] = GSSAPI_SERVICE_REALM
103104
cls.mech_properties = mech_properties
104105

105106
async def test_credentials_hashing(self):
@@ -167,7 +168,10 @@ async def test_gssapi_simple(self):
167168
await client[GSSAPI_DB].collection.find_one()
168169

169170
# Log in using URI, with authMechanismProperties.
170-
mech_uri = uri + f"&authMechanismProperties={self.mech_properties}"
171+
mech_properties_str = ""
172+
for key, value in self.mech_properties.items():
173+
mech_properties_str += f"{key}:{value},"
174+
mech_uri = uri + f"&authMechanismProperties={mech_properties_str[:-1]}"
171175
client = self.simple_client(mech_uri)
172176
await client[GSSAPI_DB].collection.find_one()
173177

@@ -268,6 +272,58 @@ async def test_gssapi_threaded(self):
268272
thread.join()
269273
self.assertTrue(thread.success)
270274

275+
async def test_gssapi_canonicalize_host_name(self):
276+
# Test the low level method.
277+
assert GSSAPI_HOST is not None
278+
result = _canonicalize_hostname(GSSAPI_HOST, "forward")
279+
if "compute-1.amazonaws.com" not in result:
280+
self.assertEqual(result, GSSAPI_HOST)
281+
result = _canonicalize_hostname(GSSAPI_HOST, "forwardAndReverse")
282+
self.assertEqual(result, GSSAPI_HOST)
283+
284+
# Use the equivalent named CANONICALIZE_HOST_NAME.
285+
props = self.mech_properties.copy()
286+
if props["CANONICALIZE_HOST_NAME"] == "true":
287+
props["CANONICALIZE_HOST_NAME"] = "forwardAndReverse"
288+
else:
289+
props["CANONICALIZE_HOST_NAME"] = "none"
290+
client = self.simple_client(
291+
GSSAPI_HOST,
292+
GSSAPI_PORT,
293+
username=GSSAPI_PRINCIPAL,
294+
password=GSSAPI_PASS,
295+
authMechanism="GSSAPI",
296+
authMechanismProperties=props,
297+
)
298+
await client.server_info()
299+
300+
async def test_gssapi_host_name(self):
301+
props = self.mech_properties
302+
props["SERVICE_HOST"] = "example.com"
303+
304+
# Authenticate with authMechanismProperties.
305+
client = self.simple_client(
306+
GSSAPI_HOST,
307+
GSSAPI_PORT,
308+
username=GSSAPI_PRINCIPAL,
309+
password=GSSAPI_PASS,
310+
authMechanism="GSSAPI",
311+
authMechanismProperties=self.mech_properties,
312+
)
313+
with self.assertRaises(OperationFailure):
314+
await client.server_info()
315+
316+
props["SERVICE_HOST"] = GSSAPI_HOST
317+
client = self.simple_client(
318+
GSSAPI_HOST,
319+
GSSAPI_PORT,
320+
username=GSSAPI_PRINCIPAL,
321+
password=GSSAPI_PASS,
322+
authMechanism="GSSAPI",
323+
authMechanismProperties=self.mech_properties,
324+
)
325+
await client.server_info()
326+
271327

272328
class TestSASLPlain(AsyncPyMongoTestCase):
273329
@classmethod

0 commit comments

Comments
 (0)