Skip to content

Introduce SOCKS5 proxy support #1180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Sep 8, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
311515e
Introduce SOCKS5 proxy support, allowing seamless connections to Mong…
vbabanin Aug 3, 2023
07a567d
Include CSFLE test suites to run via Socks5 proxy.
vbabanin Aug 17, 2023
0231ae6
Remove extra MONGODB_URI variable.
vbabanin Aug 17, 2023
53c7973
Remove unused imports.
vbabanin Aug 17, 2023
81020fb
Update driver-core/src/main/com/mongodb/connection/SocketSettings.java
vbabanin Aug 24, 2023
1313753
Update driver-core/src/main/com/mongodb/ClientEncryptionSettings.java
vbabanin Aug 24, 2023
37e0874
Update driver-core/src/main/com/mongodb/AutoEncryptionSettings.java
vbabanin Aug 24, 2023
3790094
Update driver-core/src/main/com/mongodb/connection/ProxySettings.java
vbabanin Aug 25, 2023
494e293
Apply suggestions from code review
vbabanin Aug 29, 2023
de7697d
Update driver-core/src/main/com/mongodb/internal/connection/SocksSock…
vbabanin Aug 29, 2023
3e84f5c
Revert proxy settings for key Management Service.
vbabanin Aug 31, 2023
08d3e30
Remove KMIP config.
vbabanin Sep 1, 2023
ba111ca
Restructuring testing:
vbabanin Sep 2, 2023
db8d91b
Fix checkstyle errors.
vbabanin Sep 2, 2023
ea1060c
Update driver-reactive-streams/src/main/com/mongodb/reactivestreams/c…
vbabanin Sep 5, 2023
7b93565
Update driver-core/src/main/com/mongodb/connection/ProxySettings.java
vbabanin Sep 5, 2023
e7218a8
Update driver-core/src/main/com/mongodb/connection/ProxySettings.java
vbabanin Sep 5, 2023
a56d56c
Update driver-core/src/main/com/mongodb/connection/ProxySettings.java
vbabanin Sep 5, 2023
dcac4f6
Apply suggestions from code review
vbabanin Sep 5, 2023
7eb1c11
- Change javadoc.
vbabanin Sep 5, 2023
19f2dca
Add javadoc.
vbabanin Sep 5, 2023
735e81e
Remove redundant code.
vbabanin Sep 5, 2023
34a26ce
Add @EnabledIf annotation for tests to remove skipped tests from a re…
vbabanin Sep 5, 2023
ede85de
Apply suggestions from code review
vbabanin Sep 6, 2023
840d12b
Remove redundant code.
vbabanin Sep 6, 2023
7d461a0
Add size check in domain regex.
vbabanin Sep 6, 2023
42aca98
Address checkstyle warnings.
vbabanin Sep 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .evergreen/.evg.yml
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,30 @@ functions:
MONGODB_URIS="${atlas_free_tier_uri}|${atlas_replica_set_uri}|${atlas_sharded_uri}|${atlas_tls_v11_uri}|${atlas_tls_v12_uri}|${atlas_free_tier_uri_srv}|${atlas_replica_set_uri_srv}|${atlas_sharded_uri_srv}|${atlas_tls_v11_uri_srv}|${atlas_tls_v12_uri_srv}|${atlas_serverless_uri}|${atlas_serverless_uri_srv}" \
.evergreen/run-connectivity-tests.sh

run socks5 tests:
- command: shell.exec
type: test
params:
working_dir: src
script: |
${PREPARE_SHELL}
export AWS_ACCESS_KEY_ID=${aws_access_key_id}
export AWS_SECRET_ACCESS_KEY=${aws_secret_access_key}
export AWS_DEFAULT_REGION=us-east-1
. ${DRIVERS_TOOLS}/.evergreen/csfle/set-temp-creds.sh
MONGODB_URI="${MONGODB_URI}" \
AWS_ACCESS_KEY_ID=${aws_access_key_id} AWS_SECRET_ACCESS_KEY=${aws_secret_access_key} \
AWS_TEMP_ACCESS_KEY_ID=$CSFLE_AWS_TEMP_ACCESS_KEY_ID \
AWS_TEMP_SECRET_ACCESS_KEY=$CSFLE_AWS_TEMP_SECRET_ACCESS_KEY \
AWS_TEMP_SESSION_TOKEN=$CSFLE_AWS_TEMP_SESSION_TOKEN \
AZURE_TENANT_ID=${azure_tenant_id} AZURE_CLIENT_ID=${azure_client_id} AZURE_CLIENT_SECRET=${azure_client_secret} \
GCP_EMAIL=${gcp_email} GCP_PRIVATE_KEY=${gcp_private_key} \
AZUREKMS_KEY_VAULT_ENDPOINT=${testazurekms_keyvaultendpoint} \
AZUREKMS_KEY_NAME=${testazurekms_keyname} \
SSL="${SSL}" MONGODB_URI="${MONGODB_URI}" \
JAVA_VERSION="${JAVA_VERSION}" \
.evergreen/run-socks5-tests.sh

