简体   繁体   中英

Logout at Spring Authorization Server doesn’t terminate user session in Keycloak

I am trying to implement an end-user initiated logout mechanism.

I have 4 main entities involved.

  • Client: an Angular app registered as a public OIDC client on Keycloak
  • Keycloak: behaves as an identity broker
  • Spring Authorization Server: identity provider registered on Keycloak
  • Resource Server: a Spring Boot application with a secure REST endpoint

When the end-user initiates a logout , a call is made by the Angular application to Keycloak's end_session_endpoint . I have configured the logout URL for my identity provider ( Spring Authorization Server ) in Keycloak as http://localhost:9000/logout which is the default Spring Security logout endpoint.

FYI: I haven't enabled BackChannel or FrontChannel logout.

在此处输入图像描述

In the Network tab of Developer Console , the sequence of calls happen as below:

While inspecting the DEBUG logs in the Spring Authorization Server , I am able to see the logout happen for that particular end-user including invalidating the JSESSIONID , however the session doesn't terminate in Keycloak which causes the user to stay logged in and access the secure REST endpoint.

Is the Spring Authorization Server expected to return a specific response back to Keycloak to convey that the logout process is complete at it's end and that Keycloak can end the session now?

This is my logic for logout at Spring Authorization Server .

@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {

    http.csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(
                        authorize -> authorize.mvcMatchers("/hello/**").permitAll().anyRequest().authenticated())
                .formLogin(form -> form.loginPage("/login").permitAll())
                .addFilterAfter(cookieFilter, ChannelProcessingFilter.class)
                .logout().logoutSuccessUrl("http://localhost:4200");
        
    return http.build();
}

I am totally clueless about what I am missing to make Keycloak end the session at it's end. Any leads will be greatly appreciated.

Thank you!

Update: A post_logout_redirect_uri parameter is sent in the logout request to the Spring Authorization Server . I am not able to see a redirection happen to this URI which may be the reason that Keycloak session doesn't terminate.

post_logout_redirect_uri=http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response

Got this to work finally!

The logoutSuccessUrl("http://localhost:4200") is incorrect.

As I mentioned in the Update part of my question that Keycloak sends a post_logout_redirect_uri parameter (inspected the logout endpoint in the Network calls in Chrome Developer Console ), the logoutSuccessUrl or the redirectUri should be set to

http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response

Also, note that the above URL takes in state as a request parameter. Initially, it gave me a 400 Bad Request as I didn't send the state .

Since I was required to intercept the state parameter when logout is initiated at the Spring Authorization Server , I added a custom logout handler to do the job.

@Component
public class IdpLogoutHandler implements LogoutHandler {

    private static final String STATE = "state";

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
        String state = request.getParameter(STATE);
        try {
            response.sendRedirect(
                    "http://127.0.0.1:8080/auth/realms/SpringBootKeycloak/broker/oidc/endpoint/logout_response?state="
                            + state);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Updated WebSecurityConfig :

http.csrf(csrf -> csrf.disable())
                .authorizeHttpRequests(
                        authorize -> authorize.mvcMatchers("/hello/**").permitAll().anyRequest().authenticated())
                .formLogin(form -> form.loginPage("/login").permitAll())
                .addFilterAfter(cookieFilter, ChannelProcessingFilter.class).logout()
                .addLogoutHandler(customLogoutHandler);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM