You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Describe the bug
Upgrading from Spring Boot 3.3.0 to 3.4.2 I'm suddenly getting issues with CSRF when the OidcBackChannelLogoutHandler performs a POST request for logging out. It seems to be the CsrfFilter that creates it and passes it to the AccessDeniedHandler, which results in the logout to fail. I'm using the setup as described in https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript-spa. Disabling csrf protection the OIDC backchannel logout works fine.
To Reproduce
Prepare an application which uses Spring Session stored in JDBC + OIDC backchannel logout configured and has CSRF protection
Log in to the application using OIDC integration
Trigger OIDC back channel logout
Expected behavior
The user is successfully logged out and has its session invalidated.
Actual behavior
OidcBackChannelLogoutHandler fails in its request to logout, as the MissingCsrfTokenException is caught by the AccessDeniedHandler.
Sample
@EnableWebSecurity
@EnableMethodSecurity(jsr250Enabled = true, securedEnabled = true)
public class SecurityConfig {
protected static final String LOCAL_LOGOUT_URL = "http://localhost:8080/logout";
protected static final String SESSION_COOKIE_NAME = "JSESSIONID";
@Bean
public void configure(HttpSecurity http, AccessDeniedHandler accessDeniedHandler,
AuthenticationEntryPoint authenticationEntryPoint,
GrantedAuthoritiesMapper grantedAuthoritiesMapper,
StilLoginOidcUserHandler stilLoginOidcUserHandler,
AuthenticationSuccessHandler authenticationSuccessHandler,
LogoutSuccessHandler logoutSuccessHandler,
ClientRegistrationRepository clientRegistrationRepository,
MvcRequestMatcher.Builder mvc,
OidcSessionRegistry oidcSessionRegistry,
OidcSessionLogoutHandler oidcSessionLogoutHandler) throws Exception {
http
.csrf(csrf -> csrf
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.csrfTokenRequestHandler(new SpaCsrfTokenRequestHandler())
.ignoringRequestMatchers(LOCAL_LOGOUT_URL)
)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers(mvc.pattern("/api/**")).authenticated()
// Permissions to load Angular SPA
.requestMatchers(
mvc.pattern("/"),
mvc.pattern("/index.html"),
mvc.pattern("*.css"),
mvc.pattern("*.js"),
mvc.pattern("*.woff"),
mvc.pattern("*.woff2")
).permitAll()
.requestMatchers(mvc.pattern("/logout")).authenticated()
.anyRequest().permitAll() // Let Angular handle the routing for unknown paths
)
.oauth2Login(oauth2 -> oauth2
.authorizationEndpoint(authorizationEndpointConfig -> {
var resolver = new DefaultOAuth2AuthorizationRequestResolver(clientRegistrationRepository, OAUTH2_REQUEST_BASE_URI);
resolver.setAuthorizationRequestCustomizer(OAuth2AuthorizationRequestCustomizers.withPkce());
authorizationEndpointConfig.authorizationRequestResolver(resolver);
})
.userInfoEndpoint(userInfo -> userInfo
.oidcUserService(stilLoginOidcUserHandler)
.userAuthoritiesMapper(grantedAuthoritiesMapper))
.successHandler(authenticationSuccessHandler)
.oidcSessionRegistry(oidcSessionRegistry)
)
.logout(logout -> logout
.clearAuthentication(true)
.invalidateHttpSession(true)
.deleteCookies(SESSION_COOKIE_NAME)
.addLogoutHandler(oidcSessionLogoutHandler)
.logoutSuccessHandler(logoutSuccessHandler)
)
.oidcLogout(oidcLogout -> oidcLogout
.backChannel(backChannel -> backChannel.logoutUri(LOCAL_LOGOUT_URL))
.clientRegistrationRepository(clientRegistrationRepository)
.oidcSessionRegistry(oidcSessionRegistry)
)
.exceptionHandling(exceptions -> exceptions
.authenticationEntryPoint(authenticationEntryPoint)
.accessDeniedHandler(accessDeniedHandler)
);
}
@Bean
public MvcRequestMatcher.Builder mvc(HandlerMappingIntrospector introspector) {
return new MvcRequestMatcher.Builder(introspector);
}
@Bean
public LogoutSuccessHandler oidcLogoutSuccessHandler(ClientRegistrationRepository clientRegistrationRepository) {
var oidcLogoutSuccessHandler = new OIDCLogoutSuccessHandler(clientRegistrationRepository);
oidcLogoutSuccessHandler.setPostLogoutRedirectUri("https://{baseHost}{basePort}" + ENDPOINTS_LOGOUT);
return oidcLogoutSuccessHandler;
}
@Bean
public OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
return new OidcUserService();
}
@Bean
public CookieSerializer cookieSerializer() {
var serializer = new DefaultCookieSerializer();
serializer.setCookieName(SESSION_COOKIE_NAME);
serializer.setUseBase64Encoding(false);
return serializer;
}
}
The text was updated successfully, but these errors were encountered:
Describe the bug
Upgrading from Spring Boot 3.3.0 to 3.4.2 I'm suddenly getting issues with CSRF when the OidcBackChannelLogoutHandler performs a POST request for logging out. It seems to be the CsrfFilter that creates it and passes it to the AccessDeniedHandler, which results in the logout to fail. I'm using the setup as described in https://docs.spring.io/spring-security/reference/servlet/exploits/csrf.html#csrf-integration-javascript-spa. Disabling csrf protection the OIDC backchannel logout works fine.
To Reproduce
Expected behavior
The user is successfully logged out and has its session invalidated.
Actual behavior
OidcBackChannelLogoutHandler fails in its request to logout, as the MissingCsrfTokenException is caught by the AccessDeniedHandler.
Sample
The text was updated successfully, but these errors were encountered: