[SHIRO-668] Catch unexpected errors which can lead to oom
diff --git a/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java b/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java
index 38f5109..657a377 100644
--- a/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java
+++ b/core/src/main/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationScheduler.java
@@ -111,8 +111,17 @@
if (log.isDebugEnabled()) {
log.debug("Executing session validation...");
}
+ Thread.currentThread().setUncaughtExceptionHandler((t, e) -> {
+ log.error("Error while validating the session, the thread will be stopped and session validation disabled", e);
+ this.disableSessionValidation();
+ });
long startTime = System.currentTimeMillis();
- this.sessionManager.validateSessions();
+ try {
+ this.sessionManager.validateSessions();
+ } catch (RuntimeException e) {
+ log.error("Error while validating the session", e);
+ //we don't stop the thread
+ }
long stopTime = System.currentTimeMillis();
if (log.isDebugEnabled()) {
log.debug("Session validation completed successfully in " + (stopTime - startTime) + " milliseconds.");
diff --git a/core/src/test/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationSchedulerTest.java b/core/src/test/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationSchedulerTest.java
new file mode 100644
index 0000000..bb5ba64
--- /dev/null
+++ b/core/src/test/java/org/apache/shiro/session/mgt/ExecutorServiceSessionValidationSchedulerTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.session.mgt;
+
+import org.apache.shiro.session.Session;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ExecutorServiceSessionValidationSchedulerTest {
+
+ ExecutorServiceSessionValidationScheduler executorServiceSessionValidationScheduler;
+ DefaultSessionManager defaultSessionManager;
+
+ @Before
+ public void setUp() {
+ defaultSessionManager = new DefaultSessionManager();
+ defaultSessionManager.setDeleteInvalidSessions(true);
+ executorServiceSessionValidationScheduler = new ExecutorServiceSessionValidationScheduler();
+ executorServiceSessionValidationScheduler.setSessionManager(defaultSessionManager);
+ executorServiceSessionValidationScheduler.setThreadNamePrefix("test-");
+ executorServiceSessionValidationScheduler.setInterval(1000L);
+ executorServiceSessionValidationScheduler.enableSessionValidation();
+ }
+
+ @Test
+ public void timeoutSessionValidate() throws InterruptedException {
+ Session session = new SimpleSession();
+ session.setTimeout(2000L);
+ defaultSessionManager.create(session);
+ Thread.sleep(5000L);
+ Assert.assertTrue(defaultSessionManager.getActiveSessions().isEmpty());
+ Assert.assertTrue(executorServiceSessionValidationScheduler.isEnabled());
+ }
+
+ @Test
+ public void stopSessionValidate() throws InterruptedException {
+ Session session = new SimpleSession();
+ session.setTimeout(10000L);
+ defaultSessionManager.create(session);
+ Thread.sleep(1000L);
+ session.stop();
+ Thread.sleep(3000L);
+ Assert.assertTrue(defaultSessionManager.getActiveSessions().isEmpty());
+ Assert.assertTrue(executorServiceSessionValidationScheduler.isEnabled());
+ }
+
+ @Test
+ public void enableSessionValidation() throws InterruptedException {
+ Assert.assertTrue(executorServiceSessionValidationScheduler.isEnabled());
+ executorServiceSessionValidationScheduler.disableSessionValidation();
+ Thread.sleep(2000L);
+ Assert.assertFalse(executorServiceSessionValidationScheduler.isEnabled());
+ executorServiceSessionValidationScheduler.enableSessionValidation();
+ Thread.sleep(2000L);
+ Assert.assertTrue(executorServiceSessionValidationScheduler.isEnabled());
+ }
+
+ @Test
+ public void threadException() throws InterruptedException {
+ Session session = new SimpleSession();
+ defaultSessionManager = new FakeDefaultSessionManager();
+ defaultSessionManager.setDeleteInvalidSessions(true);
+ executorServiceSessionValidationScheduler = new ExecutorServiceSessionValidationScheduler();
+ executorServiceSessionValidationScheduler.setSessionManager(defaultSessionManager);
+ executorServiceSessionValidationScheduler.setThreadNamePrefix("test-");
+ executorServiceSessionValidationScheduler.setInterval(1000L);
+ executorServiceSessionValidationScheduler.enableSessionValidation();
+ defaultSessionManager.create(session);
+ Thread.sleep(2000L);
+ session.stop();
+ Thread.sleep(2000L);
+ Assert.assertFalse(defaultSessionManager.getActiveSessions().isEmpty());
+ Assert.assertTrue(executorServiceSessionValidationScheduler.isEnabled());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ executorServiceSessionValidationScheduler.disableSessionValidation();
+ }
+
+ private class FakeDefaultSessionManager extends DefaultSessionManager {
+ public void validateSessions() throws RuntimeException {
+ throw new RuntimeException("Session test exception");
+ }
+ }
+}
\ No newline at end of file