From 53be81f9bf84f7f96543d43e3639b99938610966 Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin <18335884+vbabanin@users.noreply.github.com> Date: Fri, 6 Jun 2025 23:35:15 +0000 Subject: [PATCH 1/3] Version: bump 5.5.2-SNAPSHOT --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 85e3c33ce5..99e74d41c8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,7 +14,7 @@ # limitations under the License. # -version=5.5.1 +version=5.5.2-SNAPSHOT org.gradle.daemon=true org.gradle.jvmargs=-Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en From 7fe2223eadc844692588df47fd225bbe24c3eae4 Mon Sep 17 00:00:00 2001 From: Viacheslav Babanin Date: Wed, 11 Jun 2025 11:16:48 -0700 Subject: [PATCH 2/3] Merge changes from tls-channel to prevent accidentally calling SSLEngine (#1737) - Perform handshake after marking handshake started. - Add an integration test case, as upstream didn't include one to cover this change. JAVA-5797 --- .../tlschannel/impl/TlsChannelImpl.java | 27 ++++++++--- .../TlsChannelStreamFunctionalTest.java | 48 +++++++++++++++++++ 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/driver-core/src/main/com/mongodb/internal/connection/tlschannel/impl/TlsChannelImpl.java b/driver-core/src/main/com/mongodb/internal/connection/tlschannel/impl/TlsChannelImpl.java index 3c845ce6d0..20bc69e81f 100644 --- a/driver-core/src/main/com/mongodb/internal/connection/tlschannel/impl/TlsChannelImpl.java +++ b/driver-core/src/main/com/mongodb/internal/connection/tlschannel/impl/TlsChannelImpl.java @@ -159,7 +159,9 @@ public TlsChannelImpl( private final Lock readLock = new ReentrantLock(); private final Lock writeLock = new ReentrantLock(); - private volatile boolean negotiated = false; + private boolean handshakeStarted = false; + + private volatile boolean handshakeCompleted = false; /** * Whether a IOException was received from the underlying channel or from the {@link SSLEngine}. @@ -526,14 +528,28 @@ public void handshake() throws IOException { } private void doHandshake(boolean force) throws IOException, EofException { - if (!force && negotiated) return; + if (!force && handshakeCompleted) { + return; + } initLock.lock(); try { if (invalid || shutdownSent) throw new ClosedChannelException(); - if (force || !negotiated) { - engine.beginHandshake(); - LOGGER.trace("Called engine.beginHandshake()"); + if (force || !handshakeCompleted) { + + if (!handshakeStarted) { + engine.beginHandshake(); + LOGGER.trace("Called engine.beginHandshake()"); + + // Some engines that do not support renegotiations may be sensitive to calling + // SSLEngine.beginHandshake() more than once. This guard prevents that. + // See: https://github.com/marianobarrios/tls-channel/issues/197 + handshakeStarted = true; + } + handshake(Optional.empty(), Optional.empty()); + + handshakeCompleted = true; + // call client code try { initSessionCallback.accept(engine.getSession()); @@ -541,7 +557,6 @@ private void doHandshake(boolean force) throws IOException, EofException { LOGGER.trace("client code threw exception in session initialization callback", e); throw new TlsChannelCallbackException("session initialization callback failed", e); } - negotiated = true; } } finally { initLock.unlock(); diff --git a/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java b/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java index 3f80fcddfa..3af1eaa33e 100644 --- a/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java +++ b/driver-core/src/test/functional/com/mongodb/internal/connection/TlsChannelStreamFunctionalTest.java @@ -16,12 +16,17 @@ package com.mongodb.internal.connection; +import com.mongodb.ClusterFixture; import com.mongodb.MongoSocketOpenException; import com.mongodb.ServerAddress; import com.mongodb.connection.SocketSettings; import com.mongodb.connection.SslSettings; import com.mongodb.internal.TimeoutContext; import com.mongodb.internal.TimeoutSettings; +import org.bson.ByteBuf; +import org.bson.ByteBufNIO; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.MockedStatic; @@ -29,23 +34,34 @@ import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import java.io.IOException; import java.net.ServerSocket; +import java.nio.ByteBuffer; import java.nio.channels.InterruptedByTimeoutException; import java.nio.channels.SocketChannel; +import java.util.Collections; import java.util.concurrent.TimeUnit; +import static com.mongodb.ClusterFixture.getPrimaryServerDescription; import static com.mongodb.internal.connection.OperationContext.simpleOperationContext; import static java.lang.String.format; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; class TlsChannelStreamFunctionalTest { private static final SslSettings SSL_SETTINGS = SslSettings.builder().enabled(true).build(); @@ -98,6 +114,7 @@ void shouldEstablishConnection(final int connectTimeoutMs) throws IOException, I try (StreamFactoryFactory streamFactoryFactory = new TlsChannelStreamFactoryFactory(new DefaultInetAddressResolver()); MockedStatic socketChannelMockedStatic = Mockito.mockStatic(SocketChannel.class); ServerSocket serverSocket = new ServerSocket(0, 1)) { + SingleResultSpyCaptor singleResultSpyCaptor = new SingleResultSpyCaptor<>(); socketChannelMockedStatic.when(SocketChannel::open).thenAnswer(singleResultSpyCaptor); @@ -147,4 +164,35 @@ public T answer(final InvocationOnMock invocationOnMock) throws Throwable { private static OperationContext createOperationContext(final int connectTimeoutMs) { return simpleOperationContext(new TimeoutContext(TimeoutSettings.DEFAULT.withConnectTimeoutMS(connectTimeoutMs))); } + + @Test + @DisplayName("should not call beginHandshake more than once during TLS session establishment") + void shouldNotCallBeginHandshakeMoreThenOnceDuringTlsSessionEstablishment() throws Exception { + assumeTrue(ClusterFixture.getSslSettings().isEnabled()); + + //given + try (StreamFactoryFactory streamFactoryFactory = new TlsChannelStreamFactoryFactory(new DefaultInetAddressResolver())) { + + SSLContext sslContext = Mockito.spy(SSLContext.getDefault()); + SingleResultSpyCaptor singleResultSpyCaptor = new SingleResultSpyCaptor<>(); + when(sslContext.createSSLEngine(anyString(), anyInt())).thenAnswer(singleResultSpyCaptor); + + StreamFactory streamFactory = streamFactoryFactory.create( + SocketSettings.builder().build(), + SslSettings.builder(ClusterFixture.getSslSettings()) + .context(sslContext) + .build()); + + Stream stream = streamFactory.create(getPrimaryServerDescription().getAddress()); + stream.open(ClusterFixture.OPERATION_CONTEXT); + ByteBuf wrap = new ByteBufNIO(ByteBuffer.wrap(new byte[]{1, 3, 4})); + + //when + stream.write(Collections.singletonList(wrap), ClusterFixture.OPERATION_CONTEXT); + + //then + SECONDS.sleep(5); + verify(singleResultSpyCaptor.getResult(), times(1)).beginHandshake(); + } + } } From 347a6e6c5a4b50d773d0982609e1a1739d714553 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Mon, 7 Jul 2025 10:34:28 +0100 Subject: [PATCH 3/3] Added nexus-publish plugin (#1751) This plugin will eventually be used for the migration to the central portal Currently still uses the legacy osshr sonatype location. As the nexus-publish plugin can only be configured in the root project the username and password logic was moved out of conventions/publishing.gradle.kts and into the root buid.gradle.kts. Note: The nexus-publish plugin builds upon the gradle maven-publish plugin so even though the configuration is in the root project, it will only publish projects that use the publishing convention. JAVA-5899 --- .evergreen/publish.sh | 4 +-- README.md | 21 +++++++++----- build.gradle.kts | 29 +++++++++++++++++++ .../kotlin/conventions/publishing.gradle.kts | 25 +++------------- gradle/libs.versions.toml | 2 ++ 5 files changed, 51 insertions(+), 30 deletions(-) diff --git a/.evergreen/publish.sh b/.evergreen/publish.sh index 9a3e9eb405..ee21c7f215 100755 --- a/.evergreen/publish.sh +++ b/.evergreen/publish.sh @@ -18,12 +18,12 @@ export ORG_GRADLE_PROJECT_signingKey="${SIGNING_KEY}" export ORG_GRADLE_PROJECT_signingPassword=${SIGNING_PASSWORD} if [ "$RELEASE" == "true" ]; then - TASK="publishArchives" + TASK="publishArchives closeAndReleaseSonatypeStagingRepository" else TASK="publishSnapshots" fi -SYSTEM_PROPERTIES="-Dorg.gradle.internal.publish.checksums.insecure=true -Dorg.gradle.internal.http.connectionTimeout=120000 -Dorg.gradle.internal.http.socketTimeout=120000" +SYSTEM_PROPERTIES="-Dorg.gradle.internal.publish.checksums.insecure=true" ./gradlew -version ./gradlew ${SYSTEM_PROPERTIES} --stacktrace --info ${TASK} # Scala 2.13 is published as result of this gradle execution. diff --git a/README.md b/README.md index cc0fe3b913..1fbad5f2d7 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ time. ## Binaries Binaries and dependency information for Maven, Gradle, Ivy and others can be found at -[http://search.maven.org](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.mongodb%22%20AND%20a%3A%22mongodb-driver-sync%22). +[https://central.sonatype.com/search](https://central.sonatype.com/search?namespace=org.mongodb&name=mongodb-driver-sync). Example for Maven: @@ -100,12 +100,19 @@ Snapshot builds are also published regulary via Sonatype. Example for Maven: ```xml - - - sonatype-snapshot - https://oss.sonatype.org/content/repositories/snapshots/ - - + + + Central Portal Snapshots + central-portal-snapshots + https://central.sonatype.com/repository/maven-snapshots/ + + false + + + true + + + ``` ## Build diff --git a/build.gradle.kts b/build.gradle.kts index 287017f0ed..3112e2c59b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,8 +13,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import java.time.Duration plugins { id("eclipse") id("idea") + alias(libs.plugins.nexus.publish) +} + +val nexusUsername: Provider = providers.gradleProperty("nexusUsername") +val nexusPassword: Provider = providers.gradleProperty("nexusPassword") + +nexusPublishing { + packageGroup.set("org.mongodb") + repositories { + sonatype { + username.set(nexusUsername) + password.set(nexusPassword) + + // central portal URLs + nexusUrl.set(uri("https://ossrh-staging-api.central.sonatype.com/service/local/")) + snapshotRepositoryUrl.set(uri("https://central.sonatype.com/repository/maven-snapshots/")) + } + } + + connectTimeout.set(Duration.ofMinutes(5)) + clientTimeout.set(Duration.ofMinutes(30)) + + transitionCheckOptions { + // We have many artifacts and Maven Central can take a long time on its compliance checks. + // Set the timeout for waiting for the repository to close to a comfortable 50 minutes. + maxRetries.set(300) + delayBetween.set(Duration.ofSeconds(10)) + } } diff --git a/buildSrc/src/main/kotlin/conventions/publishing.gradle.kts b/buildSrc/src/main/kotlin/conventions/publishing.gradle.kts index 8347959b23..b243ce7df2 100644 --- a/buildSrc/src/main/kotlin/conventions/publishing.gradle.kts +++ b/buildSrc/src/main/kotlin/conventions/publishing.gradle.kts @@ -28,8 +28,6 @@ plugins { val signingKey: Provider = providers.gradleProperty("signingKey") val signingPassword: Provider = providers.gradleProperty("signingPassword") -val nexusUsername: Provider = providers.gradleProperty("nexusUsername") -val nexusPassword: Provider = providers.gradleProperty("nexusPassword") @Suppress("UNCHECKED_CAST") val gitVersion: Provider = project.findProperty("gitVersion") as Provider tasks.withType().configureEach { @@ -45,25 +43,8 @@ tasks.withType().configureEach { val localBuildRepo: Provider = rootProject.layout.buildDirectory.dir("repo") -val sonatypeRepositoryReleaseUrl: Provider = provider { - if (version.toString().endsWith("SNAPSHOT")) { - "https://oss.sonatype.org/content/repositories/snapshots/" - } else { - "https://oss.sonatype.org/service/local/staging/deploy/maven2/" - } -} - publishing { repositories { - maven { - url = uri(sonatypeRepositoryReleaseUrl) - if (nexusUsername.isPresent && nexusPassword.isPresent) { - credentials { - username = nexusUsername.get() - password = nexusPassword.get() - } - } - } // publish to local dir, for artifact tracking and testing // `./gradlew publishMavenPublicationToLocalBuildRepository` @@ -141,7 +122,8 @@ tasks.register("publishSnapshots") { description = "Publishes snapshots to Sonatype" if (version.toString().endsWith("-SNAPSHOT")) { - dependsOn(tasks.withType()) + dependsOn(tasks.named("publishAllPublicationsToLocalBuildRepository")) + dependsOn(tasks.named("publishToSonatype")) } } @@ -168,7 +150,8 @@ tasks.register("publishArchives") { } } if (gitVersionMatch) { - dependsOn(tasks.withType()) + dependsOn(tasks.named("publishAllPublicationsToLocalBuildRepository")) + dependsOn(tasks.named("publishToSonatype")) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index eab637a8b4..7341edcda1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -64,6 +64,7 @@ plugin-dokka = "1.8.10" plugin-download = "5.6.0" plugin-graalvm = "0.9.23" plugin-optional-base = "7.0.0" +plugin-nexus-publish = "2.0.0" plugin-shadow = "8.3.6" plugin-spotbugs = "6.0.15" plugin-spotless = "6.14.0" @@ -207,6 +208,7 @@ download = { id = "de.undercouch.download", version.ref = "plugin-download" } graalvm-buildtools = { id = "org.graalvm.buildtools.native", version.ref = "plugin-graalvm" } kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } +nexus-publish = { id = "io.github.gradle-nexus.publish-plugin", version.ref = "plugin-nexus-publish" } optional = { id = "nebula.optional-base", version.ref = "plugin-optional-base" } shadow = { id = "com.gradleup.shadow", version.ref = "plugin-shadow" } spotbugs = { id = "com.github.spotbugs", version.ref = "plugin-spotbugs" } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy