This is an automated email from the ASF dual-hosted git repository. robertlazarski pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-core.git
commit 52c7ba310fcaca1ff60d596d2b118d34851eb4b7 Author: Robert Lazarski <[email protected]> AuthorDate: Wed Aug 5 07:48:02 2026 -1000 Also gate the response endpoint where the transport is acquired Corrects a claim I had made: CXF does not check at the inbound-parsing layer. Its check sits in DecoupledDestination.getBackChannel -- the method that hands back the conduit for a decoupled response -- so anything reaching for that back channel is screened however the endpoint reference arrived. Checking only in AddressingInHandler was weaker, and the report's proof-of-concept showed it: it builds a MessageContext, calls setReplyTo directly and drives the transport sender, never passing through header parsing, and the server still connected out. MessageContextBuilder.setupCorrectTransportOut is the Axis2 analogue. It runs only for a server-side response to a non-anonymous, non-none destination, and it is where that destination's transport is resolved -- the same depth as CXF's check. The policy therefore moves to the kernel org.apache.axis2.addressing package, beside EndpointReference and AddressingFaultsHelper, so both the handler and the kernel can use it. The handler check stays: it faults early with a proper wsa fault on the path a remote caller actually has. The PoC now fails on both its positive cases. The resolver pool shutdown moves from the addressing module to AxisConfiguration.cleanup(), next to the multipart reaper, since the policy is no longer module-scoped. Co-Authored-By: Claude Fable 5 <[email protected]> --- .../apache/axis2/handlers/addressing/Addressing.java | 1 - .../handlers/addressing/AddressingInHandler.java | 1 + .../addressing/ResponseEndpointPolicyHandlerTest.java | 1 + .../axis2}/addressing/ResponseEndpointPolicy.java | 19 +++++++++---------- .../org/apache/axis2/engine/AxisConfiguration.java | 2 ++ .../org/apache/axis2/util/MessageContextBuilder.java | 15 +++++++++++++++ .../axis2}/addressing/ResponseEndpointPolicyTest.java | 4 +--- 7 files changed, 29 insertions(+), 14 deletions(-) diff --git a/modules/addressing/src/org/apache/axis2/handlers/addressing/Addressing.java b/modules/addressing/src/org/apache/axis2/handlers/addressing/Addressing.java index 63dbbaefbe..047e8e1be6 100644 --- a/modules/addressing/src/org/apache/axis2/handlers/addressing/Addressing.java +++ b/modules/addressing/src/org/apache/axis2/handlers/addressing/Addressing.java @@ -54,7 +54,6 @@ public class Addressing implements Module { } public void shutdown(ConfigurationContext configurationContext) throws AxisFault { - ResponseEndpointPolicy.shutdown(); } } diff --git a/modules/addressing/src/org/apache/axis2/handlers/addressing/AddressingInHandler.java b/modules/addressing/src/org/apache/axis2/handlers/addressing/AddressingInHandler.java index 1c6ffc1547..8b64481476 100644 --- a/modules/addressing/src/org/apache/axis2/handlers/addressing/AddressingInHandler.java +++ b/modules/addressing/src/org/apache/axis2/handlers/addressing/AddressingInHandler.java @@ -32,6 +32,7 @@ import org.apache.axis2.addressing.AddressingFaultsHelper; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.addressing.EndpointReferenceHelper; import org.apache.axis2.addressing.RelatesTo; +import org.apache.axis2.addressing.ResponseEndpointPolicy; import org.apache.axis2.client.Options; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.HandlerDescription; diff --git a/modules/addressing/test/org/apache/axis2/handlers/addressing/ResponseEndpointPolicyHandlerTest.java b/modules/addressing/test/org/apache/axis2/handlers/addressing/ResponseEndpointPolicyHandlerTest.java index 970294cf6b..8a2cbe3810 100644 --- a/modules/addressing/test/org/apache/axis2/handlers/addressing/ResponseEndpointPolicyHandlerTest.java +++ b/modules/addressing/test/org/apache/axis2/handlers/addressing/ResponseEndpointPolicyHandlerTest.java @@ -29,6 +29,7 @@ import org.apache.axis2.addressing.AddressingConstants; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.axis2.context.MessageContext; +import org.apache.axis2.addressing.ResponseEndpointPolicy; import org.apache.axis2.description.Parameter; /** diff --git a/modules/addressing/src/org/apache/axis2/handlers/addressing/ResponseEndpointPolicy.java b/modules/kernel/src/org/apache/axis2/addressing/ResponseEndpointPolicy.java similarity index 96% rename from modules/addressing/src/org/apache/axis2/handlers/addressing/ResponseEndpointPolicy.java rename to modules/kernel/src/org/apache/axis2/addressing/ResponseEndpointPolicy.java index 83fcfa058d..6aab3227a8 100644 --- a/modules/addressing/src/org/apache/axis2/handlers/addressing/ResponseEndpointPolicy.java +++ b/modules/kernel/src/org/apache/axis2/addressing/ResponseEndpointPolicy.java @@ -17,9 +17,8 @@ * under the License. */ -package org.apache.axis2.handlers.addressing; +package org.apache.axis2.addressing; -import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.Parameter; import org.apache.axis2.util.JavaUtils; @@ -85,15 +84,15 @@ import java.util.concurrent.TimeoutException; * appear in it, which supersedes the network-range check.</dd> * </dl> */ -final class ResponseEndpointPolicy { +public final class ResponseEndpointPolicy { private static final Log log = LogFactory.getLog(ResponseEndpointPolicy.class); - static final String ALLOW_NON_ANONYMOUS = "allowNonAnonymousResponseEndpoints"; - static final String BLOCK_PRIVATE_NETWORKS = "blockPrivateNetworkResponseEndpoints"; - static final String ALLOWED_HOSTS = "allowedResponseEndpointHosts"; - static final String ALLOWED_SCHEMES_PARAMETER = "allowedResponseEndpointSchemes"; - static final String RESOLVE_TIMEOUT = "responseEndpointResolveTimeoutMillis"; + public static final String ALLOW_NON_ANONYMOUS = "allowNonAnonymousResponseEndpoints"; + public static final String BLOCK_PRIVATE_NETWORKS = "blockPrivateNetworkResponseEndpoints"; + public static final String ALLOWED_HOSTS = "allowedResponseEndpointHosts"; + public static final String ALLOWED_SCHEMES_PARAMETER = "allowedResponseEndpointSchemes"; + public static final String RESOLVE_TIMEOUT = "responseEndpointResolveTimeoutMillis"; /** Long enough for a healthy resolver, short enough not to pin a thread. */ static final long DEFAULT_RESOLVE_TIMEOUT_MILLIS = 2000L; @@ -136,7 +135,7 @@ final class ResponseEndpointPolicy { * @param messageContext the inbound message, for parameter resolution * @return true if the endpoint may be used as a send destination */ - static boolean isAllowed(EndpointReference epr, MessageContext messageContext) { + public static boolean isAllowed(EndpointReference epr, MessageContext messageContext) { if (epr == null || epr.hasAnonymousAddress() || epr.hasNoneAddress()) { return true; } @@ -359,7 +358,7 @@ final class ResponseEndpointPolicy { * Stop the resolver pool. Called from the addressing module's shutdown so * the threads do not outlive the configuration that created them. */ - static synchronized void shutdown() { + public static synchronized void shutdown() { if (resolver != null) { resolver.shutdownNow(); resolver = null; diff --git a/modules/kernel/src/org/apache/axis2/engine/AxisConfiguration.java b/modules/kernel/src/org/apache/axis2/engine/AxisConfiguration.java index fd2d8e4606..a0dc32ac12 100644 --- a/modules/kernel/src/org/apache/axis2/engine/AxisConfiguration.java +++ b/modules/kernel/src/org/apache/axis2/engine/AxisConfiguration.java @@ -1342,6 +1342,8 @@ public class AxisConfiguration extends AxisDescription { // Stop the multipart temp-file reaper so its thread does not outlive a // redeployment and pin this web application's class loader. MultipartTempFileTracker.shutdown(); + // Same reason: the WS-Addressing endpoint resolver runs a thread pool. + org.apache.axis2.addressing.ResponseEndpointPolicy.shutdown(); this.policySupportedModules.clear(); this.moduleConfigmap.clear(); this.allEndpoints.clear(); diff --git a/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java b/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java index 9bf82f965c..91a3f786f2 100644 --- a/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java +++ b/modules/kernel/src/org/apache/axis2/util/MessageContextBuilder.java @@ -43,6 +43,7 @@ import org.apache.axis2.addressing.AddressingConstants; import org.apache.axis2.addressing.AddressingConstants.Final; import org.apache.axis2.addressing.AddressingHelper; import org.apache.axis2.addressing.EndpointReference; +import org.apache.axis2.addressing.ResponseEndpointPolicy; import org.apache.axis2.addressing.RelatesTo; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.MessageContext; @@ -380,6 +381,20 @@ public class MessageContextBuilder { EndpointReference responseEPR = context.getTo(); if (context.isServerSide() && responseEPR != null) { if (!responseEPR.hasAnonymousAddress() && !responseEPR.hasNoneAddress()) { + // Last gate before a server-side response acquires a transport + // for a caller-nominated destination. AddressingInHandler + // already screens the inbound header, which is the only route + // a remote client has; this catches everything else that turns + // an endpoint reference into an outbound target — a custom + // handler, service code, or a future dispatch path — so the + // check cannot be walked around by reaching the sender another + // way. Apache CXF places its equivalent check at the same + // depth, in DecoupledDestination.getBackChannel. + if (!ResponseEndpointPolicy.isAllowed(responseEPR, context)) { + throw new AxisFault("Refusing to send a response to the " + + "endpoint reference named by this message; see the " + + ResponseEndpointPolicy.ALLOW_NON_ANONYMOUS + " parameter"); + } URI uri = new URI(responseEPR.getAddress()); String scheme = uri.getScheme(); if ((transportOut == null) || !transportOut.getName().equals(scheme)) { diff --git a/modules/addressing/test/org/apache/axis2/handlers/addressing/ResponseEndpointPolicyTest.java b/modules/kernel/test/org/apache/axis2/addressing/ResponseEndpointPolicyTest.java similarity index 98% rename from modules/addressing/test/org/apache/axis2/handlers/addressing/ResponseEndpointPolicyTest.java rename to modules/kernel/test/org/apache/axis2/addressing/ResponseEndpointPolicyTest.java index 478d0acdf8..d672157d5c 100644 --- a/modules/addressing/test/org/apache/axis2/handlers/addressing/ResponseEndpointPolicyTest.java +++ b/modules/kernel/test/org/apache/axis2/addressing/ResponseEndpointPolicyTest.java @@ -17,11 +17,9 @@ * under the License. */ -package org.apache.axis2.handlers.addressing; +package org.apache.axis2.addressing; import junit.framework.TestCase; -import org.apache.axis2.addressing.AddressingConstants; -import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.MessageContext; import org.apache.axis2.description.Parameter;
