title: Websockets over HTTPS with spring boot 1.0.0.RC5 and tomcat 8.0.3
body: <p>I have a working example of the web socket (ws) non secure implementation application using spring boot 1.0.0.RC5 and tomcat 8.0.3.
  Now i would like to switch to wss i.e. using my own self signed certificate that had been loaded by tomcat already.</p>
  
  <p>This question has two parts one theoretical and one practical:</p>
  
  <p>Theoretical => Do i need to have tomcat listening on two ports? i.e. on http and https. The reason i am asking this is because i read that during a web socket communication the first part of the connection is made over http and then there is so called "upgrade" to websockets. I am posting example of my test </p>
  
  <pre><code>GET /hello HTTP/1.1
  Host: 127.0.0.5:8080
  User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:28.0) Gecko/20100101 Firefox/28.0
  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  Accept-Language: en,en-gb;q=0.5
  Accept-Encoding: gzip, deflate
  DNT: 1
  Sec-WebSocket-Version: 13
  Origin: http://localhost:8080
  Sec-WebSocket-Key: wIKSOMgaHbEmkaRuEHZ6IA==
  Connection: keep-alive, Upgrade
  Pragma: no-cache
  Cache-Control: no-cache
  Upgrade: websocket
  
  
  HTTP/1.1 101 Switching Protocols
  Server: Apache-Coyote/1.1
  Upgrade: websocket
  Connection: upgrade
  Sec-WebSocket-Accept: 8trj6dyzlYdDUA3nAuwiM7SijRM=
  Date: Mon, 31 Mar 2014 10:29:19 GMT
  
  
  ..,O.do..*i..nM,..\;..I=.
  C!.U.~.U....I....-..Xu.T...H...T.E.d
  .'
  CONNECTED
  heart-beat:0,0
  version:1.1
  
  .
  .....]..M...F...f9..z?...9..{4..{4..5r...4..h/..{4..|W..
  </code></pre>
  
  <p>How this communication would look like over wss? Do we have the "upgrade" part as well, if so in this case we need http in order for that construct to work.  </p>
  
  <p>Practical => The problem i am facing is that the part of the code that is responsible for creating the stomp message is not working i.e. when i open the page </p>
  
  <pre><code>https://127.0.0.5:8888/wsTest
  </code></pre>
  
  <p>firefox tels me
  "This Connection is Untrusted" then i tell firefox "I understand the risk" and add the certificate as "Security Exception". From that point the certificate is stored under the firefox "servers" tab.
  All good till now. However when i change to wss this game does not work as i expected it to work. i.e.  This is the function that is creating the socket on the client side. </p>
  
  <pre><code>     function connect() {
              var socket = new WebSocket("wss://127.0.0.5:8888/hello");
  
              stompClient = Stomp.over(socket);
              stompClient.connect({}, function(frame) {
                  setConnected(true);
                  console.log('Connected: ' + frame);
                  stompClient.subscribe('/topic/greetings', function(greeting){
                      showGreeting(JSON.parse(greeting.body).content);
                  });
              });
          } 
  </code></pre>
  
  <p>if i change the line  </p>
  
  <pre><code>var socket = new WebSocket("wss://127.0.0.5:8888/hello"); 
  </code></pre>
  
  <p>to the http version i.e. </p>
  
  <pre><code>var socket = new WebSocket("ws://127.0.0.5:8080/hello"); 
  </code></pre>
  
  <p>then all works again.  The problem seems to be with the line</p>
  
  <pre><code>stompClient.connect({}, function(frame) {
  </code></pre>
  
  <p>however according to this bug note (<a href="https://jira.spring.io/browse/SPR-11436">https://jira.spring.io/browse/SPR-11436</a>) this should be the correct line</p>
  
  <p>I have generated the ceritficate with the command:</p>
  
  <pre><code>keytool -genkey -alias tomcat -keyalg RSA  -keystore /home/tito/Projects/syncServer/Server/certificate/sync.keystore
  </code></pre>
  
  <p>The server side:</p>
  
  <pre><code>@Configuration
  public class TomcatEmbeded extends SpringServletContainerInitializer {
  
  
      final int http_port = 8080;
      final int https_port = 8888;
      final String keystoreFile = "/home/tito/Projects/syncServer/Server/certificate/sync.keystore";
      final String keystorePass = "changeit";
      final String keystoreType = "JKS";
      final String keystoreProvider = "SUN";
      final String keystoreAlias = "tomcat";
      final String https_scheme = "https";
      final String http_scheme = "http";
  
      @Bean
      public EmbeddedServletContainerFactory servletContainer() {
  
  
          TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory(http_port);
  
          factory.setTomcatContextCustomizers(
                  Arrays.asList (
                          new TomcatContextCustomizer[]{ 
                                  tomcatContextCustomizer() 
                                  } 
                              )
                          );
  
          factory.addConnectorCustomizers( new TomcatConnectorCustomizer() {
              @Override
              public void customize(Connector con) {
                      Http11NioProtocol proto = (Http11NioProtocol) con.getProtocolHandler();
  
                      try {
  
                          con.setPort(https_port);
                          con.setSecure(true);
                          con.setScheme("https");
                          con.setAttribute("keyAlias", keystoreAlias);
                          con.setAttribute("keystorePass", keystorePass.toString());
                          try {
                              con.setAttribute("keystoreFile", ResourceUtils.getFile(keystoreFile).getAbsolutePath());
                          } catch (FileNotFoundException e) {
                              throw new IllegalStateException("Cannot load keystore", e);
                          }
  
                          con.setAttribute("clientAuth", "false");
                          con.setAttribute("sslProtocol", "TLS");
                          con.setAttribute("SSLEnabled", true);
  
                          proto.setSSLEnabled(true);
                          proto.setKeystoreFile(keystoreFile);
                          proto.setKeystorePass(keystorePass);
                          proto.setKeystoreType(keystoreType);
                          proto.setProperty("keystoreProvider", keystoreProvider.toString());
                          proto.setKeyAlias(keystoreAlias);
  
                      } catch (Exception ex) {
                          throw new IllegalStateException("can't access keystore: [" + "keystore"
                                  + "] or truststore: [" + "keystore" + "]", ex);
                      }
                      System.out.println("INIT HTTPS");
  
                  }
              }
          );
  
  
          factory.addAdditionalTomcatConnectors(httpConnector());
  //      factory.addErrorPages(new ErrorPage(HttpStatus.404, "/notfound.html");
          System.out.println("TOMCAT CUSTOME SETTINGS INITILIZED");
  
          return factory;
      }
  
  
      private Connector httpConnector() {
          Connector connector = new Connector();
          connector.setScheme(this.http_scheme);
          connector.setSecure(true);
          connector.setPort(this.http_port);
          System.out.println("INIT port HTTP");
          return connector;
      }
  
  
      @Bean 
      public TomcatContextCustomizer tomcatContextCustomizer() {
          System.out.println("TOMCATCONTEXTCUSTOMIZER INITILIZED");
          return new TomcatContextCustomizer() {
  
              @Override
              public void customize(Context context) {
                  // TODO Auto-generated method stub
                  context.addServletContainerInitializer(new WsSci(), null);
  
  
              }
          };
      }
  </code></pre>
  
  <p>here is the web socket configuration portion</p>
  
  <pre><code>@Configuration
  @EnableWebSocketMessageBroker
  public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
  
      @Override
      public void configureMessageBroker(MessageBrokerRegistry config) {
          config.enableSimpleBroker("/topic");
          config.setApplicationDestinationPrefixes("/app");
      }
  
      @Override
      public void registerStompEndpoints(StompEndpointRegistry registry) {
          registry.addEndpoint("/hello");
      }
  
  
      @Override
      public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
      }
  
      @Override
      public void configureClientOutboundChannel(ChannelRegistration channelRegistration) {
      }
  
      @Override
      public boolean configureMessageConverters(List&lt;MessageConverter&gt; arg0) {
  
          return true;
      } 
  </code></pre>
  
  <p>additional messages seen on the firefox debug console</p>
  
  <pre><code>Use of getUserData() or setUserData() is deprecated.  Use WeakMap or element.dataset instead. requestNotifier.js:64
  "Opening Web Socket..." stomp.js:130
  Firefox can't establish a connection to the server at wss://127.0.0.5:8888/hello. wsTest:18
  "Whoops! Lost connection to wss://127.0.0.5:8888/hello" stomp.js:130
  </code></pre>
  
  <p>here is full version of the html page</p>
  
  <pre><code>&lt;!DOCTYPE html&gt;
  &lt;html&gt;
  &lt;head&gt;
      &lt;title&gt;Hello WebSocket&lt;/title&gt;
      &lt;script src="/js/stomp.js"&gt;&lt;/script&gt;
      &lt;script type="text/javascript"&gt;
          var stompClient = null;
  
          function setConnected(connected) {
              document.getElementById('connect').disabled = connected;
              document.getElementById('disconnect').disabled = !connected;
              document.getElementById('conversationDiv').style.visibility = connected ? 'visible' : 'hidden';
              document.getElementById('response').innerHTML = '';
          }
  
          function connect() {
              var socket = new WebSocket("wss://127.0.0.5:8888/hello");
  
              stompClient = Stomp.over(socket);
   //           stompClient.connect('tito', 'password', function(frame) {
              stompClient.connect({}, function(frame) {
                  setConnected(true);
                  console.log('Connected: ' + frame);
                  stompClient.subscribe('/topic/greetings', function(greeting){
                      showGreeting(JSON.parse(greeting.body).content);
                  });
              });
          }
  
          function disconnect() {
              stompClient.disconnect();
              setConnected(false);
              console.log("Disconnected");
          }
  
          function sendName() {
              var name = document.getElementById('name').value;
              stompClient.send("/app/hello", {}, JSON.stringify({ 'name': name }));
          }
  
          function showGreeting(message) {
              var response = document.getElementById('response');
              var p = document.createElement('p');
              p.style.wordWrap = 'break-word';
              p.appendChild(document.createTextNode(message));
              response.appendChild(p);
          }
      &lt;/script&gt;
  &lt;/head&gt;
  &lt;body&gt;
  &lt;noscript&gt;&lt;h2 style="color: #ff0000"&gt;Seems your browser doesn't support Javascript! Websocket relies on Javascript being enabled. Please enable
      Javascript and reload this page!&lt;/h2&gt;&lt;/noscript&gt;
  &lt;div&gt;
      &lt;div&gt;
          &lt;button id="connect" onclick="connect();"&gt;Connect&lt;/button&gt;
          &lt;button id="disconnect" disabled="disabled" onclick="disconnect();"&gt;Disconnect&lt;/button&gt;
      &lt;/div&gt;
      &lt;div id="conversationDiv"&gt;
          &lt;label&gt;What is your name?&lt;/label&gt;&lt;input type="text" id="name" /&gt;
          &lt;button id="sendName" onclick="sendName();"&gt;Send&lt;/button&gt;
          &lt;p id="response"&gt;&lt;/p&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>the stomp script version used is "// Generated by CoffeeScript 1.6.3"</p>
  
  <p>here is how the certificate was generated</p>
  
  <pre><code>$ keytool -genkey -alias tomcat -keyalg RSA  -keystore /home/tito/Projects/syncServer/Server/certificate/sync.keystore
  Enter keystore password:  
  Re-enter new password: 
  What is your first and last name?
    [Unknown]:  TestFirstName
  What is the name of your organizational unit?
    [Unknown]:  TestOrganizationalUnitName
  What is the name of your organization?
    [Unknown]:  TestOrganization
  What is the name of your City or Locality?
    [Unknown]:  TestCity
  What is the name of your State or Province?
    [Unknown]:  TestState
  What is the two-letter country code for this unit?
    [Unknown]:  BG
  Is CN=TestFirstName, OU=TestOrganizationalUnitName, O=TestOrganization, L=TestCity, ST=TestState, C=BG correct?
    [no]:  yes
  
  Enter key password for &lt;tomcat&gt;
          (RETURN if same as keystore password):  
  </code></pre>
  
  <p>Addition: I have also noticed that web sockets are working if i call </p>
  
  <pre><code>https://127.0.0.5:8888/wsTest  
  </code></pre>
  
  <p>but not working if I call </p>
  
  <pre><code>https://localhost:8888/wsTest
  </code></pre>
  
  <p>however i still have not found why is this happening. This behavior is the same with chrome and firefox.</p>