1

I am writing an application with spring messaging and stomp and rabbitmq. My application already sends messages from the browser to rabbitmq and back. But i dont want the predefined rabbitmq queue names based on the session id. I want to change the session id on connect. This is what i tried:

@Component
public class MyListener {

    private Logger logger = LoggerFactory.getLogger(getClass().getSimpleName());

    @EventListener
    public void x(SessionConnectEvent event) {
        Map<String, Object> headers = event.getMessage().getHeaders();
        String id = headers.get("simpSessionId").toString();
        logger.info("My current session id is " + id);
        headers.put("sessionId", "fred");
    }
}

Error is: the map is immutable

Arquillian
  • 125
  • 2
  • 16

3 Answers3

0

You need to update the sessionId before the handshake is done between client <-> server, that is when the headers attributes are defined.

On the other hand, the listener SessionConnectEvent is executed only after the handshake is done.

public class HttpHandshakeInterceptor implements HandshakeInterceptor {

@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
        Map attributes) throws Exception {
    if (request instanceof ServletServerHttpRequest) {
        ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
        HttpSession session = servletRequest.getServletRequest().getSession();
        attributes.put("sessionId", "mySessiond");
    }
    return true;
}

public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler,
        Exception ex) {
}
}

Also don't forget to register the interceptor on the specific endpoint

 @Override
 public void registerStompEndpoints(StompEndpointRegistry registry) {
  registry.addEndpoint("/greeting").addInterceptors(new HttpHandshakeInterceptor());
 }
Thomas.L
  • 321
  • 1
  • 6
  • SimpMessageHeader didnt work.Then I tried StompHeaderAccessor. here I could change the stomp sesion. But unfortunately this is already too late. It seems the websocket opening already sets a session id and connects to rabbit mq creating a session with that id. Log file says: DEBUG org.eclipse.jetty.server.HttpChannel - REQUEST for //localhost:8080/ws/821/h4wuuakg/websocket on HttpChannelOverHttp@695ff5f1{r=1,c=false,a=IDLE,uri=//localhost:8080/ws/821/h4wuuakg/websocket} – Arquillian Aug 25 '17 at 09:53
  • it is because you need to do it BEFORE the handshake is done, `SessionConnectEvent` listener is executed after the client is already subscribed. So you need to intercept the handshake I will update the code with example – Thomas.L Aug 25 '17 at 11:06
  • thank you for your ongoing help. i played around with interceptors before. tried it now again. my example is just slightly different (WebSocketConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer and stompWebSocketEndpointRegistration.withSockJS().setInterceptors(new HttpHandshakeInterceptor()); ). But all I get is a broken pipe a minute or so after starting the connection. I am using @SendToUser. Is this the problem? My url is @SendToUser("/queue/myapp"). But the log changes this to "COMMIT for /ws/812/5j1pthrs/websocket" – Arquillian Aug 25 '17 at 12:33
  • Hm I think its the wrong aproach and I stil missunderstand the #SendTo, #SendToUser and #MessageMapping annotations. – Arquillian Aug 25 '17 at 16:10
  • I think I have to check simpSessionAttributes and set the principal there. then ApplicationListeners and check before any subscription for the principal. – Arquillian Aug 25 '17 at 17:46
  • I made a new more detailed question acording this problem. Sessions dont seem to work. This question can be closed. The new question: https://stackoverflow.com/questions/45920979/securing-a-spring-messaging-based-websocket-service @Thomas.L – Arquillian Aug 28 '17 at 14:10
0

You can change the session id by creating a Principal for each handshake and then you can target each connected session with the provided username :

class CustomHandshake extends DefaultHandshakeHandler {
    @Override
    public Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) {
        Principal principal = request.getPrincipal();
        if (principal == null) {
            principal = new AnonymousPrincipal();

            String uniqueName = UUID.randomUUID().toString();

            ((AnonymousPrincipal) principal).setName(uniqueName);
        }

        return principal;
    }

}

Do not forget to register the handler as below :

.setHandshakeHandler(new CustomHandshake())

hope this is helpful

  • I haven't found documentation for a built-in `AnonymousPrincipal()`, is that just this? https://stackoverflow.com/a/43240293/114900 – msanford Sep 17 '21 at 18:17
-1

Changing the session ID was not the correct way. I used ServletFilter for Cookie and Security Checks and @SendTo for the correct use of rabbitmq queues.

Arquillian
  • 125
  • 2
  • 16
  • `Changing the session ID was not the correct way` it does not really matter since it is what you were asking for in the original question – FARS Aug 16 '23 at 15:33