Compare commits

..

No commits in common. "master" and "3.0.5" have entirely different histories.

7 changed files with 39 additions and 101 deletions

View File

@ -14,31 +14,15 @@ Going forward, we no need to enable sticky session (JSESSIONID) in Load Balancer
- Apache Tomcat 7 - Apache Tomcat 7
- Apache Tomcat 8 - Apache Tomcat 8
- Apache Tomcat 9 - Apache Tomcat 9
- Apache Tomcat 10
## Downloads: [![Total Downloads](https://img.shields.io/github/downloads/ran-jit/tomcat-cluster-redis-session-manager/total.svg)](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki) ## Downloads: [![Total Downloads](https://get-badge.herokuapp.com/ran-jit/tomcat-cluster-redis-session-manager/total)](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki)
- [latest version (4.0)](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/tag/4.0) - [latest version (3.0.4)](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/tag/3.0.4)
- [older versions](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki) - [older versions](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki)
<p align="center"> <p align="center">
<a href="https://www.buymeacoffee.com/ranmanic" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-red.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a> <a href="https://paypal.me/ranmanic1" target="_blank"><img alt="Donate" height="30%" width="30%" src="https://github.com/ran-jit/tomcat-cluster-redis-session-manager/blob/master/src/main/resources/donate.png"></a>
</p> </p>
## Maven configuration
```
<repository>
<id>repsy</id>
<name>tomcat-cluster-redis-session-manager-repo</name>
<url>https://repo.repsy.io/mvn/ranmanic/tomcat-session-manager</url>
</repository>
<dependency>
<groupId>tomcat-session-manager</groupId>
<artifactId>redis</artifactId>
<version>4.0</version>
</dependency>
```
#### Pre-requisite: #### Pre-requisite:
1. jedis.jar 1. jedis.jar
2. commons-pool2.jar 2. commons-pool2.jar
@ -49,33 +33,23 @@ more details.. https://github.com/ran-jit/tomcat-cluster-redis-session-manager/w
#### Steps to be done, #### Steps to be done,
1. Copy the downloaded jars to your tomcat/lib directory. 1. Copy the downloaded jars to your tomcat/lib directory.
``` - **tomcat/lib/**
tomcat/lib/
```
2. Add tomcat system property "catalina.base". 2. Add tomcat system property "catalina.base".
``` - **catalina.base="TOMCAT_LOCATION"**
catalina.base="TOMCAT_LOCATION" * example: env "catalina.base=/opt/tomcat" bash
example: env "catalina.base=/opt/tomcat" bash
```
3. Copy the redis-data-cache.properties file to your tomcat/conf directory and update your Redis server details. 3. Copy the redis-data-cache.properties file to your tomcat/conf directory and update your Redis server details.
``` - **tomcat/conf/redis-data-cache.properties**
tomcat/conf/redis-data-cache.properties
```
4. Add the below two lines in your tomcat/conf/context.xml file. 4. Add the below two lines in your tomcat/conf/context.xml file.
``` - **&#60;Valve className="tomcat.request.session.redis.SessionHandlerValve" &#47;&#62;**
<Valve className="tomcat.request.session.redis.SessionHandlerValve" /> - **&#60;Manager className="tomcat.request.session.redis.SessionManager" &#47;&#62;**
<Manager className="tomcat.request.session.redis.SessionManager" />
```
5. Verify the session expiration time in tomcat/conf/web.xml file. 5. Verify the session expiration time in tomcat/conf/web.xml file.
``` - **&#60;session-config&#62;**
<session-config> - &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **&#60;session-timeout&#62;60&#60;&#47;session-timeout&#62;**
<session-timeout>60</session-timeout> - **&#60;&#47;session-config&#62;**
</session-config>
```
### Note: ### Note:
- **All your session attribute values must implement java.io.Serializable.** - **All your session attribute values must implement java.io.Serializable.**
@ -93,8 +67,7 @@ tomcat/conf/redis-data-cache.properties
<tr><td>redis.sentinel.enabled</td><td>To enable redis sentinel mode<br/>- default: false<br>- supported values: true/false</td></tr> <tr><td>redis.sentinel.enabled</td><td>To enable redis sentinel mode<br/>- default: false<br>- supported values: true/false</td></tr>
<tr><td>redis.sentinel.master</td><td>Redis sentinel master name<br/>- default: mymaster</td></tr> <tr><td>redis.sentinel.master</td><td>Redis sentinel master name<br/>- default: mymaster</td></tr>
<tr><td>lb.sticky-session.enabled</td><td>To enable redis and standard session mode<br><br>If enabled,<ol><li>Must be enabled sticky session in your load balancer configuration. Else this manager may not return the updated session values</li><li>Session values are stored in local jvm and redis</li><li>If redis is down/not responding, requests uses jvm stored session values to process user requests. Redis comes back the values will be synced</li></ol>- default: false</td></tr> <tr><td>lb.sticky-session.enabled</td><td>To enable redis and standard session mode<br><br>If enabled,<ol><li>Must be enabled sticky session in your load balancer configuration. Else this manager may not return the updated session values</li><li>Session values are stored in local jvm and redis</li><li>If redis is down/not responding, requests uses jvm stored session values to process user requests. Redis comes back the values will be synced</li></ol>- default: false</td></tr>
<tr><td>session.persistent.policies</td><td>session persistent policies.<br/><br/>- policies - DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST <br/><ol><li>SAVE_ON_CHANGE: every time session.setAttribute() or session.removeAttribute() is called the session will be saved.</li><li>ALWAYS_SAVE_AFTER_REQUEST: force saving after every request, regardless of whether or not the manager has detected changes to the session.</li></ol>- default: DEFAULT</td></tr> <tr><td>session.persistent.policies</td><td>session persistent policies.<br/><br/>- policies - DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST <br/><ol><li>SAVE_ON_CHANGE: every time session.setAttribute() or session.removeAttribute() is called the session will be saved.</li><li>ALWAYS_SAVE_AFTER_REQUEST: force saving after every request, regardless of whether or not the manager has detected changes to the session.</li></ol>- default: DEFAULT</td></tr>
<tr><td>redis.sso.timeout</td><td>single-sign-on session timeout.<br/>- default: 0 ms (-no expiry)</td></tr>
</table> </table>
</body> </body>
</html> </html>

