I am upgrading my Spring application from version 2.7.15 to version 3.3.1 and have encountered issues with the SecurityConfig class. In version 2.7.15, my SecurityConfig class looks like this:
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* Login, Logout, Success, and Access Denied beans/handlers
*/
/* CORS
*/
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setExposedHeaders(Arrays.asList("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600l);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
return new CustomDaoAuthenticationProvider();
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler() {
return new CustomLogoutSuccessHandler();
}
@Bean
public AuthenticationSuccessHandler loginSuccessHandler() {
return new CustomLoginSuccessHandler();
}
@Bean
public AuthenticationFailureHandler loginFailureHandler() {
return new CustomLoginFailureHandler();
}
/**
* Authentication beans
*/
@Bean
public PasswordEncoder encoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return charSequence.toString().equals(s);
}
};
}
@Bean
public AuthenticationProvider authenticationProvider() {
return new CustomDaoAuthenticationProvider();
}
/**
* Order of precedence is very important.
* <p>
* Matching occurs from top to bottom - so, the topmost match succeeds first.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable().addFilterBefore(authenticationFilter(),
CustomAuthenticationFilter.class).cors().and().anonymous().disable()
.authorizeRequests()
.antMatchers( "/backend/index")
.permitAll()
.antMatchers(
"/secured/**/**/**",
"/secured/**/**",
"/secured/socket",
"/secured/success",
"/backend/**"
)
.authenticated()
.and()
.formLogin().disable()
.logout()
.logoutSuccessHandler(logoutSuccessHandler()).and().exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
.and()
.authenticationProvider(authenticationProvider()).anonymous().disable()
.csrf().disable().sessionManagement()
.maximumSessions(10) .expiredUrl("/")
.sessionRegistry(sessionRegistry());
;
/** Disabled for local testing */
/** This is solely required to support H2 console viewing in Spring MVC with Spring Security */
http
.headers()
.frameOptions()
.disable().and().sessionManagement()
.maximumSessions(10) .expiredUrl("/")
.sessionRegistry(sessionRegistry());
}
public CustomAuthenticationFilter authenticationFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationManager(authenticationManagerBean());
filter.setAuthenticationFailureHandler(loginFailureHandler());
filter.setAuthenticationSuccessHandler(loginSuccessHandler());
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/backend/authenticate", "POST"));
return filter;
}
@Bean
SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}
After updating to version 3.3.1, I modified the SecurityConfig class as follows:
public class SecurityConfig {
/**
* Login, Logout, Success, and Access Denied beans/handlers
*/
/* CORS
*/
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOriginPatterns(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("GET","POST"));
configuration.setExposedHeaders(Arrays.asList("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"));
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600l);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new CustomAccessDeniedHandler();
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
return new CustomDaoAuthenticationProvider();
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler() {
return new CustomLogoutSuccessHandler();
}
@Bean
public AuthenticationSuccessHandler loginSuccessHandler() {
return new CustomLoginSuccessHandler();
}
@Bean
public AuthenticationFailureHandler loginFailureHandler() {
return new CustomLoginFailureHandler();
}
/**
* Authentication beans
*/
@Bean
public PasswordEncoder encoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return charSequence.toString().equals(s);
}
};
}
@Bean
public AuthenticationProvider authenticationProvider() {
return new CustomDaoAuthenticationProvider();
}
/**
* Order of precedence is very important.
* <p>
* Matching occurs from top to bottom - so, the topmost match succeeds first.
*/
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.httpBasic(AbstractHttpConfigurer::disable).addFilterBefore(authenticationFilter(),
CustomAuthenticationFilter.class).cors(withDefaults()).anonymous(AbstractHttpConfigurer::disable)
.authorizeRequests()
.requestMatchers( antMatcher("/backend/index"))
.permitAll()
.requestMatchers(
antMatcher("/secured/**/**/**"),
antMatcher("/secured/**/**"),
antMatcher("/secured/socket"),
antMatcher("/secured/success"),
antMatcher("/backend/**")
)
.authenticated()
.and()
.formLogin(AbstractHttpConfigurer::disable)
.logout( logout -> logout.logoutSuccessHandler(logoutSuccessHandler()))
.exceptionHandling(handling -> handling.accessDeniedHandler(accessDeniedHandler()))
.authenticationProvider(authenticationProvider()).anonymous(AbstractHttpConfigurer::disable)
.csrf(AbstractHttpConfigurer::disable).sessionManagement(management -> management.maximumSessions(10)
.expiredUrl("/").sessionRegistry(sessionRegistry()));
;
/** Disabled for local testing */
/** This is solely required to support H2 console viewing in Spring MVC with Spring Security */
http
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
.sessionManagement(management -> management.maximumSessions(10) .expiredUrl("/")
.sessionRegistry(sessionRegistry()));
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(){
return new ProviderManager(authenticationProvider());
}
public CustomAuthenticationFilter authenticationFilter() throws Exception {
CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager());
filter.setAuthenticationFailureHandler(loginFailureHandler());
filter.setAuthenticationSuccessHandler(loginSuccessHandler());
filter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/backend/authenticate", "POST"));
return filter;
}
@Bean
SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
}
It seems that the security configuration is not working as expected after the update. When I try to log in from the frontend app, I get a 403 code. I use WebSockets for login, so I’m not sure if that has something to do with it.
I’ve added this to my logback.xml <logger name="org.springframework.security" level="DEBUG" />
and also enabled the debug in @EnableWebSecurity(debug = true)
but I only get these logs
3