Issue #4682 Session with no attributes unreadable from jdbc (#4688)

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2020-03-31 14:25:52 +02:00 committed by GitHub
parent 81c13f08d0
commit 524e690140
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 189 additions and 73 deletions

View File

@ -709,21 +709,15 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
statement.setLong(10, data.getExpiry());
statement.setLong(11, data.getMaxInactiveMs());
if (!data.getAllAttributes().isEmpty())
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos))
{
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos))
{
SessionData.serializeAttributes(data, oos);
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob
}
}
else
{
statement.setBinaryStream(12, EMPTY, 0);
SessionData.serializeAttributes(data, oos);
byte[] bytes = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob
}
statement.executeUpdate();
if (LOG.isDebugEnabled())
LOG.debug("Inserted session " + data);
@ -746,23 +740,17 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
statement.setLong(5, data.getExpiry());
statement.setLong(6, data.getMaxInactiveMs());
if (!data.getAllAttributes().isEmpty())
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos))
{
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos))
SessionData.serializeAttributes(data, oos);
byte[] bytes = baos.toByteArray();
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes))
{
SessionData.serializeAttributes(data, oos);
byte[] bytes = baos.toByteArray();
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes))
{
statement.setBinaryStream(7, bais, bytes.length);//attribute map as blob
}
statement.setBinaryStream(7, bais, bytes.length);//attribute map as blob
}
}
else
{
statement.setBinaryStream(7, EMPTY, 0);
}
statement.executeUpdate();
if (LOG.isDebugEnabled())

View File

@ -49,19 +49,16 @@ public class JDBCSessionDataStoreTest extends AbstractSessionDataStoreTest
public void persistSession(SessionData data)
throws Exception
{
JdbcTestHelper.insertSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(),
data.getCreated(), data.getAccessed(), data.getLastAccessed(),
data.getMaxInactiveMs(), data.getExpiry(), data.getCookieSet(),
data.getLastSaved(), data.getAllAttributes());
JdbcTestHelper.insertSession(data);
}
@Override
public void persistUnreadableSession(SessionData data) throws Exception
{
JdbcTestHelper.insertSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(),
JdbcTestHelper.insertUnreadableSession(data.getId(), data.getContextPath(), data.getVhost(), data.getLastNode(),
data.getCreated(), data.getAccessed(), data.getLastAccessed(),
data.getMaxInactiveMs(), data.getExpiry(), data.getCookieSet(),
data.getLastSaved(), null);
data.getLastSaved());
}
@Override

View File