14
pom.xml
View File

@ -2,9 +2,9 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>tomcat-session-manager</groupId> <groupId>tomcat-cluster-redis-session-manager</groupId>
<artifactId>redis</artifactId> <artifactId>tomcat-cluster-redis-session-manager</artifactId>
<version>4.0</version> <version>3.0.5</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>tomcat-cluster-redis-session-manager</name> <name>tomcat-cluster-redis-session-manager</name>
@ -36,14 +36,6 @@
<!-- For local development properties end.. --> <!-- For local development properties end.. -->
</properties> </properties>
<distributionManagement>
<repository>
<id>repsy</id>
<name>tomcat-cluster-redis-session-manager-repo</name>
<url>https://repo.repsy.io/mvn/ranmanic/tomcat-session-manager</url>
</repository>
</distributionManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>redis.clients</groupId> <groupId>redis.clients</groupId>

View File

@ -11,8 +11,6 @@ import static tomcat.request.session.annotation.Property.PropertyType.INTEGER;
/** author: Ranjith Manickam @ 5 Feb' 2020 */ /** author: Ranjith Manickam @ 5 Feb' 2020 */
public class Config implements Serializable { public class Config implements Serializable {
private static final long serialVersionUID = 3480402257971437776L;
public static final String APPLICATION_PROPERTIES_FILE = "redis-data-cache.properties"; public static final String APPLICATION_PROPERTIES_FILE = "redis-data-cache.properties";
/** Redis config type. */ /** Redis config type. */
@ -79,9 +77,6 @@ public class Config implements Serializable {
@Property(name = "session.persistent.policies", defaultValue = "DEFAULT") @Property(name = "session.persistent.policies", defaultValue = "DEFAULT")
private String sessionPersistentPolicies; private String sessionPersistentPolicies;
@Property(name = "redis.sso.timeout", type = INTEGER, defaultValue = "0")
private Integer redisSSOTimeout;
public Config() { public Config() {
} }
@ -103,8 +98,7 @@ public class Config implements Serializable {
String redisSentinelMaster, String redisSentinelMaster,
Integer redisSessionExpiryJobInterval, Integer redisSessionExpiryJobInterval,
Integer redisSessionDataSyncJobInterval, Integer redisSessionDataSyncJobInterval,
String sessionPersistentPolicies, String sessionPersistentPolicies) {
Integer redisSSOTimeout) {
this.redisHosts = redisHosts; this.redisHosts = redisHosts;
this.redisClusterEnabled = redisClusterEnabled; this.redisClusterEnabled = redisClusterEnabled;
this.redisSentinelEnabled = redisSentinelEnabled; this.redisSentinelEnabled = redisSentinelEnabled;
@ -124,7 +118,6 @@ public class Config implements Serializable {
this.redisSessionExpiryJobInterval = redisSessionExpiryJobInterval; this.redisSessionExpiryJobInterval = redisSessionExpiryJobInterval;
this.redisSessionDataSyncJobInterval = redisSessionDataSyncJobInterval; this.redisSessionDataSyncJobInterval = redisSessionDataSyncJobInterval;
this.sessionPersistentPolicies = sessionPersistentPolicies; this.sessionPersistentPolicies = sessionPersistentPolicies;
this.redisSSOTimeout = redisSSOTimeout;
} }
/** To get 'redis.hosts' value. */ /** To get 'redis.hosts' value. */
@ -222,11 +215,6 @@ public class Config implements Serializable {
return sessionPersistentPolicies; return sessionPersistentPolicies;
} }
/** To get 'redis.sso.timeout' value */
public Integer getRedisSSOTimeout() {
return redisSSOTimeout;
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public String toString() { public String toString() {
@ -250,7 +238,6 @@ public class Config implements Serializable {
", redisSessionExpiryJobInterval=" + redisSessionExpiryJobInterval + ", redisSessionExpiryJobInterval=" + redisSessionExpiryJobInterval +
", redisSessionDataSyncJobInterval=" + redisSessionDataSyncJobInterval + ", redisSessionDataSyncJobInterval=" + redisSessionDataSyncJobInterval +
", sessionPersistentPolicies='" + sessionPersistentPolicies + '\'' + ", sessionPersistentPolicies='" + sessionPersistentPolicies + '\'' +
", redisSSOTimeout='" + redisSSOTimeout + '\'' +
'}'; '}';
} }

View File

@ -31,9 +31,7 @@ public class SessionHandlerValve extends ValveBase {
LOGGER.error("Error processing request", ex); LOGGER.error("Error processing request", ex);
throw new BackendException(); throw new BackendException();
} finally { } finally {
if (this.manager != null) { this.manager.afterRequest();
this.manager.afterRequest();
}
} }
} }
} }

