From cf8d656e225688ffd3a6be1527c07176b62411f9 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Mon, 3 Aug 2026 10:24:42 -0400 Subject: [PATCH 1/5] MLE-31642 Update noSslContext Test MarkLogic 12.1 is now returning a 403 error code, like we expect, instead of closing the connection and throwing a MarkLogicIOException. - Removed @ExtendsWith(RequiresMLS11OrLower.class) annotation to run against ML12.1 - Updated comments to explain failure history if run against a MLS 12.0.x build - Removed noSslContextWithMarkLogic12() --- .../client/test/ssl/OneWaySSLTest.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java index 29059d2c8..5b11ee5a9 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java @@ -12,7 +12,6 @@ import com.marklogic.client.test.MarkLogicVersion; import com.marklogic.client.test.junit5.DisabledWhenUsingReverseProxyServer; import com.marklogic.client.test.junit5.RequireSSLExtension; -import com.marklogic.client.test.junit5.RequiresML11OrLower; import com.marklogic.client.test.junit5.RequiresML12; import com.marklogic.mgmt.ManageClient; import com.marklogic.mgmt.resource.appservers.ServerManager; @@ -120,16 +119,25 @@ void defaultSslContext() throws Exception { assertTrue(ex.getCause() instanceof SSLException, "Unexpected cause: " + ex.getCause()); } - @ExtendWith(RequiresML11OrLower.class) + /** + * Verifies that MarkLogic returns a 403 Forbidden response when a plain HTTP client connects to an + * app server that requires SSL. This is the expected behaviour for MarkLogic 11 and for MarkLogic 12.1+. + * + *

Note: early MarkLogic 12 builds (before 12.1) briefly changed this behaviour per MLE-17505, where + * the server's openssl library would close the TCP connection abruptly instead of returning HTTP 403, + * causing {@link com.marklogic.client.MarkLogicIOException} with "unexpected end of stream" to be thrown. + * That change was reverted in 12.1. If this test is run against a pre-12.1 MarkLogic 12 build it will + * fail because {@code checkConnection()} will throw rather than return a 403 {@code ConnectionResult}.

+ */ @Test void noSslContext() { DatabaseClient client = newSslClient(Map.of()); DatabaseClient.ConnectionResult result = client.checkConnection(); assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic is expected to return a 403 Forbidden when the " + - "user tries to access an HTTPS app server using HTTP. This behavior changes in MarkLogic 12, and it may " + - "be considered a bit surprising with MarkLogic 11 and earlier - that is, the user probably shouldn't get " + - "any response back since a connection cannot be made without using SSL."); + "user tries to access an HTTPS app server using HTTP. If this assertion fails with a MarkLogicIOException " + + "containing 'unexpected end of stream', the test is likely running against a pre-12.1 MarkLogic 12 build " + + "that exhibited the now-reverted MLE-17505 behaviour."); assertEquals(403, result.getStatusCode()); ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, @@ -143,17 +151,6 @@ void noSslContext() { ); } - @ExtendWith(RequiresML12.class) - @Test - void noSslContextWithMarkLogic12() { - DatabaseClient client = newSslClient(Map.of()); - - MarkLogicIOException ex = assertThrows(MarkLogicIOException.class, () -> client.checkConnection()); - assertTrue(ex.getMessage().contains("unexpected end of stream"), "Per MLE-17505, a change in the openssl " + - "library used by the server results in an IO exception when the client tries to connect to an " + - "app server that requires SSL, but the client does not use SSL. Actual message: " + ex.getMessage()); - } - @Test void tLS13ClientWithTLS12Server() { DatabaseClient client = buildTrustAllClientWithSSLProtocol(SSLUtil.DEFAULT_PROTOCOL); From 225138317614a1f05fc0501861bf4965ab620954 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Mon, 3 Aug 2026 11:04:24 -0400 Subject: [PATCH 2/5] Revert "MLE-31642 Update noSslContext Test" This reverts commit cf8d656e225688ffd3a6be1527c07176b62411f9. --- .../client/test/ssl/OneWaySSLTest.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java index 5b11ee5a9..29059d2c8 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java @@ -12,6 +12,7 @@ import com.marklogic.client.test.MarkLogicVersion; import com.marklogic.client.test.junit5.DisabledWhenUsingReverseProxyServer; import com.marklogic.client.test.junit5.RequireSSLExtension; +import com.marklogic.client.test.junit5.RequiresML11OrLower; import com.marklogic.client.test.junit5.RequiresML12; import com.marklogic.mgmt.ManageClient; import com.marklogic.mgmt.resource.appservers.ServerManager; @@ -119,25 +120,16 @@ void defaultSslContext() throws Exception { assertTrue(ex.getCause() instanceof SSLException, "Unexpected cause: " + ex.getCause()); } - /** - * Verifies that MarkLogic returns a 403 Forbidden response when a plain HTTP client connects to an - * app server that requires SSL. This is the expected behaviour for MarkLogic 11 and for MarkLogic 12.1+. - * - *

Note: early MarkLogic 12 builds (before 12.1) briefly changed this behaviour per MLE-17505, where - * the server's openssl library would close the TCP connection abruptly instead of returning HTTP 403, - * causing {@link com.marklogic.client.MarkLogicIOException} with "unexpected end of stream" to be thrown. - * That change was reverted in 12.1. If this test is run against a pre-12.1 MarkLogic 12 build it will - * fail because {@code checkConnection()} will throw rather than return a 403 {@code ConnectionResult}.

- */ + @ExtendWith(RequiresML11OrLower.class) @Test void noSslContext() { DatabaseClient client = newSslClient(Map.of()); DatabaseClient.ConnectionResult result = client.checkConnection(); assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic is expected to return a 403 Forbidden when the " + - "user tries to access an HTTPS app server using HTTP. If this assertion fails with a MarkLogicIOException " + - "containing 'unexpected end of stream', the test is likely running against a pre-12.1 MarkLogic 12 build " + - "that exhibited the now-reverted MLE-17505 behaviour."); + "user tries to access an HTTPS app server using HTTP. This behavior changes in MarkLogic 12, and it may " + + "be considered a bit surprising with MarkLogic 11 and earlier - that is, the user probably shouldn't get " + + "any response back since a connection cannot be made without using SSL."); assertEquals(403, result.getStatusCode()); ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, @@ -151,6 +143,17 @@ void noSslContext() { ); } + @ExtendWith(RequiresML12.class) + @Test + void noSslContextWithMarkLogic12() { + DatabaseClient client = newSslClient(Map.of()); + + MarkLogicIOException ex = assertThrows(MarkLogicIOException.class, () -> client.checkConnection()); + assertTrue(ex.getMessage().contains("unexpected end of stream"), "Per MLE-17505, a change in the openssl " + + "library used by the server results in an IO exception when the client tries to connect to an " + + "app server that requires SSL, but the client does not use SSL. Actual message: " + ex.getMessage()); + } + @Test void tLS13ClientWithTLS12Server() { DatabaseClient client = buildTrustAllClientWithSSLProtocol(SSLUtil.DEFAULT_PROTOCOL); From f0c2df283bd1f46d719b0df0c4c8f226d88a45db Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Mon, 3 Aug 2026 12:09:30 -0400 Subject: [PATCH 3/5] MLE-31642 Updated noSslContext Tests - Updated noSslContext() to noSslContextWithMarkLogic11OrLower() - Added RequiresML12Dot0 to test ML 12.0.x versions - Updated noSslContextWithMarkLogic12() to extend with RequiresML12Dot0.class for only ML versions 12.0.x - Added noSslContextWithMarkLogic12Dot1OrHigher() for ML 12.1 and up behavior. --- .../client/test/junit5/RequiresML12Dot0.java | 27 +++++++++++++ .../client/test/ssl/OneWaySSLTest.java | 38 +++++++++++++++---- 2 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequiresML12Dot0.java diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequiresML12Dot0.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequiresML12Dot0.java new file mode 100644 index 000000000..d828fc548 --- /dev/null +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/junit5/RequiresML12Dot0.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010-2026 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved. + */ +package com.marklogic.client.test.junit5; + +import com.marklogic.client.test.Common; +import com.marklogic.client.test.MarkLogicVersion; +import org.junit.jupiter.api.extension.ConditionEvaluationResult; +import org.junit.jupiter.api.extension.ExecutionCondition; +import org.junit.jupiter.api.extension.ExtensionContext; + +public class RequiresML12Dot0 implements ExecutionCondition { + + private static MarkLogicVersion markLogicVersion; + + @Override + public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) { + if (markLogicVersion == null) { + markLogicVersion = Common.getMarkLogicVersion(); + } + boolean supported = + markLogicVersion.getMajor() == 12 && markLogicVersion.getMinor() != null && markLogicVersion.getMinor() == 0; + return supported ? + ConditionEvaluationResult.enabled("MarkLogic is version 12.0.x") : + ConditionEvaluationResult.disabled("MarkLogic is not version 12.0.x"); + } +} diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java index 29059d2c8..a501fe40c 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java @@ -13,6 +13,8 @@ import com.marklogic.client.test.junit5.DisabledWhenUsingReverseProxyServer; import com.marklogic.client.test.junit5.RequireSSLExtension; import com.marklogic.client.test.junit5.RequiresML11OrLower; +import com.marklogic.client.test.junit5.RequiresML12Dot0; +import com.marklogic.client.test.junit5.RequiresML12Dot1; import com.marklogic.client.test.junit5.RequiresML12; import com.marklogic.mgmt.ManageClient; import com.marklogic.mgmt.resource.appservers.ServerManager; @@ -122,14 +124,12 @@ void defaultSslContext() throws Exception { @ExtendWith(RequiresML11OrLower.class) @Test - void noSslContext() { + void noSslContextWithMarkLogic11OrLower() { DatabaseClient client = newSslClient(Map.of()); DatabaseClient.ConnectionResult result = client.checkConnection(); - assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic is expected to return a 403 Forbidden when the " + - "user tries to access an HTTPS app server using HTTP. This behavior changes in MarkLogic 12, and it may " + - "be considered a bit surprising with MarkLogic 11 and earlier - that is, the user probably shouldn't get " + - "any response back since a connection cannot be made without using SSL."); + assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 11 or lower is expected to return a 403 Forbidden when the " + + "user tries to access an HTTPS app server using HTTP."); assertEquals(403, result.getStatusCode()); ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, @@ -143,15 +143,37 @@ void noSslContext() { ); } - @ExtendWith(RequiresML12.class) + @ExtendWith(RequiresML12Dot0.class) @Test - void noSslContextWithMarkLogic12() { + void noSslContextWithMarkLogic12Dot0() { DatabaseClient client = newSslClient(Map.of()); MarkLogicIOException ex = assertThrows(MarkLogicIOException.class, () -> client.checkConnection()); assertTrue(ex.getMessage().contains("unexpected end of stream"), "Per MLE-17505, a change in the openssl " + "library used by the server results in an IO exception when the client tries to connect to an " + - "app server that requires SSL, but the client does not use SSL. Actual message: " + ex.getMessage()); + "app server that requires SSL, but the client does not use SSL. This impacts all ML 12.0.x versions as of 12.0.3. " + + "Actual message: " + ex.getMessage()); + } + + @ExtendWith(RequiresML12Dot1.class) + @Test + void noSslContextWithMarkLogic12Dot1OrHigher() { + DatabaseClient client = newSslClient(Map.of()); + + DatabaseClient.ConnectionResult result = client.checkConnection(); + assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 12.1 or higher is expected to return a 403 Forbidden when the " + + "user tries to access an HTTPS app server using HTTP."); + assertEquals(403, result.getStatusCode()); + + ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, + () -> client.newServerEval().javascript("fn.currentDate()").evalAs(String.class)); + + assertEquals( + "Local message: User is not allowed to apply resource at eval. Server Message: You have attempted to access an HTTPS server using HTTP.", + ex.getMessage(), + "The user should get a clear message on why the connection failed as opposed to the previous error " + + "message of 'Server (not a REST instance?)'." + ); } @Test From f070abe71b0d94b2465389ff2978bd62e24caf6e Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Mon, 3 Aug 2026 12:16:33 -0400 Subject: [PATCH 4/5] MLE-31642 Refactor noSslContextWithMarkLogic11OrLower() -> noSslContext() and updated the ExtendsWith annotation to @ExtendWith({RequiresML11OrLower.class, RequiresML12Dot1.class}) --- .../client/test/ssl/OneWaySSLTest.java | 29 +++---------------- 1 file changed, 4 insertions(+), 25 deletions(-) diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java index a501fe40c..cd5141dac 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java @@ -122,14 +122,14 @@ void defaultSslContext() throws Exception { assertTrue(ex.getCause() instanceof SSLException, "Unexpected cause: " + ex.getCause()); } - @ExtendWith(RequiresML11OrLower.class) + @ExtendWith({RequiresML11OrLower.class, RequiresML12Dot1.class}) @Test - void noSslContextWithMarkLogic11OrLower() { + void noSslContext() { DatabaseClient client = newSslClient(Map.of()); DatabaseClient.ConnectionResult result = client.checkConnection(); - assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 11 or lower is expected to return a 403 Forbidden when the " + - "user tries to access an HTTPS app server using HTTP."); + assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 11 or lower and MarkLogic 12.1 or higher is " + + "expected to return a 403 Forbidden when the user tries to access an HTTPS app server using HTTP."); assertEquals(403, result.getStatusCode()); ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, @@ -155,27 +155,6 @@ void noSslContextWithMarkLogic12Dot0() { "Actual message: " + ex.getMessage()); } - @ExtendWith(RequiresML12Dot1.class) - @Test - void noSslContextWithMarkLogic12Dot1OrHigher() { - DatabaseClient client = newSslClient(Map.of()); - - DatabaseClient.ConnectionResult result = client.checkConnection(); - assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 12.1 or higher is expected to return a 403 Forbidden when the " + - "user tries to access an HTTPS app server using HTTP."); - assertEquals(403, result.getStatusCode()); - - ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, - () -> client.newServerEval().javascript("fn.currentDate()").evalAs(String.class)); - - assertEquals( - "Local message: User is not allowed to apply resource at eval. Server Message: You have attempted to access an HTTPS server using HTTP.", - ex.getMessage(), - "The user should get a clear message on why the connection failed as opposed to the previous error " + - "message of 'Server (not a REST instance?)'." - ); - } - @Test void tLS13ClientWithTLS12Server() { DatabaseClient client = buildTrustAllClientWithSSLProtocol(SSLUtil.DEFAULT_PROTOCOL); From b95c24dfb5488179390b89c0fa6a3064a80f0a1a Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Mon, 3 Aug 2026 12:20:08 -0400 Subject: [PATCH 5/5] Revert "MLE-31642 Refactor" This reverts commit f070abe71b0d94b2465389ff2978bd62e24caf6e. --- .../client/test/ssl/OneWaySSLTest.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java index cd5141dac..a501fe40c 100644 --- a/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java +++ b/marklogic-client-api/src/test/java/com/marklogic/client/test/ssl/OneWaySSLTest.java @@ -122,14 +122,14 @@ void defaultSslContext() throws Exception { assertTrue(ex.getCause() instanceof SSLException, "Unexpected cause: " + ex.getCause()); } - @ExtendWith({RequiresML11OrLower.class, RequiresML12Dot1.class}) + @ExtendWith(RequiresML11OrLower.class) @Test - void noSslContext() { + void noSslContextWithMarkLogic11OrLower() { DatabaseClient client = newSslClient(Map.of()); DatabaseClient.ConnectionResult result = client.checkConnection(); - assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 11 or lower and MarkLogic 12.1 or higher is " + - "expected to return a 403 Forbidden when the user tries to access an HTTPS app server using HTTP."); + assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 11 or lower is expected to return a 403 Forbidden when the " + + "user tries to access an HTTPS app server using HTTP."); assertEquals(403, result.getStatusCode()); ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, @@ -155,6 +155,27 @@ void noSslContextWithMarkLogic12Dot0() { "Actual message: " + ex.getMessage()); } + @ExtendWith(RequiresML12Dot1.class) + @Test + void noSslContextWithMarkLogic12Dot1OrHigher() { + DatabaseClient client = newSslClient(Map.of()); + + DatabaseClient.ConnectionResult result = client.checkConnection(); + assertEquals("Forbidden", result.getErrorMessage(), "MarkLogic 12.1 or higher is expected to return a 403 Forbidden when the " + + "user tries to access an HTTPS app server using HTTP."); + assertEquals(403, result.getStatusCode()); + + ForbiddenUserException ex = assertThrows(ForbiddenUserException.class, + () -> client.newServerEval().javascript("fn.currentDate()").evalAs(String.class)); + + assertEquals( + "Local message: User is not allowed to apply resource at eval. Server Message: You have attempted to access an HTTPS server using HTTP.", + ex.getMessage(), + "The user should get a clear message on why the connection failed as opposed to the previous error " + + "message of 'Server (not a REST instance?)'." + ); + } + @Test void tLS13ClientWithTLS12Server() { DatabaseClient client = buildTrustAllClientWithSSLProtocol(SSLUtil.DEFAULT_PROTOCOL);