SEC-2135: Support HttpServletRequest#changeSessionId()
This commit is contained in:
parent
75fb971d23
commit
797df51264
|
@ -27,6 +27,7 @@ import org.springframework.security.config.http.SessionCreationPolicy;
|
|||
import org.springframework.security.core.session.SessionRegistry;
|
||||
import org.springframework.security.core.session.SessionRegistryImpl;
|
||||
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.session.ChangeSessionIdAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
|
||||
import org.springframework.security.web.authentication.session.NullAuthenticatedSessionStrategy;
|
||||
|
@ -77,7 +78,7 @@ import org.springframework.util.Assert;
|
|||
* @see ConcurrentSessionFilter
|
||||
*/
|
||||
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<H> {
|
||||
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = new SessionFixationProtectionStrategy();
|
||||
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = createDefaultSessionFixationProtectionStrategy();
|
||||
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
|
||||
private SessionRegistry sessionRegistry = new SessionRegistryImpl();
|
||||
private Integer maximumSessions;
|
||||
|
@ -186,6 +187,14 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
return new ConcurrencyControlConfigurer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes {@link #postProcess(Object)} and sets the {@link SessionAuthenticationStrategy} for session fixation.
|
||||
* @param sessionFixationAuthenticationStrategy
|
||||
*/
|
||||
private void setSessionFixationAuthenticationStrategy(SessionAuthenticationStrategy sessionFixationAuthenticationStrategy) {
|
||||
this.sessionFixationAuthenticationStrategy = postProcess(sessionFixationAuthenticationStrategy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuring SessionFixation protection
|
||||
*
|
||||
|
@ -202,7 +211,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
public SessionManagementConfigurer<H> newSession() {
|
||||
SessionFixationProtectionStrategy sessionFixationProtectionStrategy = new SessionFixationProtectionStrategy();
|
||||
sessionFixationProtectionStrategy.setMigrateSessionAttributes(false);
|
||||
SessionManagementConfigurer.this.sessionFixationAuthenticationStrategy = sessionFixationProtectionStrategy;
|
||||
setSessionFixationAuthenticationStrategy(sessionFixationProtectionStrategy);
|
||||
return SessionManagementConfigurer.this;
|
||||
}
|
||||
|
||||
|
@ -214,7 +223,22 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
* @return the {@link SessionManagementConfigurer} for further customizations
|
||||
*/
|
||||
public SessionManagementConfigurer<H> migrateSession() {
|
||||
SessionManagementConfigurer.this.sessionFixationAuthenticationStrategy = new SessionFixationProtectionStrategy();
|
||||
setSessionFixationAuthenticationStrategy(new SessionFixationProtectionStrategy());
|
||||
return SessionManagementConfigurer.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies that no session fixation protection should be enabled. This
|
||||
* may be useful when utilizing other mechanisms for protecting against
|
||||
* session fixation. For example, if application container session
|
||||
* fixation protection is already in use. Otherwise, this option is not
|
||||
* recommended.
|
||||
*
|
||||
* @return the {@link SessionManagementConfigurer} for further
|
||||
* customizations
|
||||
*/
|
||||
public SessionManagementConfigurer<H> changeSessionId() {
|
||||
setSessionFixationAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy());
|
||||
return SessionManagementConfigurer.this;
|
||||
}
|
||||
|
||||
|
@ -229,7 +253,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
* customizations
|
||||
*/
|
||||
public SessionManagementConfigurer<H> none() {
|
||||
SessionManagementConfigurer.this.sessionFixationAuthenticationStrategy = new NullAuthenticatedSessionStrategy();
|
||||
setSessionFixationAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
|
||||
return SessionManagementConfigurer.this;
|
||||
}
|
||||
}
|
||||
|
@ -400,4 +424,16 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
private boolean isConcurrentSessionControlEnabled() {
|
||||
return maximumSessions != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the default {@link SessionAuthenticationStrategy} for session fixation
|
||||
* @return the default {@link SessionAuthenticationStrategy} for session fixation
|
||||
*/
|
||||
private static SessionAuthenticationStrategy createDefaultSessionFixationProtectionStrategy() {
|
||||
try {
|
||||
return new ChangeSessionIdAuthenticationStrategy();
|
||||
} catch(IllegalStateException e) {
|
||||
return new SessionFixationProtectionStrategy();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -515,8 +515,8 @@ session-management =
|
|||
element session-management {session-management.attlist, concurrency-control?}
|
||||
|
||||
session-management.attlist &=
|
||||
## Indicates whether an existing session should be invalidated when a user authenticates and a new session started. If set to "none" no change will be made. "newSession" will create a new empty session. "migrateSession" will create a new session and copy the session attributes to the new session. Defaults to "migrateSession".
|
||||
attribute session-fixation-protection {"none" | "newSession" | "migrateSession" }?
|
||||
## Indicates how session fixation protection will be applied when a user authenticates. If set to "none", no protection will be applied. "newSession" will create a new empty session, with only Spring Security-related attributes migrated. "migrateSession" will create a new session and copy all session attributes to the new session. In Servlet 3.1 (Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing session and use the container-supplied session fixation protection (HttpServletRequest#changeSessionId()). Defaults to "changeSessionId" in Servlet 3.1 and newer containers, "migrateSession" in older containers. Throws an exception if "changeSessionId" is used in older containers.
|
||||
attribute session-fixation-protection {"none" | "newSession" | "migrateSession" | "changeSessionId" }?
|
||||
session-management.attlist &=
|
||||
## The URL to which a user will be redirected if they submit an invalid session indentifier. Typically used to detect session timeouts.
|
||||
attribute invalid-session-url {xsd:token}?
|
||||
|
|
|
@ -1664,10 +1664,15 @@
|
|||
<xs:attributeGroup name="session-management.attlist">
|
||||
<xs:attribute name="session-fixation-protection">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Indicates whether an existing session should be invalidated when a user authenticates and
|
||||
a new session started. If set to "none" no change will be made. "newSession" will create a
|
||||
new empty session. "migrateSession" will create a new session and copy the session
|
||||
attributes to the new session. Defaults to "migrateSession".
|
||||
<xs:documentation>Indicates how session fixation protection will be applied when a user authenticates. If
|
||||
set to "none", no protection will be applied. "newSession" will create a new empty
|
||||
session, with only Spring Security-related attributes migrated. "migrateSession" will
|
||||
create a new session and copy all session attributes to the new session. In Servlet 3.1
|
||||
(Java EE 7) and newer containers, specifying "changeSessionId" will keep the existing
|
||||
session and use the container-supplied session fixation protection
|
||||
(HttpServletRequest#changeSessionId()). Defaults to "changeSessionId" in Servlet 3.1 and
|
||||
newer containers, "migrateSession" in older containers. Throws an exception if
|
||||
"changeSessionId" is used in older containers.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:simpleType>
|
||||
|
@ -1675,6 +1680,7 @@
|
|||
<xs:enumeration value="none"/>
|
||||
<xs:enumeration value="newSession"/>
|
||||
<xs:enumeration value="migrateSession"/>
|
||||
<xs:enumeration value="changeSessionId"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
</xs:attribute>
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* Copyright 2002-2012 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.config.http;
|
||||
|
||||
|
||||
import java.security.Principal
|
||||
import javax.servlet.Filter
|
||||
import org.springframework.beans.BeansException
|
||||
import org.springframework.beans.factory.BeanCreationException
|
||||
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException
|
||||
import org.springframework.mock.web.MockFilterChain
|
||||
import org.springframework.mock.web.MockHttpServletRequest
|
||||
import org.springframework.mock.web.MockHttpServletResponse
|
||||
import org.springframework.security.access.AccessDeniedException
|
||||
import org.springframework.security.access.SecurityConfig
|
||||
import org.springframework.security.authentication.AnonymousAuthenticationProvider;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken
|
||||
import org.springframework.security.config.BeanIds
|
||||
import org.springframework.security.config.MockUserServiceBeanPostProcessor
|
||||
import org.springframework.security.config.PostProcessedMockUserDetailsService
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext
|
||||
import org.springframework.security.core.authority.AuthorityUtils
|
||||
import org.springframework.security.core.context.SecurityContext
|
||||
import org.springframework.security.core.context.SecurityContextHolder
|
||||
import org.springframework.security.openid.OpenIDAuthenticationFilter
|
||||
import org.springframework.security.util.FieldUtils
|
||||
import org.springframework.security.web.FilterChainProxy
|
||||
import org.springframework.security.web.PortMapperImpl
|
||||
import org.springframework.security.web.access.ExceptionTranslationFilter
|
||||
import org.springframework.security.web.access.channel.ChannelProcessingFilter
|
||||
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor
|
||||
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter
|
||||
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
|
||||
import org.springframework.security.web.authentication.logout.LogoutFilter
|
||||
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler
|
||||
import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter
|
||||
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository
|
||||
import org.springframework.security.web.context.SecurityContextPersistenceFilter
|
||||
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
|
||||
import org.springframework.security.web.jaasapi.JaasApiIntegrationFilter
|
||||
import org.springframework.security.web.savedrequest.HttpSessionRequestCache
|
||||
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter
|
||||
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter
|
||||
import org.springframework.security.web.session.SessionManagementFilter
|
||||
import org.springframework.security.web.authentication.logout.CookieClearingLogoutHandler
|
||||
import org.springframework.security.web.firewall.DefaultHttpFirewall
|
||||
import org.springframework.security.BeanNameCollectingPostProcessor
|
||||
import org.springframework.security.authentication.dao.DaoAuthenticationProvider
|
||||
import org.springframework.security.access.vote.RoleVoter
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter
|
||||
import org.springframework.security.access.vote.AffirmativeBased
|
||||
import org.springframework.security.access.PermissionEvaluator
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
|
||||
import org.springframework.security.web.util.AntPathRequestMatcher
|
||||
import org.springframework.security.authentication.AuthenticationManager
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
class InterceptUrlConfigTests extends AbstractHttpConfigTests {
|
||||
|
||||
def "SEC-2256: intercept-url method is not given priority"() {
|
||||
when:
|
||||
httpAutoConfig {
|
||||
'intercept-url'(pattern: '/anyurl', access: "ROLE_USER")
|
||||
'intercept-url'(pattern: '/anyurl', 'method':'GET',access: 'ROLE_ADMIN')
|
||||
}
|
||||
createAppContext()
|
||||
|
||||
def fids = getFilter(FilterSecurityInterceptor).securityMetadataSource
|
||||
def attrs = fids.getAttributes(createFilterinvocation("/anyurl", "GET"))
|
||||
def attrsPost = fids.getAttributes(createFilterinvocation("/anyurl", "POST"))
|
||||
|
||||
then:
|
||||
attrs.size() == 1
|
||||
attrs.contains(new SecurityConfig("ROLE_USER"))
|
||||
attrsPost.size() == 1
|
||||
attrsPost.contains(new SecurityConfig("ROLE_USER"))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.config.annotation.web.configurers;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.powermock.api.mockito.PowerMockito.mock;
|
||||
import static org.powermock.api.mockito.PowerMockito.spy;
|
||||
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
|
||||
import static org.powermock.api.mockito.PowerMockito.when;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ReflectionUtils.class, Method.class})
|
||||
public class SessionManagementConfigurerServlet31Tests {
|
||||
@Mock
|
||||
Method method;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
Filter springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setServletPath("/login");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);
|
||||
|
||||
loadConfig(SessionManagementDefaultSessionFixationServlet31Config.class);
|
||||
|
||||
springSecurityFilterChain.doFilter(request,response,chain);
|
||||
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
@Configuration
|
||||
static class SessionManagementDefaultSessionFixationServlet31Config extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.sessionManagement();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerAuthentication(AuthenticationManagerBuilder auth)
|
||||
throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>...classes) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(classes);
|
||||
context.refresh();
|
||||
this.context = context;
|
||||
this.springSecurityFilterChain = this.context.getBean("springSecurityFilterChain",Filter.class);
|
||||
}
|
||||
|
||||
private void login(Authentication auth) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response);
|
||||
repo.loadContext(requestResponseHolder);
|
||||
|
||||
SecurityContextImpl securityContextImpl = new SecurityContextImpl();
|
||||
securityContextImpl.setAuthentication(auth);
|
||||
repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(), requestResponseHolder.getResponse());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.config.http;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.same;
|
||||
import static org.powermock.api.mockito.PowerMockito.mock;
|
||||
import static org.powermock.api.mockito.PowerMockito.spy;
|
||||
import static org.powermock.api.mockito.PowerMockito.verifyStatic;
|
||||
import static org.powermock.api.mockito.PowerMockito.when;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.mock.web.MockFilterChain;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
||||
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ReflectionUtils.class, Method.class})
|
||||
public class SessionManagementConfigServlet31Tests {
|
||||
private static final String XML_AUTHENTICATION_MANAGER =
|
||||
"<authentication-manager>"+
|
||||
" <authentication-provider>"+
|
||||
" <user-service>"+
|
||||
" <user name='user' password='password' authorities='ROLE_USER' />" +
|
||||
" </user-service>"+
|
||||
" </authentication-provider>"+
|
||||
"</authentication-manager>";
|
||||
|
||||
@Mock
|
||||
Method method;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
Filter springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setRequestURI("/j_spring_security_check");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("j_username", "user");
|
||||
request.setParameter("j_password", "password");
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);
|
||||
|
||||
loadContext("<http>\n" +
|
||||
" <form-login/>\n" +
|
||||
" <session-management/>\n" +
|
||||
" </http>" +
|
||||
XML_AUTHENTICATION_MANAGER);
|
||||
|
||||
springSecurityFilterChain.doFilter(request,response,chain);
|
||||
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void changeSessionId() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setRequestURI("/j_spring_security_check");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("j_username", "user");
|
||||
request.setParameter("j_password", "password");
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);
|
||||
|
||||
loadContext("<http>\n" +
|
||||
" <form-login/>\n" +
|
||||
" <session-management session-fixation-protection='changeSessionId'/>\n" +
|
||||
" </http>" +
|
||||
XML_AUTHENTICATION_MANAGER);
|
||||
|
||||
springSecurityFilterChain.doFilter(request,response,chain);
|
||||
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
private void loadContext(String context) {
|
||||
this.context = new InMemoryXmlApplicationContext(context);
|
||||
this.springSecurityFilterChain = this.context.getBean("springSecurityFilterChain",Filter.class);
|
||||
}
|
||||
|
||||
private void login(Authentication auth) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response);
|
||||
repo.loadContext(requestResponseHolder);
|
||||
|
||||
SecurityContextImpl securityContextImpl = new SecurityContextImpl();
|
||||
securityContextImpl.setAuthentication(auth);
|
||||
repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(), requestResponseHolder.getResponse());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.authentication.session;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A base class for performing session fixation protection.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
abstract class AbstractSessionFixationProtectionStrategy implements SessionAuthenticationStrategy, ApplicationEventPublisherAware {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
/**
|
||||
* Used for publishing events related to session fixation protection, such as {@link SessionFixationProtectionEvent}.
|
||||
*/
|
||||
private ApplicationEventPublisher applicationEventPublisher = new NullEventPublisher();
|
||||
/**
|
||||
* If set to {@code true}, a session will always be created, even if one didn't exist at the start of the request.
|
||||
* Defaults to {@code false}.
|
||||
*/
|
||||
private boolean alwaysCreateSession;
|
||||
|
||||
/**
|
||||
* Called when a user is newly authenticated.
|
||||
* <p>
|
||||
* If a session already exists, and matches the session Id from the client, a new session will be created, and the
|
||||
* session attributes copied to it (if {@code migrateSessionAttributes} is set).
|
||||
* If the client's requested session Id is invalid, nothing will be done, since there is no need to change the
|
||||
* session Id if it doesn't match the current session.
|
||||
* <p>
|
||||
* If there is no session, no action is taken unless the {@code alwaysCreateSession} property is set, in which
|
||||
* case a session will be created if one doesn't already exist.
|
||||
*/
|
||||
public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
|
||||
boolean hadSessionAlready = request.getSession(false) != null;
|
||||
|
||||
if (!hadSessionAlready && !alwaysCreateSession) {
|
||||
// Session fixation isn't a problem if there's no session
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new session if necessary
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
if (hadSessionAlready && request.isRequestedSessionIdValid()) {
|
||||
// We need to migrate to a new session
|
||||
String originalSessionId = session.getId();
|
||||
|
||||
session = applySessionFixation(request);
|
||||
|
||||
if (originalSessionId.equals(session.getId())) {
|
||||
logger.warn("Your servlet container did not change the session ID when a new session was created. You will" +
|
||||
" not be adequately protected against session-fixation attacks");
|
||||
}
|
||||
|
||||
onSessionChange(originalSessionId, session, authentication);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies session fixation
|
||||
*
|
||||
* @param request the {@link HttpServletRequest} to apply session fixation protection for
|
||||
* @return the new {@link HttpSession} to use. Cannot be null.
|
||||
*/
|
||||
abstract HttpSession applySessionFixation(HttpServletRequest request);
|
||||
|
||||
/**
|
||||
* Called when the session has been changed and the old attributes have been migrated to the new session.
|
||||
* Only called if a session existed to start with. Allows subclasses to plug in additional behaviour.
|
||||
* * <p>
|
||||
* The default implementation of this method publishes a {@link SessionFixationProtectionEvent} to notify
|
||||
* the application that the session ID has changed. If you override this method and still wish these events to be
|
||||
* published, you should call {@code super.onSessionChange()} within your overriding method.
|
||||
*
|
||||
* @param originalSessionId the original session identifier
|
||||
* @param newSession the newly created session
|
||||
* @param auth the token for the newly authenticated principal
|
||||
*/
|
||||
protected void onSessionChange(String originalSessionId, HttpSession newSession, Authentication auth) {
|
||||
applicationEventPublisher.publishEvent(new SessionFixationProtectionEvent(
|
||||
auth, originalSessionId, newSession.getId()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ApplicationEventPublisher} to use for submitting
|
||||
* {@link SessionFixationProtectionEvent}. The default is to not submit the
|
||||
* {@link SessionFixationProtectionEvent}.
|
||||
*
|
||||
* @param applicationEventPublisher
|
||||
* the {@link ApplicationEventPublisher}. Cannot be null.
|
||||
*/
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
Assert.notNull(applicationEventPublisher, "applicationEventPublisher cannot be null");
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
public void setAlwaysCreateSession(boolean alwaysCreateSession) {
|
||||
this.alwaysCreateSession = alwaysCreateSession;
|
||||
}
|
||||
|
||||
protected static final class NullEventPublisher implements
|
||||
ApplicationEventPublisher {
|
||||
public void publishEvent(ApplicationEvent event) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.authentication.session;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Uses {@link HttpServletRequest#changeSessionId()} to protect against session
|
||||
* fixation attacks. This is the default implementation for Servlet 3.1+.
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 3.2
|
||||
*/
|
||||
public final class ChangeSessionIdAuthenticationStrategy extends AbstractSessionFixationProtectionStrategy {
|
||||
private final Method changeSessionIdMethod;
|
||||
|
||||
public ChangeSessionIdAuthenticationStrategy() {
|
||||
Method changeSessionIdMethod = ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId");
|
||||
if(changeSessionIdMethod == null) {
|
||||
throw new IllegalStateException("HttpServletRequest.changeSessionId is undefined. Are you using a Servlet 3.1+ environment?");
|
||||
}
|
||||
this.changeSessionIdMethod = changeSessionIdMethod;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.security.web.authentication.session.AbstractSessionFixationProtectionStrategy#applySessionFixation(javax.servlet.http.HttpServletRequest)
|
||||
*/
|
||||
@Override
|
||||
HttpSession applySessionFixation(HttpServletRequest request) {
|
||||
ReflectionUtils.invokeMethod(changeSessionIdMethod, request);
|
||||
return request.getSession();
|
||||
}
|
||||
}
|
|
@ -22,19 +22,12 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* The default implementation of {@link SessionAuthenticationStrategy}.
|
||||
* The default implementation of {@link SessionAuthenticationStrategy} when using < Servlet 3.1.
|
||||
* <p>
|
||||
* Creates a new session for the newly authenticated user if they already have a session (as a defence against
|
||||
* session-fixation protection attacks), and copies their session attributes across to the new session.
|
||||
|
@ -59,19 +52,12 @@ import org.springframework.util.Assert;
|
|||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class SessionFixationProtectionStrategy implements SessionAuthenticationStrategy, ApplicationEventPublisherAware {
|
||||
protected final Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
/**
|
||||
* Used for publishing events related to session fixation protection, such as {@link SessionFixationProtectionEvent}.
|
||||
*/
|
||||
private ApplicationEventPublisher applicationEventPublisher = new NullEventPublisher();
|
||||
|
||||
public class SessionFixationProtectionStrategy extends AbstractSessionFixationProtectionStrategy {
|
||||
/**
|
||||
* Indicates that the session attributes of an existing session
|
||||
* should be migrated to the new session. Defaults to <code>true</code>.
|
||||
*/
|
||||
private boolean migrateSessionAttributes = true;
|
||||
boolean migrateSessionAttributes = true;
|
||||
|
||||
/**
|
||||
* In the case where the attributes will not be migrated, this field allows a list of named attributes
|
||||
|
@ -79,82 +65,6 @@ public class SessionFixationProtectionStrategy implements SessionAuthenticationS
|
|||
*/
|
||||
private List<String> retainedAttributes = null;
|
||||
|
||||
/**
|
||||
* If set to {@code true}, a session will always be created, even if one didn't exist at the start of the request.
|
||||
* Defaults to {@code false}.
|
||||
*/
|
||||
private boolean alwaysCreateSession;
|
||||
|
||||
/**
|
||||
* Called when a user is newly authenticated.
|
||||
* <p>
|
||||
* If a session already exists, and matches the session Id from the client, a new session will be created, and the
|
||||
* session attributes copied to it (if {@code migrateSessionAttributes} is set).
|
||||
* If the client's requested session Id is invalid, nothing will be done, since there is no need to change the
|
||||
* session Id if it doesn't match the current session.
|
||||
* <p>
|
||||
* If there is no session, no action is taken unless the {@code alwaysCreateSession} property is set, in which
|
||||
* case a session will be created if one doesn't already exist.
|
||||
*/
|
||||
public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
|
||||
boolean hadSessionAlready = request.getSession(false) != null;
|
||||
|
||||
if (!hadSessionAlready && !alwaysCreateSession) {
|
||||
// Session fixation isn't a problem if there's no session
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new session if necessary
|
||||
HttpSession session = request.getSession();
|
||||
|
||||
if (hadSessionAlready && request.isRequestedSessionIdValid()) {
|
||||
// We need to migrate to a new session
|
||||
String originalSessionId = session.getId();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Invalidating session with Id '" + originalSessionId +"' " + (migrateSessionAttributes ?
|
||||
"and" : "without") + " migrating attributes.");
|
||||
}
|
||||
|
||||
Map<String, Object> attributesToMigrate = extractAttributes(session);
|
||||
|
||||
session.invalidate();
|
||||
session = request.getSession(true); // we now have a new session
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Started new session: " + session.getId());
|
||||
}
|
||||
|
||||
if (originalSessionId.equals(session.getId())) {
|
||||
logger.warn("Your servlet container did not change the session ID when a new session was created. You will" +
|
||||
" not be adequately protected against session-fixation attacks");
|
||||
}
|
||||
|
||||
transferAttributes(attributesToMigrate, session);
|
||||
|
||||
onSessionChange(originalSessionId, session, authentication);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the session has been changed and the old attributes have been migrated to the new session.
|
||||
* Only called if a session existed to start with. Allows subclasses to plug in additional behaviour.
|
||||
* * <p>
|
||||
* The default implementation of this method publishes a {@link SessionFixationProtectionEvent} to notify
|
||||
* the application that the session ID has changed. If you override this method and still wish these events to be
|
||||
* published, you should call {@code super.onSessionChange()} within your overriding method.
|
||||
*
|
||||
* @param originalSessionId the original session identifier
|
||||
* @param newSession the newly created session
|
||||
* @param auth the token for the newly authenticated principal
|
||||
*/
|
||||
protected void onSessionChange(String originalSessionId, HttpSession newSession, Authentication auth) {
|
||||
applicationEventPublisher.publishEvent(new SessionFixationProtectionEvent(
|
||||
auth, originalSessionId, newSession.getId()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to extract the existing attributes from the session, prior to invalidating it. If
|
||||
* {@code migrateAttributes} is set to {@code false}, only Spring Security attributes will be retained.
|
||||
|
@ -169,11 +79,33 @@ public class SessionFixationProtectionStrategy implements SessionAuthenticationS
|
|||
return createMigratedAttributeMap(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
final HttpSession applySessionFixation(HttpServletRequest request) {
|
||||
HttpSession session = request.getSession();
|
||||
String originalSessionId = session.getId();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Invalidating session with Id '" + originalSessionId +"' " + (migrateSessionAttributes ?
|
||||
"and" : "without") + " migrating attributes.");
|
||||
}
|
||||
|
||||
Map<String, Object> attributesToMigrate = extractAttributes(session);
|
||||
|
||||
session.invalidate();
|
||||
session = request.getSession(true); // we now have a new session
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Started new session: " + session.getId());
|
||||
}
|
||||
|
||||
transferAttributes(attributesToMigrate, session);
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attributes the attributes which were extracted from the original session by {@code extractAttributes}
|
||||
* @param newSession the newly created session
|
||||
*/
|
||||
private void transferAttributes(Map<String, Object> attributes, HttpSession newSession) {
|
||||
void transferAttributes(Map<String, Object> attributes, HttpSession newSession) {
|
||||
if (attributes != null) {
|
||||
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
|
||||
newSession.setAttribute(entry.getKey(), entry.getValue());
|
||||
|
@ -214,19 +146,6 @@ public class SessionFixationProtectionStrategy implements SessionAuthenticationS
|
|||
return attributesToMigrate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link ApplicationEventPublisher} to use for submitting
|
||||
* {@link SessionFixationProtectionEvent}. The default is to not submit the
|
||||
* {@link SessionFixationProtectionEvent}.
|
||||
*
|
||||
* @param applicationEventPublisher
|
||||
* the {@link ApplicationEventPublisher}. Cannot be null.
|
||||
*/
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
Assert.notNull(applicationEventPublisher, "applicationEventPublisher cannot be null");
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines whether attributes should be migrated to a new session or not. Has no effect if you
|
||||
* override the {@code extractAttributes} method.
|
||||
|
@ -250,12 +169,4 @@ public class SessionFixationProtectionStrategy implements SessionAuthenticationS
|
|||
Assert.notNull(retainedAttributes);
|
||||
this.retainedAttributes = retainedAttributes;
|
||||
}
|
||||
|
||||
public void setAlwaysCreateSession(boolean alwaysCreateSession) {
|
||||
this.alwaysCreateSession = alwaysCreateSession;
|
||||
}
|
||||
|
||||
private static final class NullEventPublisher implements ApplicationEventPublisher {
|
||||
public void publishEvent(ApplicationEvent event) { }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright 2002-2013 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.authentication.session;
|
||||
|
||||
import static org.mockito.Matchers.*;
|
||||
import static org.powermock.api.mockito.PowerMockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Rob Winch
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ReflectionUtils.class, Method.class})
|
||||
public class ChangeSessionIdAuthenticationStrategyTests {
|
||||
@Mock
|
||||
private Method method;
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void constructChangeIdMethodNotFound() {
|
||||
new ChangeSessionIdAuthenticationStrategy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void applySessionFixation() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);
|
||||
|
||||
new ChangeSessionIdAuthenticationStrategy().applySessionFixation(request);
|
||||
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), eq(request));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue