Generator-jhipster: WebSocket authentication error with token and OAuth2 authentication

Created on 11 Apr 2015  Â·  61Comments  Â·  Source: jhipster/generator-jhipster

I have created the app with following config -
java 7, token based authentication, mongodb, without hazelcast.

At client side, this is the console output
Opening Web Socket...
stomp.min.js:8 Web Socket Opened...
stomp.min.js:8 >>> CONNECT
X-CSRF-TOKEN:undefined
accept-version:1.1,1.0
heart-beat:10000,10000

stomp.min.js:8 <<< ERROR
message:Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException\c Access is denied
content-length:0

At server side,

[ERROR] org.springframework.web.socket.messaging.StompSubProtocolHandler - Failed to send client message to application via MessageChannel in session 7ey98h6g. Sending STOMP ERROR to client.
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:127) ~[spring-messaging-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:267) ~[spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:309) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:72) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.delegateMessages(AbstractSockJsSession.java:385) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.handleMessage(WebSocketServerSockJsSession.java:194) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler.handleTextMessage(SockJsWebSocketHandler.java:92) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:112) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:82) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:79) [spring-websocket-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393) [tomcat-embed-websocket-8.0.20.jar:8.0.20]
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494) [tomcat-embed-websocket-8.0.20.jar:8.0.20]
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289) [tomcat-embed-websocket-8.0.20.jar:8.0.20]
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130) [tomcat-embed-websocket-8.0.20.jar:8.0.20]
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60) [tomcat-embed-websocket-8.0.20.jar:8.0.20]
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203) [tomcat-embed-websocket-8.0.20.jar:8.0.20]
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198) [tomcat-embed-core-8.0.20.jar:8.0.20]
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96) [tomcat-embed-core-8.0.20.jar:8.0.20]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:654) [tomcat-embed-core-8.0.20.jar:8.0.20]
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223) [tomcat-embed-core-8.0.20.jar:8.0.20]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558) [tomcat-embed-core-8.0.20.jar:8.0.20]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515) [tomcat-embed-core-8.0.20.jar:8.0.20]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_40]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_40]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.20.jar:8.0.20]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_40]
Caused by: org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-4.0.0.RELEASE.jar:na]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232) ~[spring-security-core-4.0.0.RELEASE.jar:na]
at org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor.preSend(ChannelSecurityInterceptor.java:71) ~[spring-security-messaging-4.0.0.RELEASE.jar:na]
at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:158) ~[spring-messaging-4.1.6.RELEASE.jar:4.1.6.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:113) ~[spring-messaging-4.1.6.RELEASE.jar:4.1.6.RELEASE]
... 30 common frames omitted

area

All 61 comments

+1

We are using java 8, token based authentication, postgresql, without hazelcast and the error is the same after upgrading to 2.7.0.

+1

You have an AccessDenied exception from Spring Security, have you checked the new WebsocketSecurityConfiguration file?

Closing this as nobody as commented on it for a long time -> if you have the error, can you have a look at your WebsocketSecurityConfiguration file? Can you post anymore information?

Same problem here:
Im using generator-jhipster 2.15.1
.yo-rc.json

{
    "generator-jhipster": {
        "baseName": "test",
        "packageName": "net.org.selector.test",
        "packageFolder": "net/org/selector/test",
        "authenticationType": "xauth",
        "hibernateCache": "no",
        "clusteredHttpSession": "no",
        "websocket": "spring-websocket",
        "databaseType": "mongodb",
        "devDatabaseType": "mongodb",
        "prodDatabaseType": "mongodb",
        "useCompass": true,
        "buildTool": "maven",
        "frontendBuilder": "grunt",
        "javaVersion": "8",
        "rememberMeKey": "b3dbdfa1da648190d5ff0a424c28b5e1b72542b6",
        "searchEngine": "no"
    }
}

WebsocketSecurityConfiguration.java

@Configuration
public class WebsocketSecurityConfiguration extends AbstractSecurityWebSocketMessageBrokerConfigurer {

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
            // message types other than MESSAGE and SUBSCRIBE
            .nullDestMatcher().authenticated()
            // matches any destination that starts with /rooms/
            .simpDestMatchers("/topic/**").authenticated()
            // (i.e. cannot send messages directly to /topic/, /queue/)
            // (i.e. cannot subscribe to /topic/messages/* to get messages sent to
            // /topic/messages-user<id>)
            .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()
            // catch all
            .anyMessage().denyAll();
    }

    /**
     * Disables CSRF for Websockets.
     */
    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}

@jdubois Can you reopen this issue?

@Selectorrr yes, but still I don't know the error, I need to have a look

I have notice that this problem happens only when I use localhost as the host name to access on the browser. If I use 127.0.0.1 or my internal ip address the error did not occur. May be it can help you to find out what is wrong.

update: I have updated my /etc/hosts and remove the reference from IPV6... no more problems.

@marcelinobadin I use ubuntu server and now my /etc/hosts look like this :

127.0.0.1<----->localhost
127.0.1.1<----->master
# The following lines are desirable for IPv6 capable hosts
#::1     localhost ip6-localhost ip6-loopback
#ff02::1 ip6-allnodes
#ff02::2 ip6-allroute

I also tried it on windows
still not work

It's problem only with token based authentication

@sadziu thanks, that would explain the issue, as I wasn't able to reproduce!

I've tried to debug it and it seems that Spring Security first login with admin rights and after that is loosing that information and trying to login as anon

Edit - had some oddness going on with yeoman.

It appears we are disabling CSRF in WebSockets correctly:
http://docs.spring.io/spring-security/site/docs/4.0.x/reference/htmlsingle/#websocket-sameorigin-disable
inside of WebsocketSecurityConfiguration.java.

I was still experiencing the problem, but after I removed

    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages)...

the problem went away. I need to do some reading, but something there seems to be causing problems.

Interesting link, were you able to disable CSRF only for a subset of the URLs as they explain it for SockJS or did you have to disable it completely?

It is disabled completely at the moment.

To me it appears the problem is that the authentication token is not being sent in the header of the WebSocket requests. No token, no authentication. SockJS does not allow for this by design.

Spring did a workaround for CSRF by including the token with the stomp header.

