-1

i am migrating java bundles from CQ 5.6.1 to AEM 6.4, bundle is working in jdk 1.7,

code is using apache shiro to serealize and deserialize session, here is the code to save and read session stored in Cassandra

it works good with AEM 5.6.1 and 6.1 (works in jdk 1.7) when i migrate it to AEM 6.4 (working in jdk 1.8) code is giving exception in "method doReadSession" when it is trying to deserialize session in bite array

it throw an exception In method doReadSession where it return "serializer.deserialize(bytes)"

exception thrown is

Caused by: org.apache.shiro.io.SerializationException: Unable to deserialze argument byte array. at org.apache.shiro.io.DefaultSerializer.deserialize(DefaultSerializer.java:82) at com.xyz.web.platform.common.security.shiro.cassandra.CassandraSessionDAO.doReadSession(CassandraSessionDAO.java:252) at org.apache.shiro.session.mgt.eis.AbstractSessionDAO.readSession(AbstractSessionDAO.java:168) at org.apache.shiro.session.mgt.DefaultSessionManager.retrieveSessionFromDataSource(DefaultSessionManager.java:236)

 import com.xyz.web.platform.common.security.shiro.session.idgenerator.UUIDSessionIdGenerator;
import com.xyz.web.platform.common.tracelogging.TMTraceLogger;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import org.apache.shiro.ShiroException;
import org.apache.shiro.io.DefaultSerializer;
import org.apache.shiro.io.Serializer;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.util.Destroyable;
import org.apache.shiro.util.Initializable;
import com.datastax.driver.core.BoundStatement;
import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.ConsistencyLevel;
import com.datastax.driver.core.PreparedStatement;
import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.Row;


public class CassandraSessionDAO extends AbstractSessionDAO implements Initializable, Destroyable {

    private static final TMTraceLogger CASSANDRA_LOGGER = TMTraceLogger
            .getLogger("cassandraLogger" + "." + CassandraSessionDAO.class.getName());

    private String DEFAULT_CONSISTENCY_LEVEL = ConsistencyLevel.LOCAL_QUORUM.toString();
    private static final String DEFAULT_CACHING = "ROWS_ONLY";
    private static final String DEFAULT_DATA_CENTER = "DC1";



    private String keyspaceName;
    private String tableName;
    private Cluster cluster;
    private Serializer<SimpleSession> serializer;
    private String readConsistencyLevel;
    private String writeConsistencyLevel;
    private String defaultTTL;
    private String gc_grace_seconds;

    private String caching = DEFAULT_CACHING;
    private String dataCenter = DEFAULT_DATA_CENTER;

    private PreparedStatement deletePreparedStatement;
    private PreparedStatement savePreparedStatement;
    private PreparedStatement readPreparedStatement;

    private com.datastax.driver.core.Session cassandraSession;

    public CassandraSessionDAO() {

        setSessionIdGenerator(new UUIDSessionIdGenerator());
        this.serializer = new DefaultSerializer<SimpleSession>();
    }

    private SimpleSession assertSimpleSession(Session session) {
        if (!(session instanceof SimpleSession)) {
            throw new IllegalArgumentException(CassandraSessionDAO.class.getName() + " implementations only support "
                    + SimpleSession.class.getName() + " instances.");
        }
        return (SimpleSession) session;
    }

    public Cluster getCluster() {
        return cluster;
    }

    public void setCluster(Cluster cluster) {
        this.cluster = cluster;
    }

    public String getKeyspaceName() {
        return keyspaceName;
    }

