title: Spring Boot, Websockets cannot obtain user (i.e, java.security.Principal) from Session
body: <p>Working with <code>Spring Boot 1.2.1.RELEASE</code> and <code>Spring Websockets</code>.  Having a deployment runtime issue where when running embedded <code>Jetty 9</code>, I cannot fake a user (<code>java.security.Principal</code>) successfully when app deployed anywhere else but localhost.</p>
  
  <p>I have consulted </p>
  
  <ul>
  <li><a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-authentication" rel="nofollow">http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-stomp-authentication</a></li>
  <li><a href="http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-server-runtime-configuration" rel="nofollow">http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html#websocket-server-runtime-configuration</a></li>
  </ul>
  
  <p>The config below (I believe) already "upgrades" a request </p>
  
  <pre><code>@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&lt;String, Object&gt; attributes) {
          return new TestPrincipal("bogus");
      }
  }
  </code></pre>
  
  <p>And here's the principal...</p>
  
  <pre><code>public class TestPrincipal  implements Principal {
  
  private final String name;
  
  
  public TestPrincipal(String name) {
      this.name = name;
  }
  
  @Override
  public String getName() {
      return this.name;
  }
  
  }
  </code></pre>
  
  <p>But this is the exception I'm receiving...</p>
  
  <pre><code>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]
  </code></pre>
  
  <p>What else should I consider here?</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>I can reproduce this reliably in a localhost deployment now.</p>
  
  <p>Interestingly, using <code>STS 3.6.3</code> in debug mode, when I set a breakpoint at line 91 of <code>JettyRequestUpgradeStrategy</code></p>
  
  <pre><code>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);
          }
  </code></pre>
  
  <p>Then continue on to another breakpoint set at line 41 of <code>PrincipalMethodArgumentResolver</code></p>
  
  <pre><code>@Override
  public Object resolveArgument(MethodParameter parameter, Message&lt;?&gt; message) throws Exception {
      Principal user = SimpMessageHeaderAccessor.getUser(message.getHeaders());
      if (user == null) {
          throw new MissingSessionUserException(message);
      }
      return user;
  }
  </code></pre>
  
  <p>the <code>user</code> is <code>null</code>.  Is there a race condition?  E.g., is there some time limit within which the socket must acquire the user from request?</p>