Skip to content

Java Driver 5.11.0 (August 28, 2026)

Latest

Choose a tag to compare

@mongodb-dbx-release-bot mongodb-dbx-release-bot released this 28 Aug 20:03
· 1 commit to 5.11.x since this release

What's Changed

CSFLE/QE Http proxies notes

  • The driver always negotiates TLS with the KMS host itself, using the SSLContext configured for
    the KMS provider. Implementations must not negotiate TLS with the KMS host; doing so would let an
    intermediary read the key material in transit.
  • An implementation may use TLS for its own connection to the intermediary, in which case it returns
    an SSLSocket and the driver layers the KMS host's TLS session on top of it.
  • Ownership of the returned socket passes to the driver, which closes it when the KMS request
    completes. A socket that is never returned must be closed by the implementation.
  • Applicable only to the synchronous driver. The reactive streams driver rejects(RuntimeException) a configured
    callback.

Code example

Code example uses only the JDK API , so no HTTP client dependency is required. If you use your own HTTP client, it must return the tunnelled socket without negotiating TLS with the KMS host

First define the callback

private static final String PROXY_HOST = "proxy.example.com";
private static final int PROXY_PORT = 8080;
private static final int TIMEOUT_MILLIS = 10_000;

// Routes every KMS request through an HTTP proxy using the HTTP CONNECT method
// refer to the docs https://www.rfc-editor.org/info/rfc9110/#section-9.3.6
KmsConnectCallback proxyCallback = context -> {
    Socket socket = new Socket();
    try {
        // 1. Connect to the proxy, not to the KMS host.
        socket.connect(new InetSocketAddress(PROXY_HOST, PROXY_PORT), TIMEOUT_MILLIS);
        socket.setSoTimeout(TIMEOUT_MILLIS);

        // 2. Ask the proxy to open a tunnel to the KMS host the driver wants to reach. Only the
        //    driver knows which host that is, so always take it from the context rather than
        //    hard-coding it.
        String target = context.getHost() + ":" + context.getPort();
        String connectRequest = "CONNECT " + target + " HTTP/1.1\r\n"
                + "Host: " + target + "\r\n"
                // If the proxy requires authentication, add the appropriate header, for example:
                // + "Proxy-Authorization: Basic " + base64("user:password") + "\r\n"
                + "\r\n";
        socket.getOutputStream().write(connectRequest.getBytes(StandardCharsets.US_ASCII));

        // 3. Check the proxy accepted the tunnel before handing the socket back.
        checkProxyAcceptedTunnel(socket.getInputStream());
    } catch (IOException | RuntimeException e) {
        // The driver never received this socket, so it cannot close it for you.
        socket.close();
        throw e;
    }

    // 4. Return the tunnelled socket. The driver now performs its own TLS handshake with the KMS
    //    host over it, verifying the KMS host's certificate. Do not negotiate TLS with the KMS
    //    host yourself.
    return socket;
};

// Reads the proxy's response to CONNECT and fails unless it is 2xx.
static void checkProxyAcceptedTunnel(InputStream in) throws IOException {
    StringBuilder response = new StringBuilder();
    int b;
    while (response.indexOf("\r\n\r\n") < 0 && (b = in.read()) != -1) {
        response.append((char) b);
    }
    String statusLine = response.toString().split("\r\n", 2)[0];
    if (!statusLine.startsWith("HTTP/1.1 2") && !statusLine.startsWith("HTTP/1.0 2")) {
        throw new IOException("Proxy refused the CONNECT request: " + statusLine);
    }
}

Then use this callback to configure the ClientEncryption

ClientEncryptionSettings settings = ClientEncryptionSettings.builder()
        .keyVaultMongoClientSettings(keyVaultClientSettings)
        .keyVaultNamespace("keyvault.datakeys")
        .kmsProviders(kmsProviders)
        .kmsConnectCallback(proxyCallback)
        .build();

Or using automatic encryption

AutoEncryptionSettings settings = AutoEncryptionSettings.builder()
        .keyVaultNamespace("keyvault.datakeys")
        .kmsProviders(kmsProviders)
        .kmsConnectCallback(proxyCallback)
        .build();

Full Changelog: r5.10.0...r5.11.0