spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.73k stars 5.86k forks source link

OidcClientInitiatedServerLogoutSuccessHandler not working #9738

Closed rigon closed 3 years ago

rigon commented 3 years ago

Describe the bug When OidcClientInitiatedServerLogoutSuccessHandler is configured, the redirect logout is not initiated in the client. I think something changed in Spring Security. This was working as expected up to version2.3.10.RELEASE of Spring Boot, but after 2.4.0 stopped working.

This behaviour is visible in these two places:

To Reproduce

  1. Login in the App using the Identity Provider.
  2. Observe the value of oidcUser when calling the endpoint GET /
  3. Perform the logout action

Expected behavior Perform the logout from the Identity Provider. The URL used for this is defined by end_session_endpoint and we should see a redirect with it in the network log (browser inspector).

Sample Used dependencies:

application.yml:

spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            provider: keycloak
            client-id: example
            client-secret: secret
        provider:
          keycloak:
            issuer-uri: http://localhost-keycloak:8080/auth/realms/example

Sample application:

package sample;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.annotation.RegisteredOAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.oidc.web.server.logout.OidcClientInitiatedServerLogoutSuccessHandler;
import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.logout.ServerLogoutSuccessHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@SpringBootApplication
@RestController
@EnableWebFluxSecurity
public class ReactiveOAuth2LoginApplication {
    @Autowired
    private ReactiveClientRegistrationRepository clientRegistrationRepository;

    public static void main(String[] args) {
        SpringApplication.run(ReactiveOAuth2LoginApplication.class, args);
    }

    @GetMapping("/")
    public Mono<String> index(@RegisteredOAuth2AuthorizedClient OAuth2AuthorizedClient authorizedClient,
                  @AuthenticationPrincipal OidcUser oidcUser) {
        return Mono.just(authorizedClient.getAccessToken().getTokenValue());
    }

    @Bean
    SecurityWebFilterChain configure(ServerHttpSecurity http) {
        http
            .authorizeExchange()
                .anyExchange()
                .authenticated()
                .and()
            .oauth2Login()
                .and()
            .logout(logout -> logout
                    .logoutSuccessHandler(oidcLogoutSuccessHandler()));

        return http.build();
    }
    private ServerLogoutSuccessHandler oidcLogoutSuccessHandler() {
        OidcClientInitiatedServerLogoutSuccessHandler oidcLogoutSuccessHandler =
                new OidcClientInitiatedServerLogoutSuccessHandler(this.clientRegistrationRepository);

        // Sets the location that the End-User's User Agent will be redirected to
        // after the logout has been performed at the Provider
        oidcLogoutSuccessHandler.setPostLogoutRedirectUri("{baseUrl}");

        return oidcLogoutSuccessHandler;
    }
}
jzheaux commented 3 years ago

I wonder if this is related to https://github.com/spring-projects/spring-security/commit/0486d5add983dd09295fffeee13015cdd74bf322.

@rigon, if you specify the list of scopes that you require in the spring.security.oauth2.client.registration.keycloak.scope property, does that repair the behavior?

It would need to at least include openid:

spring:
  security:
    oauth2:
      client:
        registration:
          keycloak:
            scope: openid
spring-projects-issues commented 3 years ago

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

rigon commented 3 years ago

@jzheaux That is actually true. Specifying the scope openid solves the problem, the application works as intended. Thanks a lot for the tip.

I was migrating my Spring Boot application from 2.3 to 2.4. The confusion with this had to do with the fact that I was relying on default scopes without realizing it and wasn't clear in the documentation. Closing this issue.

jzheaux commented 3 years ago

Glad that worked, @rigon. Is there someplace in the documentation that you feel should be changed? If so, would you be able to submit a PR?

straurob commented 2 years ago

Today I ran into the same issue with spring-boot-starter-oauth2-client:2.6.3. After having added scope: openid to my application.yml, the end_session_endpoint was correctly resolved from Keycloak configuration URL.

However, I quite don't understand the relation between the scope parameter and this issue. Has there been an update of the documentation which I might be missing? @jzheaux

Having read #5494 and especially this comment my understanding is this:

Is my understanding correct?

jzheaux commented 2 years ago

Yes, @straurob, you've got it right.