start-kms-mock-server:
- command: shell.exec
params:
Expand Down Expand Up @@ -1605,6 +1629,26 @@ tasks:
export AZUREKMS_VMNAME=${AZUREKMS_VMNAME}
export AZUREKMS_PRIVATEKEYPATH=/tmp/testazurekms_privatekey
AZUREKMS_CMD="MONGODB_URI=mongodb://localhost:27017 PROVIDER=azure AZUREKMS_KEY_VAULT_ENDPOINT=${testazurekms_keyvaultendpoint} AZUREKMS_KEY_NAME=${testazurekms_keyname} ./.evergreen/run-fle-on-demand-credential-test.sh" $DRIVERS_TOOLS/.evergreen/csfle/azurekms/run-command.sh
- name: test-socks5
tags: []
commands:
- func: start-kms-kmip-server
- func: bootstrap mongo-orchestration
vars:
VERSION: latest
TOPOLOGY: replica_set
- func: run socks5 tests
- name: test-socks5-tls
tags: []
commands:
- func: start-kms-kmip-server
- func: bootstrap mongo-orchestration
vars:
VERSION: latest
TOPOLOGY: replica_set
- func: run socks5 tests
vars:
SSL: ssl
axes:
- id: version
display_name: MongoDB Version
Expand Down Expand Up @@ -2136,6 +2180,12 @@ buildvariants:
tasks:
- name: "csfle-tests-with-mongocryptd"

- matrix_name: "socks5-tests"
matrix_spec: { os: "linux", ssl: ["nossl", "ssl"], version: [ "latest" ], topology: ["replicaset"] }
display_name: "Socks5: ${version} ${topology} ${ssl} ${jdk} ${os}"
tasks:
- name: test-socks5

- name: testgcpkms-variant
display_name: "GCP KMS"
run_on:
Expand Down
106 changes: 106 additions & 0 deletions .evergreen/run-socks5-tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/bash

set -o xtrace # Write all commands first to stderr
set -o errexit # Exit the script with error if any of the commands fail

SSL=${SSL:-nossl}
MONGODB_URI=${MONGODB_URI:-}
SOCKS5_SERVER_SCRIPT="$DRIVERS_TOOLS/.evergreen/socks5srv.py"
PYTHON_BINARY=${PYTHON_BINARY:-python3}
# Grab a connection string that only refers to *one* of the hosts in MONGODB_URI
FIRST_HOST=$(echo "$MONGODB_URI" | awk -F[/:,] '{print $4":"$5}')
# Use 127.0.0.1:12345 as the URL for the single host that we connect to,
# we configure the Socks5 proxy server script to redirect from this to FIRST_HOST
export MONGODB_URI_SINGLEHOST="mongodb://127.0.0.1:12345"

if [ "${SSL}" = "ssl" ]; then
MONGODB_URI="${MONGODB_URI}&ssl=true&sslInvalidHostNameAllowed=true"
MONGODB_URI_SINGLEHOST="${MONGODB_URI_SINGLEHOST}/?ssl=true&sslInvalidHostNameAllowed=true"
fi

# Compute path to socks5 fake server script in a way that works on Windows
if [ "Windows_NT" == "$OS" ]; then
SOCKS5_SERVER_SCRIPT=$(cygpath -m $DRIVERS_TOOLS)
fi

RELATIVE_DIR_PATH="$(dirname "${BASH_SOURCE:-$0}")"
. "${RELATIVE_DIR_PATH}/javaConfig.bash"

############################################
# Functions #
############################################

provision_ssl () {
# We generate the keystore and truststore on every run with the certs in the drivers-tools repo
if [ ! -f client.pkc ]; then
openssl pkcs12 -CAfile ${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem -export -in ${DRIVERS_TOOLS}/.evergreen/x509gen/client.pem -out client.pkc -password pass:bithere
fi

cp ${JAVA_HOME}/lib/security/cacerts mongo-truststore
${JAVA_HOME}/bin/keytool -importcert -trustcacerts -file ${DRIVERS_TOOLS}/.evergreen/x509gen/ca.pem -keystore mongo-truststore -storepass changeit -storetype JKS -noprompt

# We add extra gradle arguments for SSL
export GRADLE_SSL_VARS="-Pssl.enabled=true -Pssl.keyStoreType=pkcs12 -Pssl.keyStore=`pwd`/client.pkc -Pssl.keyStorePassword=bithere -Pssl.trustStoreType=jks -Pssl.trustStore=`pwd`/mongo-truststore -Pssl.trustStorePassword=changeit"
}

run_csfle_tests () {
local MONGODB_URI=$1 # Get MongoDB URI from the first argument
echo "Running CSFE tests with Java ${JAVA_VERSION} for $TOPOLOGY and connecting to $MONGODB_URI with socks5"
# By not specifying the path to the `crypt_shared` via the `org.mongodb.test.crypt.shared.lib.path` Java system property,
# we force the driver to start `mongocryptd` instead of loading and using `crypt_shared`.
./gradlew -PjavaVersion=${JAVA_VERSION} -Dorg.mongodb.test.uri=${MONGODB_URI} \
-Dorg.mongodb.test.fle.on.demand.credential.test.failure.enabled="true" \
-Dorg.mongodb.test.fle.on.demand.credential.test.azure.keyVaultEndpoint="${AZUREKMS_KEY_VAULT_ENDPOINT}" \
-Dorg.mongodb.test.fle.on.demand.credential.test.azure.keyName="${AZUREKMS_KEY_NAME}" \
-Dorg.mongodb.test.awsAccessKeyId=${AWS_ACCESS_KEY_ID} -Dorg.mongodb.test.awsSecretAccessKey=${AWS_SECRET_ACCESS_KEY} \
-Dorg.mongodb.test.tmpAwsAccessKeyId=${AWS_TEMP_ACCESS_KEY_ID} -Dorg.mongodb.test.tmpAwsSecretAccessKey=${AWS_TEMP_SECRET_ACCESS_KEY} -Dorg.mongodb.test.tmpAwsSessionToken=${AWS_TEMP_SESSION_TOKEN} \
-Dorg.mongodb.test.azureTenantId=${AZURE_TENANT_ID} -Dorg.mongodb.test.azureClientId=${AZURE_CLIENT_ID} -Dorg.mongodb.test.azureClientSecret=${AZURE_CLIENT_SECRET} \
-Dorg.mongodb.test.gcpEmail=${GCP_EMAIL} -Dorg.mongodb.test.gcpPrivateKey=${GCP_PRIVATE_KEY} \
${GRADLE_SSL_VARS} \
--stacktrace --info --continue \
driver-sync:test \
--tests "*Client*Encryption*"
}

run_socks5_prose_tests () {
local PROXY_PORT=$1
local AUTH_ENABLED=$2
echo "Running Socks5 tests with Java ${JAVA_VERSION} over $SSL for $TOPOLOGY and connecting to $MONGODB_URI with socks auth enabled $AUTH_ENABLED"
./gradlew -PjavaVersion=${JAVA_VERSION} -Dorg.mongodb.test.uri=${MONGODB_URI} \
-Dorg.mongodb.test.uri.singleHost=${MONGODB_URI_SINGLEHOST} \
-Dorg.mongodb.test.uri.proxyHost="127.0.0.1" \
-Dorg.mongodb.test.uri.proxyPort=${PROXY_PORT} \
-Dorg.mongodb.test.uri.socks.auth.enabled=${AUTH_ENABLED} \
${GRADLE_SSL_VARS} \
--stacktrace --info --continue \
driver-sync:test \
--tests "com.mongodb.client.Socks5ProseTest*"
}

############################################
# Main Program #
############################################

# Set up keystore/truststore
provision_ssl

# First, test with Socks5 + authentication required
echo "Running tests with Java ${JAVA_VERSION} over $SSL for $TOPOLOGY and connecting to $MONGODB_URI with socks5 auth enabled"
./gradlew -version
"$PYTHON_BINARY" "$SOCKS5_SERVER_SCRIPT" --port 1080 --auth username:p4ssw0rd --map "127.0.0.1:12345 to $FIRST_HOST" &
SOCKS5_SERVER_PID_1=$!
trap "kill $SOCKS5_SERVER_PID_1" EXIT

run_socks5_prose_tests "1080" "true"
run_csfle_tests "$MONGODB_URI&proxyHost=127.0.0.1&proxyPort=1080&proxyUsername=username&proxyPassword=p4ssw0rd"

# Second, test with Socks5 + no authentication
echo "Running tests with Java ${JAVA_VERSION} over $SSL for $TOPOLOGY and connecting to $MONGODB_URI with socks5 auth disabled"
./gradlew -version
"$PYTHON_BINARY" "$SOCKS5_SERVER_SCRIPT" --port 1081 --map "127.0.0.1:12345 to $FIRST_HOST" &
# Set up trap to kill both processes when the script exits
SOCKS5_SERVER_PID_2=$!
trap "kill $SOCKS5_SERVER_PID_1; kill $SOCKS5_SERVER_PID_2" EXIT

run_socks5_prose_tests "1081" "false"
run_csfle_tests "$MONGODB_URI&proxyHost=127.0.0.1&proxyPort=1081"
20 changes: 20 additions & 0 deletions THIRD-PARTY-NOTICES
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,23 @@ https://github.com/mongodb/mongo-java-driver.
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

8) The following files (originally from https://github.com/google/guava):

InetAddresses.java.java

Copyright 2008-present MongoDB, Inc.
Copyright (C) 2008 The Guava Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

9 changes: 8 additions & 1 deletion config/spotbugs/exclude.xml
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,17 @@

<!-- Spotbugs assumes that SSLSocket#getSSLParameters never returns null, when that is not the case for all JDKs -->
<Match>
<Class name="com.mongodb.internal.connection.SocketStreamHelper"/>
<Class name="com.mongodb.internal.connection.SslHelper"/>
<Bug pattern="RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE"/>
</Match>

<!-- FindBugs currently does not prune infeasible exception paths, this is a false warning.-->
<Match>
<Class name="com.mongodb.internal.connection.SocksSocket"/>
<Method name="getPort"/>
<Bug pattern="NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE"/>
</Match>

<Match>
<Class name="com.mongodb.client.internal.CryptConnection"/>
<Method name="retain"/>
Expand Down
44 changes: 44 additions & 0 deletions driver-core/src/main/com/mongodb/AutoEncryptionSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.mongodb;

import com.mongodb.annotations.NotThreadSafe;
import com.mongodb.connection.ProxySettings;
import com.mongodb.connection.SocketSettings;
import com.mongodb.lang.Nullable;
import org.bson.BsonDocument;

Expand Down Expand Up @@ -73,6 +75,14 @@ public final class AutoEncryptionSettings {
private final boolean bypassAutoEncryption;
private final Map<String, BsonDocument> encryptedFieldsMap;
private final boolean bypassQueryAnalysis;
/**
* Proxy setting used for connecting to Key Management Service via a SOCKS5 proxy server.
* <p>
* NOTE: If this field is left unset, the default behavior is to utilize the {@link SocketSettings#getProxySettings()}
* from the {@link MongoClientSettings} where the {@link AutoEncryptionSettings} are specified.
*/
@Nullable
private final ProxySettings proxySettings;

/**
* A builder for {@code AutoEncryptionSettings} so that {@code AutoEncryptionSettings} can be immutable, and to support easier
Expand All @@ -90,6 +100,10 @@ public static final class Builder {
private boolean bypassAutoEncryption;
private Map<String, BsonDocument> encryptedFieldsMap = Collections.emptyMap();
private boolean bypassQueryAnalysis;
/**
* Proxy setting used for connecting to Key Management Service via a SOCKS5 proxy server.
*/
private ProxySettings proxySettings;

/**
* Sets the key vault settings.
Expand All @@ -103,6 +117,24 @@ public Builder keyVaultMongoClientSettings(final MongoClientSettings keyVaultMon
return this;
}

/**
* Sets the {@link ProxySettings} used for connecting to Key Management Service via a SOCKS5 proxy server.
*
* <p>
* NOTE: If this field is left unset, the default behavior is to utilize the {@link SocketSettings#getProxySettings()}
* from the {@link MongoClientSettings} where the {@link AutoEncryptionSettings} are specified.
*
* @param proxySettings {@link ProxySettings} to set.
* @return this.
* @see #getProxySettings()
* @since 4.11
*/
public Builder proxySettings(final ProxySettings proxySettings) {
notNull("proxySettings", proxySettings);
this.proxySettings = proxySettings;
return this;
}

/**
* Sets the key vault namespace
*
Expand Down Expand Up @@ -275,6 +307,17 @@ public MongoClientSettings getKeyVaultMongoClientSettings() {
return keyVaultMongoClientSettings;
}

/**
* Gets the proxy settings used for connecting to Key Management Service via a SOCKS5 proxy server.
*
* @return The {@link ProxySettings} instance containing the SOCKS5 proxy configuration.
* @since 4.11
*/
@Nullable
public ProxySettings getProxySettings() {
return proxySettings;
}

/**
* Gets the key vault namespace.
*
Expand Down Expand Up @@ -493,6 +536,7 @@ private AutoEncryptionSettings(final Builder builder) {
this.bypassAutoEncryption = builder.bypassAutoEncryption;
this.encryptedFieldsMap = builder.encryptedFieldsMap;
this.bypassQueryAnalysis = builder.bypassQueryAnalysis;
this.proxySettings = builder.proxySettings;
}

@Override
Expand Down
38 changes: 38 additions & 0 deletions driver-core/src/main/com/mongodb/ClientEncryptionSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
package com.mongodb;

import com.mongodb.annotations.NotThreadSafe;
import com.mongodb.connection.ProxySettings;
import com.mongodb.lang.Nullable;

import javax.net.ssl.SSLContext;
import java.util.HashMap;
Expand All @@ -42,6 +44,12 @@ public final class ClientEncryptionSettings {
private final Map<String, Map<String, Object>> kmsProviders;
private final Map<String, Supplier<Map<String, Object>>> kmsProviderPropertySuppliers;
private final Map<String, SSLContext> kmsProviderSslContextMap;
/**
* Proxy setting used for connecting to Key Management Service via a SOCKS5 proxy server.
*/
@Nullable
private final ProxySettings proxySettings;

/**
* A builder for {@code ClientEncryptionSettings} so that {@code ClientEncryptionSettings} can be immutable, and to support easier
* construction through chaining.
Expand All @@ -53,6 +61,10 @@ public static final class Builder {
private Map<String, Map<String, Object>> kmsProviders;
private Map<String, Supplier<Map<String, Object>>> kmsProviderPropertySuppliers = new HashMap<>();
private Map<String, SSLContext> kmsProviderSslContextMap = new HashMap<>();
/**
* Proxy setting used for connecting to Key Management Service via a SOCKS5 proxy server.
*/
private ProxySettings proxySettings;

/**
* Sets the {@link MongoClientSettings} that will be used to access the key vault.
Expand All @@ -66,6 +78,20 @@ public Builder keyVaultMongoClientSettings(final MongoClientSettings keyVaultMon
return this;
}

/**
* Sets the {@link ProxySettings} used for connecting to Key Management Service via a SOCKS5 proxy server.
*
* @param proxySettings {@link ProxySettings} to set.
* @return this.
* @see #getProxySettings()
* @since 4.11
*/
public Builder proxySettings(final ProxySettings proxySettings) {
notNull("proxySettings", proxySettings);
this.proxySettings = proxySettings;
return this;
}

/**
* Sets the key vault namespace
*
Expand Down Expand Up @@ -151,6 +177,17 @@ public MongoClientSettings getKeyVaultMongoClientSettings() {
return keyVaultMongoClientSettings;
}

/**
* Gets the proxy settings used for connecting to Key Management Service via a SOCKS5 proxy server.
*
* @return The {@link ProxySettings} instance containing the SOCKS5 proxy configuration.
* @since 4.11
*/
@Nullable
public ProxySettings getProxySettings() {
return proxySettings;
}

/**
* Gets the key vault namespace.
* <p>
Expand Down Expand Up @@ -259,6 +296,7 @@ private ClientEncryptionSettings(final Builder builder) {
this.kmsProviders = notNull("kmsProviders", builder.kmsProviders);
this.kmsProviderPropertySuppliers = notNull("kmsProviderPropertySuppliers", builder.kmsProviderPropertySuppliers);
this.kmsProviderSslContextMap = notNull("kmsProviderSslContextMap", builder.kmsProviderSslContextMap);
this.proxySettings = builder.proxySettings;
}

}
Loading