Compare commits

..

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

15 changed files with 44 additions and 615 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 8
- 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)
- [latest version (4.0)](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/tag/4.0)
## Downloads:
- [latest version (3.0.3)](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/releases/tag/3.0.3)
- [older versions](https://github.com/ran-jit/tomcat-cluster-redis-session-manager/wiki)
<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>
## 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:
1. jedis.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,
1. Copy the downloaded jars to your tomcat/lib directory.
```
tomcat/lib/
```
- **tomcat/lib/**
2. Add tomcat system property "catalina.base".
```
catalina.base="TOMCAT_LOCATION"
example: env "catalina.base=/opt/tomcat" bash
```
- **catalina.base="TOMCAT_LOCATION"**
* 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.
```
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.
```
<Valve className="tomcat.request.session.redis.SessionHandlerValve" />
<Manager className="tomcat.request.session.redis.SessionManager" />
```
- **&#60;Valve className="tomcat.request.session.redis.SessionHandlerValve" &#47;&#62;**
- **&#60;Manager className="tomcat.request.session.redis.SessionManager" &#47;&#62;**
5. Verify the session expiration time in tomcat/conf/web.xml file.
```
<session-config>
<session-timeout>60</session-timeout>
</session-config>
```
- **&#60;session-config&#62;**
- &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; **&#60;session-timeout&#62;60&#60;&#47;session-timeout&#62;**
- **&#60;&#47;session-config&#62;**
### Note:
- **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.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>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>
<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>
</table>
</body>
</html>

48
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">
<modelVersion>4.0.0</modelVersion>
<groupId>tomcat-session-manager</groupId>
<artifactId>redis</artifactId>
<version>4.0</version>
<groupId>tomcat-cluster-redis-session-manager</groupId>
<artifactId>tomcat-cluster-redis-session-manager</artifactId>
<version>3.0.4</version>
<packaging>jar</packaging>
<name>tomcat-cluster-redis-session-manager</name>
@ -32,18 +32,12 @@
<target-java.version>${source-java.version}</target-java.version>
<!-- For local development properties begins.. -->
<tomcat.version>8.5.32</tomcat.version>
<!--<tomcat-catalina.version>apache-tomcat-8.5.32</tomcat-catalina.version>-->
<!--<tomcat-servlet-api.version>apache-tomcat-8.5.32</tomcat-servlet-api.version>-->
<!--<tomcat-api.version>apache-tomcat-8.5.32</tomcat-api.version>-->
<!-- For local development properties end.. -->
</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>
<dependency>
<groupId>redis.clients</groupId>
@ -62,21 +56,21 @@
</dependency>
<!-- For local development dependency begins.. -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-servlet-api</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-api</artifactId>
<version>${tomcat.version}</version>
</dependency>
<!--<dependency>-->
<!--<groupId>apache-tomcat</groupId>-->
<!--<artifactId>catalina</artifactId>-->
<!--<version>${tomcat-catalina.version}</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>apache-tomcat</groupId>-->
<!--<artifactId>servlet-api</artifactId>-->
<!--<version>${tomcat-servlet-api.version}</version>-->
<!--</dependency>-->
<!--<dependency>-->
<!--<groupId>apache-tomcat</groupId>-->
<!--<artifactId>tomcat-api</artifactId>-->
<!--<version>${tomcat-api.version}</version>-->
<!--</dependency>-->
<!-- For local development dependency end.. -->
</dependencies>

View File

@ -45,12 +45,4 @@ public interface DataCache {
* @return - Returns the number of keys that were removed.
*/
Long delete(String key);
/**
* Check the key exists in data-cache.
*
* @param key - key with which the specified value is to be associated.
* @return - Returns true, if the key exists.
*/
Boolean exists(String key);
}

View File

