You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jena.apache.org by an...@apache.org on 2026/07/07 11:00:29 UTC
(jena) 02/02: GH-4033: Disable sessions
This is an automated email from the ASF dual-hosted git repository.
afs pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
commit 05a06f44631f3a0d7ea8ab449c70f066ebbbfe6b
Author: Andy Seaborne <an...@apache.org>
AuthorDate: Fri Jul 3 17:05:11 2026 +0100
GH-4033: Disable sessions
---
.../apache/jena/fuseki/mod/shiro/FMod_Shiro.java | 109 +++++++++++----------
.../apache/jena/fuseki/mod/shiro/FusekiShiro.java | 8 +-
...a => FusekiShiroEnvironmentLoaderListener.java} | 8 +-
.../jena/fuseki/mod/shiro/FusekiShiroFilter.java | 74 ++++++++++++++
4 files changed, 142 insertions(+), 57 deletions(-)
diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java
index 675a4b09d6..da8acf965e 100644
--- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java
+++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FMod_Shiro.java
@@ -26,23 +26,23 @@ import java.util.List;
import java.util.Set;
import jakarta.servlet.Filter;
-import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpSessionEvent;
+import jakarta.servlet.http.HttpSessionListener;
import org.apache.jena.atlas.io.IOX;
import org.apache.jena.atlas.lib.Lib;
import org.apache.jena.atlas.logging.FmtLog;
+import org.apache.jena.atlas.logging.Log;
import org.apache.jena.cmd.ArgDecl;
import org.apache.jena.cmd.CmdException;
import org.apache.jena.cmd.CmdGeneral;
import org.apache.jena.fuseki.Fuseki;
import org.apache.jena.fuseki.FusekiConfigException;
-import org.apache.jena.fuseki.FusekiException;
import org.apache.jena.fuseki.main.FusekiServer;
import org.apache.jena.fuseki.main.runner.ServerArgs;
import org.apache.jena.fuseki.main.sys.FusekiModule;
import org.apache.jena.fuseki.mgt.FusekiServerCtl;
import org.apache.jena.rdf.model.Model;
import org.apache.shiro.lang.io.ResourceUtils;
-import org.apache.shiro.web.servlet.ShiroFilter;
import org.eclipse.jetty.ee11.servlet.ServletContextHandler;
import org.eclipse.jetty.ee11.servlet.SessionHandler;
import org.slf4j.Logger;
@@ -77,12 +77,25 @@ public class FMod_Shiro implements FusekiModule {
/** Shiro configuration file given a a command line argument. */
private String argShiroFile = null;
+ /** Control for whether to have Jetty/Jakarta sessions,
+ * which are then used by Shiro.
+ * But they don't get cleared up and keep hold of RAM.
+ * See <a href="https://github.com/apache/jena/issues/4033">GH-4033</a>.
+ * <p>
+ * If {@code true}, then disable Shiro session creation on every request,
+ * and don't create a Jetty sever session manager.
+ * <p>
+ * It the future, it is likely that this flag is dropped
+ * and the code support only "disabled sessions".
+ */
+ private static final boolean DISABLE_SESSIONS = false;
+
public FMod_Shiro() {}
// ---- If used from the command line
@Override
public void serverArgsModify(CmdGeneral fusekiCmd, ServerArgs serverArgs) {
- fusekiCmd.add(argShiroIni);
+ fusekiCmd.add(argShiroIni, "--shiro", "Set the shiro.ini file");
argShiroFile = null;
}
@@ -117,7 +130,7 @@ public class FMod_Shiro implements FusekiModule {
if ( shiroConfig != null )
return shiroConfig;
- // Environment variable: FUSEKI_SHIRO
+ // Environment variable: FUSEKI_SHIRO
shiroConfig = Lib.getenv(FusekiServerCtl.envFusekiShiro);
if ( shiroConfig != null )
return shiroConfig;
@@ -144,83 +157,73 @@ public class FMod_Shiro implements FusekiModule {
if ( shiroConfig == null )
return;
- // Shiro prints stack traces and exceptions. Rather than silence
- //checkShiroConfiguration(shiroConfig);
-
// Shiro-style.
String shiroResourceName = FusekiShiro.withResourcePrefix(shiroConfig);
if ( ! ResourceUtils.resourceExists(shiroResourceName) )
throw new FusekiConfigException("Shiro resource does not exist");
- Filter filter = new FusekiShiroFilter(shiroResourceName);
+
+ Filter filter = new FusekiShiroFilter(shiroResourceName, DISABLE_SESSIONS);
// This is a "before" filter.
serverBuilder.addFilter("/*", filter);
serverBuilder.setServletAttribute(Fuseki.attrShiroResource, shiroResourceName);
-
// Clear.
this.argShiroFile = null;
}
- /**
- * FusekiShiroFilter, includes Shiro initialization. Fuseki is a
- * not a webapp so it needs to trigger off servlet initialization.
- */
- private static class FusekiShiroFilter extends ShiroFilter {
-
- private final String shiroInitializationResource;
-
- FusekiShiroFilter(String shiroResourceName) {
- // Shiro file -- URLs are "file:<no encoding>"
- shiroInitializationResource = shiroResourceName;
- }
-
- @Override
- public void init() throws Exception {
- try {
- // Intercept Shiro initialization.
- List<String> locations = List.of();
- if ( shiroInitializationResource != null ) {
- locations = List.of(shiroInitializationResource);
- }
- FusekiShiro.shiroEnvironment(getServletContext(), locations);
- } catch (FusekiException ex) {
- // Wrap so ShiroFilter does not log it.
- throw new ServletException(ex);
- }
- super.init();
- }
- }
-
@Override
public void serverBeforeStarting(FusekiServer server) {
try {
String x =(String)server.getServletContext().getAttribute(Fuseki.attrShiroResource);
if ( x != null )
FmtLog.info(shiroConfigLog, "Shiro configuration: %s", x);
-// else
-// FmtLog.info(shiroConfigLog, "No Shiro configuration");
+ // else
+ // FmtLog.info(shiroConfigLog, "No Shiro configuration");
} catch (ClassCastException ex) {
FmtLog.warn(shiroConfigLog, "Unexpected Shiro configuration: %s", server.getServletContext().getAttribute(Fuseki.attrShiroResource));
}
- // Shiro requires a session handler.
- // This needs the Jetty server to have been created.
- org.eclipse.jetty.server.Server jettyServer = server.getJettyServer();
- try {
- ServletContextHandler servletContextHandler = (ServletContextHandler)(jettyServer.getHandler());
- if ( servletContextHandler.getSessionHandler() == null ) {
- SessionHandler sessionsHandler = new SessionHandler();
- servletContextHandler.setHandler(sessionsHandler);
+ if ( ! DISABLE_SESSIONS ) {
+ // If shiro requires a session handler.
+ // This needs the Jetty server to have been created.
+ // Allocate a Jakarta SessionHandler
+ try {
+ org.eclipse.jetty.server.Server jettyServer = server.getJettyServer();
+
+ ServletContextHandler servletContextHandler = (ServletContextHandler)(jettyServer.getHandler());
+ if ( servletContextHandler.getSessionHandler() == null ) {
+ SessionHandler sessionHandler = new SessionHandler();
+ if ( true )
+ addHttpSessionListener(sessionHandler);
+ servletContextHandler.setHandler(sessionHandler);
+ }
+ } catch (RuntimeException ex) {
+ shiroConfigLog.error("Failed to set a session manager - server aborted");
+ throw ex;
}
- } catch (RuntimeException ex) {
- shiroConfigLog.error("Failed to set a session manager - server aborted");
- throw ex;
}
}
+
// Later:
// Reload shirio.ini file and reset.
// // Currently, no actual - the server admin area does not move during the run of a server.
// /** {@inheritDoc} */
// @Override
// public void serverReload(FusekiServer server) { }
+
+
+ private static void addHttpSessionListener( SessionHandler sessionHandler) {
+ // Development
+ HttpSessionListener httpSessionListener = new HttpSessionListener() {
+ @Override
+ public void sessionCreated(HttpSessionEvent se) {
+ Log.info(Fuseki.serverLog, "Jakarta session created");
+ }
+ @Override
+ public void sessionDestroyed(HttpSessionEvent se) {
+ Log.info(Fuseki.serverLog, "Jakarta session destroyed");
+ }
+ };
+ sessionHandler.addEventListener(httpSessionListener);
+ }
}
diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiro.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiro.java
index 1b6424db40..2d418c859e 100644
--- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiro.java
+++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiro.java
@@ -39,7 +39,7 @@ import org.slf4j.LoggerFactory;
static void shiroEnvironment(ServletContext servletContext, List<String> possibleShiroIniFiles) {
// Shiro environment initialization, done here because we don't have webapp listeners.
- EnvironmentLoaderListener shiroListener = new ShiroEnvironmentLoaderListener(possibleShiroIniFiles);
+ EnvironmentLoaderListener shiroListener = new FusekiShiroEnvironmentLoaderListener(possibleShiroIniFiles);
// Silence these - handle the errors ourselves.
LogCtl.disable(org.apache.shiro.web.env.IniWebEnvironment.class);
LogCtl.disable(org.apache.shiro.web.env.EnvironmentLoader.class);
@@ -83,6 +83,9 @@ import org.slf4j.LoggerFactory;
return null;
}
+ /**
+ * Ensure a filename is formatted the way SHiro wants it.
+ */
public static String withResourcePrefix(String shiroFileName) {
if ( shiroFileName.startsWith(fileShiroPrefix) )
return shiroFileName;
@@ -90,6 +93,9 @@ import org.slf4j.LoggerFactory;
return fileShiroPrefix+shiroFileName;
}
+ /**
+ * Reverse formatting a file mae. See {@link #withResourcePrefix}.
+ */
public static String removeResourcePrefix(String shiroFileResource) {
if ( shiroFileResource.startsWith(fileShiroPrefix) ) {
// Shiro format resource name.
diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/ShiroEnvironmentLoaderListener.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiroEnvironmentLoaderListener.java
similarity index 92%
rename from jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/ShiroEnvironmentLoaderListener.java
rename to jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiroEnvironmentLoaderListener.java
index 514798467d..72c02e2827 100644
--- a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/ShiroEnvironmentLoaderListener.java
+++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiroEnvironmentLoaderListener.java
@@ -34,11 +34,11 @@ import org.apache.shiro.web.env.WebEnvironment;
* locations for a {@code shiro.ini} file. It will return the first found in a list
* of possible file names.
*/
-class ShiroEnvironmentLoaderListener extends EnvironmentLoaderListener{
+class FusekiShiroEnvironmentLoaderListener extends EnvironmentLoaderListener{
private List<String> locations;
- /*package*/ ShiroEnvironmentLoaderListener(List<String> locations) {
+ /*package*/ FusekiShiroEnvironmentLoaderListener(List<String> locations) {
this.locations = locations;
}
@@ -51,8 +51,10 @@ class ShiroEnvironmentLoaderListener extends EnvironmentLoaderListener{
*/
@Override
protected void customizeEnvironment(WebEnvironment environment) {
- if ( locations == null )
+ if ( locations == null ) {
+ super.customizeEnvironment(environment);
return;
+ }
// Look for shiro.ini
if ( environment instanceof ResourceBasedWebEnvironment ) {
diff --git a/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiroFilter.java b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiroFilter.java
new file mode 100644
index 0000000000..dbcd5fe984
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-main/src/main/java/org/apache/jena/fuseki/mod/shiro/FusekiShiroFilter.java
@@ -0,0 +1,74 @@
+/*
+ * 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
+ *
+ * https://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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.apache.jena.fuseki.mod.shiro;
+
+import java.util.List;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import org.apache.jena.fuseki.FusekiException;
+import org.apache.shiro.subject.support.DefaultSubjectContext;
+import org.apache.shiro.web.servlet.ShiroFilter;
+
+/**
+ * FusekiShiroFilter, includes Shiro initialization. Fuseki is a
+ * not a webapp so it needs to trigger off servlet initialization.
+ */
+/*package*/ class FusekiShiroFilter extends ShiroFilter {
+
+ private final String shiroInitializationResource;
+ private final boolean disableSessions;
+
+ /*package*/ FusekiShiroFilter(String shiroResourceName, boolean disableSessions) {
+ // Shiro file -- URLs are "file:<no encoding>"
+ this.shiroInitializationResource = shiroResourceName;
+ this.disableSessions = disableSessions;
+ }
+
+ @Override
+ public void init() throws Exception {
+ try {
+ // Intercept Shiro initialization.
+ List<String> locations = List.of();
+ if ( shiroInitializationResource != null ) {
+ locations = List.of(shiroInitializationResource);
+ }
+ FusekiShiro.shiroEnvironment(getServletContext(), locations);
+ } catch (FusekiException ex) {
+ // Wrap so ShiroFilter does not log it.
+ throw new ServletException(ex);
+ }
+ super.init();
+ }
+
+ @Override
+ protected ServletRequest prepareServletRequest(ServletRequest request, ServletResponse response, FilterChain chain) {
+ if ( disableSessions ) {
+ // GH-4033 : https://github.com/apache/jena/issues/4033
+ // See NoSessionCreationFilter
+ request.setAttribute(DefaultSubjectContext.SESSION_CREATION_ENABLED, Boolean.FALSE);
+ }
+ return super.prepareServletRequest(request, response, chain);
+ }
+}
\ No newline at end of file