diff --git a/modules/webapp/src/main/webapp/axis2-web/HappyAxis.jsp b/modules/webapp/src/main/webapp/axis2-web/HappyAxis.jsp
index 786bd9a460..72398eda67 100644
--- a/modules/webapp/src/main/webapp/axis2-web/HappyAxis.jsp
+++ b/modules/webapp/src/main/webapp/axis2-web/HappyAxis.jsp
@@ -46,7 +46,6 @@
-<%IP = request.getRequestURL().toString();%>
<%!
/*
* Happiness tests for axis2. These look at the classpath and warn if things
@@ -54,8 +53,6 @@
* but here we want to validate JSP compilation too, and have a drop-in
* page for easy re-use
*/
- String IP;
-
/**
* Get a string providing install information.
* TODO: make this platform aware and give specific hints
@@ -325,20 +322,24 @@
return method;
}
- public boolean invokeTheService() {
+ public boolean invokeTheService(HttpServletRequest request) {
try {
// since this one is an internal request we do not use public frontendHostUrl
- // for it
- int lastindex = IP.lastIndexOf('/');
- IP = IP.substring(0, lastindex);
- ///axis2/axis2-web/services/version
- IP = IP.replaceAll("axis2-web", "");
+ // for it. The address is that of the connector this request arrived on, not
+ // request.getRequestURL(): that is built from the client's Host header, which
+ // would let an anonymous caller choose the host and port the server connects to.
+ String host = request.getLocalAddr();
+ if (host.indexOf(':') >= 0) {
+ host = "[" + host + "]";
+ }
+ String address = request.getScheme() + "://" + host + ":" + request.getLocalPort()
+ + request.getContextPath() + "/";
OMElement payload = createEnvelope();
ConfigurationContext configctx =
ConfigurationContextFactory.createConfigurationContextFromFileSystem(null, null);
ServiceClient client = new ServiceClient(configctx, null);
- EndpointReference targetEPR = new EndpointReference(IP + configctx.getServicePath() + "/Version");
+ EndpointReference targetEPR = new EndpointReference(address + configctx.getServicePath() + "/Version");
Options options = new Options();
client.setOptions(options);
options.setTo(targetEPR);
@@ -438,7 +439,7 @@
Examining Version Service
<%
- boolean serviceStatus = invokeTheService();
+ boolean serviceStatus = invokeTheService(request);
if (serviceStatus) {
%>
diff --git a/systests/webapp-tests/src/test/java/org/apache/axis2/webapp/HappyAxisHostHeaderITCase.java b/systests/webapp-tests/src/test/java/org/apache/axis2/webapp/HappyAxisHostHeaderITCase.java
new file mode 100644
index 0000000000..a6b846d899
--- /dev/null
+++ b/systests/webapp-tests/src/test/java/org/apache/axis2/webapp/HappyAxisHostHeaderITCase.java
@@ -0,0 +1,90 @@
+/*
+ * 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.axis2.webapp;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.sun.net.httpserver.HttpServer;
+
+/**
+ * HappyAxis.jsp probes the Version service with a request the server sends to itself.
+ * The address of that request used to come from the client's Host header, so an
+ * anonymous caller could make the server connect to a host and port of their choosing.
+ */
+public class HappyAxisHostHeaderITCase {
+ private final List received = new CopyOnWriteArrayList<>();
+ private HttpServer listener;
+
+ @Before
+ public void startListener() throws Exception {
+ listener = HttpServer.create(new InetSocketAddress("127.0.0.1", 0), 0);
+ listener.createContext("/", exchange -> {
+ received.add(exchange.getRequestMethod() + " " + exchange.getRequestURI());
+ exchange.sendResponseHeaders(404, -1);
+ exchange.close();
+ });
+ listener.start();
+ }
+
+ @After
+ public void stopListener() {
+ listener.stop(0);
+ }
+
+ @Test
+ public void testHostHeaderDoesNotChooseProbeTarget() throws Exception {
+ int port = Integer.getInteger("jetty.httpPort", 8080);
+ String hostileHost = "127.0.0.1:" + listener.getAddress().getPort();
+ String response;
+ try (Socket socket = new Socket("localhost", port)) {
+ socket.setSoTimeout(120000);
+ OutputStream out = socket.getOutputStream();
+ out.write(("GET /axis2/axis2-web/HappyAxis.jsp HTTP/1.0\r\n"
+ + "Host: " + hostileHost + "\r\n\r\n").getBytes(StandardCharsets.ISO_8859_1));
+ out.flush();
+ InputStream in = socket.getInputStream();
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ byte[] chunk = new byte[8192];
+ int n;
+ while ((n = in.read(chunk)) != -1) {
+ buffer.write(chunk, 0, n);
+ }
+ response = buffer.toString("UTF-8");
+ }
+ String statusLine = response.substring(0, Math.max(response.indexOf("\r\n"), 0));
+ assertThat(statusLine).contains(" 200 ");
+ // The probe must never go to the host the request named...
+ assertThat(received).isEmpty();
+ // ...and must still reach the Version service on this server.
+ assertThat(response).contains("Found Axis2 default Version service");
+ }
+}