SEC-1754: Added an InvalidSessionStrategy to allow SessionManagementFilter to delegate out the behaviour when an invalid session identifier is submitted.

This commit is contained in:
Luke Taylor 2011-07-14 16:29:43 +01:00
parent ac3d8b25f2
commit a1c714cff4
8 changed files with 101 additions and 33 deletions

View File

@ -46,6 +46,7 @@ import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.security.web.session.SimpleRedirectInvalidSessionStrategy;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@ -270,7 +271,7 @@ class HttpConfigurationBuilder {
}
if (StringUtils.hasText(invalidSessionUrl)) {
sessionMgmtFilter.addPropertyValue("invalidSessionUrl", invalidSessionUrl);
sessionMgmtFilter.addPropertyValue("invalidSessionStrategy", new SimpleRedirectInvalidSessionStrategy(invalidSessionUrl));
}
sessionMgmtFilter.addPropertyReference("sessionAuthenticationStrategy", sessionAuthStratRef);

View File

@ -124,7 +124,7 @@ class SessionManagementConfigTests extends AbstractHttpConfigTests {
Object sessionRegistryFromFormLoginFilter = FieldUtils.getFieldValue(
getFilter(UsernamePasswordAuthenticationFilter.class),"sessionStrategy.sessionRegistry");
Object sessionRegistryFromMgmtFilter = FieldUtils.getFieldValue(
getFilter(SessionManagementFilter.class),"sessionStrategy.sessionRegistry");
getFilter(SessionManagementFilter.class),"sessionAuthenticationStrategy.sessionRegistry");
assertSame(sessionRegistry, sessionRegistryFromConcurrencyFilter);
assertSame(sessionRegistry, sessionRegistryFromMgmtFilter);
@ -183,7 +183,7 @@ class SessionManagementConfigTests extends AbstractHttpConfigTests {
expect:
filter instanceof SessionManagementFilter
filter.invalidSessionUrl == '/timeoutUrl'
filter.invalidSessionStrategy.destinationUrl == '/timeoutUrl'
}
}

View File

@ -404,6 +404,14 @@
configured <classname>DefaultSessionAuthenticationStrategy</classname>. See the
Javadoc for this class for more details. </para>
</section>
<section xml:id="nsa-invalid-session-url">
<title><literal>invalid-session-url</literal></title>
<para>Setting this attribute will inject the <classname>SessionManagementFilter</classname>
with a <classname>SimpleRedirectInvalidSessionStrategy</classname> configured with
the attribute value. When an invalid session ID is submitted, the strategy will be invoked,
redirecting to the configured URL.
</para>
</section>
</section>
<section xml:id="nsa-concurrent-session-control">
<title>The <literal>&lt;concurrency-control&gt;</literal> Element</title>

View File

@ -28,10 +28,12 @@
invoke the configured
<interfacename>SessionAuthenticationStrategy</interfacename>.</para>
<para>If the user is not currently authenticated, the filter will check whether an invalid
session ID has been requested (because of a timeout, for example) and will redirect to
the configured <literal>invalidSessionUrl</literal> if set. The easiest way to configure
this is through the namespace, <link xlink:href="#ns-session-mgmt">as described
earlier</link>.</para>
session ID has been requested (because of a timeout, for example) and will invoke the configured
<interfacename>InvalidSessionStrategy</interfacename>, if one is set. The most common behaviour
is just to redirect to a fixed URL and this is encapsulated in the standard implementation
<classname>SimpleRedirectInvalidSessionStrategy</classname>. The latter is also used
when configuring an invalid session URL through the namespace,
<link xlink:href="#ns-session-mgmt">as described earlier</link>.</para>
</section>
<section>
<title><interfacename>SessionAuthenticationStrategy</interfacename></title>

View File

@ -0,0 +1,18 @@
package org.springframework.security.web.session;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Determines the behaviour of the {@code SessionManagementFilter} when an invalid session Id is submitted and
* detected in the {@code SessionManagementFilter}.
*
* @author Luke Taylor
*/
public interface InvalidSessionStrategy {
void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
}

View File

@ -13,8 +13,6 @@ import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
@ -41,11 +39,10 @@ public class SessionManagementFilter extends GenericFilterBean {
//~ Instance fields ================================================================================================
private final SecurityContextRepository securityContextRepository;
private SessionAuthenticationStrategy sessionStrategy;
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private final AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
private String invalidSessionUrl;
private InvalidSessionStrategy invalidSessionStrategy = null;
private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
public SessionManagementFilter(SecurityContextRepository securityContextRepository) {
this(securityContextRepository, new SessionFixationProtectionStrategy());
@ -55,7 +52,7 @@ public class SessionManagementFilter extends GenericFilterBean {
Assert.notNull(securityContextRepository, "SecurityContextRepository cannot be null");
Assert.notNull(sessionStrategy, "SessionAuthenticationStrategy cannot be null");
this.securityContextRepository = securityContextRepository;
this.sessionStrategy = sessionStrategy;
this.sessionAuthenticationStrategy = sessionStrategy;
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
@ -76,7 +73,7 @@ public class SessionManagementFilter extends GenericFilterBean {
if (authentication != null && !authenticationTrustResolver.isAnonymous(authentication)) {
// The user has been authenticated during the current request, so call the session strategy
try {
sessionStrategy.onAuthentication(authentication, request, response);
sessionAuthenticationStrategy.onAuthentication(authentication, request, response);
} catch (SessionAuthenticationException e) {
// The session strategy can reject the authentication
logger.debug("SessionAuthenticationStrategy rejected the authentication object", e);
@ -93,11 +90,8 @@ public class SessionManagementFilter extends GenericFilterBean {
if (request.getRequestedSessionId() != null && !request.isRequestedSessionIdValid()) {
logger.debug("Requested session ID" + request.getRequestedSessionId() + " is invalid.");
if (invalidSessionUrl != null) {
logger.debug("Starting new session (if required) and redirecting to '" + invalidSessionUrl + "'");
request.getSession();
redirectStrategy.sendRedirect(request, response, invalidSessionUrl);
if (invalidSessionStrategy != null) {
invalidSessionStrategy.onInvalidSessionDetected(request, response);
return;
}
}
@ -115,19 +109,19 @@ public class SessionManagementFilter extends GenericFilterBean {
* @deprecated Use constructor injection
*/
@Deprecated
public void setSessionAuthenticationStrategy(SessionAuthenticationStrategy sessionStrategy) {
Assert.notNull(sessionStrategy, "authenticatedSessionStratedy must not be null");
this.sessionStrategy = sessionStrategy;
public void setSessionAuthenticationStrategy(SessionAuthenticationStrategy sessionAuthenticationStrategy) {
Assert.notNull(sessionAuthenticationStrategy, "authenticatedSessionStratedy must not be null");
this.sessionAuthenticationStrategy = sessionAuthenticationStrategy;
}
/**
* Sets the URL to which the response should be redirected if the user agent requests an invalid session Id.
* If the property is not set, no action will be taken.
* Sets the strategy which will be invoked instead of allowing the filter chain to prceed, if the user agent
* requests an invalid session Id. If the property is not set, no action will be taken.
*
* @param invalidSessionUrl
* @param invalidSessionStrategy the strategy to invoke. Typically a {@link SimpleRedirectInvalidSessionStrategy}.
*/
public void setInvalidSessionUrl(String invalidSessionUrl) {
this.invalidSessionUrl = invalidSessionUrl;
public void setInvalidSessionStrategy(InvalidSessionStrategy invalidSessionStrategy) {
this.invalidSessionStrategy = invalidSessionStrategy;
}
/**
@ -140,8 +134,4 @@ public class SessionManagementFilter extends GenericFilterBean {
Assert.notNull(failureHandler, "failureHandler cannot be null");
this.failureHandler = failureHandler;
}
public void setRedirectStrategy(RedirectStrategy redirectStrategy) {
this.redirectStrategy = redirectStrategy;
}
}

View File

@ -0,0 +1,48 @@
package org.springframework.security.web.session;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Performs a redirect to a fixed URL when an invalid requested session is detected by the {@code SessionManagementFilter}.
*
* @author Luke Taylor
*/
public final class SimpleRedirectInvalidSessionStrategy implements InvalidSessionStrategy {
private final Log logger = LogFactory.getLog(getClass());
private final String destinationUrl;
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private boolean createNewSession = true;
public SimpleRedirectInvalidSessionStrategy(String invalidSessionUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(invalidSessionUrl), "url must start with '/' or with 'http(s)'");
this.destinationUrl = invalidSessionUrl;
}
public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse response) throws IOException {
logger.debug("Starting new session (if required) and redirecting to '" + destinationUrl + "'");
if (createNewSession) {
request.getSession();
}
redirectStrategy.sendRedirect(request, response, destinationUrl);
}
/**
* Determines whether a new session should be created before redirecting (to avoid possible looping issues where
* the same session ID is sent with the redirected request). Alternatively, ensure that the configured URL
* does not pass through the {@code SessionManagementFilter}.
*
* @param createNewSession defaults to {@code true}.
*/
public void setCreateNewSession(boolean createNewSession) {
this.createNewSession = createNewSession;
}
}

View File

@ -121,7 +121,6 @@ public class SessionManagementFilterTests {
SessionAuthenticationStrategy strategy = mock(SessionAuthenticationStrategy.class);
SessionManagementFilter filter = new SessionManagementFilter(repo);
filter.setSessionAuthenticationStrategy(strategy);
filter.setRedirectStrategy(new DefaultRedirectStrategy());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setRequestedSessionId("xxx");
request.setRequestedSessionIdValid(false);
@ -134,7 +133,9 @@ public class SessionManagementFilterTests {
request = new MockHttpServletRequest();
request.setRequestedSessionId("xxx");
request.setRequestedSessionIdValid(false);
filter.setInvalidSessionUrl("/timedOut");
SimpleRedirectInvalidSessionStrategy iss = new SimpleRedirectInvalidSessionStrategy("/timedOut");
iss.setCreateNewSession(true);
filter.setInvalidSessionStrategy(iss);
FilterChain fc = mock(FilterChain.class);
filter.doFilter(request, response, fc);
verifyZeroInteractions(fc);