SockJS uses a POST on the CONNECT messages for any HTTP based transport. Typically we need to include the CSRF token in an HTTP header or an HTTP parameter. However, SockJS does not allow for these options. Instead, we must include the token in the Stomp headers.

I'm not too familiar with this, but I know we can store the authentication token in the Stomp headers. Could it be pulled out in the same way Spring does with CSRF tokens for authentication?

I got same issue just after upgrading to 2.17

As @CodyBrokeIt mentioned above. It works if we remove configureInbound() in WebsocketSecurityConfiguration but will it affect other websocket context in terms of security issues ?

+1

I have the same problem with OAuth2 authentication type configuration. I use the method CodyBrokeIt mentioned to work around this issue temporarily.

At generator-jhipster 2.18.0, upgrade sockjs-client to 1.0.1 version in bower.json and update tracker.service.js as above
var loc = window.location;
var url = '//' + loc.host + loc.pathname + 'websocket/tracker';
var token = localStorageService.get('token');
if (token && token.expires_at && token.expires_at > new Date().getTime()) {
url += '?access_token=' + token.access_token;
}
var socket = new SockJS(url);
stompClient = Stomp.over(socket);

@lanbuithe I have tried your method but it did'n work for me. I am using OAuth2 authentication.

@lanbuithe I tried your method with no luck either.

You can clone source at https://github.com/lanbuithe/Simple-POS, it's is working

To work the solution proposed by @lanbuithe be sure to have in your app.js config section the following

//enable CSRF
        $httpProvider.defaults.xsrfCookieName = 'CSRF-TOKEN';
        $httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN';

Sorry for being unfamiliar with the file. Where to put those two lines of code in app.js?

@vw98075 in the .config. But sorry, my mistake. It still not working for me.

@marcelinobadin @vw98075 Working for me.

I just made the two changes

At generator-jhipster 2.18.0, upgrade sockjs-client to 1.0.1 version in bower.json and update tracker.service.js as above
var loc = window.location;
var url = '//' + loc.host + loc.pathname + 'websocket/tracker';
var token = localStorageService.get('token');
if (token && token.expires_at && token.expires_at > new Date().getTime()) {
url += '?access_token=' + token.access_token;
}
var socket = new SockJS(url);
stompClient = Stomp.over(socket);

and

//enable CSRF
$httpProvider.defaults.xsrfCookieName = 'CSRF-TOKEN';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRF-TOKEN'; 

@tomhughesnice Hi. When you look in your browser console is it not returning websocket errors?

Found my problem. Since I have created my project using version prior 2.7.0 and I am updating since then, one thing that got missing was the WebSecurityConfiguration which should have

.simpDestMatchers("/topic/**").authenticated()

instead of what I had on my version

.simpDestMatchers("/topic*").authenticated()

(see the difference in the ant-style pattern)

Corrected and it is working fine.

But anyway the solution from @lanbuithe and the other I have published should be applied anyway.

@Excrulon You should probably try to understand how Angular framework and dependancy injection works before getting involved with these kind of fixes. Try this course https://www.codeschool.com/courses/shaping-up-with-angular-js, its free and helps you get a grasp on the fundamentals.

In answer to the original question, you need to load the localStorageService as a dependancy.
Change this
.factory('Tracker', function ($rootScope, $cookies, $http, $q)
to
.factory('Tracker', function ($rootScope, $cookies, $http, $q, localStorageService)

@Excrulon Not be condescending, just being thorough. From your previous question I assumed you had little Angular experience as you didn't seem understand how localStorageService works.

The localStorageService prefix's all values being stored with 'ls' by default. You should use this service as its used across the Jhipster application for all localstorage operations. One feature of the localStorageService is it falls back to cookies if localstorage is not available. So if you chose to fix this problem the standard javascript way you need to check cookies too.

@tomhughesnice @marcelinobadin What type of authorization do you use? oauth2?
I guess this solution proposed by @lanbuithe did'n work for xauth.

The solution proposed by @lanbuithe works for me, I've oauth2 token configuration for security. It seems that the oauth token was not been sent on the websocket request.

Hi! @Selectorrr my authorization is OAuth2. But as @Excrulon said, it still returns "connected to server undefined".

Actually after all discussions during this weekend I really don't you if I miss something or not. But anyway, at least is not returning error on the java console and the only thing is this "connected to server undefined".

Again, I think my major problem is that I'm upgrading my project since version 2.6.X... so, something could be missing yet.

Yes, the proposed solution will work for OAuth because spring is smart enough to look for the token in the query string parameters. I guess that's part of the OAuth spec.

It will not work for the Token based authentication because there is only logic to pull the token from the headers, not the url.

So I think there are two ways to fix this for token based authentication. Both will take some work.

1) Like the above solution, we can add the token to the url. We would need to write a new filter to parse the token out of the url query string parameters and authenticate.

2) Set the token via the SIMP header:
tracker.service.js

var token = localStorageService.get('token');
var socket = new SockJS(url);
stompClient = Stomp.over(socket);
var headers = {};
headers['x-auth-token'] = token.token;
stompClient.connect(headers,...

and then write a new Channel Interceptor for the inbound channel to do the authentication much like spring checks the csrf token.

I started working on the second, but Spring isn't too friendly towards custom tokens in Websocket simp headers.

i got the same error.
i am using jh2.18,oauth + mysql. and i tried mongodb + oauth. the problem still there.

2015-07-29 3 10 30

2015-07-29 3 10 53

Same here (mongodb+oauth on Heroku):

2015-07-31T11:21:05.716969+00:00 app[web.1]: [ERROR] org.springframework.web.socket.messaging.StompSubProtocolHandler - Failed to send client message to application via MessageChannel in session gffj3d7v. Sending STOMP ERROR to client.
2015-07-31T11:21:05.716976+00:00 app[web.1]: org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
2015-07-31T11:21:05.716979+00:00 app[web.1]: at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:127) ~[spring-messaging-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.716980+00:00 app[web.1]: at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.716982+00:00 app[web.1]: at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:263) ~[spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.716992+00:00 app[web.1]: at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:309) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.716994+00:00 app[web.1]: at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.716995+00:00 app[web.1]: at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.716997+00:00 app[web.1]: at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:72) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.716998+00:00 app[web.1]: at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.delegateMessages(AbstractSockJsSession.java:385) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717000+00:00 app[web.1]: at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.handleMessage(WebSocketServerSockJsSession.java:194) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717001+00:00 app[web.1]: at org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler.handleTextMessage(SockJsWebSocketHandler.java:92) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717003+00:00 app[web.1]: at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717004+00:00 app[web.1]: at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:112) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717006+00:00 app[web.1]: at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717007+00:00 app[web.1]: at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:82) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717025+00:00 app[web.1]: at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:79) [spring-websocket-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717027+00:00 app[web.1]: at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393) [tomcat-embed-websocket-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717028+00:00 app[web.1]: at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494) [tomcat-embed-websocket-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717030+00:00 app[web.1]: at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289) [tomcat-embed-websocket-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717031+00:00 app[web.1]: at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130) [tomcat-embed-websocket-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717033+00:00 app[web.1]: at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60) [tomcat-embed-websocket-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717035+00:00 app[web.1]: at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203) [tomcat-embed-websocket-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717044+00:00 app[web.1]: at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198) [tomcat-embed-core-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717045+00:00 app[web.1]: at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96) [tomcat-embed-core-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717046+00:00 app[web.1]: at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:663) [tomcat-embed-core-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717048+00:00 app[web.1]: at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521) [tomcat-embed-core-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717049+00:00 app[web.1]: at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478) [tomcat-embed-core-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717055+00:00 app[web.1]: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_51-cedar14]
2015-07-31T11:21:05.717056+00:00 app[web.1]: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_51-cedar14]
2015-07-31T11:21:05.717058+00:00 app[web.1]: at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.23.jar!/:8.0.23]
2015-07-31T11:21:05.717059+00:00 app[web.1]: at java.lang.Thread.run(Thread.java:745) [na:1.8.0_51-cedar14]
2015-07-31T11:21:05.717061+00:00 app[web.1]: Caused by: org.springframework.security.access.AccessDeniedException: Access is denied
2015-07-31T11:21:05.717062+00:00 app[web.1]: at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-4.0.1.RELEASE.jar!/:4.0.1.RELEASE]
2015-07-31T11:21:05.717064+00:00 app[web.1]: at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232) ~[spring-security-core-4.0.1.RELEASE.jar!/:4.0.1.RELEASE]
2015-07-31T11:21:05.717065+00:00 app[web.1]: at org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor.preSend(ChannelSecurityInterceptor.java:71) ~[spring-security-messaging-4.0.1.RELEASE.jar!/:4.0.1.RELEASE]
2015-07-31T11:21:05.717066+00:00 app[web.1]: at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:158) ~[spring-messaging-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717068+00:00 app[web.1]: at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:113) ~[spring-messaging-4.1.7.RELEASE.jar!/:4.1.7.RELEASE]
2015-07-31T11:21:05.717070+00:00 app[web.1]: ... 29 common frames omitted

Hi,

I just updated to the latest version of jhipster 2.19.0 and I get the same error.

[ERROR] org.springframework.web.socket.messaging.StompSubProtocolHandler - Failed to send client message to application via MessageChannel in session hp4qrfkx. Sending STOMP ERROR to client.
org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied

I tried the changes suggested by @lanbuithe and @marcelinobadin and I dont see the error anymore but I am unable to login with admin/admin.

EDIT: I forgot to add localStorageService to tracker.service.js. Its working great now! Thanks to @tomhughesnice

should someone make a PR?

I am having issues to connect to the websocket/tracker via a simple spring-integration web socket client too.

[SimpleAsyncTaskExecutor-1] ERROR o.s.i.w.ClientWebSocketContainer$IntegrationWebSocketConnectionManager - Failed to connect
javax.websocket.DeploymentException: The HTTP response from the server [HTTP/1.1 200 OK
] did not permit the HTTP upgrade to WebSocket

You can simply create a test app for testing

@SpringApplicationConfiguration
public class Application {
    //working example via xml configuration 
    public static void main(String[] args) throws Exception {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("client-context.xml", Application.class);
        System.in.read();
        ctx.close();
    }
}

and the xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:int="http://www.springframework.org/schema/integration"
    xmlns:int-websocket="http://www.springframework.org/schema/integration/websocket"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:int-jpa="http://www.springframework.org/schema/integration/jpa"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
        http://www.springframework.org/schema/integration/websocket http://www.springframework.org/schema/integration/websocket/spring-integration-websocket.xsd
        http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/integration/jpa http://www.springframework.org/schema/integration/jpa/spring-integration-jpa.xsd">

    <context:property-placeholder />

    <bean id="webSocketClient" class="org.springframework.web.socket.client.standard.StandardWebSocketClient"/>

    <int-websocket:client-container id="clientWebSocketContainer"
                                    client="webSocketClient"
                                    uri="ws://localhost:${local.server.port:8080}/websocket/tracker"/>

    <int-websocket:inbound-channel-adapter
        container="clientWebSocketContainer" channel="loopback" />




    <int-websocket:outbound-channel-adapter
        container="clientWebSocketContainer" id="loopback">
    </int-websocket:outbound-channel-adapter>

</beans>

+1

As this is a bit complex, let me rephrase and summarize the issue.

How to reproduce

Generate the application with the latest JHipster version (currently 2.20.0), with all default options excepted:

  • For security: OAuth2 or Token-based. Both fail, possibly for different reasons. If you want a working application, use the default (session-based), and it will be OK
  • And select WebSocket

Then run the application (just type mvn) and go to localhost:8080. You need to authenticate, for example using admin/admin, and open up the Chrome Console. You will see the Access denied exception, as well as in the application log.

Current thoughts

  • This is probably not linked to CSRF as it is disabled in the WebsocketSecurityConfiguration class
  • Upgrading to "sockjs-client": "1.0.3" in the bower.json does not seem to help, but could nevertheless be a good idea
  • If you want to see how authentication can be done in OAuth and Token, you can have a look at https://github.com/jhipster/generator-jhipster/blob/v2.20.0/entity/templates/src/test/gatling/simulations/_EntityGatlingTest.scala#L41 -> this is how I do it in Gatling, and it's working
  • My current opinion is that we can send data to the /websocket URL, so authentication works at this level. Where it fails is when that we send this message on the /topic/ , it looks like .simpDestMatchers("/topic/**").authenticated() does not work. What I don't understand is that it works with session-based authentication, and I don't see why there would be a difference.

