Jackie
Jackie

Reputation: 23607

Is there a way to notify a web socket if they are not permitted to subscribe using spring-security?

For the full repo look here

I have the following...

    @Bean
    fun messageAuthorizationManager(
        messages: MessageMatcherDelegatingAuthorizationManager.Builder
    ): AuthorizationManager<Message<*>> {
        messages
            // Next 2 lines are required for requests without auth.
            // Remove these if all paths require auth
            .simpTypeMatchers(SimpMessageType.CONNECT).permitAll()
            .simpTypeMatchers(SimpMessageType.DISCONNECT).permitAll()
            .simpDestMatchers("/topic/greetings", "/app/hello").authenticated()
            .simpDestMatchers("/topic/status", "/app/status").permitAll()
            .anyMessage().authenticated()
        return messages.build()
    }
    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    fun greeting(message: TestMessage): Greeting {
        logger.info(message.toString())
        return Greeting("Hello, " + message.name + "!")
    }

    @MessageMapping("/status")
    @SendTo("/topic/status")
    fun status(message: String): String {
        return "Status: $message"
    }

However, when I try to consume these in JS like

    const subscribeToGreetings = useCallback(() => {
        if (!client || !client.active) return;

        setCanRetryGreetings(false);
        console.log('Attempting to subscribe to greetings...');
        client.subscribe('/topic/greetings',
            (message) => {
                console.log('Received greeting:', message);
                setMessages(prev => [...prev, `Greeting: ${message.body}`]);
            },
            {
                onError: (err) => {
                    console.error('Subscription error frame:', err.command, err.headers, err.body);
                    setMessages(prev => [...prev, `Permission denied: Cannot subscribe to greetings (${err.headers?.message || 'Unknown error'})`]);
                    setCanRetryGreetings(true);
                }
            }
        );
    }, [client]);

On the front end I just see

Attempting to subscribe to greetings...

I never actually see the onError part run. On the backend I do see....

2025-02-07T12:59:38.360-05:00 DEBUG 50220 --- [websocket] [nio-7443-exec-4] .s.m.a.i.AuthorizationChannelInterceptor : Failed to authorize message with authorization manager org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager@30c62bbb and result AuthorizationDecision [granted=false]
2025-02-07T12:59:38.360-05:00 DEBUG 50220 --- [websocket] [nio-7443-exec-4] o.s.w.s.m.StompSubProtocolHandler        : Failed to send message to MessageChannel in session da876e1d-f266-eb9f-08e4-8dc7e068b0fa
...
Caused by: org.springframework.security.access.AccessDeniedException: Access Denied
    at org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor.preSend(AuthorizationChannelInterceptor.java:75) ~[spring-security-messaging-6.4.2.jar:6.4.2]

So what am I missing why isn't the front end getting notified that their request to subscribe has failed?

Upvotes: 0

Views: 85

Answers (0)

Related Questions