@ -110,12 +110,6 @@ public class StandardDataCache extends RedisCache {
return (value == null) ? 0L : 1L;
}
/** {@inheritDoc} */
@Override
public Boolean exists(String key) {
return this.sessionData.containsKey(key);
}
/** Session data. */
private static class SessionData implements Serializable {
private byte[] value;

View File

@ -24,37 +24,31 @@ public class RedisCache implements DataCache {
/** {@inheritDoc} */
@Override
public byte[] set(String key, byte[] value) {
return this.dataCache.set(key, value);
return dataCache.set(key, value);
}
/** {@inheritDoc} */
@Override
public Long setnx(String key, byte[] value) {
return this.dataCache.setnx(key, value);
return dataCache.setnx(key, value);
}
/** {@inheritDoc} */
@Override
public Long expire(String key, int seconds) {
return this.dataCache.expire(key, seconds);
return dataCache.expire(key, seconds);
}
/** {@inheritDoc} */
@Override
public byte[] get(String key) {
return this.dataCache.get(key);
return dataCache.get(key);
}
/** {@inheritDoc} */
@Override
public Long delete(String key) {
return this.dataCache.delete(key);
}
/** {@inheritDoc} */
@Override
public Boolean exists(String key) {
return this.dataCache.exists(key);
return dataCache.delete(key);
}
private void initialize(Config config) {

View File

@ -115,22 +115,4 @@ class RedisClusterManager extends RedisManager {
} while (retry && tries <= NUM_RETRIES);
return retVal;
}
/** {@inheritDoc} */
@Override
public Boolean exists(String key) {
int tries = 0;
boolean retry = true;
Boolean retVal = null;
do {
tries++;
try {
retVal = this.cluster.exists(key);
retry = false;
} catch (JedisRedirectionException | JedisConnectionException ex) {
handleException(tries, ex);
}
} while (retry && tries <= NUM_RETRIES);
return retVal;
}
}

View File

@ -113,24 +113,6 @@ abstract class RedisManager implements DataCache {
return retVal;
}
/** {@inheritDoc} */
@Override
public Boolean exists(String key) {
int tries = 0;
boolean retry = true;
Boolean retVal = null;
do {
tries++;
try (Jedis jedis = this.pool.getResource()) {
retVal = jedis.exists(key);
retry = false;
} catch (JedisConnectionException ex) {
handleException(tries, ex);
}
} while (retry && tries <= NUM_RETRIES);
return retVal;
}
/**
* To handle jedis exception.
*

View File

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

View File

@ -1,100 +0,0 @@
package tomcat.request.session.model;
import org.apache.catalina.Session;
import org.apache.catalina.authenticator.SingleSignOnListener;
import org.apache.catalina.authenticator.SingleSignOnSessionKey;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.Principal;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/** author: Ranjith Manickam @ 20 Mar' 2020 */
public class SingleSignOnEntry implements Serializable {
private static final long serialVersionUID = 4590485271396917062L;
private String authType;
private String password;
private Principal principal;
private String username;
private boolean canReauthenticate = false;
private final ConcurrentMap<SingleSignOnSessionKey, SingleSignOnSessionKey> sessionKeys;
public SingleSignOnEntry() {
this.sessionKeys = new ConcurrentHashMap<>();
}
public SingleSignOnEntry(Principal principal, String authType, String username, String password) {
this.sessionKeys = new ConcurrentHashMap<>();
this.updateCredentials(principal, authType, username, password);
}
public void addSession(String ssoId, Session session) {
SingleSignOnSessionKey key = new SingleSignOnSessionKey(session);
SingleSignOnSessionKey currentKey = this.sessionKeys.putIfAbsent(key, key);
if (currentKey == null) {
session.addSessionListener(new SingleSignOnListener(ssoId));
}
}
public void removeSession(Session session) {
SingleSignOnSessionKey key = new SingleSignOnSessionKey(session);
this.sessionKeys.remove(key);
}
public Set<SingleSignOnSessionKey> findSessions() {
return this.sessionKeys.keySet();
}
public String getAuthType() {
return this.authType;
}
public boolean getCanReauthenticate() {
return this.canReauthenticate;
}
public String getPassword() {
return this.password;
}
public Principal getPrincipal() {
return this.principal;
}
public String getUsername() {
return this.username;
}
public synchronized void updateCredentials(Principal principal, String authType, String username, String password) {
this.principal = principal;
this.authType = authType;
this.username = username;
this.password = password;
this.canReauthenticate = "BASIC".equals(authType) || "FORM".equals(authType);
}
public void writeObjectData(ObjectOutputStream out) throws IOException {
try (ObjectOutputStream outputStream = new ObjectOutputStream(out)) {
outputStream.writeObject(this);
outputStream.flush();
}
}
public void readObjectData(ObjectInputStream in) throws IOException, ClassNotFoundException {
try (ObjectInputStream inputStream = new ObjectInputStream(in)) {
SingleSignOnEntry entry = (SingleSignOnEntry) inputStream.readObject();
this.authType = entry.authType;
this.password = entry.password;
this.principal = entry.principal;
this.username = entry.username;
this.canReauthenticate = entry.canReauthenticate;
this.sessionKeys.putAll(entry.sessionKeys);
}
}
}

View File

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

View File

@ -17,7 +17,6 @@ import tomcat.request.session.model.Config;
import tomcat.request.session.model.Session;
import tomcat.request.session.model.SessionContext;
import tomcat.request.session.model.SessionMetadata;
import tomcat.request.session.model.SingleSignOnEntry;
import tomcat.request.session.util.ConfigUtil;
import tomcat.request.session.util.SerializationUtil;
@ -32,11 +31,10 @@ public class SessionManager extends ManagerBase implements Lifecycle {
private static final Logger LOGGER = LoggerFactory.getLogger(SessionManager.class);
private Integer ssoTimeout;
private DataCache dataCache;
private SerializationUtil serializer;
private final ThreadLocal<SessionContext> sessionContext = new ThreadLocal<>();
private final Set<SessionPolicy> sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT);
private ThreadLocal<SessionContext> sessionContext = new ThreadLocal<>();
private Set<SessionPolicy> sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT);
public boolean getSaveOnChange() {
return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE);
@ -211,7 +209,6 @@ public class SessionManager extends ManagerBase implements Lifecycle {
private void initialize() {
try {
Config config = ConfigUtil.getConfig();
this.ssoTimeout = config.getRedisSSOTimeout();
this.dataCache = new DataCacheFactory(config, getSessionTimeout(null)).getDataCache();
this.serializer = new SerializationUtil();
@ -338,47 +335,4 @@ public class SessionManager extends ManagerBase implements Lifecycle {
this.sessionPolicy.add(SessionPolicy.fromName(sessionPolicyName));
}
}
/** To set single-sign-on entry to cache. */
void setSingleSignOnEntry(String ssoId, SingleSignOnEntry entry) {
if (entry == null) {
return;
}
try {
byte[] data = this.serializer.serializeSingleSignOnEntry(entry);
this.dataCache.set(ssoId, data);
if (this.ssoTimeout > 0) {
this.dataCache.expire(ssoId, this.ssoTimeout);
}
} catch (IOException ex) {
LOGGER.error("Error occurred while serializing the single-sign-on entry..", ex);
}
}
/** To get single-sign-on entry from cache. */
SingleSignOnEntry getSingleSignOnEntry(String ssoId) {
byte[] data = this.dataCache.get(ssoId);
if (data == null) {
return null;
}
SingleSignOnEntry entry = new SingleSignOnEntry();
try {
this.serializer.deserializeSingleSignOnEntry(data, entry);
} catch (IOException | ClassNotFoundException ex) {
LOGGER.error("Error occurred while de-serializing the single-sign-on entry..", ex);
return null;
}
return entry;
}
/** To check single-sign-on entry exists from cache. */
Boolean singleSignOnEntryExists(String ssoId) {
return this.dataCache.exists(ssoId);
}
/** To delete single-sign-on entry from cache. */
void deleteSingleSignOnEntry(String ssoId) {
this.dataCache.delete(ssoId);
}
}

View File

@ -1,263 +0,0 @@
package tomcat.request.session.redis;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Manager;
import org.apache.catalina.Realm;
import org.apache.catalina.Session;
import org.apache.catalina.authenticator.Constants;
import org.apache.catalina.authenticator.SingleSignOn;
import org.apache.catalina.authenticator.SingleSignOnSessionKey;
import org.apache.catalina.connector.Request;
import org.apache.catalina.connector.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tomcat.request.session.exception.BackendException;
import tomcat.request.session.model.SingleSignOnEntry;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import java.io.IOException;
import java.security.Principal;
import java.util.Set;
/** author: Ranjith Manickam @ 20 Mar' 2020 */
public class SingleSignOnValve extends SingleSignOn {
private static final Logger LOGGER = LoggerFactory.getLogger(SingleSignOnValve.class);
private Engine engine;
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} */
@Override
public void invoke(Request request, Response response) throws BackendException {
try {
this.setSessionManager(request.getContext().getManager());
request.removeNote("org.apache.catalina.request.SSOID");
LOGGER.debug("singleSignOn.debug.invoke, requestURI: {}", request.getRequestURI());
if (request.getUserPrincipal() == null) {
LOGGER.debug("singleSignOn.debug.cookieCheck");
Cookie cookie = null;
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie value : cookies) {
if (Constants.SINGLE_SIGN_ON_COOKIE.equals(value.getName())) {
cookie = value;
break;
}
}
}
if (cookie == null) {
LOGGER.debug("singleSignOn.debug.cookieNotFound");
} else {
LOGGER.debug("singleSignOn.debug.principalCheck, ssoId: {}", cookie.getValue());
SingleSignOnEntry entry = this.manager.getSingleSignOnEntry(cookie.getValue());
if (entry == null) {
LOGGER.debug("singleSignOn.debug.principalNotFound, ssoId: {}", cookie.getValue());
cookie.setValue("REMOVE");
cookie.setMaxAge(0);
cookie.setPath("/");
String domain = this.getCookieDomain();
if (domain != null) {
cookie.setDomain(domain);
}
cookie.setSecure(request.isSecure());
if (request.getServletContext().getSessionCookieConfig().isHttpOnly() || request.getContext().getUseHttpOnly()) {
cookie.setHttpOnly(true);
}
response.addCookie(cookie);
} else {
LOGGER.debug("singleSignOn.debug.principalFound, principal: {}, authType: {}", (entry.getPrincipal() != null ? entry.getPrincipal().getName() : ""), entry.getAuthType());
request.setNote("org.apache.catalina.request.SSOID", cookie.getValue());
if (!this.getRequireReauthentication()) {
request.setAuthType(entry.getAuthType());
request.setUserPrincipal(entry.getPrincipal());
}
}
}
} else {
LOGGER.debug("singleSignOn.debug.hasPrincipal, principal: {}", request.getUserPrincipal().getName());
}
this.getNext().invoke(request, response);
} catch (IOException | ServletException | RuntimeException ex) {
LOGGER.error("Error processing request", ex);
throw new BackendException();
}
}
/** {@inheritDoc} */
@Override
public void sessionDestroyed(String ssoId, Session session) {
if (this.getState().isAvailable()) {
if ((session.getMaxInactiveInterval() <= 0 ||
session.getIdleTimeInternal() < (long) (session.getMaxInactiveInterval() * 1000))
&& session.getManager().getContext().getState().isAvailable()) {
LOGGER.debug("singleSignOn.debug.sessionLogout, session: {}", session);
this.removeSession(ssoId, session);
if (this.manager.singleSignOnEntryExists(ssoId)) {
this.deregister(ssoId);
}
return;
}
LOGGER.debug("singleSignOn.debug.sessionTimeout, ssoId: {}, session: {}", ssoId, session);
this.removeSession(ssoId, session);
}
}
/** {@inheritDoc} */
@Override
protected boolean associate(String ssoId, Session session) {
SingleSignOnEntry entry = this.manager.getSingleSignOnEntry(ssoId);
if (entry == null) {
LOGGER.debug("singleSignOn.debug.associateFail, ssoId: {}, session: {}", ssoId, session);
return false;
}
LOGGER.debug("singleSignOn.debug.associate, ssoId: {}, session: {}", ssoId, session);
entry.addSession(ssoId, session);
this.manager.setSingleSignOnEntry(ssoId, entry);
return true;
}
/** {@inheritDoc} */
@Override
protected void deregister(String ssoId) {
SingleSignOnEntry entry = this.manager.getSingleSignOnEntry(ssoId);
this.manager.deleteSingleSignOnEntry(ssoId);
if (entry == null) {
LOGGER.debug("singleSignOn.debug.deregisterFail, ssoId: {}", ssoId);
return;
}
Set<SingleSignOnSessionKey> ssoKeys = entry.findSessions();
if (ssoKeys.isEmpty()) {
LOGGER.debug("singleSignOn.debug.deregisterNone, ssoId: {}", ssoId);
}
for (SingleSignOnSessionKey ssoKey : ssoKeys) {
this.expire(ssoKey);
LOGGER.debug("singleSignOn.debug.deregister, ssoKey: {}, ssoId: {}", ssoKey, ssoId);
}
}
/** {@inheritDoc} */
@Override
protected boolean reauthenticate(String ssoId, Realm realm, Request request) {
if (ssoId == null || realm == null) {
return false;
}
boolean reAuthenticated = false;
SingleSignOnEntry entry = this.manager.getSingleSignOnEntry(ssoId);
if (entry != null && entry.getCanReauthenticate()) {
String username = entry.getUsername();
if (username != null) {
Principal reAuthPrincipal = realm.authenticate(username, entry.getPassword());
if (reAuthPrincipal != null) {
reAuthenticated = true;
request.setAuthType(entry.getAuthType());
request.setUserPrincipal(reAuthPrincipal);
}
}
}
return reAuthenticated;
}
/** {@inheritDoc} */
@Override
protected void register(String ssoId, Principal principal, String authType, String username, String password) {
LOGGER.debug("singleSignOn.debug.register, ssoId: {}, principal: {}, authType: {}", ssoId, (principal != null ? principal.getName() : ""), authType);
SingleSignOnEntry entry = new SingleSignOnEntry(principal, authType, username, password);
this.manager.setSingleSignOnEntry(ssoId, entry);
}
/** {@inheritDoc} */
@Override
protected boolean update(String ssoId, Principal principal, String authType, String username, String password) {
SingleSignOnEntry entry = this.manager.getSingleSignOnEntry(ssoId);
if (entry == null || !entry.getCanReauthenticate()) {
return false;
}
LOGGER.debug("singleSignOn.debug.update, ssoId: {}, authType: {}", ssoId, authType);
entry.updateCredentials(principal, authType, username, password);
this.manager.setSingleSignOnEntry(ssoId, entry);
return true;
}
/** {@inheritDoc} */
@Override
protected void removeSession(String ssoId, Session session) {
LOGGER.debug("singleSignOn.debug.removeSession, ssoId: {}, session: {}", ssoId, session);
SingleSignOnEntry entry = this.manager.getSingleSignOnEntry(ssoId);
if (entry != null) {
entry.removeSession(session);
if (entry.findSessions().size() == 0) {
this.deregister(ssoId);
}
}
}
/** To set session manager. */
void setSessionManager(Manager manager) {
if (manager != null) {
this.manager = (SessionManager) manager;
}
}
/** To expire session. */
private void expire(SingleSignOnSessionKey key) {
if (this.engine == null) {
LOGGER.warn("singleSignOn.sessionExpire.engineNull, key: {}", key);
} else {
Container host = this.engine.findChild(key.getHostName());
if (host == null) {
LOGGER.warn("singleSignOn.sessionExpire.hostNotFound, key: {}", key);
} else {
Context context = (Context) host.findChild(key.getContextName());
if (context == null) {
LOGGER.warn("singleSignOn.sessionExpire.contextNotFound, key: {}", key);
} else {
Session session;
try {
session = this.manager.findSession(key.getSessionId());
} catch (IOException ex) {
LOGGER.warn("singleSignOn.sessionExpire.managerError, key: {}, exception: {}", key, ex);
return;
}
if (session == null) {
LOGGER.warn("singleSignOn.sessionExpire.sessionNotFound, key: {}", key);
} else {
session.expire();
}
}
}
}
}
}

View File

@ -3,7 +3,6 @@ package tomcat.request.session.util;
import org.apache.catalina.util.CustomObjectInputStream;
import tomcat.request.session.model.Session;
import tomcat.request.session.model.SessionMetadata;
import tomcat.request.session.model.SingleSignOnEntry;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@ -77,25 +76,4 @@ public class SerializationUtil {
session.readObjectData(ois);
}
}
/** To serialize single-sign-on entry. */
public byte[] serializeSingleSignOnEntry(SingleSignOnEntry entry) throws IOException {
byte[] serialized;
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(bos))) {
entry.writeObjectData(oos);
oos.flush();
serialized = bos.toByteArray();
}
return serialized;
}
/** To de-serialize single-sign-on entry. */
public void deserializeSingleSignOnEntry(byte[] data, SingleSignOnEntry entry)
throws IOException, ClassNotFoundException {
try (BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(data));
ObjectInputStream ois = new CustomObjectInputStream(bis, this.loader)) {
entry.readObjectData(ois);
}
}
}

View File

@ -1,33 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
</head>
<body>
<div id="download_summary"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>
$( document ).ready(function() {
$.ajax({
type: "GET",
dataType: "jsonp",
url: "https://api.github.com/repos/ran-jit/tomcat-cluster-redis-session-manager/releases",
success: function(data){
let content = "<table border='1px' style='width: 80%;margin-left: 10%;margin-right: 10%;line-height: 1.5;'><tr><th style='width: 30%;'>tag</th><th>asset name & download count</th></tr>";
for(let i=0; i< data.data.length; i++) {
const tag = data.data[i];
for(var j=0; j< tag.assets.length; j++) {
const asset = tag.assets[j];
content = content + "<tr><td style='width: 10%;'>"+ tag.tag_name + "</td>";
content = content + "<td>" + asset.name + "<div style='text-align:right;'>" + asset.download_count + "</div></td></tr>";
}
}
content = content + "</table>";
document.getElementById("download_summary").innerHTML=content;
}
});
});
</script>
</body>
</html>

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.
# 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
#- single-sign-on session timeout. (default value: 0 ms (-no expiry))
redis.sso.timeout=0