I'm working on a Java application where a user registers a password for his/her account. The following are being used:
preHandle
method)For the Spring Security part, there's really no authentication required. I just use it to handle CSRF and the configuration is as follows:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// CSRF feature only
http.authorizeRequests().anyRequest().permitAll();
}
}
Now, this is where things get messy. When I deploy it to Tomcat in a Unix environment, ;jsessionid
gets appended to the URL and Spring Security is not happy. I have scrounged the Internet and found the following solutions to remove it (alongside my results).
server.servlet.session.tracking-modes=cookie
in application.properties
does nothing.
web.xml
<session-config>
<tracking-mode>COOKIE</tracking-mode>
</session-config>
or
@Configuration
public class WebConfig implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext servletContext) {
HashSet<SessionTrackingMode> set = new HashSet<>();
set.add(SessionTrackingMode.COOKIE);
servletContext.setSessionTrackingModes(set);
}
}
yields an IllegalArgumentException: The session tracking mode [COOKIE] requested for context [/<context-name>] is not supported by that context
I'm about to pull what remains of my hair off so I reverted any cookie
-related changes and thought of just allowing semicolons in the URL (I know, I know, not secure) using the snippet below in the same SecurityConfig
class.
@Bean
public HttpFirewall allowUrlSemicolonHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowSemicolon(true);
return firewall;
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.httpFirewall(allowUrlSemicolonHttpFirewall());
}
And voila! The web flow runs on an infinite redirect.
Questions:
IllegalArgumentException: The session tracking mode [COOKIE] requested for context [/<context-name>] is not supported by that context
before? I've searched far and wide and the closest that I could find is this.server.servlet.session.tracking-modes=cookie
not working be the same as above?http.authorizeRequests().anyRequest().permitAll()
? I tried using anonymous()
but the result was the same.Please note that allowing semicolons in the URL is working fine and dandy in my localhost
, so I have a hunch that what's causing the redirects is SSL-related. In the same way that locally ;jsessionid
is not being appended to the URL.
My next step is to try configuring SSL locally in an attempt to replicate the issue. In the meantime, any help would be highly appreciated. My apologies if there's too much information here; I'm willing to repost it as multiple questions if that's necessary.
Answering this one myself as further development this year actually led to a solution from a teammate of mine when he extended the base code to a new application which required Spring Security. Turns out the persistent jsessionid
in our case was due to the cookies
attribute below in our Tomcat context.xml
.
<Context useHttpOnly="true" cookies="false" reloadable="false">
On the Java side, the generic security configuration below (for the original application) worked even with the Tomcat configuration above.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity(debug = true)
@ConditionalOnExpression("${permit.all:true}")
public class SecurityConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(SecurityConfig.class);
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(authorize -> authorize.antMatchers("/**").permitAll())
.csrf(httpSecurityCsrfConfigurer -> httpSecurityCsrfConfigurer.ignoringAntMatchers("/**"))
.sessionManagement().enableSessionUrlRewriting(true)
.sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
LOGGER.debug("Default {} loaded", SecurityConfig.class.getSimpleName());
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
DefaultHttpFirewall firewall = new DefaultHttpFirewall();
return web -> web.httpFirewall(firewall);
}
}