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 7dfbcd40faac45abe9823c4261f424b6f39a4974
Author: Markus Jung <[email protected]>
AuthorDate: Sun Aug 23 21:32:37 2026 +0200

    keep client failover and redirect locations on the configured transport 
scheme
    
    (cherry picked from commit 2e4ed54f3a6cce80cc4ae82dfdf62e2752b021a3)
---
 .../java/org/apache/openejb/client/Client.java     | 24 +++++--
 .../org/apache/openejb/client/JNDIContext.java     |  8 ++-
 .../org/apache/openejb/client/ServerMetaData.java  |  6 +-
 .../openejb/client/TransportSecurityPolicy.java    | 81 ++++++++++++++++++++++
 .../client/TransportSecurityPolicyTest.java        | 81 ++++++++++++++++++++++
 5 files changed, 192 insertions(+), 8 deletions(-)

diff --git 
a/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java 
b/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java
index 8d19769722..2e19618e3d 100644
--- a/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java
+++ b/server/openejb-client/src/main/java/org/apache/openejb/client/Client.java
@@ -506,18 +506,30 @@ public class Client {
                 throw new IllegalArgumentException("clusterMetaData cannot be 
null");
             }
 
+            ClusterMetaData accepted = updated;
+            final URI[] filtered = 
TransportSecurityPolicy.filter(serverMetaData.getLocation(), 
updated.getLocations());
+            if (filtered != updated.getLocations()) {
+                if (filtered.length == 0) {
+                    logger.log(Level.WARNING, "Ignoring cluster update: no 
pushed location preserves the transport security of "
+                        + serverMetaData.getLocation() + ". Set -D" + 
TransportSecurityPolicy.ALLOW_DOWNGRADE + "=true to allow it.");
+                    return;
+                }
+                accepted = new ClusterMetaData(updated.getVersion(), filtered);
+                
accepted.setConnectionStrategy(updated.getConnectionStrategy());
+            }
+
             final ClusterMetaData previous = this.clusterMetaData;
-            this.clusterMetaData = updated;
+            this.clusterMetaData = accepted;
 
-            if (updated.getConnectionStrategy() == null) {
-                
updated.setConnectionStrategy(previous.getConnectionStrategy());
+            if (accepted.getConnectionStrategy() == null) {
+                
accepted.setConnectionStrategy(previous.getConnectionStrategy());
             }
-            updated.setLastLocation(previous.getLastLocation());
-            final ClusterMetaDataUpdated clusterMetaDataUpdated = new 
ClusterMetaDataUpdated(serverMetaData, updated, previous);
+            accepted.setLastLocation(previous.getLastLocation());
+            final ClusterMetaDataUpdated clusterMetaDataUpdated = new 
ClusterMetaDataUpdated(serverMetaData, accepted, previous);
 
             fireEvent(clusterMetaDataUpdated);
 
-            final Set<URI> found = locations(updated);
+            final Set<URI> found = locations(accepted);
             final Set<URI> existing = locations(previous);
 
             for (final URI uri : diff(existing, found)) {
diff --git 
a/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
 
b/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
index 4159ae773a..51fe24fbcb 100644
--- 
a/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
+++ 
b/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java
@@ -386,7 +386,13 @@ public class JNDIContext implements InitialContextFactory, 
Context {
                 break;
             case ResponseCodes.AUTH_REDIRECT:
                 client = res.getIdentity();
-                server = res.getServer();
+                final ServerMetaData redirect = res.getServer();
+                if (redirect != null && 
!TransportSecurityPolicy.accepts(server.getLocation(), redirect.getLocation())) 
{
+                    throw new AuthenticationException("Refusing authentication 
redirect to " + redirect.getLocation()
+                        + ": it would downgrade the transport security of " + 
server.getLocation()
+                        + ". Set -D" + TransportSecurityPolicy.ALLOW_DOWNGRADE 
+ "=true to allow it.");
+                }
+                server = redirect;
                 break;
             case ResponseCodes.AUTH_DENIED:
                 throw (AuthenticationException) new 
AuthenticationException("This principle is not 
authorized.").initCause(res.getDeniedCause());
diff --git 
a/server/openejb-client/src/main/java/org/apache/openejb/client/ServerMetaData.java
 
b/server/openejb-client/src/main/java/org/apache/openejb/client/ServerMetaData.java
index bb9e36d3af..69d993d458 100644
--- 
a/server/openejb-client/src/main/java/org/apache/openejb/client/ServerMetaData.java
+++ 
b/server/openejb-client/src/main/java/org/apache/openejb/client/ServerMetaData.java
@@ -43,7 +43,11 @@ public class ServerMetaData implements Externalizable {
     }
 
     public void merge(final ServerMetaData toMerge) {
-        locations = toMerge.locations;
+        final URI[] filtered = TransportSecurityPolicy.filter(location, 
toMerge.locations);
+        if (filtered != null && filtered.length == 0) {
+            return;
+        }
+        locations = filtered;
     }
 
     public URI getLocation() {
diff --git 
a/server/openejb-client/src/main/java/org/apache/openejb/client/TransportSecurityPolicy.java
 
b/server/openejb-client/src/main/java/org/apache/openejb/client/TransportSecurityPolicy.java
new file mode 100644
index 0000000000..f9daa6187c
--- /dev/null
+++ 
b/server/openejb-client/src/main/java/org/apache/openejb/client/TransportSecurityPolicy.java
@@ -0,0 +1,81 @@
+/**
+ * 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.client;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Keeps server-pushed locations (cluster updates, failover lists,
+ * authentication redirects) on a transport at least as protected as the one
+ * the client was configured with: a client using a TLS scheme
+ * (ejbds/zejbds/https) only follows pushed locations with an equally
+ * protected scheme unless {@link #ALLOW_DOWNGRADE} is set.
+ */
+final class TransportSecurityPolicy {
+
+    public static final String ALLOW_DOWNGRADE = 
"openejb.client.allowTransportDowngrade";
+
+    private static final Logger LOGGER = Logger.getLogger("OpenEJB.client");
+
+    private TransportSecurityPolicy() {
+        // utility class
+    }
+
+    static boolean isSecure(final URI uri) {
+        if (uri == null) {
+            return false;
+        }
+        final String scheme = uri.getScheme();
+        return "ejbds".equalsIgnoreCase(scheme) || 
"zejbds".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme);
+    }
+
+    static boolean accepts(final URI baseline, final URI pushed) {
+        return !isSecure(baseline) || isSecure(pushed) || allowDowngrade();
+    }
+
+    /**
+     * @return the pushed array untouched when no filtering applies, else a new
+     * array retaining only the locations at least as protected as the baseline
+     */
+    static URI[] filter(final URI baseline, final URI[] pushed) {
+        if (pushed == null || !isSecure(baseline) || allowDowngrade()) {
+            return pushed;
+        }
+        final List<URI> accepted = new ArrayList<>(pushed.length);
+        for (final URI uri : pushed) {
+            if (isSecure(uri)) {
+                accepted.add(uri);
+            } else {
+                LOGGER.log(Level.WARNING, "Ignoring server-pushed location " + 
uri
+                    + ": it would downgrade the transport security of " + 
baseline
+                    + ". Set -D" + ALLOW_DOWNGRADE + "=true to allow it.");
+            }
+        }
+        if (accepted.size() == pushed.length) {
+            return pushed;
+        }
+        return accepted.toArray(new URI[0]);
+    }
+
+    private static boolean allowDowngrade() {
+        return Boolean.getBoolean(ALLOW_DOWNGRADE);
+    }
+}
diff --git 
a/server/openejb-client/src/test/java/org/apache/openejb/client/TransportSecurityPolicyTest.java
 
b/server/openejb-client/src/test/java/org/apache/openejb/client/TransportSecurityPolicyTest.java
new file mode 100644
index 0000000000..790299bae3
--- /dev/null
+++ 
b/server/openejb-client/src/test/java/org/apache/openejb/client/TransportSecurityPolicyTest.java
@@ -0,0 +1,81 @@
+/**
+ * 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.client;
+
+import org.junit.Test;
+
+import java.net.URI;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+public class TransportSecurityPolicyTest {
+
+    @Test
+    public void plaintextLocationsAreDroppedForSecureBaseline() {
+        final URI baseline = URI.create("ejbds://app1:4203");
+        final URI[] pushed = {
+            URI.create("ejbd://app2:4201"),
+            URI.create("ejbds://app3:4203"),
+            URI.create("http://app4:80/ejb";),
+        };
+        final URI[] filtered = TransportSecurityPolicy.filter(baseline, 
pushed);
+        assertArrayEquals(new URI[]{URI.create("ejbds://app3:4203")}, 
filtered);
+    }
+
+    @Test
+    public void plaintextBaselineIsNotFiltered() {
+        final URI baseline = URI.create("ejbd://app1:4201");
+        final URI[] pushed = {URI.create("ejbd://app2:4201"), 
URI.create("ejbds://app3:4203")};
+        assertSame(pushed, TransportSecurityPolicy.filter(baseline, pushed));
+    }
+
+    @Test
+    public void accepts() {
+        
assertTrue(TransportSecurityPolicy.accepts(URI.create("ejbds://a:4203"), 
URI.create("https://b:8443";)));
+        
assertTrue(TransportSecurityPolicy.accepts(URI.create("ejbd://a:4201"), 
URI.create("ejbd://b:4201")));
+        
assertFalse(TransportSecurityPolicy.accepts(URI.create("ejbds://a:4203"), 
URI.create("ejbd://b:4201")));
+        
assertFalse(TransportSecurityPolicy.accepts(URI.create("zejbds://a:4203"), 
URI.create("zejbd://b:4201")));
+    }
+
+    @Test
+    public void clusterUpdateKeepsTransportOfSecureBaseline() {
+        final ServerMetaData server = new 
ServerMetaData(URI.create("ejbds://transport-test-1:4203"));
+        final Client.Context context = Client.getContext(server);
+
+        context.setClusterMetaData(new ClusterMetaData(2, 
URI.create("ejbd://member1:4201")));
+        assertArrayEquals(new 
URI[]{URI.create("ejbds://transport-test-1:4203")},
+            context.getClusterMetaData().getLocations());
+
+        context.setClusterMetaData(new ClusterMetaData(3,
+            URI.create("ejbd://member1:4201"), 
URI.create("ejbds://member2:4203")));
+        assertArrayEquals(new URI[]{URI.create("ejbds://member2:4203")},
+            context.getClusterMetaData().getLocations());
+    }
+
+    @Test
+    public void mergeKeepsTransportOfSecureBaseline() {
+        final ServerMetaData server = new 
ServerMetaData(URI.create("ejbds://transport-test-2:4203"));
+        server.merge(new ServerMetaData(URI.create("ejbd://member1:4201")));
+        assertArrayEquals(new 
URI[]{URI.create("ejbds://transport-test-2:4203")}, server.getLocations());
+
+        server.merge(new ServerMetaData(URI.create("ejbds://member2:4203"), 
URI.create("ejbd://member1:4201")));
+        assertArrayEquals(new URI[]{URI.create("ejbds://member2:4203")}, 
server.getLocations());
+    }
+}

Reply via email to