Issue #10323 Fix ee10 Request.isRequestedSessionIdValid (#10331)

* Issue #10323 Fix ee10 Request.isRequestedSessionIdValid
This commit is contained in:
Jan Bartel 2023-08-18 03:19:53 +02:00 committed by GitHub
parent 5160ad29ef
commit fe1831008a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 258 additions and 14 deletions

View File

@ -412,7 +412,7 @@ public class ServletApiRequest implements HttpServletRequest
public boolean isRequestedSessionIdValid()
{
AbstractSessionManager.RequestedSession requestedSession = getServletRequestInfo().getRequestedSession();
return requestedSession != null && requestedSession.sessionId() != null && !requestedSession.sessionIdFromCookie();
return requestedSession != null && requestedSession.sessionId() != null && requestedSession.session() != null;
}
@Override

View File

@ -16,6 +16,8 @@ package org.eclipse.jetty.ee10.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Files;
@ -23,6 +25,7 @@ import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@ -57,6 +60,7 @@ import org.eclipse.jetty.session.SessionDataStoreFactory;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.URIUtil;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -359,6 +363,162 @@ public class SessionHandlerTest
}
}
@Test
public void testRequestedSessionIdFromCookie() throws Exception
{
String contextPath = "/";
String servletMapping = "/server";
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
server.addConnector(connector);
DefaultSessionIdManager sessionIdManager = new DefaultSessionIdManager(server);
server.addBean(sessionIdManager, true);
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
server.addBean(cacheFactory);
SessionDataStoreFactory storeFactory = new NullSessionDataStoreFactory();
server.addBean(storeFactory);
HouseKeeper housekeeper = new HouseKeeper();
housekeeper.setIntervalSec(-1); //turn off scavenging
sessionIdManager.setSessionHouseKeeper(housekeeper);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath(contextPath);
server.setHandler(context);
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setSessionIdManager(sessionIdManager);
sessionHandler.setMaxInactiveInterval(-1); //immortal session
context.setSessionHandler(sessionHandler);
TestRequestedSessionIdServlet servlet = new TestRequestedSessionIdServlet();
ServletHolder holder = new ServletHolder(servlet);
context.addServlet(holder, servletMapping);
server.start();
int port = connector.getLocalPort();
try (StacklessLogging stackless = new StacklessLogging(SessionHandlerTest.class.getPackage()))
{
HttpClient client = new HttpClient();
client.start();
//test with no session cookie
String path = contextPath + (contextPath.endsWith("/") && servletMapping.startsWith("/") ? servletMapping.substring(1) : servletMapping);
String url = "http://localhost:" + port + path;
ContentResponse response = client.GET(url);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertThat(response.getContentAsString(), containsString("valid=false"));
//test with a cookie for non-existant session
URI uri = URIUtil.toURI(URIUtil.newURI("http", "localhost", port, path, ""));
HttpCookie cookie = HttpCookie.build(SessionHandler.__DefaultSessionCookie, "123456789").path("/").domain("localhost").build();
client.getHttpCookieStore().add(uri, cookie);
response = client.GET(url);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
String content = response.getContentAsString();
assertThat(content, containsString("requestedId=123456789"));
assertThat(content, containsString("valid=false"));
//Get rid of fake cookie
client.getHttpCookieStore().clear();
//Make a real session
response = client.GET(url + "?action=create");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertNotNull(response.getHeaders().get("Set-Cookie"));
//Check the requestedSessionId is valid
response = client.GET(url);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
content = response.getContentAsString();
assertThat(content, containsString("valid=true"));
}
finally
{
server.stop();
}
}
@Test
public void testRequestedSessionIdFromURL() throws Exception
{
String contextPath = "/";
String servletMapping = "/server";
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
server.addConnector(connector);
DefaultSessionIdManager sessionIdManager = new DefaultSessionIdManager(server);
server.addBean(sessionIdManager, true);
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
cacheFactory.setEvictionPolicy(SessionCache.NEVER_EVICT);
server.addBean(cacheFactory);
SessionDataStoreFactory storeFactory = new NullSessionDataStoreFactory();
server.addBean(storeFactory);
HouseKeeper housekeeper = new HouseKeeper();
housekeeper.setIntervalSec(-1); //turn off scavenging
sessionIdManager.setSessionHouseKeeper(housekeeper);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath(contextPath);
server.setHandler(context);
SessionHandler sessionHandler = new SessionHandler();
sessionHandler.setUsingCookies(false);
sessionHandler.setSessionIdManager(sessionIdManager);
sessionHandler.setMaxInactiveInterval(-1); //immortal session
context.setSessionHandler(sessionHandler);
TestRequestedSessionIdServlet servlet = new TestRequestedSessionIdServlet();
ServletHolder holder = new ServletHolder(servlet);
context.addServlet(holder, servletMapping);
server.start();
int port = connector.getLocalPort();
try (StacklessLogging stackless = new StacklessLogging(SessionHandlerTest.class.getPackage()))
{
HttpClient client = new HttpClient();
client.start();
//test with no session cookie
String path = contextPath + (contextPath.endsWith("/") && servletMapping.startsWith("/") ? servletMapping.substring(1) : servletMapping);
String url = "http://localhost:" + port + path;
ContentResponse response = client.GET(url);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
assertThat(response.getContentAsString(), containsString("valid=false"));
//test with id for non-existent session
response = client.GET(url + ";" + SessionHandler.__DefaultSessionIdPathParameterName + "=" + "123456789");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
String content = response.getContentAsString();
assertThat(content, containsString("requestedId=123456789"));
assertThat(content, containsString("valid=false"));
//Make a real session
response = client.GET(url + "?action=create");
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
content = response.getContentAsString();
assertThat(content, containsString("createdId="));
String sessionId = content.substring(content.indexOf("createdId=") + 10);
sessionId = sessionId.trim();
//Check the requestedSessionId is valid
response = client.GET(url + ";" + SessionHandler.__DefaultSessionIdPathParameterName + "=" + sessionId);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
content = response.getContentAsString();
assertThat(content, containsString("valid=true"));
}
finally
{
server.stop();
}
}
public static class TestServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
@ -386,6 +546,26 @@ public class SessionHandlerTest
}
}
public static class TestRequestedSessionIdServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
public String _id = null;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
PrintWriter writer = response.getWriter();
writer.println("requestedId=" + request.getRequestedSessionId());
writer.println("valid=" + request.isRequestedSessionIdValid());
if ("create".equals(request.getParameter("action")))
{
HttpSession session = request.getSession(true);
writer.println("createdId=" + session.getId());
}
}
}
public class MockSessionCache extends AbstractSessionCache
{
@ -395,8 +575,9 @@ public class SessionHandlerTest
}
@Override
public void shutdown()
public ManagedSession doDelete(String key)
{
return null;
}
@Override
@ -411,12 +592,6 @@ public class SessionHandlerTest
return null;
}
@Override
public ManagedSession doDelete(String key)
{
return null;
}
@Override
public boolean doReplace(String id, ManagedSession oldValue, ManagedSession newValue)
{
@ -429,6 +604,11 @@ public class SessionHandlerTest
return null;
}
@Override
public void shutdown()
{
}
@Override
protected ManagedSession doComputeIfAbsent(String id, Function<String, ManagedSession> mappingFunction)
{

View File

@ -50,7 +50,6 @@ import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
@ -87,6 +86,7 @@ public class SessionHandlerTest
String pathInContext = request.getPathInfo();
String[] split = pathInContext.substring(1).split("/");
String requestedSessionId = request.getRequestedSessionId();
HttpSession session = request.getSession(false);
if (split.length > 0)
@ -135,6 +135,10 @@ public class SessionHandlerTest
}
StringBuilder out = new StringBuilder();
out.append("requestedSessionId=" + requestedSessionId).append('\n');
out.append("requestedSessionIdValid=" + request.isRequestedSessionIdValid()).append('\n');
if (session == null)
out.append("No Session\n");
else
@ -309,8 +313,9 @@ public class SessionHandlerTest
String setCookie = response.get("SET-COOKIE");
assertThat(setCookie, containsString("Path=/"));
String content = response.getContent();
assertThat(content, startsWith("Session="));
String id = content.substring(content.indexOf('=') + 1, content.indexOf('\n'));
assertThat(content, containsString("Session="));
String id = content.substring(content.indexOf("Session=") + 8);
id = id.trim();
assertThat(id, not(equalTo("oldCookieId")));
endPoint.addInput("""
@ -326,6 +331,64 @@ public class SessionHandlerTest
assertThat(content, containsString("Session=" + id));
}
@Test
public void testRequestedSessionIdFromCookie() throws Exception
{
_server.stop();
_sessionHandler.setSessionPath(null);
_contextHandler.setContextPath("/");
_server.start();
//test with no session cookie
LocalConnector.LocalEndPoint endPoint = _connector.connect();
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
""");
HttpTester.Response response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
assertThat(response.getContent(), containsString("No Session"));
assertThat(response.getContent(), containsString("requestedSessionIdValid=false"));
//test with a cookie for non-existant session
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: JSESSIONID=%s
""".formatted("123456789"));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
assertThat(response.getContent(), containsString("No Session"));
assertThat(response.getContent(), containsString("requestedSessionIdValid=false"));
//Make a real session
endPoint.addInput("""
GET /create HTTP/1.1
Host: localhost
""");
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
String content = response.getContent();
assertThat(content, containsString("Session="));
String id = content.substring(content.indexOf("Session=") + 8);
id = id.trim();
//Check the requestedSessionId is valid
endPoint.addInput("""
GET / HTTP/1.1
Host: localhost
Cookie: JSESSIONID=%s
""".formatted(id));
response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getContent(), containsString("requestedSessionIdValid=true"));
}
@Test
public void testSetAttribute() throws Exception
{
@ -339,8 +402,9 @@ public class SessionHandlerTest
HttpTester.Response response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
String content = response.getContent();
assertThat(content, startsWith("Session="));
String id = content.substring(content.indexOf('=') + 1, content.indexOf('\n'));
assertThat(content, containsString("Session="));
String id = content.substring(content.indexOf("Session=") + 8);
id = id.trim();
endPoint.addInput("""
GET /set/attribute/value HTTP/1.1
@ -380,7 +444,7 @@ public class SessionHandlerTest
HttpTester.Response response = HttpTester.parseResponse(endPoint.getResponse());
assertThat(response.getStatus(), equalTo(200));
String content = response.getContent();
assertThat(content, startsWith("Session="));
assertThat(content, containsString("Session="));
String setCookie = response.get(HttpHeader.SET_COOKIE);
String id = setCookie.substring(setCookie.indexOf("JSESSIONID=") + 11, setCookie.indexOf("; Path=/"));