Index: jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java =================================================================== --- jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java (revision 1902386) +++ jackrabbit-spi2dav/src/main/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImpl.java (working copy) @@ -361,6 +361,8 @@ HttpClientBuilder hcb = HttpClients.custom(); + final SSLConnectionSocketFactory sslSocketFactory; + // request config RequestConfig requestConfig = RequestConfig.custom(). setConnectTimeout(connectionOptions.getConnectionTimeoutMs()). @@ -371,30 +373,44 @@ log.debug("Using system properties for establishing connection!"); // support Java system proxy? (JCR-3211) hcb.useSystemProperties(); - } - - // TLS settings (via connection manager) - final SSLContext sslContext; - try { + + sslSocketFactory = SSLConnectionSocketFactory.getSystemSocketFactory(); + if (connectionOptions.isAllowSelfSignedCertificates()) { - log.warn("Nonsecure TLS setting: Accepting self-signed certificates!"); - sslContext = SSLContextBuilder.create().loadTrustMaterial(new TrustSelfSignedStrategy()).build(); - hcb.setSSLContext(sslContext); + throw new RepositoryException(ConnectionOptions.PARAM_ALLOW_SELF_SIGNED_CERTIFICATES + + " is not allowed when system properties (jackrabbit.client.useSystemProperties) have been specified."); + } + if (connectionOptions.isDisableHostnameVerification()) { + throw new RepositoryException(ConnectionOptions.PARAM_DISABLE_HOSTNAME_VERIFICATION + + " is not allowed when system properties (jackrabbit.client.useSystemProperties) have been specified."); + } + + } else { + + // TLS settings (via connection manager) + final SSLContext sslContext; + try { + if (connectionOptions.isAllowSelfSignedCertificates()) { + log.warn("Nonsecure TLS setting: Accepting self-signed certificates!"); + sslContext = SSLContextBuilder.create().loadTrustMaterial(new TrustSelfSignedStrategy()).build(); + hcb.setSSLContext(sslContext); + } else { + sslContext = SSLContextBuilder.create().build(); + } + } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { + throw new RepositoryException(e); + } + + if (connectionOptions.isDisableHostnameVerification()) { + log.warn("Nonsecure TLS setting: Host name verification of TLS certificates disabled!"); + // we can optionally disable hostname verification. + sslSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); } else { - sslContext = SSLContextBuilder.create().build(); + sslSocketFactory = new SSLConnectionSocketFactory(sslContext); } - } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) { - throw new RepositoryException(e); + } - final SSLConnectionSocketFactory sslSocketFactory; - if (connectionOptions.isDisableHostnameVerification()) { - log.warn("Nonsecure TLS setting: Host name verification of TLS certificates disabled!"); - // we can optionally disable hostname verification. - sslSocketFactory = new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE); - } else { - sslSocketFactory = new SSLConnectionSocketFactory(sslContext); - } - + Registry socketFactoryRegistry = RegistryBuilder.create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactory) Index: jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImplIT.java =================================================================== --- jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImplIT.java (nonexistent) +++ jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImplIT.java (working copy) @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.jackrabbit.spi2dav; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assume.assumeTrue; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; + +import javax.jcr.RepositoryException; +import javax.net.ssl.SSLException; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.BasicResponseHandler; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +public class RepositoryServiceImplIT { + + @Rule + public TemporaryFolder tmpDirectory = new TemporaryFolder(); + + static boolean canConnectTo(String urlSpec) throws MalformedURLException { + URL url = new URL(urlSpec); + try { + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.connect(); + return true; + } catch (IOException e) { + return false; + } + } + + @Test + public void testGetAgainstTrustedCertServer() throws RepositoryException, ClientProtocolException, IOException { + assumeTrue("Cannot connect to http://www.apache.org", canConnectTo("http://www.apache.org")); + RepositoryServiceImpl repositoryServiceImpl = RepositoryServiceImplTest.getRepositoryService("https://jackrabbit.apache.org/jcr", ConnectionOptions.builder().build()); + HttpClient client = repositoryServiceImpl.getClient(null); + HttpGet get = new HttpGet("https://jackrabbit.apache.org/jcr/index.html"); + String content = client.execute(get, new BasicResponseHandler()); + assertFalse(content.isEmpty()); + } + + @Test + public void testGetAgainstTrustedCertServerWithSystemProperties() throws RepositoryException, ClientProtocolException, IOException { + assumeTrue("Cannot connect to http://www.apache.org", canConnectTo("http://www.apache.org")); + // use dedicated trust store + Path keyStorePath = tmpDirectory.getRoot().toPath().resolve("emptyPKCS12.keystore"); + try (InputStream is = this.getClass().getResourceAsStream("emptyPKCS12.keystore")) { + Files.copy(is, keyStorePath); + } + + String oldTrustStore = System.setProperty("javax.net.ssl.trustStore", keyStorePath.toString()); + String oldTrustStorePassword = System.setProperty("javax.net.ssl.trustStorePassword", "storePassword"); + String oldDebug = System.setProperty("javax.net.debug", "ssl"); + try { + // use dedicated trust store + System.setProperty("javax.net.ssl.trustStore", keyStorePath.toString()); + System.setProperty("javax.net.ssl.trustStorePassword", "storePassword"); + System.setProperty("javax.net.debug", "ssl"); + + ConnectionOptions connectionOptions = ConnectionOptions.builder().useSystemProperties(true).build(); + RepositoryServiceImpl repositoryServiceImpl = RepositoryServiceImplTest.getRepositoryService("https://jackrabbit.apache.org/jcr", connectionOptions); + HttpClient client = repositoryServiceImpl.getClient(null); + HttpGet get = new HttpGet("https://jackrabbit.apache.org/jcr/index.html"); + // connection must fail as cert is not trusted due to used trust store being empty + assertThrows(SSLException.class, () -> client.execute(get, new BasicResponseHandler())); + } finally { + setOrClearSystemProperty("javax.net.ssl.trustStore", oldTrustStore); + setOrClearSystemProperty("javax.net.ssl.trustStorePassword", oldTrustStorePassword); + setOrClearSystemProperty("javax.net.debug", oldDebug); + } + } + + private static void setOrClearSystemProperty(String key, String value) { + if (value == null) { + System.clearProperty(key); + } else { + System.setProperty(key, value); + } + } +} Index: jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImplTest.java =================================================================== --- jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImplTest.java (nonexistent) +++ jackrabbit-spi2dav/src/test/java/org/apache/jackrabbit/spi2dav/RepositoryServiceImplTest.java (working copy) @@ -0,0 +1,52 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.jackrabbit.spi2dav; + +import static org.junit.Assert.assertThrows; + +import javax.jcr.RepositoryException; + +import org.apache.jackrabbit.spi.IdFactory; +import org.apache.jackrabbit.spi.NameFactory; +import org.apache.jackrabbit.spi.PathFactory; +import org.apache.jackrabbit.spi.QValueFactory; +import org.apache.jackrabbit.spi.commons.ItemInfoCacheImpl; +import org.apache.jackrabbit.spi.commons.identifier.IdFactoryImpl; +import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl; +import org.apache.jackrabbit.spi.commons.name.PathFactoryImpl; +import org.apache.jackrabbit.spi.commons.value.QValueFactoryImpl; +import org.junit.Test; + +public class RepositoryServiceImplTest { + + @Test + public void testWithSystemPropertiesAndIncompatibleConnectionOptions() throws RepositoryException { + ConnectionOptions connectionOptions = ConnectionOptions.builder().useSystemProperties(true).allowSelfSignedCertificates(true).build(); + assertThrows(RepositoryException.class, ()->getRepositoryService("https://jackrabbit.apache.org/jcr", connectionOptions)); + ConnectionOptions connectionOptions2 = ConnectionOptions.builder().useSystemProperties(true).disableHostnameVerification(true).build(); + assertThrows(RepositoryException.class, ()->getRepositoryService("https://jackrabbit.apache.org/jcr", connectionOptions2)); + } + + static RepositoryServiceImpl getRepositoryService(String uri, ConnectionOptions connectionOptions) throws RepositoryException { + IdFactory idFactory = IdFactoryImpl.getInstance(); + NameFactory nFactory = NameFactoryImpl.getInstance(); + PathFactory pFactory = PathFactoryImpl.getInstance(); + QValueFactory vFactory = QValueFactoryImpl.getInstance(); + return new RepositoryServiceImpl(uri, idFactory, nFactory, pFactory, vFactory, ItemInfoCacheImpl.DEFAULT_CACHE_SIZE, connectionOptions); + } + +} Index: jackrabbit-spi2dav/src/test/resources/org/apache/jackrabbit/spi2dav/emptyPKCS12.keystore =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Property changes on: jackrabbit-spi2dav/src/test/resources/org/apache/jackrabbit/spi2dav/emptyPKCS12.keystore ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property