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 186322a85f538a25f3534e8d5cdae1905af059ab
Author: Richard Zowalla <[email protected]>
AuthorDate: Tue Oct 13 08:48:26 2026 +0200

    Make only_from authoritative for server services (#3075)
    
    only_from is now authoritative; the legacy behavior can be restored
    with openejb.server.only_from.implicit-local=true.
    
    (cherry picked from commit 6099c1a04d420ea3f960412732657ada5f025708)
---
 docs/startup.adoc                                  | 10 +--
 .../openejb/server/ServiceAccessController.java    | 22 +++++--
 .../META-INF/org.apache.openejb.cli/start.examples |  8 ++-
 .../server/ServiceAccessControllerTest.java        | 73 ++++++++++++++++++++++
 4 files changed, 100 insertions(+), 13 deletions(-)

diff --git a/docs/startup.adoc b/docs/startup.adoc
index c2545acde7..ddc5764499 100644
--- a/docs/startup.adoc
+++ b/docs/startup.adoc
@@ -197,10 +197,12 @@ java.naming.security.principal = myuser 
java.naming.security.credentials
 
 _openejb start -Dadmin.only_from=192.168.1.12_
 
-Adds 192.168.1.12 to the list of IP addresses that are authorized to
-shut down the server or access the server via a telnet client. The host
-that this server was started on is always allowed to administer the
-server.
+Sets 192.168.1.12 as the only IP address that is authorized to shut
+down the server or access the server via a telnet client. Only the
+listed hosts are allowed, so add localhost to the list to keep local
+access. Setting `-Dopenejb.server.only_from.implicit-local=true`
+restores the legacy behavior where the host this server was started on
+is always allowed.
 
 Multiple hosts can be given administrative access to this server by
 listing all the host names separated by commas as such:
diff --git 
a/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java
 
b/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java
index cd7d0df637..3a13016ae3 100644
--- 
a/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java
+++ 
b/server/openejb-server/src/main/java/org/apache/openejb/server/ServiceAccessController.java
@@ -22,6 +22,7 @@ import 
org.apache.openejb.server.auth.ExactIPAddressPermission;
 import org.apache.openejb.server.auth.ExactIPv6AddressPermission;
 import org.apache.openejb.server.auth.IPAddressPermission;
 import org.apache.openejb.server.auth.IPAddressPermissionFactory;
+import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.server.auth.PermitAllPermission;
 
 import java.io.IOException;
@@ -40,10 +41,19 @@ import java.util.StringTokenizer;
 @Managed
 public class ServiceAccessController extends ServerServiceFilter implements 
Unwrappable {
 
+    /**
+     * When true, restores the legacy behavior where localhost and clients
+     * connecting from the server's own address are always admitted, even
+     * if they are not listed in only_from.
+     */
+    public static final String IMPLICIT_LOCAL_ACCESS = 
"openejb.server.only_from.implicit-local";
+
     private final Event rejections = new Event();
 
     private IPAddressPermission[] hostPermissions;
 
+    private boolean implicitLocalAccess;
+
     public ServiceAccessController(final ServerService next) {
         super(next);
     }
@@ -62,10 +72,8 @@ public class ServiceAccessController extends 
ServerServiceFilter implements Unwr
     }
 
     public void checkHostsAuthorization(final InetAddress clientAddress, final 
InetAddress serverAddress) throws SecurityException {
-        // Check the client ip against the server ip. Hosts are
-        // allowed to access themselves, so if these ips
-        // match, the following for loop will be skipped.
-        if (clientAddress.equals(serverAddress)) {
+        // legacy mode only: hosts are allowed to access themselves
+        if (implicitLocalAccess && clientAddress.equals(serverAddress)) {
             return;
         }
 
@@ -87,8 +95,9 @@ public class ServiceAccessController extends 
ServerServiceFilter implements Unwr
         if (ipString == null) {
             permissions.add(new PermitAllPermission());
         } else {
-            final String hostname = "localhost";
-            addIPAddressPermissions(permissions, hostname);
+            if (implicitLocalAccess) {
+                addIPAddressPermissions(permissions, "localhost");
+            }
 
             final StringTokenizer st = new StringTokenizer(ipString, ", \n\t");
             while (st.hasMoreTokens()) {
@@ -124,6 +133,7 @@ public class ServiceAccessController extends 
ServerServiceFilter implements Unwr
 
     @Override
     public void init(final Properties props) throws Exception {
+        implicitLocalAccess = 
SystemInstance.get().getOptions().get(IMPLICIT_LOCAL_ACCESS, false);
         parseAdminIPs(props);
         super.init(props);
     }
diff --git 
a/server/openejb-server/src/main/resources/META-INF/org.apache.openejb.cli/start.examples
 
b/server/openejb-server/src/main/resources/META-INF/org.apache.openejb.cli/start.examples
index 540c19466d..b7b0559413 100644
--- 
a/server/openejb-server/src/main/resources/META-INF/org.apache.openejb.cli/start.examples
+++ 
b/server/openejb-server/src/main/resources/META-INF/org.apache.openejb.cli/start.examples
@@ -95,10 +95,12 @@ Example: -D<service>.only_from=<addresses>
 
  openejb start -Dadmin.only_from=192.168.1.12
 
- Adds 192.168.1.12 to the list of IP addresses that are
+ Sets 192.168.1.12 as the only IP address that is
  authorized to shutdown the server or access the server
- via a telnet client.  The host that this server was
- started on is always allowed to administer the server.
+ via a telnet client.  Only the listed hosts are allowed,
+ add localhost to the list to keep local access.  Setting
+ -Dopenejb.server.only_from.implicit-local=true restores
+ the legacy behavior of always admitting the local host.
 
  Multiple hosts can be given administrative access to
  this server by listing all the host names separated
diff --git 
a/server/openejb-server/src/test/java/org/apache/openejb/server/ServiceAccessControllerTest.java
 
b/server/openejb-server/src/test/java/org/apache/openejb/server/ServiceAccessControllerTest.java
index 934afcc9fb..ef039f9637 100644
--- 
a/server/openejb-server/src/test/java/org/apache/openejb/server/ServiceAccessControllerTest.java
+++ 
b/server/openejb-server/src/test/java/org/apache/openejb/server/ServiceAccessControllerTest.java
@@ -17,6 +17,7 @@
 package org.apache.openejb.server;
 
 import junit.framework.TestCase;
+import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.server.auth.IPAddressPermission;
 import org.apache.openejb.server.auth.IPAddressPermissionFactory;
 
@@ -29,6 +30,78 @@ import java.util.Properties;
 
 public class ServiceAccessControllerTest extends TestCase {
 
+    private static final byte[] LOOPBACK = {127, 0, 0, 1};
+    private static final byte[] SERVER = {10, 0, 0, 5};
+    private static final byte[] LISTED = {121, 122, 123, 124};
+
+    @Override
+    protected void tearDown() throws Exception {
+        SystemInstance.reset();
+        super.tearDown();
+    }
+
+    public void testOnlyFromDoesNotAdmitUnlistedLocalhost() throws Exception {
+        final ServiceAccessController controller = 
newController("121.122.123.124");
+
+        assertRejected(controller, LOOPBACK, LOOPBACK);
+        assertRejected(controller, LOOPBACK, SERVER);
+    }
+
+    public void testOnlyFromDoesNotAdmitUnlistedSelfAddress() throws Exception 
{
+        final ServiceAccessController controller = 
newController("121.122.123.124");
+
+        assertRejected(controller, SERVER, SERVER);
+    }
+
+    public void testOnlyFromAdmitsListedHost() throws Exception {
+        final ServiceAccessController controller = 
newController("121.122.123.124");
+
+        controller.checkHostsAuthorization(InetAddress.getByAddress(LISTED), 
InetAddress.getByAddress(SERVER));
+    }
+
+    public void testOnlyFromLocalhostAdmitsLoopback() throws Exception {
+        final ServiceAccessController controller = newController("localhost");
+
+        for (final InetAddress local : InetAddress.getAllByName("localhost")) {
+            controller.checkHostsAuthorization(local, local);
+        }
+        assertRejected(controller, LISTED, LOOPBACK);
+    }
+
+    public void testNoOnlyFromPermitsAll() throws Exception {
+        final ServiceAccessController controller = newController(null);
+
+        controller.checkHostsAuthorization(InetAddress.getByAddress(new 
byte[]{(byte) 198, 51, 100, 7}), InetAddress.getByAddress(SERVER));
+    }
+
+    public void testImplicitLocalAccessRestoresLegacyBehavior() throws 
Exception {
+        
SystemInstance.get().setProperty(ServiceAccessController.IMPLICIT_LOCAL_ACCESS, 
"true");
+        final ServiceAccessController controller = 
newController("121.122.123.124");
+
+        controller.checkHostsAuthorization(InetAddress.getByAddress(LOOPBACK), 
InetAddress.getByAddress(SERVER));
+        controller.checkHostsAuthorization(InetAddress.getByAddress(SERVER), 
InetAddress.getByAddress(SERVER));
+        assertRejected(controller, new byte[]{121, 122, 123, 125}, SERVER);
+    }
+
+    private static ServiceAccessController newController(final String 
onlyFrom) throws Exception {
+        final ServiceAccessController controller = new 
ServiceAccessController(new MockServerService());
+        final Properties properties = new Properties();
+        if (onlyFrom != null) {
+            properties.put("only_from", onlyFrom);
+        }
+        controller.init(properties);
+        return controller;
+    }
+
+    private static void assertRejected(final ServiceAccessController 
controller, final byte[] client, final byte[] server) throws Exception {
+        try {
+            
controller.checkHostsAuthorization(InetAddress.getByAddress(client), 
InetAddress.getByAddress(server));
+            fail("client should have been rejected");
+        } catch (final SecurityException expected) {
+            // ok
+        }
+    }
+
     public void testWrongExactIPAddressPermission1() throws Exception {
         try {
             IPAddressPermissionFactory.getIPAddressMask("121.122.123.a");

Reply via email to