Polish SessionInformationExpiredStrategy
* Fix passivity and add tests * Introduce SessionInformationExpiredEvent as a value object * Rename ExpiredSessionStrategy to SessionInformationExpiredStrategy to account for the need of SessionInformation * Switch to Constructor Injection * Move the changes to the xsd to 4.2 xsd instead of 4.1 Issue gh-3808
This commit is contained in:
@@ -17,21 +17,37 @@
|
||||
package org.springframework.security.web.concurrent;
|
||||
|
||||
import java.util.Date;
|
||||
import javax.servlet.FilterChain;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.session.SessionInformation;
|
||||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.RedirectStrategy;
|
||||
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.SimpleRedirectExpiredSessionStrategy;
|
||||
import org.springframework.security.web.session.SessionInformationExpiredStrategy;
|
||||
import org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Tests {@link ConcurrentSessionFilter}.
|
||||
@@ -41,6 +57,33 @@ import static org.mockito.Mockito.*;
|
||||
*/
|
||||
public class ConcurrentSessionFilterTests {
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorSessionRegistryWhenSessionRegistryNullThenExceptionThrown() {
|
||||
new ConcurrentSessionFilter(null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorSessionRegistryExpiresUrlWhenInvalidUrlThenExceptionThrown() {
|
||||
new ConcurrentSessionFilter(new SessionRegistryImpl(), "oops");
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorSessionRegistryExpiresUrlWhenSessionRegistryNullThenExceptionThrown() {
|
||||
new ConcurrentSessionFilter(null, "/expired");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorSessionRegistrySessionInformationExpiredStrategyWhenStrategyIsNullThenThrowsException() {
|
||||
new ConcurrentSessionFilter(new SessionRegistryImpl(), (SessionInformationExpiredStrategy) null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void detectsExpiredSessions() throws Exception {
|
||||
// Setup our HTTP request
|
||||
@@ -56,9 +99,8 @@ public class ConcurrentSessionFilterTests {
|
||||
|
||||
// Setup our test fixture and registry to want this session to be expired
|
||||
|
||||
SimpleRedirectExpiredSessionStrategy expiredSessionStrategy = new SimpleRedirectExpiredSessionStrategy("/expired.jsp");
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry);
|
||||
filter.setExpiredSessionStrategy(expiredSessionStrategy);
|
||||
SimpleRedirectSessionInformationExpiredStrategy expiredSessionStrategy = new SimpleRedirectSessionInformationExpiredStrategy("/expired.jsp");
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry, expiredSessionStrategy);
|
||||
filter.setLogoutHandlers(new LogoutHandler[] { new SecurityContextLogoutHandler() });
|
||||
filter.afterPropertiesSet();
|
||||
|
||||
@@ -110,9 +152,8 @@ public class ConcurrentSessionFilterTests {
|
||||
// Setup our test fixture
|
||||
SessionRegistry registry = new SessionRegistryImpl();
|
||||
registry.registerNewSession(session.getId(), "principal");
|
||||
SimpleRedirectExpiredSessionStrategy expiredSessionStrategy = new SimpleRedirectExpiredSessionStrategy("/expired.jsp");
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry);
|
||||
filter.setExpiredSessionStrategy(expiredSessionStrategy);
|
||||
SimpleRedirectSessionInformationExpiredStrategy expiredSessionStrategy = new SimpleRedirectSessionInformationExpiredStrategy("/expired.jsp");
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry, expiredSessionStrategy);
|
||||
|
||||
Date lastRequest = registry.getSessionInformation(session.getId()).getLastRequest();
|
||||
|
||||
@@ -123,4 +164,165 @@ public class ConcurrentSessionFilterTests {
|
||||
verify(fc).doFilter(request, response);
|
||||
assertThat(registry.getSessionInformation(session.getId()).getLastRequest().after(lastRequest)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNoSessionThenChainIsContinued() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
RedirectStrategy redirect = mock(RedirectStrategy.class);
|
||||
SessionRegistry registry = mock(SessionRegistry.class);
|
||||
SessionInformation information = new SessionInformation("user", "sessionId", new Date(System.currentTimeMillis() - 1000));
|
||||
information.expireNow();
|
||||
when(registry.getSessionInformation(anyString())).thenReturn(information);
|
||||
|
||||
|
||||
String expiredUrl = "/expired";
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry,
|
||||
expiredUrl);
|
||||
filter.setRedirectStrategy(redirect);
|
||||
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
assertThat(chain.getRequest()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNoSessionInformationThenChainIsContinued() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setSession(new MockHttpSession());
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
RedirectStrategy redirect = mock(RedirectStrategy.class);
|
||||
SessionRegistry registry = mock(SessionRegistry.class);
|
||||
|
||||
|
||||
String expiredUrl = "/expired";
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry,
|
||||
expiredUrl);
|
||||
filter.setRedirectStrategy(redirect);
|
||||
|
||||
MockFilterChain chain = new MockFilterChain();
|
||||
|
||||
filter.doFilter(request, response, chain);
|
||||
|
||||
assertThat(chain.getRequest()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomRedirectStrategyThenCustomRedirectStrategyUsed() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpSession session = new MockHttpSession();
|
||||
request.setSession(session);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
RedirectStrategy redirect = mock(RedirectStrategy.class);
|
||||
SessionRegistry registry = mock(SessionRegistry.class);
|
||||
SessionInformation information = new SessionInformation("user", "sessionId", new Date(System.currentTimeMillis() - 1000));
|
||||
information.expireNow();
|
||||
when(registry.getSessionInformation(anyString())).thenReturn(information);
|
||||
|
||||
|
||||
String expiredUrl = "/expired";
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry,
|
||||
expiredUrl);
|
||||
filter.setRedirectStrategy(redirect);
|
||||
|
||||
filter.doFilter(request, response, new MockFilterChain());
|
||||
|
||||
verify(redirect).sendRedirect(request, response, expiredUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenOverrideThenCustomRedirectStrategyUsed() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpSession session = new MockHttpSession();
|
||||
request.setSession(session);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
RedirectStrategy redirect = mock(RedirectStrategy.class);
|
||||
SessionRegistry registry = mock(SessionRegistry.class);
|
||||
SessionInformation information = new SessionInformation("user", "sessionId", new Date(System.currentTimeMillis() - 1000));
|
||||
information.expireNow();
|
||||
when(registry.getSessionInformation(anyString())).thenReturn(information);
|
||||
|
||||
|
||||
final String expiredUrl = "/expired";
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry,
|
||||
expiredUrl + "will-be-overrridden") {
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.web.session.ConcurrentSessionFilter#determineExpiredUrl(javax.servlet.http.HttpServletRequest, org.springframework.security.core.session.SessionInformation)
|
||||
*/
|
||||
@Override
|
||||
protected String determineExpiredUrl(HttpServletRequest request,
|
||||
SessionInformation info) {
|
||||
return expiredUrl;
|
||||
}
|
||||
|
||||
};
|
||||
filter.setRedirectStrategy(redirect);
|
||||
|
||||
filter.doFilter(request, response, new MockFilterChain());
|
||||
|
||||
verify(redirect).sendRedirect(request, response, expiredUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNoExpiredUrlThenResponseWritten() throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpSession session = new MockHttpSession();
|
||||
request.setSession(session);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
SessionRegistry registry = mock(SessionRegistry.class);
|
||||
SessionInformation information = new SessionInformation("user", "sessionId", new Date(System.currentTimeMillis() - 1000));
|
||||
information.expireNow();
|
||||
when(registry.getSessionInformation(anyString())).thenReturn(information);
|
||||
|
||||
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry);
|
||||
|
||||
filter.doFilter(request, response, new MockFilterChain());
|
||||
|
||||
assertThat(response.getContentAsString()).contains(
|
||||
"This session has been expired (possibly due to multiple concurrent logins being attempted as the same user).");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomLogoutHandlersThenHandlersUsed() throws Exception {
|
||||
LogoutHandler handler = mock(LogoutHandler.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
MockHttpSession session = new MockHttpSession();
|
||||
request.setSession(session);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
SessionRegistry registry = mock(SessionRegistry.class);
|
||||
SessionInformation information = new SessionInformation("user", "sessionId", new Date(System.currentTimeMillis() - 1000));
|
||||
information.expireNow();
|
||||
when(registry.getSessionInformation(anyString())).thenReturn(information);
|
||||
|
||||
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(registry);
|
||||
filter.setLogoutHandlers(new LogoutHandler[] { handler } );
|
||||
|
||||
filter.doFilter(request, response, new MockFilterChain());
|
||||
|
||||
verify(handler).logout(eq(request), eq(response), any(Authentication.class));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setLogoutHandlersWhenNullThenThrowsException() {
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(new SessionRegistryImpl());
|
||||
|
||||
filter.setLogoutHandlers(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setLogoutHandlersWhenEmptyThenThrowsException() {
|
||||
ConcurrentSessionFilter filter = new ConcurrentSessionFilter(new SessionRegistryImpl());
|
||||
|
||||
filter.setLogoutHandlers(new LogoutHandler[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-2016 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
|
||||
*
|
||||
* 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.springframework.security.web.session;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.core.session.SessionInformation;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
* @since 4.2
|
||||
*/
|
||||
public class SessionInformationExpiredEventTests {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorWhenSessionInformationNullThenThrowsException() {
|
||||
new SessionInformationExpiredEvent(null, new MockHttpServletRequest(), new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorWhenRequestNullThenThrowsException() {
|
||||
new SessionInformationExpiredEvent(new SessionInformation("fake", "sessionId", new Date()), null, new MockHttpServletResponse());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void constructorWhenResponseNullThenThrowsException() {
|
||||
new SessionInformationExpiredEvent(new SessionInformation("fake", "sessionId", new Date()), new MockHttpServletRequest(), null);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user