Skip to content

Single sign-off: RP-Initiated logout #24

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

Closed
heruan opened this issue Aug 22, 2022 · 6 comments · Fixed by #32
Closed

Single sign-off: RP-Initiated logout #24

heruan opened this issue Aug 22, 2022 · 6 comments · Fixed by #32
Assignees
Labels

Comments

@heruan
Copy link
Member

heruan commented Aug 22, 2022

In #22 are described the requirements of proper session management when dealing with single sign-on providers, and single sign-off is among the others a sensible one as it involves different scenarios; for example:

  1. the currently authenticated user in the app clicks on the logout button, which sessions should be invalidated?
  2. the user invalidates the single sign-on session from elsewhere (outside Vaadin, or from another Vaadin app), how the current app would know about this?

The first scenario can be managed within the app, by invalidating both Vaadin's and the servlet's sessions and signaling the provider redirecting the user to the provider's own logout URL.

The OpenID Connect standard specify a standardized way to approach the second scenario, which is called Back-Channel Logout. The spec requires a in-app stateless URL to send logout requests from the provider, with the Session-ID (SID) of the user sessions which should be terminated (being that currently active or not).

Currently Spring does not offer that support, but there is an open request to have this part of the Spring's OIDC implementation: spring-projects/spring-security#7845

We can start implementing support for the first scenario and in the meanwhile investigate if Spring is going to add support for back-channel logout in the short-term.

@heruan heruan added the core label Aug 22, 2022
@knoobie
Copy link

knoobie commented Aug 23, 2022

While spring doesn't support Back-Channel-Logout, some can use (for example with keycloak) OpenID Connect RP-Initiated Logout with e.g. a custom logout success handler like described here: https://stackoverflow.com/a/67853291/1662997

@heruan
Copy link
Member Author

heruan commented Aug 23, 2022

Yes, exactly! The implementation will start with an RP-Initiated Logout for the first scenario, using the OidcClientInitiatedLogoutSuccessHandler as mentioned in the SO answer you linked or also here in this Okta blog post: https://developer.okta.com/blog/2020/03/27/spring-oidc-logout-options

@heruan
Copy link
Member Author

heruan commented Aug 25, 2022

We can also provide some configuration properties to handle the logout process, for example:

vaadin:
  auth:
    logout-url: /logout
    logout-redirect-url: /

Those values would be the default, but in case the developer wants to provide a logout confirmation view they'd be able to do so setting a custom logout-redirect-url.

@heruan
Copy link
Member Author

heruan commented Aug 25, 2022

Seems like what Spring does to logout the user when hitting /logout is configured in LogoutConfigurer.java#L327-L338 which is then handled by LogoutFilter.java#L96-L108.

So the SecurityContextLogoutHandler is always used, plus any additional LogoutHandlers configured and then at last the single LogoutSuccessHandler.

For example, this would properly logout from the local security-context and the OIDC provider:

public class LogoutView extends VerticalLayout {

    public LogoutView(ClientRegistrationRepository clientRegistrationRepository, ApplicationEventPublisher eventPublisher) {
        add(new Button("Logout", click -> {
            var auth = SecurityContextHolder.getContext().getAuthentication();
            var logoutHandler = new SecurityContextLogoutHandler();
            var eventPublishingHandler = new LogoutSuccessEventPublishingLogoutHandler();
            eventPublishingHandler.setApplicationEventPublisher(eventPublisher);
            var handler = new CompositeLogoutHandler(logoutHandler, eventPublishingHandler);
            var req = VaadinServletRequest.getCurrent().getHttpServletRequest();
            var res = VaadinServletResponse.getCurrent().getHttpServletResponse();
            handler.logout(req, res, auth);
            var oidcLogoutHandler = OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository);
            try {
                oidcLogoutHandler.onLogoutSuccess(req, res, auth);
            } catch (IOException | ServletException e) {
                e.printStackTrace();
            }
        });
    }
}

But this does not take into account any custom logout handler that could be added to the security configuration, so it's not optimal.

The other way around would be hitting /logout for real, i.e. with a POST request and a valid CSRF token, which means:

  • adding a <form method="post"> element (not sure we have one);
  • adding an hidden <input> with the CSRF token (not sure how to get that);
  • adding a <button type="submit"> to submit the form to the /logout URL.

See also this issue which is related to RP-Initiated logout: https://github.com/vaadin/start/issues/2010

@heruan
Copy link
Member Author

heruan commented Aug 29, 2022

To avoid writing enormous click listeners we might provide helpers via some kind of object which could also provide the logout functionality, for example the context bean described to get user informations in #14 (comment)

@heruan
Copy link
Member Author

heruan commented Aug 31, 2022

This issue will track RP-Initiated logout, while support for back-channel logout will be tracked by #29.

@heruan heruan changed the title Single sign-off Single sign-off: RP-Initiated logout Aug 31, 2022
@heruan heruan closed this as completed in #32 Sep 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants