From 39df08832adb30584a7a87284dc64f94b1fb5895 Mon Sep 17 00:00:00 2001 From: Ranjith Manickam Date: Sat, 2 May 2020 14:39:17 +0530 Subject: [PATCH] changes to support single-sign-on (sso) --- .../tomcat/request/session/model/Config.java | 15 +++++++++- .../request/session/redis/SessionManager.java | 17 +++++------ .../session/redis/SingleSignOnValve.java | 28 +++++++++++++------ .../resources/redis-data-cache.properties | 5 +++- 4 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/main/java/tomcat/request/session/model/Config.java b/src/main/java/tomcat/request/session/model/Config.java index f731394..8fe480f 100644 --- a/src/main/java/tomcat/request/session/model/Config.java +++ b/src/main/java/tomcat/request/session/model/Config.java @@ -11,6 +11,8 @@ /** 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. */ @@ -77,6 +79,9 @@ public enum RedisConfigType { @Property(name = "session.persistent.policies", defaultValue = "DEFAULT") private String sessionPersistentPolicies; + @Property(name = "redis.sso.timeout", type = INTEGER, defaultValue = "0") + private Integer redisSSOTimeout; + public Config() { } @@ -98,7 +103,8 @@ public Config(String redisHosts, String redisSentinelMaster, Integer redisSessionExpiryJobInterval, Integer redisSessionDataSyncJobInterval, - String sessionPersistentPolicies) { + String sessionPersistentPolicies, + Integer redisSSOTimeout) { this.redisHosts = redisHosts; this.redisClusterEnabled = redisClusterEnabled; this.redisSentinelEnabled = redisSentinelEnabled; @@ -118,6 +124,7 @@ public Config(String redisHosts, this.redisSessionExpiryJobInterval = redisSessionExpiryJobInterval; this.redisSessionDataSyncJobInterval = redisSessionDataSyncJobInterval; this.sessionPersistentPolicies = sessionPersistentPolicies; + this.redisSSOTimeout = redisSSOTimeout; } /** To get 'redis.hosts' value. */ @@ -215,6 +222,11 @@ public String getSessionPersistentPolicies() { return sessionPersistentPolicies; } + /** To get 'redis.sso.timeout' value */ + public Integer getRedisSSOTimeout() { + return redisSSOTimeout; + } + /** {@inheritDoc} */ @Override public String toString() { @@ -238,6 +250,7 @@ public String toString() { ", redisSessionExpiryJobInterval=" + redisSessionExpiryJobInterval + ", redisSessionDataSyncJobInterval=" + redisSessionDataSyncJobInterval + ", sessionPersistentPolicies='" + sessionPersistentPolicies + '\'' + + ", redisSSOTimeout='" + redisSSOTimeout + '\'' + '}'; } diff --git a/src/main/java/tomcat/request/session/redis/SessionManager.java b/src/main/java/tomcat/request/session/redis/SessionManager.java index 1fd201d..7cfa41c 100644 --- a/src/main/java/tomcat/request/session/redis/SessionManager.java +++ b/src/main/java/tomcat/request/session/redis/SessionManager.java @@ -32,10 +32,11 @@ 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 ThreadLocal sessionContext = new ThreadLocal<>(); - private Set sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT); + private final ThreadLocal sessionContext = new ThreadLocal<>(); + private final Set sessionPolicy = EnumSet.of(SessionPolicy.DEFAULT); public boolean getSaveOnChange() { return this.sessionPolicy.contains(SessionPolicy.SAVE_ON_CHANGE); @@ -78,14 +79,6 @@ protected synchronized void startInternal() throws LifecycleException { initializedValve = true; break; } - - if (valve instanceof SingleSignOnValve) { - SingleSignOnValve ssoValve = (SingleSignOnValve) valve; - ssoValve.setSessionManager(this); - ssoValve.setContext(context); - initializedValve = true; - break; - } } if (!initializedValve) { @@ -218,6 +211,7 @@ public void unload() { private void initialize() { try { Config config = ConfigUtil.getConfig(); + this.ssoTimeout = config.getRedisSSOTimeout(); this.dataCache = new DataCacheFactory(config, getSessionTimeout(null)).getDataCache(); this.serializer = new SerializationUtil(); @@ -353,6 +347,9 @@ void setSingleSignOnEntry(String ssoId, SingleSignOnEntry entry) { 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); } diff --git a/src/main/java/tomcat/request/session/redis/SingleSignOnValve.java b/src/main/java/tomcat/request/session/redis/SingleSignOnValve.java index a6fa489..49f58c1 100644 --- a/src/main/java/tomcat/request/session/redis/SingleSignOnValve.java +++ b/src/main/java/tomcat/request/session/redis/SingleSignOnValve.java @@ -2,6 +2,8 @@ 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; @@ -26,14 +28,27 @@ public class SingleSignOnValve extends SingleSignOn { private static final Logger LOGGER = LoggerFactory.getLogger(SingleSignOnValve.class); - private Context context; + 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.setContext(request.getContext()); this.setSessionManager(request.getContext().getManager()); request.removeNote("org.apache.catalina.request.SSOID"); @@ -213,17 +228,12 @@ void setSessionManager(Manager manager) { this.manager = (SessionManager) manager; } - /** To set context. */ - void setContext(Context context) { - this.context = context; - } - /** To expire session. */ private void expire(SingleSignOnSessionKey key) { - if (this.context == null) { + if (this.engine == null) { LOGGER.warn("singleSignOn.sessionExpire.engineNull, key: {}", key); } else { - Container host = this.context.findChild(key.getHostName()); + Container host = this.engine.findChild(key.getHostName()); if (host == null) { LOGGER.warn("singleSignOn.sessionExpire.hostNotFound, key: {}", key); } else { diff --git a/src/main/resources/redis-data-cache.properties b/src/main/resources/redis-data-cache.properties index 5023ecb..f76167b 100644 --- a/src/main/resources/redis-data-cache.properties +++ b/src/main/resources/redis-data-cache.properties @@ -33,4 +33,7 @@ lb.sticky-session.enabled=false # policies - DEFAULT, SAVE_ON_CHANGE, ALWAYS_SAVE_AFTER_REQUEST # 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 \ No newline at end of file +session.persistent.policies=DEFAULT + +#- single-sign-on session timeout. (default value: 0 ms (-no expiry)) +redis.sso.timeout=0