Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Oidc Logout Improvements #15540

Merged
merged 14 commits into from
Sep 16, 2024
Merged

Oidc Logout Improvements #15540

merged 14 commits into from
Sep 16, 2024

Conversation

jzheaux
Copy link
Contributor

@jzheaux jzheaux commented Aug 8, 2024

This brings support for #13841 and #14904.

To configure OIDC Back-Channel logout to reuse the Back-Channel endpoint to invalidate each individual session (thus removing the need for the CSRF token), configure OIDC logout in the following way:

.oidcLogout((oidc) -> oidc
    .backChannel(Customizer.withDefaults())
)

NOTE that for simplicity, this changes the default internal URI. Since it changes it to point back to the OIDC back-channel URL itself, I believe this will go unnoticed by most applications. That said, in case you need your URI to stay as-is, you can specify the URI as follows:

// ...
.oidcLogout((oidc) -> oidc
    .backChannel((backChannel) -> backChannel
        .logoutUri(myCustomInternalUri)
    )
)

To configure OIDC Back-Channel Logout with a different cookie name, configure it as follows:

@Bean 
OidcSessionRegistry sessionRegistry() {
    return new InMemoryOidcSessionRegistry();
}

@Bean
OidcBackChannelLogoutHandler oidcLogoutHandler(OidcSessionRegistry sessionRegistry) {
    OidcBackChannelLogoutHandler logoutHandler = new OidcBackChannelLogoutHandler(sessionRegistry);
    // the logout URI can also be configured here
    logoutHandler.setSessionCookieName("SESSION");
    return logoutHandler;
}

Or it can also be specified in the DSL directly:

// ...
.oidcLogout((oidc) -> oidc
    .backChannel((backChannel) -> backChannel
        .logoutHandler(logoutHandler)
    )
)

@jzheaux jzheaux added type: enhancement A general enhancement in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) labels Aug 8, 2024
@jzheaux jzheaux added this to the 6.4.0-M2 milestone Aug 8, 2024
@jzheaux jzheaux self-assigned this Aug 8, 2024
@jzheaux
Copy link
Contributor Author

jzheaux commented Aug 8, 2024

@ch4mpy would you please look over this PR as see if is addresses your concerns about CSRF and Spring Session?

@ch4mpy
Copy link
Contributor

ch4mpy commented Aug 12, 2024

@jzheaux I can confirm that, when building the branch for this PR locally, Back-Channel Logout works in this project of mine. The OP is Keycloak. The RP used to trigger the Back-Channel Logout is Keycloak's user account management. The RP receiving the Back-Channel Logout request is a spring-cloud-gateway instance (the reactive version) configured with:

  • oauth2Login
  • cookie-based protection against CSRF (because it is called by a SPA authorizing requests with a session cookie)
  • RP-Initiated Logout (keeps working, validating the CSRF token)
  • Back-Channel Logout (fails with latest release, but is successful with this PR)

I can confirm too that configuring the Back-Channel logout URI works as documented in your comment above.

But warning: I had to configure a custom URI because the port for the "internal" request was determined using the original request instead of application properties. My client is behind a reverse proxy that uses a custom hostname and a path prefix for the BFF. The port for the proxy is 80 and the port for the Spring client with oauth2Login and Back-Channel Logout is 7080. The port was resolved to 80, which required the request to go through the reverse-proxy. As you made this URI configurable, I could walk around the problem, but shouldn't OidcBackChannelLogoutHandler resolve "all or none" of scheme, authority, and basePath from the original request?

  • The "all" strategy is appealing because it is easy: we need to call the same endpoint. However, it requires the entry-point of the system to be accessible from the Spring OAuth2 client with the same hostname (if the Spring app runs in a Docker container, it is possible that this hostname is not resolved or resolved to the wrong host).
  • the "none" strategy (URI built around localhost from application properties instead of the original request) has the advantage of working even on dev machines with Spring app running in Docker. But maybe is it acceptable to configure the URI in that case?

@sjohnr sjohnr modified the milestones: 6.4.0-M2, 6.4.0-M3 Aug 19, 2024
@marcusdacoregio marcusdacoregio modified the milestones: 6.4.0-M3, 6.4.0-M4 Aug 22, 2024
@jzheaux jzheaux force-pushed the gh-13841 branch 5 times, most recently from e59dba7 to faf4ce7 Compare September 4, 2024 00:20
This component already uses by default a URI that doesn't require
a CSRF token and aalready allows for configuring a cookie name.

So, by making it public and configurable in the DSL, both
of these tickets quite naturally close.

Closes spring-projectsgh-13841
Closes spring-projectsgh-14904
@jzheaux jzheaux merged commit b311b81 into spring-projects:main Sep 16, 2024
6 checks passed
@jzheaux jzheaux deleted the gh-13841 branch September 16, 2024 04:31
@ch4mpy
Copy link
Contributor

ch4mpy commented Sep 27, 2024

@jzheaux I like what you did with the OidcBackChannelServerLogoutHandler bean to configure Back-Channel Logout. It made my life very easy to adapt my starter to enable this feature and configure it with application properties. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: oauth2 An issue in OAuth2 modules (oauth2-core, oauth2-client, oauth2-resource-server, oauth2-jose) type: enhancement A general enhancement
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

4 participants