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

rzo1 pushed a commit to branch tomee-10.x
in repository https://gitbox.apache.org/repos/asf/tomee.git

commit 5323aefd02d917e7ac0b0c048b18441912a7f59d
Author: Richard Zowalla <[email protected]>
AuthorDate: Tue Oct 13 08:48:56 2026 +0200

    Warn when tomee-maven-plugin sends credentials over plain HTTP (#3078)
    
    Deploy and other command goals default to http; make the cleartext
    credential exposure visible when targeting a remote host.
    
    (cherry picked from commit 5f1dbebd64149dc1f784651a0955573d07f68541)
---
 .../openejb/maven/plugin/AbstractCommandMojo.java  | 27 +++++-
 .../maven/plugin/AbstractCommandMojoTest.java      | 97 ++++++++++++++++++++++
 2 files changed, 121 insertions(+), 3 deletions(-)

diff --git 
a/maven/tomee-maven-plugin/src/main/java/org/apache/openejb/maven/plugin/AbstractCommandMojo.java
 
b/maven/tomee-maven-plugin/src/main/java/org/apache/openejb/maven/plugin/AbstractCommandMojo.java
index 13f06002ee..281b14f0e8 100644
--- 
a/maven/tomee-maven-plugin/src/main/java/org/apache/openejb/maven/plugin/AbstractCommandMojo.java
+++ 
b/maven/tomee-maven-plugin/src/main/java/org/apache/openejb/maven/plugin/AbstractCommandMojo.java
@@ -21,6 +21,7 @@ import org.apache.maven.plugins.annotations.Parameter;
 
 import javax.naming.Context;
 import javax.naming.InitialContext;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 
@@ -35,7 +36,9 @@ public abstract class AbstractCommandMojo extends 
AbstractAddressMojo {
     protected String ejbdEndpoint;
 
     /**
-     * Flag to force https usage.
+     * Flag to force https usage. Without it, the command is sent over plain 
http
+     * unless only an https port is configured; a warning is logged when 
credentials
+     * would then be sent in clear text to a host other than the loopback one.
      */
     @Parameter(property = "tomee-plugin.command-force-https", defaultValue = 
"false")
     protected boolean forceHttps;
@@ -65,7 +68,9 @@ public abstract class AbstractCommandMojo extends 
AbstractAddressMojo {
 
         final Properties props = new Properties();
         props.put(Context.INITIAL_CONTEXT_FACTORY, 
"org.apache.openejb.client.RemoteInitialContextFactory");
-        props.put(Context.PROVIDER_URL, providerUrl());
+        final String providerUrl = providerUrl();
+        props.put(Context.PROVIDER_URL, providerUrl);
+        warnIfCleartextCredentials(providerUrl);
         if (user != null) {
             props.put(Context.SECURITY_PRINCIPAL, user);
         }
@@ -87,7 +92,23 @@ public abstract class AbstractCommandMojo extends 
AbstractAddressMojo {
         }
     }
 
-    private String providerUrl() {
+    void warnIfCleartextCredentials(final String providerUrl) {
+        if ((user != null || password != null) && 
providerUrl.startsWith("http://";) && !isLoopback(tomeeHost)) {
+            getLog().warn("Sending credentials over plain http to '" + 
tomeeHost + "', they can be intercepted. "
+                    + "Configure an https port (tomee-plugin.https) and set 
tomee-plugin.command-force-https=true.");
+        }
+    }
+
+    private static boolean isLoopback(final String host) {
+        if (host == null) {
+            return true;
+        }
+        final String h = host.toLowerCase(Locale.ENGLISH);
+        return "localhost".equals(h) || h.endsWith(".localhost") || 
h.startsWith("127.")
+                || "::1".equals(h) || "[::1]".equals(h) || 
"0:0:0:0:0:0:0:1".equals(h);
+    }
+
+    String providerUrl() {
         if (forceHttps || (tomeeHttpPort == null && tomeeHttpsPort != null)) {
             return "https://"; + tomeeHost + ":" + tomeeHttpsPort + 
ejbdEndpoint;
         }
diff --git 
a/maven/tomee-maven-plugin/src/test/java/org/apache/openejb/maven/plugin/AbstractCommandMojoTest.java
 
b/maven/tomee-maven-plugin/src/test/java/org/apache/openejb/maven/plugin/AbstractCommandMojoTest.java
new file mode 100644
index 0000000000..f37342a20f
--- /dev/null
+++ 
b/maven/tomee-maven-plugin/src/test/java/org/apache/openejb/maven/plugin/AbstractCommandMojoTest.java
@@ -0,0 +1,97 @@
+/*
+ * 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.openejb.maven.plugin;
+
+import org.apache.maven.plugin.logging.SystemStreamLog;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class AbstractCommandMojoTest {
+    @Test
+    public void warnsForCredentialsOverHttpToRemoteHost() {
+        final List<String> warnings = new ArrayList<>();
+        final AbstractCommandMojo mojo = mojo("staging.example.com", "8080", 
null, warnings);
+        mojo.user = "admin";
+        mojo.password = "secret";
+
+        final String url = mojo.providerUrl();
+        assertEquals("http://staging.example.com:8080/tomee/ejb";, url);
+        mojo.warnIfCleartextCredentials(url);
+        assertEquals(1, warnings.size());
+        assertTrue(warnings.get(0).contains("staging.example.com"));
+    }
+
+    @Test
+    public void noWarningForLoopbackHost() {
+        for (final String host : new String[]{"localhost", "127.0.0.1", 
"::1"}) {
+            final List<String> warnings = new ArrayList<>();
+            final AbstractCommandMojo mojo = mojo(host, "8080", null, 
warnings);
+            mojo.user = "admin";
+            mojo.password = "secret";
+            mojo.warnIfCleartextCredentials(mojo.providerUrl());
+            assertTrue(host, warnings.isEmpty());
+        }
+    }
+
+    @Test
+    public void noWarningWithoutCredentials() {
+        final List<String> warnings = new ArrayList<>();
+        final AbstractCommandMojo mojo = mojo("staging.example.com", "8080", 
null, warnings);
+        mojo.warnIfCleartextCredentials(mojo.providerUrl());
+        assertTrue(warnings.isEmpty());
+    }
+
+    @Test
+    public void noWarningOverHttps() {
+        final List<String> warnings = new ArrayList<>();
+        final AbstractCommandMojo mojo = mojo("staging.example.com", "8080", 
"8443", warnings);
+        mojo.forceHttps = true;
+        mojo.user = "admin";
+        mojo.password = "secret";
+
+        final String url = mojo.providerUrl();
+        assertEquals("https://staging.example.com:8443/tomee/ejb";, url);
+        mojo.warnIfCleartextCredentials(url);
+        assertTrue(warnings.isEmpty());
+    }
+
+    private static AbstractCommandMojo mojo(final String host, final String 
httpPort, final String httpsPort,
+                                            final List<String> warnings) {
+        final AbstractCommandMojo mojo = new AbstractCommandMojo() {
+            @Override
+            public void execute() {
+                // no-op
+            }
+        };
+        mojo.tomeeHost = host;
+        mojo.tomeeHttpPort = httpPort;
+        mojo.tomeeHttpsPort = httpsPort;
+        mojo.ejbdEndpoint = "/tomee/ejb";
+        mojo.setLog(new SystemStreamLog() {
+            @Override
+            public void warn(final CharSequence content) {
+                warnings.add(content.toString());
+            }
+        });
+        return mojo;
+    }
+}

Reply via email to