SocketSecurityConfig.java

package org.flasby.security;

import org.flasby.entity.Authority;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.messaging.MessageSecurityMetadataSourceRegistry;
import org.springframework.security.config.annotation.web.socket.AbstractSecurityWebSocketMessageBrokerConfigurer;

import lombok.extern.log4j.Log4j2;

@Log4j2
@Configuration
public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected boolean sameOriginDisabled() {
        // This is acceptable as the security rules below require an authenticated connection.
        // Not sure why at this point, but all web socket connections fail if this is not overriden.
        return true;
    }

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { 
        log.info("Configuring WebSocket Security");
        messages
            // Any message without a destination (i.e. anything other than Message type of MESSAGE or 
            // SUBSCRIBE) will require the user to be authenticated
            // This is the rule that allows STOMP in the client to connect.
            // The user needs to be authenticated, but no particular role is needed.
            .nullDestMatcher().authenticated() 
            
            // Anyone can subscribe to /user/queue/errors
            //.simpSubscribeDestMatchers("/user/queue/errors").permitAll() // Not used here, we want auth

            // Any message that has a destination starting with "/app/" will be require
            // the user to have the role ROLE_USER
            .simpDestMatchers("/app/**").hasAuthority(Authority.USER.getAuthority()) 
            .simpDestMatchers("/app/**/**").hasAuthority(Authority.USER.getAuthority()) 
            
            // Any message that starts with "/user/", "/queue/" or "/topic/" that is of
            // type SUBSCRIBE will require ROLE_USER
            .simpSubscribeDestMatchers("/user/**", "/topic/**", "/queue/**").hasAuthority(Authority.USER.getAuthority())
            
            // Any other message of type MESSAGE or SUBSCRIBE is rejected. Due to 6 we do not need 
            // this step, but it illustrates how one can match on specific message types.
            // .simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() 
            // Any other Message is rejected. This is a good idea to ensure that you do not miss any messages.
            //.anyMessage().hasRole("USER")
            .anyMessage().denyAll()
            //.anyMessage().denyAll()
            //.anyMessage().authenticated()
            //.anyMessage().permitAll()
            ; 
    }
}