PROBLEM: I am not getting Spring Security with Websockets to work in a Webflux project.
NOTE: I am using Kotlin instead of Java.
DEPENDENCIES:
Spring Boot 2.0.0
Spring Security 5.0.3
Spring WebFlux 5.0.4
IMPORTANT UPDATE: I have raised a Spring Issue bug (March 30) here and one of the Spring security maintainers said its NOT SUPPORTED but they can add it for Spring Security 5.1.0 M2.
LINK: Add WebFlux WebSocket Support #5188
Webflux Security Configuration
@EnableWebFluxSecurity
class SecurityConfig
{
@Bean
fun configure(http: ServerHttpSecurity): SecurityWebFilterChain
{
return http.authorizeExchange()
.pathMatchers("/").permitAll()
.anyExchange().authenticated()
.and().httpBasic()
.and().formLogin().disable().csrf().disable()
.build()
}
@Bean
fun userDetailsService(): MapReactiveUserDetailsService
{
val user = User.withDefaultPasswordEncoder()
.username("user")
.password("pass")
.roles("USER")
.build()
return MapReactiveUserDetailsService(user)
}
}
Webflux Websocket Configuration
@Configuration
class ReactiveWebSocketConfiguration
{
@Bean
fun webSocketMapping(handler: WebSocketHandler): HandlerMapping
{
val map = mapOf(Pair("/event", handler))
val mapping = SimpleUrlHandlerMapping()
mapping.order = -1
mapping.urlMap = map
return mapping
}
@Bean
fun handlerAdapter() = WebSocketHandlerAdapter()
@Bean
fun websocketHandler() = WebSocketHandler { session ->
// Should print authenticated principal BUT does show NULL
println("${session.handshakeInfo.principal.block()}")
// Just for testing we send hello world to the client
session.send(Mono.just(session.textMessage("hello world")))
}
}
Client Code
// Lets create a websocket and pass Basic Auth to it
new WebSocket("ws://user:pass@localhost:8000/event");
// ...
Obserservations
In the websocket handler the principal shows null
The client can connect without being authenticated. If I do
WebSocket("ws://localhost:8000/event")without the Basic Auth it stills works! So Spring Security does not authenticate anything.
What I am missing? What I do wrong?