Skip to content

Commit 3b51230

Browse files
committed
Fix BZ 66471 - JSessionId secure attribute missing with RemoteIpFilter and X-Forwarded-Proto set to https
https://bz.apache.org/bugzilla/show_bug.cgi?id=66471
1 parent a4ea8cc commit 3b51230

5 files changed

Lines changed: 100 additions & 29 deletions

File tree

‎java/org/apache/catalina/Globals.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ public final class Globals {
111111
public static final String SENDFILE_SUPPORTED_ATTR = org.apache.coyote.Constants.SENDFILE_SUPPORTED_ATTR;
112112

113113

114+
/**
115+
* The request attribute that is set to the value of {@code Boolean.TRUE}
116+
* if {@link org.apache.catalina.filters.RemoteIpFilter} determines
117+
* that this request was submitted via a secure channel.
118+
*/
119+
public static final String REMOTE_IP_FILTER_SECURE = "org.apache.catalina.filters.RemoteIpFilter.secure";
120+
114121
/**
115122
* The request attribute that can be used by a servlet to pass
116123
* to the connector the name of the file that is to be served

‎java/org/apache/catalina/connector/Request.java‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3611,6 +3611,20 @@ public void set(Request request, String name, Object value) {
36113611
// NO-OP
36123612
}
36133613
});
3614+
specialAttributes.put(Globals.REMOTE_IP_FILTER_SECURE,
3615+
new SpecialAttributeAdapter() {
3616+
@Override
3617+
public Object get(Request request, String name) {
3618+
return Boolean.valueOf(request.isSecure());
3619+
}
3620+
3621+
@Override
3622+
public void set(Request request, String name, Object value) {
3623+
if (value instanceof Boolean) {
3624+
request.setSecure(((Boolean) value).booleanValue());
3625+
}
3626+
}
3627+
});
36143628
specialAttributes.put(Globals.STREAM_ID,
36153629
new SpecialAttributeAdapter() {
36163630
@Override

‎java/org/apache/catalina/filters/RemoteIpFilter.java‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -585,11 +585,6 @@ public int getServerPort() {
585585
return serverPort;
586586
}
587587

588-
@Override
589-
public boolean isSecure() {
590-
return secure;
591-
}
592-
593588
public void removeHeader(String name) {
594589
Map.Entry<String, List<String>> header = getHeaderEntry(name);
595590
if (header != null) {
@@ -629,7 +624,7 @@ public void setScheme(String scheme) {
629624
}
630625

631626
public void setSecure(boolean secure) {
632-
this.secure = secure;
627+
super.getRequest().setAttribute(Globals.REMOTE_IP_FILTER_SECURE, Boolean.valueOf(secure));
633628
}
634629

635630
public void setServerName(String serverName) {

‎test/org/apache/catalina/filters/TestRemoteIpFilter.java‎

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,21 @@ public static class MockHttpServlet extends HttpServlet {
8282

8383
private static final long serialVersionUID = 1L;
8484

85-
private transient HttpServletRequest request;
86-
87-
public HttpServletRequest getRequest() {
88-
return request;
89-
}
85+
public String remoteAddr;
86+
public String remoteHost;
87+
public String scheme;
88+
public String serverName;
89+
public int serverPort;
90+
public boolean isSecure;
9091

9192
@Override
9293
public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
93-
this.request = request;
94+
this.isSecure = request.isSecure();
95+
this.remoteAddr = request.getRemoteAddr();
96+
this.remoteHost = request.getRemoteHost();
97+
this.scheme = request.getScheme();
98+
this.serverName = request.getServerName();
99+
this.serverPort = request.getServerPort();
94100
PrintWriter writer = response.getWriter();
95101

96102
writer.println("request.remoteAddr=" + request.getRemoteAddr());
@@ -129,16 +135,6 @@ public void setScheme(String scheme) {
129135
getCoyoteRequest().scheme().setString(scheme);
130136
}
131137

132-
@Override
133-
public void setAttribute(String name, Object value) {
134-
getCoyoteRequest().getAttributes().put(name, value);
135-
}
136-
137-
@Override
138-
public Object getAttribute(String name) {
139-
return getCoyoteRequest().getAttributes().get(name);
140-
}
141-
142138
@Override
143139
public String getServerName() {
144140
return "localhost";
@@ -770,16 +766,70 @@ public void testWithTomcatServer() throws Exception {
770766

771767
// VALIDATE
772768
Assert.assertEquals(HttpURLConnection.HTTP_OK, httpURLConnection.getResponseCode());
773-
HttpServletRequest request = mockServlet.getRequest();
774-
Assert.assertNotNull(request);
775769

776770
// VALIDATE X-FORWARDED-FOR
777-
Assert.assertEquals(expectedRemoteAddr, request.getRemoteAddr());
778-
Assert.assertEquals(expectedRemoteAddr, request.getRemoteHost());
771+
Assert.assertEquals(expectedRemoteAddr, mockServlet.remoteAddr);
772+
Assert.assertEquals(expectedRemoteAddr, mockServlet.remoteHost);
779773

780774
// VALIDATE X-FORWARDED-PROTO
781-
Assert.assertTrue(request.isSecure());
782-
Assert.assertEquals("https", request.getScheme());
783-
Assert.assertEquals(443, request.getServerPort());
775+
Assert.assertTrue(mockServlet.isSecure);
776+
Assert.assertEquals("https", mockServlet.scheme);
777+
Assert.assertEquals(443, mockServlet.serverPort);
778+
}
779+
780+
@Test
781+
public void testJSessionIdSecureAttributeMissing() throws Exception {
782+
783+
// mostly default configuration : enable "x-forwarded-proto"
784+
Map<String, String> remoteIpFilterParameter = new HashMap<>();
785+
remoteIpFilterParameter.put("protocolHeader", "x-forwarded-proto");
786+
787+
// SETUP
788+
Tomcat tomcat = getTomcatInstance();
789+
Context root = tomcat.addContext("", TEMP_DIR);
790+
791+
FilterDef filterDef = new FilterDef();
792+
filterDef.getParameterMap().putAll(remoteIpFilterParameter);
793+
filterDef.setFilterClass(RemoteIpFilter.class.getName());
794+
filterDef.setFilterName(RemoteIpFilter.class.getName());
795+
796+
root.addFilterDef(filterDef);
797+
798+
FilterMap filterMap = new FilterMap();
799+
filterMap.setFilterName(RemoteIpFilter.class.getName());
800+
filterMap.addURLPatternDecoded("*");
801+
root.addFilterMap(filterMap);
802+
803+
Bug66471Servlet bug66471Servlet = new Bug66471Servlet();
804+
805+
Tomcat.addServlet(root, bug66471Servlet.getClass().getName(), bug66471Servlet);
806+
root.addServletMappingDecoded("/test", bug66471Servlet.getClass().getName());
807+
808+
getTomcatInstance().start();
809+
810+
Map<String, List<String>> resHeaders = new HashMap<>();
811+
Map<String, List<String>> reqHeaders = new HashMap<>();
812+
String expectedRemoteAddr = "my-remote-addr";
813+
List<String> forwardedFor = new ArrayList<>(1);
814+
forwardedFor.add(expectedRemoteAddr);
815+
List<String> forwardedProto = new ArrayList<>(1);
816+
forwardedProto.add("https");
817+
reqHeaders.put("x-forwarded-for", forwardedFor);
818+
reqHeaders.put("x-forwarded-proto", forwardedProto);
819+
820+
getUrl("http://localhost:" + tomcat.getConnector().getLocalPort() +
821+
"/test", null, reqHeaders, resHeaders);
822+
String setCookie = resHeaders.get("Set-Cookie").get(0);
823+
Assert.assertTrue(setCookie.contains("Secure"));
824+
Assert.assertTrue(bug66471Servlet.isSecure.booleanValue());
825+
}
826+
public static class Bug66471Servlet extends HttpServlet {
827+
private static final long serialVersionUID = 1L;
828+
public Boolean isSecure;
829+
@Override
830+
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
831+
req.getSession();
832+
isSecure = (Boolean) req.getAttribute(Globals.REMOTE_IP_FILTER_SECURE);
833+
}
784834
}
785835
}

‎webapps/docs/changelog.xml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,11 @@
121121
external web server. Based on code and ideas from pull request
122122
<pr>506</pr> provided by Max Fortun. (remm)
123123
</add>
124+
<fix>
125+
<bug>66471</bug>: Fix JSessionId secure attribute missing When
126+
<code>RemoteIpFilter</code> determines that this request was submitted
127+
via a secure channel. (lihan)
128+
</fix>
124129
</changelog>
125130
</subsection>
126131
<subsection name="Coyote">

0 commit comments

Comments
 (0)