    public void setKeyspaceName(String keyspaceName) {
        this.keyspaceName = keyspaceName;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public String getReadConsistencyLevel() {
        return readConsistencyLevel;
    }

    public void setReadConsistencyLevel(String readConsistencyLevel) {
        this.readConsistencyLevel = readConsistencyLevel;
    }

    public String getWriteConsistencyLevel() {
        return writeConsistencyLevel;
    }

    public void setWriteConsistencyLevel(String writeConsistencyLevel) {
        this.writeConsistencyLevel = writeConsistencyLevel;
    }

    public String getDefaultTTL() {
        return defaultTTL;
    }

    public void setDefaultTTL(String defaultTTL) {
        this.defaultTTL = defaultTTL;
    }

    public String getGc_grace_seconds() {
        return gc_grace_seconds;
    }

    public void setGc_grace_seconds(String gc_grace_seconds) {
        this.gc_grace_seconds = gc_grace_seconds;
    }

    public String getCaching() {
        return caching;
    }

    public void setCaching(String caching) {
        this.caching = caching;
    }

    public String getDataCenter() {
        return dataCenter;
    }

    public void setDataCenter(String dataCenter) {
        this.dataCenter = dataCenter;
    }

    public void init() throws ShiroException {
        com.datastax.driver.core.Session systemSession = cluster.connect();
        boolean create = false;
        try {
            if (!isKeyspacePresent(systemSession)) {
                create = true;
                createKeyspace(systemSession);
                if (!isKeyspacePresent(systemSession)) {
                    throw new IllegalStateException("Unable to create keyspace " + keyspaceName);
                }
            }
        } finally {
            systemSession.shutdown();
        }

        cassandraSession = cluster.connect(keyspaceName);
        if (create) {
            createTable();
        }

        prepareReadStatement();
        prepareSaveStatement();
        prepareDeleteStatement();
    }

    public void destroy() throws Exception {
        if (cassandraSession != null) {
            cassandraSession.shutdown();
            cluster.shutdown();
        }
    }

    protected boolean isKeyspacePresent(com.datastax.driver.core.Session systemSession) {
        PreparedStatement ps = systemSession.prepare("select * from system.schema_keyspaces");
        BoundStatement bs = new BoundStatement(ps);
        ResultSet results = systemSession.execute(bs);
        // ResultSet results = systemSession.execute("select * from
        // system.schema_keyspaces");
        for (Row row : results) {
            if (row.getString("keyspace_name").equalsIgnoreCase(keyspaceName)) {
                return true;
            }
        }
        return false;
    }

    protected void createKeyspace(com.datastax.driver.core.Session systemSession) {
        String query = "create keyspace " + this.keyspaceName
                + " with replication = {'class' : 'NetworkTopologyStrategy', '" + dataCenter + "': 2};";
        systemSession.execute(query);
    }

    protected void createTable() {

        long defaultTTLLong = Long.parseLong(defaultTTL);
        long gc_grace_secondsLong = Long.parseLong(gc_grace_seconds);
        String query = "CREATE TABLE " + tableName + " ( " + "    id varchar PRIMARY KEY, " + "    start_ts timestamp, "
                + "    stop_ts timestamp, " + "    last_access_ts timestamp, " + "    timeout bigint, "
                + "    expired boolean, " + "    host varchar, " + "    serialized_value blob " + ") " + "WITH "
                + "    gc_grace_seconds = " + gc_grace_secondsLong + " AND default_time_to_live = " + defaultTTLLong
                + " AND caching = '" + caching + "' AND " + "    compaction = {'class':'LeveledCompactionStrategy'};";
        cassandraSession.execute(query);
    }

    @Override
    protected Serializable doCreate(Session session) {
        SimpleSession ss = assertSimpleSession(session);
        Serializable timeUuid = generateSessionId(session);
        assignSessionId(ss, timeUuid);
        save(ss);
        return timeUuid;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {

        long startTime = System.currentTimeMillis();
        if (CASSANDRA_LOGGER.isDebugEnabled()) {
            CASSANDRA_LOGGER.logDebug("In the doReadSession()..");
            CASSANDRA_LOGGER.logDebug("The start time is " + startTime + " ms");
        }

        // put a not-null & not-empty check
        if (sessionId != null && !sessionId.equals("")) {

            String id = sessionId.toString();

            PreparedStatement ps = prepareReadStatement();
            /*
             * String query = "SELECT * from " + tableName + " where id = ?";
             * PreparedStatement ps = cassandraSession.prepare(query);
             */
            BoundStatement bs = new BoundStatement(ps);
            bs.bind(id);
            if (readConsistencyLevel == null) {
                readConsistencyLevel = DEFAULT_CONSISTENCY_LEVEL;
            }
            bs.setConsistencyLevel(ConsistencyLevel.valueOf(readConsistencyLevel));
            ResultSet results = cassandraSession.execute(bs);
            for (Row row : results) {
                String rowId = row.getString("id");
                if (id.equals(rowId)) {
                    ByteBuffer buffer = row.getBytes("serialized_value");
                    if (buffer != null) {
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        return serializer.deserialize(bytes);
                    }

                }
            }
        }
        long endTime = System.currentTimeMillis();
        long timeTaken = endTime - startTime;
        if (CASSANDRA_LOGGER.isDebugEnabled()) {
            CASSANDRA_LOGGER.logDebug("The total time taken is " + timeTaken + " ms");
        }
        return null;
    }

    private PreparedStatement prepareReadStatement() {
        if (this.readPreparedStatement == null) {
            String query = "SELECT * from " + tableName + " where id = ?";
            this.readPreparedStatement = cassandraSession.prepare(query);
        }
        return this.readPreparedStatement;
    }

    // In CQL, insert and update are effectively the same, so we can use a single
    // query for both:
    protected void save(SimpleSession ss) {
        // long timeoutInSeconds = ss.getTimeout() / 1000;
        /*
         * String query = "UPDATE " + tableName + " SET " + "start_ts = ?, " +
         * "stop_ts = ?, " + "last_access_ts = ?, " + "timeout = ?, " + "expired = ?, "
         * + "host = ?, " + "serialized_value = ? " + "WHERE " + "id = ?";
         * PreparedStatement ps = cassandraSession.prepare(query);
         */
        long startTime = System.currentTimeMillis();
        if (CASSANDRA_LOGGER.isDebugEnabled()) {
            CASSANDRA_LOGGER.logDebug("In the save()..");
            CASSANDRA_LOGGER.logDebug("The start time is " + startTime + " ms");
        }
        PreparedStatement ps = prepareSaveStatement();
        BoundStatement bs = new BoundStatement(ps);
        byte[] serialized = serializer.serialize(ss);
        ByteBuffer bytes = ByteBuffer.wrap(serialized);



        bs.bind(ss.getStartTimestamp(), ss.getStopTimestamp() != null ? ss.getStartTimestamp() : null,
                ss.getLastAccessTime(), ss.getTimeout(), ss.isExpired(), ss.getHost(), bytes, ss.getId().toString());
        if (writeConsistencyLevel == null) {
            writeConsistencyLevel = DEFAULT_CONSISTENCY_LEVEL;
        }
        bs.setConsistencyLevel(ConsistencyLevel.valueOf(writeConsistencyLevel));
        cassandraSession.execute(bs);
        long endTime = System.currentTimeMillis();
        long timeTaken = endTime - startTime;
        if (CASSANDRA_LOGGER.isDebugEnabled()) {
            CASSANDRA_LOGGER.logDebug("The total time taken is " + timeTaken + " ms");
        }
    }

    private PreparedStatement prepareSaveStatement() {
        if (this.savePreparedStatement == null) {
            String query = "UPDATE " + tableName + " SET " + "start_ts = ?, " + "stop_ts = ?, " + "last_access_ts = ?, "
                    + "timeout = ?, " + "expired = ?, " + "host = ?, " + "serialized_value = ? " + "WHERE " + "id = ?";
            this.savePreparedStatement = cassandraSession.prepare(query);
        }
        return this.savePreparedStatement;
    }

    public void update(Session session) throws UnknownSessionException {
        SimpleSession ss = assertSimpleSession(session);
        save(ss);
    }

    public void delete(Session session) {
        /*
         * String query = "DELETE from " + tableName + " where id = ?";
         * PreparedStatement ps = cassandraSession.prepare(query);
         */

        long startTime = System.currentTimeMillis();
        if (CASSANDRA_LOGGER.isDebugEnabled()) {
            CASSANDRA_LOGGER.logDebug("In the delete()..");
            CASSANDRA_LOGGER.logDebug("The start time is " + startTime + " ms");
        }
        PreparedStatement ps = prepareDeleteStatement();
        BoundStatement bs = new BoundStatement(ps);
        bs.bind(session.getId().toString());
        cassandraSession.execute(bs);
        long endTime = System.currentTimeMillis();
        long timeTaken = endTime - startTime;
        if (CASSANDRA_LOGGER.isDebugEnabled()) {
            CASSANDRA_LOGGER.logDebug("The total time taken is " + timeTaken + " ms");
        }
    }

    private PreparedStatement prepareDeleteStatement() {
        if (this.deletePreparedStatement == null) {
            String query = "DELETE from " + tableName + " where id = ?";
            this.deletePreparedStatement = cassandraSession.prepare(query);
        }
        return this.deletePreparedStatement;
    }

    public Collection<Session> getActiveSessions() {
        return Collections.emptyList();
    }

}

1 Answers1

0

Need to add your class or pacakge in the configuration in whitelist section https://helpx.adobe.com/experience-manager/6-4/sites/administering/using/mitigating-serialization-issues.html