View File

@ -32,11 +32,10 @@ public class SessionManager extends ManagerBase implements Lifecycle {
private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class); private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class);
private Integer ssoTimeout;
private DataCache dataCache; private DataCache dataCache;
private SerializationUtil serializer; private SerializationUtil serializer;
private final ThreadLocal<SessionContext> sessionContext = new ThreadLocal<>(); private ThreadLocal<SessionContext> sessionContext = new ThreadLocal<>();
private final Set<SessionPolicy> sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT); private Set<SessionPolicy> sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT);
public boolean getSaveOnChange() { public boolean getSaveOnChange() {
return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE); return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE);
@ -79,6 +78,14 @@ public class SessionManager extends ManagerBase implements Lifecycle {
initializedValve = true; initializedValve = true;
break; break;
} }
if (valve instanceof SingleSignOnValve) {
SingleSignOnValve ssoValve = (SingleSignOnValve) valve;
ssoValve.setSessionManager(this);
ssoValve.setContext(context);
initializedValve = true;
break;
}
} }
if (!initializedValve) { if (!initializedValve) {
@ -211,7 +218,6 @@ public class SessionManager extends ManagerBase implements Lifecycle {
private void initialize() { private void initialize() {
try { try {
Config config = ConfigUtil.getConfig(); Config config = ConfigUtil.getConfig();
this.ssoTimeout = config.getRedisSSOTimeout();
this.dataCache = new DataCacheFactory(config, getSessionTimeout(null)).getDataCache(); this.dataCache = new DataCacheFactory(config, getSessionTimeout(null)).getDataCache();
this.serializer = new SerializationUtil(); this.serializer = new SerializationUtil();
@ -347,9 +353,6 @@ public class SessionManager extends ManagerBase implements Lifecycle {
try { try {
byte[] data = this.serializer.serializeSingleSignOnEntry(entry); byte[] data = this.serializer.serializeSingleSignOnEntry(entry);
this.dataCache.set(ssoId, data); this.dataCache.set(ssoId, data);
if (this.ssoTimeout > 0) {
this.dataCache.expire(ssoId, this.ssoTimeout);
}
} catch (IOException ex) { } catch (IOException ex) {
LOGGER.error("Error occurred while serializing the single-sign-on entry..", ex); LOGGER.error("Error occurred while serializing the single-sign-on entry..", ex);
} }

View File

@ -2,8 +2,6 @@ package tomcat.request.session.redis;
import org.apache.catalina.Container; import org.apache.catalina.Container;
import org.apache.catalina.Context; import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Manager; import org.apache.catalina.Manager;
import org.apache.catalina.Realm; import org.apache.catalina.Realm;
import org.apache.catalina.Session; import org.apache.catalina.Session;
@ -28,27 +26,14 @@ public class SingleSignOnValve extends SingleSignOn {
private static final Logger LOGGER = LoggerFactory.getLogger(SingleSignOnValve.class); private static final Logger LOGGER = LoggerFactory.getLogger(SingleSignOnValve.class);
private Engine engine; private Context context;
private SessionManager manager; private SessionManager manager;
/** {@inheritDoc} */
@Override
protected synchronized void startInternal() throws LifecycleException {
Container c;
for (c = this.getContainer(); c != null && !(c instanceof Engine); c = c.getParent()) {
}
if (c instanceof Engine) {
this.engine = (Engine) c;
}
super.startInternal();
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public void invoke(Request request, Response response) throws BackendException { public void invoke(Request request, Response response) throws BackendException {
try { try {
this.setContext(request.getContext());
this.setSessionManager(request.getContext().getManager()); this.setSessionManager(request.getContext().getManager());
request.removeNote("org.apache.catalina.request.SSOID"); request.removeNote("org.apache.catalina.request.SSOID");
@ -225,17 +210,20 @@ public class SingleSignOnValve extends SingleSignOn {
/** To set session manager. */ /** To set session manager. */
void setSessionManager(Manager manager) { void setSessionManager(Manager manager) {
if (manager != null) { this.manager = (SessionManager) manager;
this.manager = (SessionManager) manager; }
}
/** To set context. */
void setContext(Context context) {
this.context = context;
} }
/** To expire session. */ /** To expire session. */
private void expire(SingleSignOnSessionKey key) { private void expire(SingleSignOnSessionKey key) {
if (this.engine == null) { if (this.context == null) {
LOGGER.warn("singleSignOn.sessionExpire.engineNull, key: {}", key); LOGGER.warn("singleSignOn.sessionExpire.engineNull, key: {}", key);
} else { } else {
Container host = this.engine.findChild(key.getHostName()); Container host = this.context.findChild(key.getHostName());
if (host == null) { if (host == null) {
LOGGER.warn("singleSignOn.sessionExpire.hostNotFound, key: {}", key); LOGGER.warn("singleSignOn.sessionExpire.hostNotFound, key: {}", key);
} else { } else {

View File

@ -34,6 +34,3 @@ lb.sticky-session.enabled=false
# 1. SAVE_ON_CHANGE: every time session.setAttribute() or session.removeAttribute() is called the session will be saved. # 1. SAVE_ON_CHANGE: every time session.setAttribute() or session.removeAttribute() is called the session will be saved.
# 2. ALWAYS_SAVE_AFTER_REQUEST: force saving after every request, regardless of whether or not the manager has detected changes to the session. # 2. ALWAYS_SAVE_AFTER_REQUEST: force saving after every request, regardless of whether or not the manager has detected changes to the session.
session.persistent.policies=DEFAULT session.persistent.policies=DEFAULT
#- single-sign-on session timeout. (default value: 0 ms (-no expiry))
redis.sso.timeout=0