I need to upgrade Spring Boot, Spring Security, and JDK from 11 to 17
To perform this upgrade, I had to replace javax.servlet.http.*
with jakarta.servlet.http.*
The problem I am running into is the compilation of the Line http.addFilterBefore(new MySecurityFilter(), ChannelProcessingFilter.class);
It gives me the compilation error WebSecurityConfig.java:[47,85] incompatible types: java.lang.Class<org.springframework.security.web.access.channel.ChannelProcessingFilter> cannot be converted to java.lang.Class<? extends jakarta.servlet.Filter>
If I do NOT specify this line, the inbuilt security runs for all /api/**
requests since they contain the Bearer token. I want to authenticate them myself using MySecurityFilter
Any idea how to fix this since I'm not sure what class in the Jakarta library could be used as a replacement for the ChannelProcessingFilter
?
I'll be grateful for any help
// OLD CODE
package com.my.server.security;
import com.my.server.security.filter.MySecurityFilter;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter;
import org.keycloak.adapters.springsecurity.filter.AdapterStateCookieRequestMatcher;
import org.keycloak.adapters.springsecurity.filter.KeycloakAuthenticationProcessingFilter;
import org.keycloak.adapters.springsecurity.filter.QueryParamPresenceRequestMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
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.core.authority.mapping.SimpleAuthorityMapper;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import javax.servlet.http.HttpServletRequest;
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
class WebSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.cors().and().csrf().disable();
http.authorizeRequests()
.antMatchers("/echo/**", "/api/**").permitAll()
.antMatchers("/js/**", "/css/**", "/img/**").permitAll()
.antMatchers("/admin/**").hasAnyRole("USER")
.anyRequest().authenticated();
http.addFilterBefore(new MySecurityFilter(), ChannelProcessingFilter.class);
}
@Bean
@Override
protected KeycloakAuthenticationProcessingFilter keycloakAuthenticationProcessingFilter() throws Exception {
RequestMatcher requestMatcher =
new OrRequestMatcher(
new AntPathRequestMatcher("/sso/login"),
new IgnoreKeycloakProcessingFilterRequestMatcher(), // verify Bearer in MySecurityFilter
new QueryParamPresenceRequestMatcher("access_token"),
new AdapterStateCookieRequestMatcher()
);
return new KeycloakAuthenticationProcessingFilter(authenticationManagerBean(), requestMatcher);
}
private class IgnoreKeycloakProcessingFilterRequestMatcher implements RequestMatcher {
IgnoreKeycloakProcessingFilterRequestMatcher() {}
public boolean matches(HttpServletRequest request) {
String authorizationHeaderValue = request.getHeader("Authorization");
return authorizationHeaderValue != null && !authorizationHeaderValue.startsWith("Bearer ");
}
}
}
import org.springframework.web.filter.GenericFilterBean;
public class MySecurityFilter extends GenericFilterBean {
...
}
// NEW CODE
package com.my.server.security;
import com.my.server.security.filter.MySecurityFilter;
import jakarta.servlet.http.HttpServletRequest;
import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents;
import org.keycloak.adapters.springsecurity.filter.AdapterStateCookieRequestMatcher;
import org.keycloak.adapters.springsecurity.filter.QueryParamPresenceRequestMatcher;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = KeycloakSecurityComponents.class)
public class WebSecurityConfig {
@Bean
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests()
.requestMatchers("/echo/**", "/api/**").permitAll()
.requestMatchers("/js/**", "/css/**", "/img/**").permitAll()
.requestMatchers("/admin/**").hasAnyRole("USER")
.anyRequest().authenticated();
http.addFilterBefore(new MySecurityFilter(), ChannelProcessingFilter.class);
return http.build();
}
@Bean
public WebSecurityCustomizer webSecurityCustomizer() throws Exception {
return (web) -> web.ignoring()
.requestMatchers(
new OrRequestMatcher(
new AntPathRequestMatcher("/sso/login"),
new IgnoreKeycloakProcessingFilterRequestMatcher(),
new QueryParamPresenceRequestMatcher("access_token"),
new AdapterStateCookieRequestMatcher()
)
);
}
private class IgnoreKeycloakProcessingFilterRequestMatcher implements RequestMatcher {
IgnoreKeycloakProcessingFilterRequestMatcher() {}
public boolean matches(HttpServletRequest request) {
String authorizationHeaderValue = request.getHeader("Authorization");
return authorizationHeaderValue != null && !authorizationHeaderValue.startsWith("Bearer ");
}
}
}
import jakarta.servlet.Filter;
import jakarta.servlet.http.HttpFilter;
public class MySecurityFilter extends HttpFilter implements Filter {
...
}