SHIRO-361 Added property to support disabling of JSESSIONID in URL
This can be turned off by setting: `sessionManager.sessionIdUrlRewritingEnabled` to false (recommended)
in the shiro.ini (or equivalent configuration)
This is a stop gap on the way to SHIRO-360
diff --git a/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletRequest.java b/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletRequest.java
index 74f5da5..6b71250 100644
--- a/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletRequest.java
+++ b/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletRequest.java
@@ -51,6 +51,7 @@
public static final String REFERENCED_SESSION_IS_NEW = ShiroHttpServletRequest.class.getName() + "_REFERENCED_SESSION_IS_NEW";
public static final String REFERENCED_SESSION_ID_SOURCE = ShiroHttpServletRequest.class.getName() + "REFERENCED_SESSION_ID_SOURCE";
public static final String IDENTITY_REMOVED_KEY = ShiroHttpServletRequest.class.getName() + "_IDENTITY_REMOVED_KEY";
+ public static final String SESSION_ID_URL_REWRITING_ENABLED = ShiroHttpServletRequest.class.getName() + "_SESSION_ID_URL_REWRITING_ENABLED";
protected ServletContext servletContext = null;
diff --git a/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletResponse.java b/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletResponse.java
index 438b3e6..744a736 100644
--- a/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletResponse.java
+++ b/web/src/main/java/org/apache/shiro/web/servlet/ShiroHttpServletResponse.java
@@ -136,6 +136,10 @@
*/
protected boolean isEncodeable(final String location) {
+ // First check if URL rewriting is disabled globally
+ if (Boolean.FALSE.equals(request.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)))
+ return (false);
+
if (location == null)
return (false);
diff --git a/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java b/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java
index f8baf11..eb7eda1 100644
--- a/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java
+++ b/web/src/main/java/org/apache/shiro/web/session/mgt/DefaultWebSessionManager.java
@@ -51,12 +51,14 @@
private Cookie sessionIdCookie;
private boolean sessionIdCookieEnabled;
+ private boolean sessionIdUrlRewritingEnabled;
public DefaultWebSessionManager() {
Cookie cookie = new SimpleCookie(ShiroHttpSession.DEFAULT_SESSION_ID_NAME);
cookie.setHttpOnly(true); //more secure, protects against XSS attacks
this.sessionIdCookie = cookie;
this.sessionIdCookieEnabled = true;
+ this.sessionIdUrlRewritingEnabled = true;
}
public Cookie getSessionIdCookie() {
@@ -77,6 +79,15 @@
this.sessionIdCookieEnabled = sessionIdCookieEnabled;
}
+ public boolean isSessionIdUrlRewritingEnabled() {
+ return sessionIdUrlRewritingEnabled;
+ }
+
+ @SuppressWarnings({"UnusedDeclaration"})
+ public void setSessionIdUrlRewritingEnabled(boolean sessionIdUrlRewritingEnabled) {
+ this.sessionIdUrlRewritingEnabled = sessionIdUrlRewritingEnabled;
+ }
+
private void storeSessionId(Serializable currentId, HttpServletRequest request, HttpServletResponse response) {
if (currentId == null) {
String msg = "sessionId cannot be null when persisting for subsequent requests.";
@@ -139,6 +150,10 @@
//onUnknownSession method below will be invoked and we'll remove the attribute at that time.
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
}
+
+ // always set rewrite flag - SHIRO-361
+ request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, isSessionIdUrlRewritingEnabled());
+
return id;
}
diff --git a/web/src/test/groovy/org/apache/shiro/web/servlet/ShiroHttpServletResponseTest.groovy b/web/src/test/groovy/org/apache/shiro/web/servlet/ShiroHttpServletResponseTest.groovy
new file mode 100644
index 0000000..a26dca7
--- /dev/null
+++ b/web/src/test/groovy/org/apache/shiro/web/servlet/ShiroHttpServletResponseTest.groovy
@@ -0,0 +1,166 @@
+/*
+ * 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.web.servlet
+
+import org.junit.Test
+
+import javax.servlet.ServletContext
+import javax.servlet.http.HttpServletResponse
+import javax.servlet.http.HttpSession
+
+import static org.easymock.EasyMock.*
+import static org.junit.Assert.*
+
+/**
+ * Unit tests for {@link ShiroHttpServletResponse}.
+ */
+class ShiroHttpServletResponseTest {
+
+ private static String URL_SESSION_ID = "url_session_id"
+
+ @Test
+ void testEncodeURLNoSessionId() {
+
+ def servletContext = createStrictMock(ServletContext)
+ def httpServletResponse = createStrictMock(HttpServletResponse)
+ def shiroHttpServletRequest = setupRequestMock()
+ expect(shiroHttpServletRequest.getSession(false)).andReturn(null)
+ expect(shiroHttpServletRequest.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)).andReturn(true)
+ replay shiroHttpServletRequest, servletContext, httpServletResponse
+
+ def shiroHttpServletResponse = new ShiroHttpServletResponse(httpServletResponse, servletContext, shiroHttpServletRequest)
+
+ assertEquals "/foobar", shiroHttpServletResponse.encodeURL("/foobar")
+ verify shiroHttpServletRequest, servletContext, httpServletResponse
+ }
+
+ @Test
+ void testEncodeURLSessionIdInURL() {
+
+ def servletContext = createStrictMock(ServletContext)
+ def httpServletResponse = createStrictMock(HttpServletResponse)
+ def session = createMock(HttpSession)
+ def shiroHttpServletRequest = setupRequestMock()
+ expect(session.getId()).andReturn(URL_SESSION_ID).anyTimes()
+ expect(shiroHttpServletRequest.getSession(false)).andReturn(session)
+ expect(shiroHttpServletRequest.getSession()).andReturn(session)
+ expect(shiroHttpServletRequest.isRequestedSessionIdFromCookie()).andReturn(false)
+ expect(shiroHttpServletRequest.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)).andReturn(true)
+ replay shiroHttpServletRequest, servletContext, httpServletResponse, session
+
+ def shiroHttpServletResponse = new ShiroHttpServletResponse(httpServletResponse, servletContext, shiroHttpServletRequest)
+
+ assertEquals "/foobar;JSESSIONID=" + URL_SESSION_ID, shiroHttpServletResponse.encodeURL("/foobar")
+ verify shiroHttpServletRequest, servletContext, httpServletResponse, session
+ }
+
+ @Test
+ void testEncodeURLSessionIdInCookie() {
+
+ def servletContext = createStrictMock(ServletContext)
+ def httpServletResponse = createStrictMock(HttpServletResponse)
+ def session = createMock(HttpSession)
+ def shiroHttpServletRequest = setupRequestMock()
+ expect(shiroHttpServletRequest.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)).andReturn(false)
+ replay shiroHttpServletRequest, servletContext, httpServletResponse, session
+
+ def shiroHttpServletResponse = new ShiroHttpServletResponse(httpServletResponse, servletContext, shiroHttpServletRequest)
+
+ assertEquals "/foobar", shiroHttpServletResponse.encodeURL("/foobar")
+ verify shiroHttpServletRequest, servletContext, httpServletResponse, session
+ }
+
+ @Test
+ void testEncodeURLSessionIdInWhenRewriteDisabled() {
+
+ def servletContext = createStrictMock(ServletContext)
+ def httpServletResponse = createStrictMock(HttpServletResponse)
+ def session = createMock(HttpSession)
+ def shiroHttpServletRequest = setupRequestMock()
+ expect(shiroHttpServletRequest.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)).andReturn(false)
+ replay shiroHttpServletRequest, servletContext, httpServletResponse, session
+
+ def shiroHttpServletResponse = new ShiroHttpServletResponse(httpServletResponse, servletContext, shiroHttpServletRequest)
+
+ assertEquals "/foobar", shiroHttpServletResponse.encodeURL("/foobar")
+ verify shiroHttpServletRequest, servletContext, httpServletResponse, session
+ }
+
+ /**
+ * Tests if the request attribute {@link ShiroHttpServletRequest}.SESSION_ID_URL_REWRITING_ENABLED is not false
+ * boolean, the default behavior is to encode the URL.
+ */
+ @Test
+ void testEncodeURLSessionIdInWhenRewriteInvalid() {
+
+ def servletContext = createStrictMock(ServletContext)
+ def httpServletResponse = createStrictMock(HttpServletResponse)
+ def session = createMock(HttpSession)
+ def shiroHttpServletRequest = setupRequestMock()
+ expect(session.getId()).andReturn(URL_SESSION_ID).anyTimes()
+ expect(shiroHttpServletRequest.getSession(false)).andReturn(session)
+ expect(shiroHttpServletRequest.getSession()).andReturn(session)
+ expect(shiroHttpServletRequest.isRequestedSessionIdFromCookie()).andReturn(false)
+ expect(shiroHttpServletRequest.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)).andReturn("something-else")
+ replay shiroHttpServletRequest, servletContext, httpServletResponse, session
+
+ def shiroHttpServletResponse = new ShiroHttpServletResponse(httpServletResponse, servletContext, shiroHttpServletRequest)
+
+ assertEquals "/foobar;JSESSIONID=" + URL_SESSION_ID, shiroHttpServletResponse.encodeURL("/foobar")
+ verify shiroHttpServletRequest, servletContext, httpServletResponse, session
+ }
+
+ /**
+ * Tests if the request attribute {@link ShiroHttpServletRequest}.SESSION_ID_URL_REWRITING_ENABLED is null,
+ * the default behavior is NOT to encode the URL.
+ */
+ @Test
+ void testEncodeURLSessionIdInWhenRewriteInvalidAndNull() {
+
+ def servletContext = createStrictMock(ServletContext)
+ def httpServletResponse = createStrictMock(HttpServletResponse)
+ def session = createMock(HttpSession)
+ def shiroHttpServletRequest = setupRequestMock()
+ expect(session.getId()).andReturn(URL_SESSION_ID).anyTimes()
+ expect(shiroHttpServletRequest.getSession(false)).andReturn(session)
+ expect(shiroHttpServletRequest.getSession()).andReturn(session)
+ expect(shiroHttpServletRequest.isRequestedSessionIdFromCookie()).andReturn(false)
+ expect(shiroHttpServletRequest.getAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED)).andReturn(null)
+ replay shiroHttpServletRequest, servletContext, httpServletResponse, session
+
+ def shiroHttpServletResponse = new ShiroHttpServletResponse(httpServletResponse, servletContext, shiroHttpServletRequest)
+
+ assertEquals "/foobar;JSESSIONID=" + URL_SESSION_ID, shiroHttpServletResponse.encodeURL("/foobar")
+ verify shiroHttpServletRequest, servletContext, httpServletResponse, session
+ }
+
+
+ private static ShiroHttpServletRequest setupRequestMock() {
+ def shiroHttpServletRequest = createMock(ShiroHttpServletRequest)
+
+ expect(shiroHttpServletRequest.getScheme()).andReturn("http").anyTimes()
+ expect(shiroHttpServletRequest.getServerName()).andReturn("localhost").anyTimes()
+ expect(shiroHttpServletRequest.getServerPort()).andReturn(8080).anyTimes()
+ expect(shiroHttpServletRequest.getContextPath()).andReturn("/").anyTimes()
+
+
+ return shiroHttpServletRequest
+ }
+
+}
diff --git a/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy b/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
index f06762b..526636c 100644
--- a/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
+++ b/web/src/test/groovy/org/apache/shiro/web/session/mgt/DefaultWebSessionManagerTest.groovy
@@ -126,6 +126,7 @@
ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
+ request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.TRUE);
replay(cookie);
replay(request);
@@ -160,6 +161,7 @@
ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
+ request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.TRUE);
replay(cookie);
replay(request);
@@ -195,6 +197,7 @@
ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
+ request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.TRUE);
replay(cookie);
replay(request);
@@ -225,6 +228,7 @@
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, ShiroHttpServletRequest.URL_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
+ request.setAttribute(ShiroHttpServletRequest.SESSION_ID_URL_REWRITING_ENABLED, Boolean.TRUE);
replay(request);
replay(response);