Spring Boot, Websockets cannot obtain user (i.e, java.security.Principal) from Session

若如初见. 提交于 2019-12-09 18:33:59

问题


Working with Spring Boot 1.2.1.RELEASE and Spring Websockets. Having a deployment runtime issue where when running embedded Jetty 9, I cannot fake a user (java.security.Principal) successfully when app deployed anywhere else but localhost.

I have consulted

  • http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-authentication
  • http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-server-runtime-configuration

The config below (I believe) already "upgrades" a request

@Configuration
@EnableWebSocketMessageBroker
@EnableScheduling
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
    // see http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-handle-broker-relay
    // requires an external broker like AMQP or RabbitMQ
    //registry.enableStompBrokerRelay("/queue/", "/topic/");

    // XXX This might wind up being the impl we actually deploy; but be aware it has certain constraints
    // see http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-message-flow
    registry.enableSimpleBroker("/queue/", "/topic/");
    registry.setApplicationDestinationPrefixes("/app");
}

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/cards").setHandshakeHandler(new UserHandler()).withSockJS();
}

// cheat; ensure that we have a Principal w/o relying on authentication
class UserHandler extends DefaultHandshakeHandler {

    @Override
    protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler,
                    Map<String, Object> attributes) {
        return new TestPrincipal("bogus");
    }
}

And here's the principal...

public class TestPrincipal  implements Principal {

private final String name;


public TestPrincipal(String name) {
    this.name = name;
}

@Override
public String getName() {
    return this.name;
}

}

But this is the exception I'm receiving...

Logger=org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler Type=ERROR Message=Unhandled exception
org.springframework.messaging.simp.annotation.support.MissingSessionUserException: No "user" header in message
at org.springframework.messaging.simp.annotation.support.PrincipalMethodArgumentResolver.resolveArgument(PrincipalMethodArgumentResolver.java:42) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:127) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:100) ~[spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMatch(AbstractMethodMessageHandler.java:451) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:443) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.simp.annotation.support.SimpAnnotationMethodMessageHandler.handleMatch(SimpAnnotationMethodMessageHandler.java:82) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessageInternal(AbstractMethodMessageHandler.java:412) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.handler.invocation.AbstractMethodMessageHandler.handleMessage(AbstractMethodMessageHandler.java:350) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at org.springframework.messaging.support.ExecutorSubscribableChannel$SendTask.run(ExecutorSubscribableChannel.java:135) [spring-messaging-4.1.4.RELEASE.jar!/:4.1.4.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_05]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_05]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_05]

What else should I consider here?

UPDATE

I can reproduce this reliably in a localhost deployment now.

Interestingly, using STS 3.6.3 in debug mode, when I set a breakpoint at line 91 of JettyRequestUpgradeStrategy

public JettyRequestUpgradeStrategy(WebSocketServerFactory factory) {
    Assert.notNull(factory, "WebSocketServerFactory must not be null");
    this.factory = factory;
    this.factory.setCreator(new WebSocketCreator() {
        @Override
        public Object createWebSocket(ServletUpgradeRequest request, ServletUpgradeResponse response) {
            // Cast to avoid infinite recursion
            return createWebSocket((UpgradeRequest) request, (UpgradeResponse) response);
        }

Then continue on to another breakpoint set at line 41 of PrincipalMethodArgumentResolver

@Override
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
    Principal user = SimpMessageHeaderAccessor.getUser(message.getHeaders());
    if (user == null) {
        throw new MissingSessionUserException(message);
    }
    return user;
}

the user is null. Is there a race condition? E.g., is there some time limit within which the socket must acquire the user from request?

来源:https://stackoverflow.com/questions/28417189/spring-boot-websockets-cannot-obtain-user-i-e-java-security-principal-from-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!