jetty / jetty.project

Eclipse Jetty® - Web Container & Clients - supports HTTP/2, HTTP/1.1, HTTP/1.0, websocket, servlets, and more
https://eclipse.dev/jetty
Other
3.86k stars 1.91k forks source link

Jetty 11 / Spring Boot 3.x - Basic auth not working anymore on websocket endpoint #10433

Closed rcosne closed 1 month ago

rcosne commented 1 year ago

Hi,

I'm currently migrating an application to Spring Boot 3.x which comes with Jetty 11. This application declare a rest controller and a websocket endpoint authenticated via basic auth. But the basic auth does not work anymore on the websocket endpoint.

Sample application: https://github.com/rcosne/ws-test

RestController: http://localhost:8080/test Websocket endpoint: ws://localhost:8080/wstest

It seems that the whole security filter chain is skipped in this case. I've tried to declare a customer filter via @Component, and via a JettyServerCustomizer, in both case, the filter is applied in the rest controller, but not in the websocket endpoint.

I've also tested with Tomcat, then the basic auth works with the websocket.

I've first open an issue on Spring Boot, but they replied the issue is more related to Jetty itself.

Best Regards, Rémy

joakime commented 1 year ago

The default location of the WebSocketUpgradeFilter is at the start of the Filter Chain to prevent breaking countless thousands of existing Filters that are not websocket aware.

The normal process of a request in servlet is (loosely) defined like ...

  1. Servlet Security
  2. Servlet Session Handling
  3. Figure out Filter Chain
  4. Call Filter Chain
  5. Eventually reach Servlet endpoint

The Jetty approach for WebSocketUpgradeFilter default is to add WebSocket upgrade support after Servlet Security and Session Handling and before the Filter Chain.

How do you get around this?

Add the WebSocketUpgradeFilter to your webapp before the webapp is started in any location you want, and before you access the websocket ServerContainer or attempt to add an endpoint.

You might want to set it up as a ServletContainerInitializer of your own.

Something like ...

import java.util.EnumSet;
import java.util.Set;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;

import org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter;

public class ArbitraryWebsocketUpgradeSCI
    implements ServletContainerInitializer
{
    @Override
    public void onStartup(Set<Class<?>> c, ServletContext ctx)
    {
        FilterRegistration.Dynamic filterDynamic = ctx.addFilter("WebSocketUpgrade", WebSocketUpgradeFilter.class);
        filterDynamic.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
        filterDynamic.setAsyncSupported(true);
    }
}

The default WebSocketUpgradeFilter is added by the (jetty-11) class org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer, which can be executed via embedded-jetty or through normal Servlet WebApp initialization of a ServletContainerInitializer.

Using standard Servlet WebApp descriptors you can execute your SCI before others.

You can control the Jetty JakartaWebSocketServletContainerInitializer in a few limited ways, such as turning it off via a ServletContext init-param (or attribute) with the key name org.eclipse.jetty.websocket.jakarta and the value being false (String or Boolean). But be aware that discovered endpoints will not be automatically added. Your own SCI could add them manually if you wanted, or have your SCI just register what you are interested in ...

import jakarta.websocket.Endpoint;
import jakarta.websocket.server.ServerApplicationConfig;
import jakarta.websocket.server.ServerContainer;
import jakarta.websocket.server.ServerEndpoint;
import jakarta.websocket.server.ServerEndpointConfig;

@HandlesTypes({ServerApplicationConfig.class, ServerEndpoint.class, Endpoint.class})
public class ArbitraryWebsocketUpgradeSCI
    implements ServletContainerInitializer

and add what's discovered to the ServerContainer yourself.

joakime commented 1 year ago

This isn't a bug in Jetty that needs fixing.

There are ways to work with WebSocketUpgradeFilter in a non-default way. Spring-Boot is more than capable of making things work with WebSocketUpgradeFilter in a consistent way for other spring-boot components. In fact, I've reached out to spring-boot to see if they are interested in the help.

github-actions[bot] commented 2 months ago

This issue has been automatically marked as stale because it has been a full year without activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] commented 1 month ago

This issue has been closed due to it having no activity.