Skip to content

Commit

Permalink
Add ContinueRequestSessionInformationExpiredStrategy
Browse files Browse the repository at this point in the history
- continues to execute subsequent filters even after session expiration.
- Issue #14077
  • Loading branch information
Ilpyo-Yang committed Apr 14, 2024
1 parent 2fbbcc4 commit 724d895
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ private void doFilter(HttpServletRequest request, HttpServletResponse response,
.of(() -> "Requested session ID " + request.getRequestedSessionId() + " has expired."));
doLogout(request, response);
this.sessionInformationExpiredStrategy
.onExpiredSessionDetected(new SessionInformationExpiredEvent(info, request, response));
.onExpiredSessionDetected(new SessionInformationExpiredEvent(info, request, response, chain));
return;
}
// Non-expired - update last request date/time
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2024 the original author or authors.
*
* Licensed 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.
*/

package org.springframework.security.web.session;

import jakarta.servlet.ServletException;
import java.io.IOException;

/**
* A {@link SessionInformationExpiredStrategy} continues to execute subsequent filters
* even after session expiration.
*
* @author Rosie Yang
* @since 6.3
*/
public final class ContinueRequestSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {

@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws ServletException, IOException {
event.getFilterChain().doFilter(event.getRequest(), event.getResponse());
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2016 the original author or authors.
* Copyright 2012-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,6 +16,7 @@

package org.springframework.security.web.session;

import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

Expand All @@ -27,6 +28,7 @@
* An event for when a {@link SessionInformation} is expired.
*
* @author Rob Winch
* @author Rosie Yang
* @since 4.2
*/
public final class SessionInformationExpiredEvent extends ApplicationEvent {
Expand All @@ -35,6 +37,8 @@ public final class SessionInformationExpiredEvent extends ApplicationEvent {

private final HttpServletResponse response;

private final FilterChain filterChain;

/**
* Creates a new instance
* @param sessionInformation the SessionInformation that is expired
Expand All @@ -48,6 +52,17 @@ public SessionInformationExpiredEvent(SessionInformation sessionInformation, Htt
Assert.notNull(response, "response cannot be null");
this.request = request;
this.response = response;
this.filterChain = null;
}

public SessionInformationExpiredEvent(SessionInformation sessionInformation, HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain) {
super(sessionInformation);
Assert.notNull(request, "request cannot be null");
Assert.notNull(response, "response cannot be null");
this.request = request;
this.response = response;
this.filterChain = filterChain;
}

/**
Expand All @@ -68,4 +83,7 @@ public SessionInformation getSessionInformation() {
return (SessionInformation) getSource();
}

public FilterChain getFilterChain() {
return this.filterChain;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.ContinueRequestSessionInformationExpiredStrategy;
import org.springframework.security.web.session.SessionInformationExpiredEvent;
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;

Expand All @@ -59,6 +61,7 @@
* @author Ben Alex
* @author Luke Taylor
* @author Onur Kagan Ozcan
* @author Rosie Yang
*/
public class ConcurrentSessionFilterTests {

Expand Down Expand Up @@ -301,4 +304,18 @@ public void setLogoutHandlersWhenEmptyThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> filter.setLogoutHandlers(new LogoutHandler[0]));
}

@Test
public void doFilterWhenRequestSessionInformationExpiredThenChainIsContinued() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setSession(new MockHttpSession());
MockHttpServletResponse response = new MockHttpServletResponse();
RedirectStrategy redirect = mock(RedirectStrategy.class);
SessionRegistry registry = mock(SessionRegistry.class);
ContinueRequestSessionInformationExpiredStrategy expiredStrategy = new ContinueRequestSessionInformationExpiredStrategy();
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry, expiredStrategy);
MockFilterChain chain = new MockFilterChain();
filter.doFilter(request, response, chain);
assertThat(chain.getRequest()).isNotNull();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,19 @@ public class SessionInformationExpiredEventTests {
@Test
public void constructorWhenSessionInformationNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new SessionInformationExpiredEvent(null,
new MockHttpServletRequest(), new MockHttpServletResponse()));
new MockHttpServletRequest(), new MockHttpServletResponse(), null));
}

@Test
public void constructorWhenRequestNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new SessionInformationExpiredEvent(
new SessionInformation("fake", "sessionId", new Date()), null, new MockHttpServletResponse()));
new SessionInformation("fake", "sessionId", new Date()), null, new MockHttpServletResponse(), null));
}

@Test
public void constructorWhenResponseNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> new SessionInformationExpiredEvent(
new SessionInformation("fake", "sessionId", new Date()), new MockHttpServletRequest(), null));
new SessionInformation("fake", "sessionId", new Date()), new MockHttpServletRequest(), null, null));
}

}

0 comments on commit 724d895

Please sign in to comment.