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");
