diff --git a/pom.xml b/pom.xml
index 16d9bdc0e..f6d726285 100644
--- a/pom.xml
+++ b/pom.xml
@@ -79,6 +79,17 @@
io.jenkins.plugins
apache-httpcomponents-client-5-api
+
+ io.github.hakky54
+ sslcontext-kickstart-for-apache5
+ 9.1.1-SNAPSHOT
+
+
+ org.slf4j
+ slf4j-api
+
+
+
io.jenkins.plugins
commons-lang3-api
diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/credentials/BitbucketClientCertificateAuthenticator.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/credentials/BitbucketClientCertificateAuthenticator.java
index c02c90adb..ce2d710fa 100644
--- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/credentials/BitbucketClientCertificateAuthenticator.java
+++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/impl/credentials/BitbucketClientCertificateAuthenticator.java
@@ -25,25 +25,23 @@
package com.cloudbees.jenkins.plugins.bitbucket.impl.credentials;
import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketAuthenticator;
-import com.cloudbees.jenkins.plugins.bitbucket.api.BitbucketException;
-import com.cloudbees.jenkins.plugins.bitbucket.impl.client.BitbucketTlsSocketStrategy;
import com.cloudbees.plugins.credentials.common.StandardCertificateCredentials;
import hudson.util.Secret;
-import java.security.KeyManagementException;
import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import javax.net.ssl.SSLContext;
-import org.apache.hc.client5.http.protocol.HttpClientContext;
+import java.util.logging.Logger;
+import nl.altindag.ssl.SSLFactory;
+import nl.altindag.ssl.util.KeyManagerUtils;
+import nl.altindag.ssl.util.KeyStoreUtils;
import org.apache.hc.core5.http.HttpHost;
-import org.apache.hc.core5.ssl.SSLContextBuilder;
-import org.apache.hc.core5.ssl.SSLContexts;
+import org.kohsuke.accmod.Restricted;
+import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Authenticates against Bitbucket using a TLS client certificate
*/
public class BitbucketClientCertificateAuthenticator implements BitbucketAuthenticator {
+ private static final Logger logger = Logger.getLogger(BitbucketClientCertificateAuthenticator.class.getName());
+
private final String credentialsId;
private final KeyStore keyStore;
private final Secret password;
@@ -55,23 +53,22 @@ public BitbucketClientCertificateAuthenticator(StandardCertificateCredentials cr
}
/**
- * Sets the SSLContext for the builder to one that will connect with the selected certificate.
- * @param context The client builder context
+ * Sets the SSLContext for the builder to one that will connect with the
+ * selected certificate.
+ *
+ * @param sslFactory The client SSL context configured in the connection
+ * pool
* @param host the target host name
*/
- @Override
- public void configureContext(HttpClientContext context, HttpHost host) {
- try {
- context.setAttribute(BitbucketTlsSocketStrategy.SOCKET_FACTORY_REGISTRY, buildSSLContext()); // override SSL registry for this context
- } catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException | KeyManagementException e) {
- throw new BitbucketException("Failed to set up SSL context from provided client certificate", e);
- }
- }
-
- private SSLContext buildSSLContext() throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, KeyManagementException {
- SSLContextBuilder contextBuilder = SSLContexts.custom();
- contextBuilder.loadKeyMaterial(keyStore, Secret.toString(password).toCharArray());
- return contextBuilder.build();
+ @Restricted(NoExternalUse.class)
+ public void configureContext(SSLFactory sslFactory, HttpHost host) {
+ sslFactory.getKeyManager().ifPresent(baseKeyManager -> {
+ for (String alias : KeyStoreUtils.getAliases(keyStore)) {
+ KeyManagerUtils.addIdentityMaterial(baseKeyManager, keyStore, Secret.toString(password).toCharArray());
+ KeyManagerUtils.addIdentityRoute(baseKeyManager, alias, host.toString());
+ logger.info(() -> "Add new identity material (keyStore) " + alias + " to the SSLContext.");
+ }
+ });
}
@Override
diff --git a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java
index ff0e93971..7b702e21a 100644
--- a/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java
+++ b/src/main/java/com/cloudbees/jenkins/plugins/bitbucket/server/client/BitbucketServerAPIClient.java
@@ -39,7 +39,6 @@
import com.cloudbees.jenkins.plugins.bitbucket.client.repository.UserRoleInRepository;
import com.cloudbees.jenkins.plugins.bitbucket.filesystem.BitbucketSCMFile;
import com.cloudbees.jenkins.plugins.bitbucket.impl.client.AbstractBitbucketApi;
-import com.cloudbees.jenkins.plugins.bitbucket.impl.client.BitbucketTlsSocketStrategy;
import com.cloudbees.jenkins.plugins.bitbucket.impl.credentials.BitbucketAccessTokenAuthenticator;
import com.cloudbees.jenkins.plugins.bitbucket.impl.credentials.BitbucketClientCertificateAuthenticator;
import com.cloudbees.jenkins.plugins.bitbucket.impl.credentials.BitbucketUsernamePasswordAuthenticator;
@@ -75,6 +74,7 @@
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -88,11 +88,15 @@
import jenkins.scm.api.SCMFile;
import jenkins.scm.api.SCMFile.Type;
import jenkins.scm.impl.avatars.AvatarImage;
+import nl.altindag.ssl.SSLFactory;
+import nl.altindag.ssl.SSLFactory.Builder;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
+import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
+import org.apache.hc.client5.http.ssl.DefaultClientTlsStrategy;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.message.BasicNameValuePair;
@@ -140,10 +144,24 @@ public class BitbucketServerAPIClient extends AbstractBitbucketApi implements Bi
private static final String API_MIRRORS_PATH = "/rest/mirroring/1.0/mirrorServers";
private static final Integer DEFAULT_PAGE_LIMIT = 200;
+ private static Builder sslFactoryBuilder() {
+ Builder builder = SSLFactory.builder()
+ .withSystemTrustMaterial()
+ .withDefaultTrustMaterial()
+ .withTrustMaterial(Paths.get("D:\\Download\\JENKINS-75676\\jenkins\\trustStore.jks"), "JENKINS-75676".toCharArray())
+ .withDummyIdentityMaterial()
+ .withInflatableIdentityMaterial();
+ if (System.getProperty("javax.net.ssl.trustStore") != null) {
+ builder.withSystemPropertyDerivedTrustMaterial();
+ }
+ return builder;
+ }
+
+ private static final SSLFactory sslFactory = sslFactoryBuilder().build();
private static final HttpClientConnectionManager connectionManager = connectionManagerBuilder()
- .setMaxConnPerRoute(20)
- .setMaxConnTotal(40 /* should be 20 * number of server instances */)
- .setTlsSocketStrategy(new BitbucketTlsSocketStrategy())
+ .setMaxConnPerRoute(1) // FIXME restore to 20
+ .setMaxConnTotal(1 /* should be 20 * number of server instances */) // FIXME restore to 40
+ .setTlsSocketStrategy(new DefaultClientTlsStrategy(sslFactory.getSslContext()))
.build();
/**
@@ -162,6 +180,7 @@ public class BitbucketServerAPIClient extends AbstractBitbucketApi implements Bi
private final BitbucketServerWebhookImplementation webhookImplementation;
private final CloseableHttpClient client;
+
public BitbucketServerAPIClient(@NonNull String baseURL, @NonNull String owner, @CheckForNull String repositoryName,
@CheckForNull BitbucketAuthenticator authenticator, boolean userCentric) {
this(baseURL, owner, repositoryName, authenticator, userCentric, BitbucketServerEndpoint.findWebhookImplementation(baseURL));
@@ -182,6 +201,14 @@ public BitbucketServerAPIClient(@NonNull String baseURL, @NonNull String owner,
this.client = setupClientBuilder().build();
}
+ @Override
+ protected HttpClientBuilder setupClientBuilder() {
+ if (getAuthenticator() instanceof BitbucketClientCertificateAuthenticator certificateAuthenticator) {
+ certificateAuthenticator.configureContext(sslFactory, getHost());
+ }
+ return super.setupClientBuilder();
+ }
+
@Override
protected boolean isSupportedAuthenticator(@CheckForNull BitbucketAuthenticator authenticator) {
return authenticator == null