This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git


The following commit(s) were added to refs/heads/master by this push:
     new 5e8d5137 [MRESOLVER-328] SSL insecure mode (#255)
5e8d5137 is described below

commit 5e8d51371d7e0dd4188278fd85875cb5f68da8e1
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Thu Mar 2 10:14:32 2023 +0100

    [MRESOLVER-328] SSL insecure mode (#255)
    
    The transport-http now has "insecure" HTTPS mode that simply ignores any 
kind of SSL validation error (trust, certificate dates, hostnames). This mode 
is NOT MEANT for production, as it is inherently insecure but may come handy in 
small shops using self signed certificates. As mode value is string, we can 
later improve by adding flags, like ignore-hostname-validation, 
ignore-cert-dates etc.
    
    ---
    
    https://issues.apache.org/jira/browse/MRESOLVER-328
---
 .../eclipse/aether/ConfigurationProperties.java    |  24 ++++++++++++
 .../eclipse/aether/transport/http/GlobalState.java |  41 +++++++++++++++++----
 .../aether/transport/http/HttpTransporter.java     |   7 +++-
 .../eclipse/aether/transport/http/SslConfig.java   |   5 ++-
 .../eclipse/aether/transport/http/HttpServer.java  |  24 +++++++++---
 .../aether/transport/http/HttpTransporterTest.java |  31 ++++++++++++++++
 .../src/test/resources/ssl/server-store-selfsigned | Bin 0 -> 2750 bytes
 src/site/markdown/configuration.md                 |   1 +
 8 files changed, 119 insertions(+), 14 deletions(-)

diff --git 
a/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java
 
b/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java
index 5c9095ba..0cfa9f4e 100644
--- 
a/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java
+++ 
b/maven-resolver-api/src/main/java/org/eclipse/aether/ConfigurationProperties.java
@@ -159,6 +159,30 @@ public final class ConfigurationProperties {
      */
     public static final boolean DEFAULT_HTTP_PREEMPTIVE_AUTH = false;
 
+    /**
+     * The mode that sets HTTPS transport "security mode": to ignore any SSL 
errors (certificate validity checks,
+     * hostname verification). The default value is {@link 
#HTTPS_SECURITY_MODE_DEFAULT}.
+     *
+     * @see #HTTPS_SECURITY_MODE_DEFAULT
+     * @see #HTTPS_SECURITY_MODE_INSECURE
+     * @since 1.9.6
+     */
+    public static final String HTTPS_SECURITY_MODE = PREFIX_CONNECTOR + 
"https.securityMode";
+
+    /**
+     * The default HTTPS security mode.
+     *
+     * @since 1.9.6
+     */
+    public static final String HTTPS_SECURITY_MODE_DEFAULT = "default";
+
+    /**
+     * The insecure HTTPS security mode (certificate validation, hostname 
verification are all ignored).
+     *
+     * @since 1.9.6
+     */
+    public static final String HTTPS_SECURITY_MODE_INSECURE = "insecure";
+
     /**
      * A flag indicating whether checksums which are retrieved during checksum 
validation should be persisted in the
      * local filesystem next to the file they provide the checksum for.
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
index 4d925aa6..1f6d7789 100644
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
+++ 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/GlobalState.java
@@ -33,8 +33,12 @@ import org.apache.http.config.RegistryBuilder;
 import org.apache.http.conn.HttpClientConnectionManager;
 import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.SSLInitializationException;
+import org.eclipse.aether.ConfigurationProperties;
 import org.eclipse.aether.RepositoryCache;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.util.ConfigUtils;
@@ -154,19 +158,42 @@ final class GlobalState implements Closeable {
         if (sslConfig == null) {
             registryBuilder.register("https", 
SSLConnectionSocketFactory.getSystemSocketFactory());
         } else {
-            SSLSocketFactory sslSocketFactory = (sslConfig.context != null)
-                    ? sslConfig.context.getSocketFactory()
-                    : (SSLSocketFactory) SSLSocketFactory.getDefault();
-
-            HostnameVerifier hostnameVerifier = (sslConfig.verifier != null)
-                    ? sslConfig.verifier
-                    : SSLConnectionSocketFactory.getDefaultHostnameVerifier();
+            // config present: use provided, if any, or create (depending on 
httpsSecurityMode)
+            SSLSocketFactory sslSocketFactory = sslConfig.context != null ? 
sslConfig.context.getSocketFactory() : null;
+            HostnameVerifier hostnameVerifier = sslConfig.verifier;
+            if 
(ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT.equals(sslConfig.httpsSecurityMode))
 {
+                if (sslSocketFactory == null) {
+                    sslSocketFactory = (SSLSocketFactory) 
SSLSocketFactory.getDefault();
+                }
+                if (hostnameVerifier == null) {
+                    hostnameVerifier = 
SSLConnectionSocketFactory.getDefaultHostnameVerifier();
+                }
+            } else if 
(ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(sslConfig.httpsSecurityMode))
 {
+                if (sslSocketFactory == null) {
+                    try {
+                        sslSocketFactory = new SSLContextBuilder()
+                                .loadTrustMaterial(null, (chain, auth) -> true)
+                                .build()
+                                .getSocketFactory();
+                    } catch (Exception e) {
+                        throw new SSLInitializationException(
+                                "Could not configure '" + 
sslConfig.httpsSecurityMode + "' HTTPS security mode", e);
+                    }
+                }
+                if (hostnameVerifier == null) {
+                    hostnameVerifier = NoopHostnameVerifier.INSTANCE;
+                }
+            } else {
+                throw new IllegalArgumentException(
+                        "Unsupported '" + sslConfig.httpsSecurityMode + "' 
HTTPS security mode.");
+            }
 
             registryBuilder.register(
                     "https",
                     new SSLConnectionSocketFactory(
                             sslSocketFactory, sslConfig.protocols, 
sslConfig.cipherSuites, hostnameVerifier));
         }
+
         PoolingHttpClientConnectionManager connMgr = new 
PoolingHttpClientConnectionManager(registryBuilder.build());
         connMgr.setMaxTotal(100);
         connMgr.setDefaultMaxPerRoute(50);
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
index 59bbfc07..3e370d18 100644
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
+++ 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/HttpTransporter.java
@@ -146,7 +146,12 @@ final class HttpTransporter extends AbstractTransporter {
         this.repoAuthContext = AuthenticationContext.forRepository(session, 
repository);
         this.proxyAuthContext = AuthenticationContext.forProxy(session, 
repository);
 
-        this.state = new LocalState(session, repository, new 
SslConfig(session, repoAuthContext));
+        String httpsSecurityMode = ConfigUtils.getString(
+                session,
+                ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT,
+                ConfigurationProperties.HTTPS_SECURITY_MODE + "." + 
repository.getId(),
+                ConfigurationProperties.HTTPS_SECURITY_MODE);
+        this.state = new LocalState(session, repository, new 
SslConfig(session, repoAuthContext, httpsSecurityMode));
 
         this.headers = ConfigUtils.getMap(
                 session,
diff --git 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java
 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java
index b08e393c..33f04617 100644
--- 
a/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java
+++ 
b/maven-resolver-transport-http/src/main/java/org/eclipse/aether/transport/http/SslConfig.java
@@ -45,7 +45,9 @@ final class SslConfig {
 
     final String[] protocols;
 
-    SslConfig(RepositorySystemSession session, AuthenticationContext 
authContext) {
+    final String httpsSecurityMode;
+
+    SslConfig(RepositorySystemSession session, AuthenticationContext 
authContext, String httpsSecurityMode) {
         context = (authContext != null) ? 
authContext.get(AuthenticationContext.SSL_CONTEXT, SSLContext.class) : null;
         verifier = (authContext != null)
                 ? authContext.get(AuthenticationContext.SSL_HOSTNAME_VERIFIER, 
HostnameVerifier.class)
@@ -53,6 +55,7 @@ final class SslConfig {
 
         cipherSuites = split(get(session, CIPHER_SUITES));
         protocols = split(get(session, PROTOCOLS));
+        this.httpsSecurityMode = httpsSecurityMode;
     }
 
     private static String get(RepositorySystemSession session, String key) {
diff --git 
a/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java
 
b/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java
index 3834096f..0c46e31f 100644
--- 
a/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java
+++ 
b/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpServer.java
@@ -136,13 +136,27 @@ public class HttpServer {
     }
 
     public HttpServer addSslConnector() {
+        return addSslConnector(true);
+    }
+
+    public HttpServer addSelfSignedSslConnector() {
+        return addSslConnector(false);
+    }
+
+    private HttpServer addSslConnector(boolean needClientAuth) {
         if (httpsConnector == null) {
             SslContextFactory.Server ssl = new SslContextFactory.Server();
-            ssl.setNeedClientAuth(true);
-            ssl.setKeyStorePath(new 
File("src/test/resources/ssl/server-store").getAbsolutePath());
-            ssl.setKeyStorePassword("server-pwd");
-            ssl.setTrustStorePath(new 
File("src/test/resources/ssl/client-store").getAbsolutePath());
-            ssl.setTrustStorePassword("client-pwd");
+            if (needClientAuth) {
+                ssl.setNeedClientAuth(true);
+                ssl.setKeyStorePath(new 
File("src/test/resources/ssl/server-store").getAbsolutePath());
+                ssl.setKeyStorePassword("server-pwd");
+                ssl.setTrustStorePath(new 
File("src/test/resources/ssl/client-store").getAbsolutePath());
+                ssl.setTrustStorePassword("client-pwd");
+            } else {
+                ssl.setNeedClientAuth(false);
+                ssl.setKeyStorePath(new 
File("src/test/resources/ssl/server-store-selfsigned").getAbsolutePath());
+                ssl.setKeyStorePassword("server-pwd");
+            }
             httpsConnector = new ServerConnector(server, ssl);
             server.addConnector(httpsConnector);
             try {
diff --git 
a/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java
 
b/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java
index db00dc66..752640a7 100644
--- 
a/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java
+++ 
b/maven-resolver-transport-http/src/test/java/org/eclipse/aether/transport/http/HttpTransporterTest.java
@@ -395,6 +395,37 @@ public class HttpTransporterTest {
         assertEquals(task.getDataString(), new 
String(listener.baos.toByteArray(), StandardCharsets.UTF_8));
     }
 
+    @Test
+    public void testGet_HTTPS_Unknown_SecurityMode() throws Exception {
+        session.setConfigProperty("aether.connector.https.securityMode", 
"unknown");
+        httpServer.addSelfSignedSslConnector();
+        try {
+            newTransporter(httpServer.getHttpsUrl());
+            fail("Unsupported security mode");
+        } catch (IllegalArgumentException a) {
+            // good
+        }
+    }
+
+    @Test
+    public void testGet_HTTPS_Insecure_SecurityMode() throws Exception {
+        // here we use alternate server-store-selfigned key (as the key set it 
static initalizer is probably already
+        // used to init SSLContext/SSLSocketFactory/etc
+        session.setConfigProperty(
+                "aether.connector.https.securityMode", 
ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE);
+        httpServer.addSelfSignedSslConnector();
+        newTransporter(httpServer.getHttpsUrl());
+        RecordingTransportListener listener = new RecordingTransportListener();
+        GetTask task = new 
GetTask(URI.create("repo/file.txt")).setListener(listener);
+        transporter.get(task);
+        assertEquals("test", task.getDataString());
+        assertEquals(0L, listener.dataOffset);
+        assertEquals(4L, listener.dataLength);
+        assertEquals(1, listener.startedCount);
+        assertTrue("Count: " + listener.progressedCount, 
listener.progressedCount > 0);
+        assertEquals(task.getDataString(), new 
String(listener.baos.toByteArray(), StandardCharsets.UTF_8));
+    }
+
     @Test
     public void testGet_WebDav() throws Exception {
         httpServer.setWebDav(true);
diff --git 
a/maven-resolver-transport-http/src/test/resources/ssl/server-store-selfsigned 
b/maven-resolver-transport-http/src/test/resources/ssl/server-store-selfsigned
new file mode 100644
index 00000000..caf6e52b
Binary files /dev/null and 
b/maven-resolver-transport-http/src/test/resources/ssl/server-store-selfsigned 
differ
diff --git a/src/site/markdown/configuration.md 
b/src/site/markdown/configuration.md
index 649cc3c9..615b7121 100644
--- a/src/site/markdown/configuration.md
+++ b/src/site/markdown/configuration.md
@@ -40,6 +40,7 @@ Option | Type | Description | Default Value | Supports Repo 
ID Suffix
 `aether.connector.http.preemptiveAuth` | boolean | Should HTTP client use 
preemptive-authentication (works only w/ BASIC) or not. | `false` | yes
 `aether.connector.http.retryHandler.count` | int | The maximum number of times 
a request to a remote HTTP server should be retried in case of an error. | `3` 
| yes
 `aether.connector.https.cipherSuites` | String | Comma-separated list of 
[Cipher 
Suites](https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#ciphersuites)
 which are enabled for HTTPS connections. | - (no restriction) | no
+`aether.connector.https.securityMode` | String | Using this flag resolver may 
set the "security mode" of HTTPS connector. Any other mode than 'default' is 
NOT MEANT for production, as it is inherently not secure. Accepted values: 
"default", "insecure" (ignore any kind of certificate validation errors and 
hostname validation checks). | `"default"` | yes
 `aether.connector.https.protocols` | String | Comma-separated list of 
[Protocols](https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#jssenames)
 which are enabled for HTTPS connections. | - (no restriction) | no
 `aether.connector.perms.fileMode` | String | [Octal numerical notation of 
permissions](https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation)
 to set for newly created files. Only considered by certain Wagon providers. | 
- | no
 `aether.connector.perms.dirMode` | String | [Octal numerical notation of 
permissions](https://en.wikipedia.org/wiki/File_system_permissions#Numeric_notation)
 to set for newly created directories. Only considered by certain Wagon 
providers. | - | no

Reply via email to