@ -29,7 +29,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
@ -131,6 +130,35 @@ public class JdbcTestHelper
sessionTableSchema.prepareTables();
}
public static void dumpRow(ResultSet row) throws SQLException
{
if (row != null)
{
String id = row.getString(ID_COL);
long created = row.getLong(CREATE_COL);
long accessed = row.getLong(ACCESS_COL);
long lastAccessed = row.getLong(LAST_ACCESS_COL);
long maxIdle = row.getLong(MAX_IDLE_COL);
long cookieSet = row.getLong(COOKIE_COL);
String node = row.getString(LAST_NODE_COL);
long expires = row.getLong(EXPIRY_COL);
long lastSaved = row.getLong(LAST_SAVE_COL);
String context = row.getString(CONTEXT_COL);
Blob blob = row.getBlob(MAP_COL);
String dump = "id=" + id +
" ctxt=" + context +
" node=" + node +
" exp=" + expires +
" acc=" + accessed +
" lacc=" + lastAccessed +
" ck=" + cookieSet +
" lsv=" + lastSaved +
" blob length=" + blob.length();
System.err.println(dump);
}
}
public static boolean existsInSessionTable(String id, boolean verbose)
throws Exception
@ -151,6 +179,7 @@ public class JdbcTestHelper
while (result.next())
{
results = true;
dumpRow(result);
}
return results;
}
@ -232,41 +261,53 @@ public class JdbcTestHelper
return true;
}
public static void insertSession(String id, String contextPath, String vhost)
throws Exception
public static void insertSession(SessionData data) throws Exception
{
Class.forName(DRIVER_CLASS);
try (Connection con = DriverManager.getConnection(DEFAULT_CONNECTION_URL);)
{
PreparedStatement statement = con.prepareStatement("insert into " + TABLE +
" (" + ID_COL + ", " + CONTEXT_COL + ", virtualHost, " + LAST_NODE_COL +
", " + ACCESS_COL + ", " + LAST_ACCESS_COL + ", " + CREATE_COL + ", " + COOKIE_COL +
", " + LAST_SAVE_COL + ", " + EXPIRY_COL + " " + ") " +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
", " + LAST_SAVE_COL + ", " + EXPIRY_COL + ", " + MAX_IDLE_COL + "," + MAP_COL + " ) " +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
statement.setString(1, id);
statement.setString(2, contextPath);
statement.setString(3, vhost);
statement.setString(4, "0");
statement.setString(1, data.getId());
statement.setString(2, data.getContextPath());
statement.setString(3, data.getVhost());
statement.setString(4, data.getLastNode());
statement.setLong(5, System.currentTimeMillis());
statement.setLong(6, System.currentTimeMillis());
statement.setLong(7, System.currentTimeMillis());
statement.setLong(8, System.currentTimeMillis());
statement.setLong(5, data.getAccessed());
statement.setLong(6, data.getLastAccessed());
statement.setLong(7, data.getCreated());
statement.setLong(8, data.getCookieSet());
statement.setLong(9, System.currentTimeMillis());
statement.setLong(10, System.currentTimeMillis());
statement.setLong(9, data.getLastSaved());
statement.setLong(10, data.getExpiry());
statement.setLong(11, data.getMaxInactiveMs());
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);)
{
SessionData.serializeAttributes(data, oos);
byte[] bytes = baos.toByteArray();
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);)
{
statement.setBinaryStream(12, bais, bytes.length);
}
}
statement.execute();
assertEquals(1, statement.getUpdateCount());
}
}
public static void insertSession(String id, String contextPath, String vhost,
public static void insertUnreadableSession(String id, String contextPath, String vhost,
String lastNode, long created, long accessed,
long lastAccessed, long maxIdle, long expiry,
long cookieSet, long lastSaved, Map<String, Object> attributes)
long cookieSet, long lastSaved)
throws Exception
{
Class.forName(DRIVER_CLASS);
@ -292,23 +333,7 @@ public class JdbcTestHelper
statement.setLong(10, expiry);
statement.setLong(11, maxIdle);
if (attributes != null)
{
SessionData tmp = new SessionData(id, contextPath, vhost, created, accessed, lastAccessed, maxIdle);
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);)
{
SessionData.serializeAttributes(tmp, oos);
byte[] bytes = baos.toByteArray();
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);)
{
statement.setBinaryStream(12, bais, bytes.length);
}
}
}
else
statement.setBinaryStream(12, new ByteArrayInputStream("".getBytes()), 0);
statement.setBinaryStream(12, new ByteArrayInputStream("".getBytes()), 0);
statement.execute();
assertEquals(1, statement.getUpdateCount());

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.server.session;
import java.io.ByteArrayInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@ -70,6 +71,46 @@ public class SessionTableSchemaTest
JdbcTestHelper.shutdown(null);
}
/**
* This inserts a session into the db that does not set the session attributes MAP column. As such
* this results in a row that is unreadable by the JDBCSessionDataStore, but is readable by using
* only jdbc api, which is what this test does.
*
* @param id id of session
* @param contextPath the context path of the session
* @param vhost the virtual host of the session
* @throws Exception
*/
public static void insertSessionWithoutAttributes(String id, String contextPath, String vhost)
throws Exception
{
Class.forName(JdbcTestHelper.DRIVER_CLASS);
try (Connection con = DriverManager.getConnection(JdbcTestHelper.DEFAULT_CONNECTION_URL);)
{
PreparedStatement statement = con.prepareStatement("insert into " + JdbcTestHelper.TABLE +
" (" + JdbcTestHelper.ID_COL + ", " + JdbcTestHelper.CONTEXT_COL + ", virtualHost, " + JdbcTestHelper.LAST_NODE_COL +
", " + JdbcTestHelper.ACCESS_COL + ", " + JdbcTestHelper.LAST_ACCESS_COL + ", " + JdbcTestHelper.CREATE_COL + ", " + JdbcTestHelper.COOKIE_COL +
", " + JdbcTestHelper.LAST_SAVE_COL + ", " + JdbcTestHelper.EXPIRY_COL + " " + ") " +
" values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
statement.setString(1, id);
statement.setString(2, contextPath);
statement.setString(3, vhost);
statement.setString(4, "0");
statement.setLong(5, System.currentTimeMillis());
statement.setLong(6, System.currentTimeMillis());
statement.setLong(7, System.currentTimeMillis());
statement.setLong(8, System.currentTimeMillis());
statement.setLong(9, System.currentTimeMillis());
statement.setLong(10, System.currentTimeMillis());
statement.execute();
assertEquals(1, statement.getUpdateCount());
}
}
@Test
public void testLoad()
throws Exception
@ -79,7 +120,7 @@ public class SessionTableSchemaTest
_tableSchema.prepareTables();
//insert a fake session at the root context
JdbcTestHelper.insertSession("1234", "/", "0.0.0.0");
insertSessionWithoutAttributes("1234", "/", "0.0.0.0");
//test if it can be seen
try (Connection con = _da.getConnection())
@ -104,7 +145,7 @@ public class SessionTableSchemaTest
_tableSchema.prepareTables();
//insert a fake session at the root context
JdbcTestHelper.insertSession("1234", "/", "0.0.0.0");
insertSessionWithoutAttributes("1234", "/", "0.0.0.0");
//test if it can be seen
try (Connection con = _da.getConnection())
@ -128,7 +169,7 @@ public class SessionTableSchemaTest
_tableSchema.prepareTables();
//insert a fake session at the root context
JdbcTestHelper.insertSession("1234", "/", "0.0.0.0");
insertSessionWithoutAttributes("1234", "/", "0.0.0.0");
//test if it can be deleted
try (Connection con = _da.getConnection())
@ -152,7 +193,7 @@ public class SessionTableSchemaTest
_tableSchema.prepareTables();
//insert a fake session at the root context
JdbcTestHelper.insertSession("1234", "/", "0.0.0.0");
insertSessionWithoutAttributes("1234", "/", "0.0.0.0");
try (Connection con = _da.getConnection())
{
@ -178,7 +219,7 @@ public class SessionTableSchemaTest
_tableSchema.prepareTables();
//insert a fake session at the root context
JdbcTestHelper.insertSession("1234", "/", "0.0.0.0");
insertSessionWithoutAttributes("1234", "/", "0.0.0.0");
try (Connection con = _da.getConnection())
{
@ -203,7 +244,7 @@ public class SessionTableSchemaTest
_tableSchema.prepareTables();
//insert a fake session at the root context
JdbcTestHelper.insertSession("1234", "/", "0.0.0.0");
insertSessionWithoutAttributes("1234", "/", "0.0.0.0");
try (Connection con = _da.getConnection())
{

View File

@ -427,7 +427,72 @@ public abstract class AbstractSessionDataStoreTest
//expected exception
}
}
/**
* Test that a session containing no attributes can be stored and re-read
* @throws Exception
*/
@Test
public void testEmptyLoadSession() throws Exception
{
//create the SessionDataStore
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/test");
SessionDataStoreFactory factory = createSessionDataStoreFactory();
((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC);
SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler());
SessionContext sessionContext = new SessionContext("foo", context.getServletContext());
store.initialize(sessionContext);
store.start();
//persist a session that has no attributes
long now = System.currentTimeMillis();
SessionData data = store.newSessionData("222", 100, now, now - 1, -1);
data.setLastNode(sessionContext.getWorkerName());
//persistSession(data);
store.store("222", data);
//test that we can retrieve it
SessionData savedSession = store.load("222");
assertEquals(0, savedSession.getAllAttributes().size());
}
//Test that a session that had attributes can be modified to contain no
//attributes, and still read
@Test
public void testModifyEmptyLoadSession() throws Exception
{
//create the SessionDataStore
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/test");
SessionDataStoreFactory factory = createSessionDataStoreFactory();
((AbstractSessionDataStoreFactory)factory).setGracePeriodSec(GRACE_PERIOD_SEC);
SessionDataStore store = factory.getSessionDataStore(context.getSessionHandler());
SessionContext sessionContext = new SessionContext("foo", context.getServletContext());
store.initialize(sessionContext);
store.start();
//persist a session that has attributes
long now = System.currentTimeMillis();
SessionData data = store.newSessionData("222", 100, now, now - 1, -1);
data.setAttribute("foo", "bar");
data.setLastNode(sessionContext.getWorkerName());
store.store("222", data);
//test that we can retrieve it
SessionData savedSession = store.load("222");
assertEquals("bar", savedSession.getAttribute("foo"));
//now modify so there are no attributes
savedSession.setAttribute("foo", null);
store.store("222", savedSession);
//check its still readable
savedSession = store.load("222");
assertEquals(0, savedSession.getAllAttributes().size());
}
/**
* Test that we can delete a persisted session.
*/