5

I'm using Spring 4.3.5 and WebSocket with SockJS, STOMP and SimpleBrokerMessageHandler.

In my application I have three separate WebSocket endpoints running on a different address: /endPointA, /ednpointB, /endpointC To be even more specific, I have three separate configuration classes annotated with @Configuration @EnableWebSocketMessageBroker annotations.

I also have a Class that has @Autowired SimpMessagingTemplate.

Finally I have three clients, each connected to one, different EndPoint. All of them, however are subscribed to the "same" channel address which is /topic/messages

  • ClientOne is connected endpointA
  • ClientTwo is connected endpointB
  • ClientThree is connected endpointC

When I use SimpMessagingTemplate to send something to /topic/messages, then all clients receives this message.

After that I have two questions:

  1. Is there a way to "isolate" the web Socket endpoints so the message will not be propagated to all endpoints?
  2. Why is this actually happening here?

I did some investigation (heap dump analysis) and I found that for my configuration I have:

  • Three instances of SimpMessagingTemplate, However I'm using always the same one instance to send a message (because of @Autowire - additionaly I'm printing SimpMessagingTemplate.toString()).
  • One instance of SimpleBrokerMessageHandler
  • Three instances of SockJsWebSocketHandler

So I wonder, if this message propagation over all endpoits is a "feature" of SimpleBrokerMessageHandler or SimpMessagingTemplate.

Kristoff
  • 326
  • 2
  • 13
  • I have a similar issue. Can you recall how you resolved this? – YetAnotherBot Feb 25 '19 at 05:27
  • Hi, unfortunately we didn't. We accept the reality - it was proof of concept app. Although I'm still curious what was the reason behind it. – Kristoff Feb 26 '19 at 08:31
  • Reason depends on your configuration. Possibly all the clients were subscribed to the same topic. Instead, they should be subscribed to their respective *queues* – YetAnotherBot Feb 26 '19 at 09:20
  • Yes there were subscribed to the same topic, although I thought that there is a topic isolation between endpoints with different names. – Kristoff Feb 26 '19 at 21:17
  • Na, messaging does not work that way. Isolation can be done through dedicated queues. – YetAnotherBot Feb 27 '19 at 05:25

1 Answers1

3

I facing the same issue in a multi-tenant application that I solved thanks to this thread :

My websocket endpoint is: ws://127.0.0.1/my-context-app/ws , java config file is:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

   @Override
   public void registerStompEndpoints(StompEndpointRegistry registry) {       
      registry.addEndpoint("/ws").setAllowedOrigins("*");
      registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS(); 
   }
}

My websocket queues url forms are prefixed by tenant-id: /[tenant-id]/[url-of-queue].

Each client subscribe on its own tenant-id. It can not subscribe to queue of another client thanks to WebSocketSecurityConfig.configureInbound(MessageSecurityMetadataSourceRegistry) method and a custom spring bean which has a 'websocket-queue-subscription-security-check' method :

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
          .simpSubscribeDestMatchers("/**")
          .access("@customWSSecurityCheck.isSubscriptionAllowed(authentication, message)");
    }

}

My custom bean named customWSSecurityCheck check if authenticated user is allowed to subscribe on queue. Keep in mind that CustomAuthentication implements org.springframework.security.core.Authentication with additional tenantId attribute that is filled by additional code not mentioned there on a custom spring security filter / authentication method:

@Bean()
public class CustomWSSecurityCheck {

    public boolean isSubscriptionAllowed(CustomAuthentication authentication, Message message) {

       StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
       String url = sha.getDestination().substring(1);
       String tenantId = url.substring(0, url.indexOf("/"));

       return tenantId.equals(authentication.getTenantId());
    }
}

Of course It involve that every message sended by the server should be prefixed by the right tenant-id: MessagingService.convertAndSend("[tenant-id]/[url-of-queue]", messagePayload)

asyncmind
  • 185
  • 1
  • 9