The problem is that the x-auth-token (or OAuth Token) is not included in the request so Spring Security does not see view the user as authenticated. Unfortunately, SockJS clients do not provide a way to include additional HTTP headers. See sockjs/sockjs-client/issues/196 for details.

This problem is further complicated by the fact that the servlet specification uses the Principal that was present at the time of the handshake for all of the WebSocket requests. The issue suggests using sockjs message for authentication. However, the headers on the WebSocket message are not available to the Servlet container. This means we cannot authenticate the HTTP request using the WebSocket message as suggested in the above issue. This also means there is no native way to ensure the Principal is correctly resolved with anything but cookies.

A workaround for authorization would be to create something similar to SecurityContextChannelInterceptor and extract the current user from the headers. You would then need to ensure that the header is populated in the stomp requests (similar to the CSRF token).

NOTE The Principal in @MessageMappings will still not be resolved properly with this workaround. However, you could access it with the SecurityContextHolder.getContext()

There is a Spring Security issue (SEC-3006)[https://jira.spring.io/browse/SEC-3006] to provide support for something like this within Spring Security, but we haven't had time to implement this due to:

  • We will be fighting with Servlet Container limitations
  • There is a simple workaround (use cookies)
  • Lack of interest up to this point

If this is a feature that interests you, I would encourage you to vote on the issue and we will be sure to prioritize it accordingly.

Thanks a lot @rwinch !! Let's all vote for https://jira.spring.io/browse/SEC-3006 then!

@rwinch is the cookies workaround also working for machine to machine communication?

@artjomg

It's really a limitation with STOMP. The problem is that the STOMP client will not allow you to include a custom header in the handshake. However, browsers will automatically include cookies (so this is automatically included for you).

If you are sure to include the credentials (i.e. x-auth-token header or OAuth token) in the handshake, then you should not have an issue. Presumably in a machine to machine communication you would be able to do this without any limitations of the STOMP js client.

@jdubois

Thanks a lot @rwinch !! Let's all vote for https://jira.spring.io/browse/SEC-3006 then!

No problem. Please don't hesitate to ping me via Twitter and/or via github mentions for any additional Spring Security related questions.

I investigated the issue as well and found a solution working for me. It consists of 2 parts:

  • pass the oauth bearer token as request parameter ´access_token`. This is handled by spring similar to the authentication header. So at least as long as no logout or re-authentication happens, this works. My solution looks like the code below, I have rewritten the whole websocket stuff in TypeScript, so I can't tell you the exact position in the current JHipster release. Somewhere in the tracker.service.js connect() method where the SockJS connection is created ...
//building absolute path so that websocket doesnt fail when deploying with a context path
var loc = window.location;
var webSocketUrl = '//' + loc.host + loc.pathname + 'websocket/tracker';
var token = this.localStorageService.get('token');
if (token && token.expires_at && token.expires_at > new Date().getTime()) {
    webSocketUrl += '?access_token=' + token.access_token;
} else {
    webSocketUrl += '?access_token=no token';
}

// Define the connection
var socket = new SockJS(webSocketUrl);
  • modify the authentication on the server side in WebsocketSecurityConfiguration:
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
    messages
        // message types other than MESSAGE and SUBSCRIBE
        .simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.HEARTBEAT, SimpMessageType.UNSUBSCRIBE, SimpMessageType.DISCONNECT).permitAll()
        // matches any destination that starts with /rooms/
        .simpDestMatchers("/topic/**").authenticated()
        .simpDestMatchers("/app/**").authenticated()
        // (i.e. cannot send messages directly to /topic/, /queue/)
        // (i.e. cannot subscribe to /topic/messages/* to get messages sent to
        // /topic/messages-user<id>)
        .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll()
        // catch all
        .anyMessage().denyAll();
}

So the important parts are passing the bearer token as request parameter and removing the .nullDestMatcher() in the WebsocketSecurityConfiguration.

Thanks!!! I got it working for OAuth2!!
I need to review my changes and add a new documentation page to explain all
this, this will be done tomorrow evening

@rwinch Thanks for the hint, I will try to test this and update the example referenced.

Code is commited with OAuth2 support, documentation has been added at https://github.com/jhipster/jhipster.github.io/commit/644f0a1f3ee6c5cf4e4d53a7fc97546c6007b07d is now live!
Should we close this?

I'm closing this:

  • This is solved for OAuth2
  • This can't be solved for XAuth at the moment, but this is documented

Any one found solution for token based authentication?

@CodyBrokeIt Any luck with token based authentication?

Hi EveryOne,

I developed a chat application with springboot,spring security,spring websockets and sockjs.
I am using angular and sockjs client to send requests.when I try to connect to connect STOMP end point its giving the error at developer console(front end) and back end console.Below is the track trace,
From Developer console:
Opening Web Socket...
stomp.min.js (line 8)
GET http://localhost:8082/ws/info?t=1451547968350

200 OK
565ms
sockjs-1.0.1.js (line 1610)
Web Socket Opened...
stomp.min.js (line 8)

CONNECT
login:test
passcode:test
accept-version:1.1,1.0
heart-beat:10000,10000

�

stomp.min.js (line 8)

<<< ERROR
message:Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException\c Access is denied
content-length:0

�

stomp.min.js (line 8)

errrooooooo======= ERROR
content-length:0
message:Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException\c Access is denied

chatController.js (line 114)
Whoops! Lost connection to http://localhost:8082/ws
stomp.min.js (line 8)

errrooooooo======= Whoops! Lost connection to http://localhost:8082/ws

chatController.js (line 114)

Back end Error :
2015-12-31 13:16:09.035 DEBUG 8116 --- [0.0-8082-exec-1] o.s.b.f.s.DefaultListableBeanFactory : Finished creating instance of bean 'org.springframework.web.servlet.support.SessionFlashMapManager'
2015-12-31 13:16:09.035 DEBUG 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : Unable to locate FlashMapManager with name 'flashMapManager': using default [org.springframework.web.servlet.support.SessionFlashMapManager@7f7b82f5]
2015-12-31 13:16:09.035 DEBUG 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : Published WebApplicationContext of servlet 'dispatcherServlet' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcherServlet]
2015-12-31 13:16:09.035 INFO 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 73 ms
2015-12-31 13:16:09.036 DEBUG 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : Servlet 'dispatcherServlet' configured successfully
2015-12-31 13:16:09.080 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/info'; against '/css/'
2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/info'; against '/js/
'
2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/info'; against '/images/'
2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/info'; against '/
/favicon.ico'
2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/info'; against '/error'
2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /ws/info' doesn't match 'POST /person/*
2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/info'; against '/lookup/'
2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /ws/info' doesn't match 'POST /upload/image/

2015-12-31 13:16:09.081 DEBUG 8116 --- [0.0-8082-exec-1] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/info'; against '/ws/'
2015-12-31 13:16:09.082 DEBUG 8116 --- [0.0-8082-exec-1] o.s.security.web.FilterChainProxy : /ws/info?t=1451547968350 has an empty filter list
2015-12-31 13:16:09.093 DEBUG 8116 --- [0.0-8082-exec-1] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'managementServerProperties'
2015-12-31 13:16:09.110 DEBUG 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/ws/info]
2015-12-31 13:16:09.120 DEBUG 8116 --- [0.0-8082-exec-1] o.s.b.a.e.mvc.EndpointHandlerMapping : Looking up handler method for path /ws/info
2015-12-31 13:16:09.160 DEBUG 8116 --- [0.0-8082-exec-1] o.s.b.a.e.mvc.EndpointHandlerMapping : Did not find handler method for [/ws/info]
2015-12-31 13:16:09.161 DEBUG 8116 --- [0.0-8082-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /ws/info
2015-12-31 13:16:09.164 DEBUG 8116 --- [0.0-8082-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/ws/info]
2015-12-31 13:16:09.165 DEBUG 8116 --- [0.0-8082-exec-1] o.s.w.s.s.s.WebSocketHandlerMapping : Matching patterns for request [/ws/info] are [/ws/
]
2015-12-31 13:16:09.168 DEBUG 8116 --- [0.0-8082-exec-1] o.s.w.s.s.s.WebSocketHandlerMapping : URI Template variables for request [/ws/info] are {}
2015-12-31 13:16:09.171 DEBUG 8116 --- [0.0-8082-exec-1] o.s.w.s.s.s.WebSocketHandlerMapping : Mapping [/ws/info] to HandlerExecutionChain with handler [org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler@3e16086] and 1 interceptor
2015-12-31 13:16:09.177 DEBUG 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/ws/info] is: -1
2015-12-31 13:16:09.280 DEBUG 8116 --- [0.0-8082-exec-1] o.s.w.s.s.t.h.DefaultSockJsService : Processing transport request: GET http://localhost:8082/ws/info?t=1451547968350
2015-12-31 13:16:09.292 DEBUG 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2015-12-31 13:16:09.292 DEBUG 8116 --- [0.0-8082-exec-1] o.s.web.servlet.DispatcherServlet : Successfully completed request
2015-12-31 13:16:09.298 DEBUG 8116 --- [0.0-8082-exec-1] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/849/3qaa31j0/websocket'; against '/css/'
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/849/3qaa31j0/websocket'; against '/js/
'
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/849/3qaa31j0/websocket'; against '/images/'
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/849/3qaa31j0/websocket'; against '/
/favicon.ico'
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/849/3qaa31j0/websocket'; against '/error'
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /ws/849/3qaa31j0/websocket' doesn't match 'POST /person/
*
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/849/3qaa31j0/websocket'; against '/lookup/'
2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Request 'GET /ws/849/3qaa31j0/websocket' doesn't match 'POST /upload/image/

2015-12-31 13:16:09.657 DEBUG 8116 --- [0.0-8082-exec-2] o.s.s.w.u.matcher.AntPathRequestMatcher : Checking match of request : '/ws/849/3qaa31j0/websocket'; against '/ws/'
2015-12-31 13:16:09.658 DEBUG 8116 --- [0.0-8082-exec-2] o.s.security.web.FilterChainProxy : /ws/849/3qaa31j0/websocket has an empty filter list
2015-12-31 13:16:09.659 DEBUG 8116 --- [0.0-8082-exec-2] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/ws/849/3qaa31j0/websocket]
2015-12-31 13:16:09.659 DEBUG 8116 --- [0.0-8082-exec-2] o.s.b.a.e.mvc.EndpointHandlerMapping : Looking up handler method for path /ws/849/3qaa31j0/websocket
2015-12-31 13:16:09.688 DEBUG 8116 --- [0.0-8082-exec-2] o.s.b.a.e.mvc.EndpointHandlerMapping : Did not find handler method for [/ws/849/3qaa31j0/websocket]
2015-12-31 13:16:09.688 DEBUG 8116 --- [0.0-8082-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /ws/849/3qaa31j0/websocket
2015-12-31 13:16:09.690 DEBUG 8116 --- [0.0-8082-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Did not find handler method for [/ws/849/3qaa31j0/websocket]
2015-12-31 13:16:09.690 DEBUG 8116 --- [0.0-8082-exec-2] o.s.w.s.s.s.WebSocketHandlerMapping : Matching patterns for request [/ws/849/3qaa31j0/websocket] are [/ws/
]
2015-12-31 13:16:09.690 DEBUG 8116 --- [0.0-8082-exec-2] o.s.w.s.s.s.WebSocketHandlerMapping : URI Template variables for request [/ws/849/3qaa31j0/websocket] are {}
2015-12-31 13:16:09.690 DEBUG 8116 --- [0.0-8082-exec-2] o.s.w.s.s.s.WebSocketHandlerMapping : Mapping [/ws/849/3qaa31j0/websocket] to HandlerExecutionChain with handler [org.springframework.web.socket.sockjs.support.SockJsHttpRequestHandler@3e16086] and 1 interceptor
2015-12-31 13:16:09.690 DEBUG 8116 --- [0.0-8082-exec-2] o.s.web.servlet.DispatcherServlet : Last-Modified value for [/ws/849/3qaa31j0/websocket] is: -1
2015-12-31 13:16:09.692 DEBUG 8116 --- [0.0-8082-exec-2] o.s.w.s.s.t.h.DefaultSockJsService : Processing transport request: GET http://localhost:8082/ws/849/3qaa31j0/websocket
2015-12-31 13:16:09.812 DEBUG 8116 --- [0.0-8082-exec-2] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2015-12-31 13:16:09.813 DEBUG 8116 --- [0.0-8082-exec-2] o.s.web.servlet.DispatcherServlet : Successfully completed request
2015-12-31 13:16:09.882 DEBUG 8116 --- [0.0-8082-exec-2] s.w.s.h.LoggingWebSocketHandlerDecorator : New WebSocketServerSockJsSession[id=3qaa31j0]
2015-12-31 13:16:10.091 DEBUG 8116 --- [0.0-8082-exec-3] o.s.s.m.a.i.ChannelSecurityInterceptor : Secure object: GenericMessage [payload=byte[0], headers={simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={login=[test], passcode=[PROTECTED], accept-version=[1.1,1.0], heart-beat=[10000,10000]}, simpSessionAttributes={IP_ADDRESS=/127.0.0.1:51223, Access-Control-Allow-Origin=*}, simpHeartbeat=[J@574f3f7d, stompCredentials=[PROTECTED], simpUser=org.springframework.security.authentication.AnonymousAuthenticationToken@55c70fe4: Principal: anonymous; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ANONYMOUS, simpSessionId=3qaa31j0}]; Attributes: [authenticated]
2015-12-31 13:16:10.091 DEBUG 8116 --- [0.0-8082-exec-3] o.s.s.m.a.i.ChannelSecurityInterceptor : Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@55c70fe4: Principal: anonymous; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ANONYMOUS
2015-12-31 13:16:10.104 DEBUG 8116 --- [0.0-8082-exec-3] o.s.s.access.vote.AffirmativeBased : Voter: org.springframework.security.messaging.access.expression.MessageExpressionVoter@6f9f78f9, returned: -1
2015-12-31 13:16:10.119 DEBUG 8116 --- [0.0-8082-exec-3] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2015-12-31 13:16:10.120 DEBUG 8116 --- [0.0-8082-exec-3] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'authorizationAuditListener'
2015-12-31 13:16:10.121 DEBUG 8116 --- [0.0-8082-exec-3] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'delegatingApplicationListener'
2015-12-31 13:16:10.122 DEBUG 8116 --- [0.0-8082-exec-3] o.s.b.f.s.DefaultListableBeanFactory : Returning cached instance of singleton bean 'auditListener'
2015-12-31 13:16:10.122 DEBUG 8116 --- [0.0-8082-exec-3] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Thu Dec 31 13:16:10 IST 2015, principal=anonymous, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]
2015-12-31 13:16:10.125 ERROR 8116 --- [0.0-8082-exec-3] o.s.w.s.m.StompSubProtocolHandler : Failed to send client message to application via MessageChannel in session 3qaa31j0. Sending STOMP ERROR to client.

org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]; nested exception is org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:127) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:104) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.messaging.StompSubProtocolHandler.handleMessageFromClient(StompSubProtocolHandler.java:280) ~[spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.messaging.SubProtocolWebSocketHandler.handleMessage(SubProtocolWebSocketHandler.java:317) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.handler.WebSocketHandlerDecorator.handleMessage(WebSocketHandlerDecorator.java:75) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator.handleMessage(LoggingWebSocketHandlerDecorator.java:56) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.handler.ExceptionWebSocketHandlerDecorator.handleMessage(ExceptionWebSocketHandlerDecorator.java:72) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.AbstractSockJsSession.delegateMessages(AbstractSockJsSession.java:385) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.sockjs.transport.session.WebSocketServerSockJsSession.handleMessage(WebSocketServerSockJsSession.java:194) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.sockjs.transport.handler.SockJsWebSocketHandler.handleTextMessage(SockJsWebSocketHandler.java:92) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.handler.AbstractWebSocketHandler.handleMessage(AbstractWebSocketHandler.java:43) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.handleTextMessage(StandardWebSocketHandlerAdapter.java:112) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter.access$000(StandardWebSocketHandlerAdapter.java:42) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:82) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.web.socket.adapter.standard.StandardWebSocketHandlerAdapter$3.onMessage(StandardWebSocketHandlerAdapter.java:79) [spring-websocket-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.apache.tomcat.websocket.WsFrameBase.sendMessageText(WsFrameBase.java:393) [tomcat-embed-websocket-8.0.28.jar:8.0.28]
at org.apache.tomcat.websocket.WsFrameBase.processDataText(WsFrameBase.java:494) [tomcat-embed-websocket-8.0.28.jar:8.0.28]
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:289) [tomcat-embed-websocket-8.0.28.jar:8.0.28]
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130) [tomcat-embed-websocket-8.0.28.jar:8.0.28]
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60) [tomcat-embed-websocket-8.0.28.jar:8.0.28]
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203) [tomcat-embed-websocket-8.0.28.jar:8.0.28]
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198) [tomcat-embed-core-8.0.28.jar:8.0.28]
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96) [tomcat-embed-core-8.0.28.jar:8.0.28]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668) [tomcat-embed-core-8.0.28.jar:8.0.28]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500) [tomcat-embed-core-8.0.28.jar:8.0.28]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456) [tomcat-embed-core-8.0.28.jar:8.0.28]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.0.28.jar:8.0.28]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
Caused by: org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232) ~[spring-security-core-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.security.messaging.access.intercept.ChannelSecurityInterceptor.preSend(ChannelSecurityInterceptor.java:69) ~[spring-security-messaging-4.0.3.RELEASE.jar:4.0.3.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:158) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:113) ~[spring-messaging-4.2.3.RELEASE.jar:4.2.3.RELEASE]
... 29 common frames omitted

2015-12-31 13:17:00.002 DEBUG 8116 --- [MessageBroker-2] s.s.d.r.RedisOperationsSessionRepository : Cleaning up sessions expiring at Thu Dec 31 13:17:00 IST 2015

Angular and sockjs code file:

chatController.js

angular.module('letsCatchApp').controller(
'chatController',
function($scope, $location, $interval, toaster, chatSocket,$state) {

        console.log('chat controller============');

        var typing = undefined;

        $scope.username     = '';
        $scope.sendTo       = 'everyone';
        $scope.participants = [];
        $scope.messages     = [];
        $scope.newMessage   = ''; 

        $scope.sendMessage = function() {
            console.log('22222');
            var destination = "http://localhost:8082/app/chat.message";

            if($scope.sendTo != "everyone") {
                destination = "http://localhost:8082/app/chat.private." + $scope.sendTo;
                $scope.messages.unshift({message: $scope.newMessage, username: 'you', priv: true, to: $scope.sendTo});
            }

            chatSocket.send(destination, {}, JSON.stringify({message: $scope.newMessage}));
            $scope.newMessage = '';
        };

        $scope.startTyping = function() {
            console.log('333333');
            // Don't send notification if we are still typing or we are typing a private message
            if (angular.isDefined(typing) || $scope.sendTo != "everyone") return;

            typing = $interval(function() {
                    $scope.stopTyping();
                }, 500);

            chatSocket.send("http://localhost:8082/topic/chat.typing", {}, JSON.stringify({username: $scope.username, typing: true}));
        };

        $scope.stopTyping = function() {
            console.log('44444');
            if (angular.isDefined(typing)) {
                $interval.cancel(typing);
                typing = undefined;

                chatSocket.send("http://localhost:8082/topic/chat.typing", {}, JSON.stringify({username: $scope.username, typing: false}));
            }
        };

        $scope.privateSending = function(username) {
            console.log('55555');
                $scope.sendTo = (username != $scope.sendTo) ? username : 'everyone';
        };

        $scope.initStompClient = function() {
            console.log('66666');
            chatSocket.init('http://localhost:8082/ws');
            console.log('66666rrrrrrrrrrrrrrrrr');
            chatSocket.connect(function(frame) {

                console.log('101010101010101');
                $scope.username = frame.headers['user-name'];

                chatSocket.subscribe("http://localhost:8082/app/chat.participants", function(message) {
                    console.log('7777');
                    $scope.participants = JSON.parse(message.body);
                });

                chatSocket.subscribe("http://localhost:8082/topic/chat.login", function(message) {
                    console.log('888888');
                    $scope.participants.unshift({username: JSON.parse(message.body).username, typing : false});
                });

                chatSocket.subscribe("http://localhost:8082/topic/chat.logout", function(message) {
                    console.log('99999');
                    var username = JSON.parse(message.body).username;
                    for(var index in $scope.participants) {
                        if($scope.participants[index].username == username) {
                            $scope.participants.splice(index, 1);
                        }
                    }
                });

                chatSocket.subscribe("http://localhost:8082/topic/chat.typing", function(message) {
                    var parsed = JSON.parse(message.body);
                    if(parsed.username == $scope.username) return;

                    for(var index in $scope.participants) {
                        var participant = $scope.participants[index];

                        if(participant.username == parsed.username) {
                            $scope.participants[index].typing = parsed.typing;
                        }
                    } 
                });

                chatSocket.subscribe("http://localhost:8082/topic/chat.message", function(message) {
                    console.log('88888');
                    $scope.messages.unshift(JSON.parse(message.body));
                });

                chatSocket.subscribe("http://localhost:8082/user/exchange/amq.direct/chat.message", function(message) {
                    console.log('9999');
                    var parsed = JSON.parse(message.body);
                    parsed.priv = true;
                    $scope.messages.unshift(parsed);
                });

                chatSocket.subscribe("http://localhost:8082/user/exchange/amq.direct/errors", function(message) {
                    toaster.pop('error', "Error", message.body);
                });

            }, function(error) {
                console.log("errrooooooo=======   "+error);
                toaster.pop('error', 'Error', 'Connection error ' + error);

            });
        };

        //initStompClient();



    });

chatService.js

angular.module('letsCatchApp').service('chatSocket',
function($rootScope,$http) {

        console.log('Chat service is called.... ');


    var stompClient;

     this.test = function() {
         console.log('Chat service test... ');
         return $http.get('http://localhost:8082/app/')
      }

 this.init = function(url) {
       console.log('Chat service init ... '+url);
        stompClient = Stomp.over(new SockJS(url));
        console.log('Chat service init ...end---- '+url);
  }

 this.connect = function(successCallback, errorCallback) {
     console.log('Chat service init ... connect');

        stompClient.connect({'login': 'test',
            'passcode': 'test'}, function(frame) {
           $rootScope.$apply(function() {
                return successCallback(frame);
            });
            }, function(error) {
                $rootScope.$apply(function(){
                    return errorCallback(error);
            });
        });
    }

   this.subscribe = function(destination, callback) {
       console.log('Chat service init ... subscribe');
        stompClient.subscribe(destination, function(message) {
                $rootScope.$apply(function(){
                    return callback(message);
            });
      });   
    }

  this.send = function(destination, headers, object) {
        return stompClient.send(destination, headers, object);
    }

});

WebsocketConfig files:

package com.sergialmar.wschat.config;

import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
import org.springframework.messaging.handler.invocation.HandlerMethodReturnValueHandler;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.session.ExpiringSession;
import org.springframework.session.web.socket.config.annotation.AbstractSessionWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
import org.springframework.web.socket.server.HandshakeInterceptor;
import org.springframework.web.socket.server.support.DefaultHandshakeHandler;

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer{
//AbstractSessionWebSocketMessageBrokerConfigurer {

 public static final String IP_ADDRESS = "IP_ADDRESS";
// public static final String IP_ADDRESS = "IP_ADDRESS";

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    /*
     * System.out.println("registering the endpoint ==ws==============");
     * registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
     */

    registry.addEndpoint("/ws").setAllowedOrigins("*")
            .setHandshakeHandler(new DefaultHandshakeHandler() {
                @Override
                protected Principal determineUser(
                        ServerHttpRequest request,
                        WebSocketHandler wsHandler,
                        Map<String, Object> attributes) {
                    Principal principal = request.getPrincipal();
                    if (principal == null) {
                        Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
                        authorities.add(new SimpleGrantedAuthority(
                                "ANONYMOUS"));
                        principal = new AnonymousAuthenticationToken(
                                "WebsocketConfiguration", "anonymous",
                                authorities);
                    }
                    return principal;
                }
            }).withSockJS()
            .setInterceptors(httpSessionHandshakeInterceptor());
}

@Bean
public HandshakeInterceptor httpSessionHandshakeInterceptor() {
    return new HandshakeInterceptor() {

        @Override
        public boolean beforeHandshake(ServerHttpRequest request,
                ServerHttpResponse response, WebSocketHandler wsHandler,
                Map<String, Object> attributes) throws Exception {
            if (request instanceof ServletServerHttpRequest) {
                ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
                attributes.put(IP_ADDRESS,
                        servletRequest.getRemoteAddress());
                attributes.put("Access-Control-Allow-Origin",
                        "*");
            }
            return true;
        }

        @Override
        public void afterHandshake(ServerHttpRequest request,
                ServerHttpResponse response, WebSocketHandler wsHandler,
                Exception exception) {

        }
    };
}

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    System.out
            .println("registering the endpoint ==of ===/queue/===========");
    registry.enableSimpleBroker("/queue/", "/topic/", "/exchange/");
    // registry.enableStompBrokerRelay("/queue/", "/topic/", "/exchange/");
    registry.setApplicationDestinationPrefixes("/app");
}

@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> arg0) {
    // TODO Auto-generated method stub

}

@Override
public void addReturnValueHandlers(
        List<HandlerMethodReturnValueHandler> arg0) {
    // TODO Auto-generated method stub

}

@Override
public void configureClientInboundChannel(ChannelRegistration arg0) {
    // TODO Auto-generated method stub

}

@Override
public void configureClientOutboundChannel(ChannelRegistration arg0) {
    // TODO Auto-generated method stub

}

@Override
public boolean configureMessageConverters(List<MessageConverter> arg0) {
    // TODO Auto-generated method stub
    return false;
}

@Override
public void configureWebSocketTransport(WebSocketTransportRegistration arg0) {
    // TODO Auto-generated method stub

}

}

package com.sergialmar.wschat.config;

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

@Configuration
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {

@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
    messages
            // users cannot send to these broker destinations, only the application can
            .simpMessageDestMatchers("/topic/chat.login", "/topic/chat.logout", "/topic/chat.message").denyAll()
            .anyMessage().authenticated().simpDestMatchers("/**").permitAll();



}

@Override
protected boolean sameOriginDisabled() {
    //disable CSRF for websockets for now...
    return true;
}

}

Please suggest what is the problem in my code.

Although the issue is closed, websocket with (x-auth) token based authentication is still not working.

To get that working: Similar to the solution for oauth you have to pass the token as a query param to the url. Additionally, you have to tell the authfilter to look for the parameter.

In the XAuthTokenFilter.java replace

String authToken = httpServletRequest.getHeader(XAUTH_TOKEN_HEADER_NAME);

with

String authToken = resolveToken(httpServletRequest);

and add this method to get either the header or the query param:

private String resolveToken(HttpServletRequest request){
    String authToken = request.getHeader(XAUTH_TOKEN_HEADER_NAME);
    if(StringUtils.hasText(authToken)){
        return authToken;
    }else{
        authToken = request.getParameter(XAUTH_TOKEN_HEADER_NAME);
        if(StringUtils.hasText(authToken)) {
            return authToken;
        }else{
            return null;
        }
    }
}

Then, you have to add the current token to the url in the tracker.service.js:

....
var url = '//' + loc.host + loc.pathname + 'websocket/tracker';
var token = localStorageService.get('token');
if (token && token.expires && token.expires > new Date().getTime()) {
        url += '?x-auth-token=' + token.token;
}
var socket = new SockJS(url);
....

and to forget to inject the localStorageService in the factory :)

I would make a PR, but after having a short look, it seems that the x-auth-token will be removed?!
Will this be replaced with JWT?
If I'm right, there would be the same problem with websockets, or not?!

@geesen yes you are totally right!! X-Auth is replaced by JWT (works the same way, but it's standard and we use a library for that), and there is still the same issue, of course.
This is tracked on this new issue: #2807
-> this is very important for me, so a PR is really warmly welcome. Don't hesitate to comment on that other ticket, and send a PR (even if it's not perfect, the most important thing is to solve the issue)

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
java 40252 XXX 159u IPv6 0x8118ce77b4c5a995 0t0 TCP *:http-alt (LISTEN)
Google 46424 XXX 118u IPv4 0x8118ce77b3f1e985 0t0 TCP localhost:53715->10.58.1.221:http-alt (ESTABLISHED)
I started a application with stateful using session management, but I can't start the index.html on http://127.0.0.1:8080. And I tried all of the ways above and didn't work yet. Then I found the app listened 8080 on IPv6. Is it the course for the problem?

The reason is that WebSocket get principal failed from the request.
You should share the session with spring mvc.

@Override protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) { messages // append this line solve // .simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.HEARTBEAT, SimpMessageType.UNSUBSCRIBE, SimpMessageType.DISCONNECT).permitAll() .nullDestMatcher().authenticated() .simpDestMatchers("/topic/tracker").permitAll() // matches any destination that starts with /topic/ // (i.e. cannot send messages directly to /topic/) // (i.e. cannot subscribe to /topic/messages/* to get messages sent to // /topic/messages-user<id>) .simpDestMatchers("/topic/**").permitAll() // message types other than MESSAGE and SUBSCRIBE .simpTypeMatchers(SimpMessageType.MESSAGE, SimpMessageType.SUBSCRIBE).denyAll() // catch all .anyMessage().denyAll(); }

@no-today I just tried your solution and it works for me! I had the issue of having to login before being able to get messages from a /topic but now I can do it as anonymous user. Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jdubois picture jdubois  Â·  61Comments

deepu105 picture deepu105  Â·  50Comments

deepu105 picture deepu105  Â·  53Comments

cmoine picture cmoine  Â·  57Comments

abhinav910 picture abhinav910  Â·  50Comments