I am new to SAML security and KEYCLOAK. I have a client in KEYCLOAK with SAML protocol. My application is configured to this SAML client. When I log in to my application, the authentication is successful at SAML and I am able to log into my application. User session is also created in keycloak. While performing logout operation, the user is just logged out from my application and not from SAML.The user remains active.
How do I perform a logout so that saml session is also cleared. I found that spring saml supports "/saml/logout" to clear the session. But this url needs to be explicitly called from the browser and then again a logout has to be performed from my application. Is there a way to perform both these calls in one shot.
below is my samlSecurityconfig java code:
@Bean
public FilterChainProxy samlFilter() throws Exception {
List<SecurityFilterChain> chains = new ArrayList<>();
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"),
samlEntryPoint()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"),
samlLogoutFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"),
metadataDisplayFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"),
samlWebSSOProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSOHoK/**"),
samlWebSSOHoKProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"),
samlLogoutProcessingFilter()));
return new FilterChainProxy(chains);
}
// Handler for successful logout
@Bean
public SimpleUrlLogoutSuccessHandler successLogoutHandler() {
SimpleUrlLogoutSuccessHandler successLogoutHandler = new CustomSimpleUrlLogoutSuccessHandler();
successLogoutHandler.setDefaultTargetUrl(config().getSp().getEntityBaseURL());
return successLogoutHandler;
}
// Logout handler terminating local session
@Bean
public SecurityContextLogoutHandler logoutHandler() {
SecurityContextLogoutHandler logoutHandler =
new SecurityContextLogoutHandler();
logoutHandler.setInvalidateHttpSession(true);
logoutHandler.setClearAuthentication(true);
return logoutHandler;
}
// Filter processing incoming logout messages
// First argument determines URL user will be redirected to after successful
// global logout
@Bean
public SAMLLogoutProcessingFilter samlLogoutProcessingFilter() {
return new SAMLLogoutProcessingFilter(successLogoutHandler(),
logoutHandler());
}
// Overrides default logout processing filter with the one processing SAML
// messages
@Bean
public SAMLLogoutFilter samlLogoutFilter() {
return new SAMLLogoutFilter(successLogoutHandler(),
new LogoutHandler[]{logoutHandler()},
new LogoutHandler[]{logoutHandler()});
}
@Bean
public FilterChainProxy samlFilter() throws Exception {
List<SecurityFilterChain> chains = new ArrayList<>();
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"),
samlEntryPoint()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"),
samlLogoutFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"),
metadataDisplayFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"),
samlWebSSOProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSOHoK/**"),
samlWebSSOHoKProcessingFilter()));
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"),
samlLogoutProcessingFilter()));
return new FilterChainProxy(chains);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.httpBasic()
.authenticationEntryPoint(samlEntryPoint());
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.ignoringAntMatchers("/saml/**");
http
.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class)
.addFilterAfter(samlFilter(), BasicAuthenticationFilter.class);
http
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/saml/logout"))
.deleteCookies("JSESSIONID")
.logoutSuccessUrl(config().getSp().getEntityBaseURL() + LOGIN);
http
.headers()
.frameOptions()
.disable();
http
.sessionManagement()
.sessionAuthenticationErrorUrl(config().getSp().getEntityBaseURL() + LOGIN)
.invalidSessionUrl(config().getSp().getEntityBaseURL() + LOGIN);
http
.sessionManagement()
.maximumSessions(1)
.expiredUrl(config().getSp().getEntityBaseURL() + LOGIN);
http
.sessionManagement()
.sessionFixation()
.newSession();
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.NEVER);
permitEndpoints(http);
}
public class CustomSimpleUrlLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
if(config().getSp().getEntityBaseURL().equalsIgnoreCase(this.getDefaultTargetUrl())) {
URLBuilder builder = new URLBuilder(request.getRequestURL().toString());
builder.setPath("/");
builder.setFragment("/login");
builder.setPort(CmsUtil.getWebServerPort());
this.setDefaultTargetUrl(builder.buildURL());
}
super.onLogoutSuccess(request, response, authentication);
}
}
please help