Websockets over HTTPS with spring boot 1.0.0.RC5 and tomcat 8.0.3

匿名 (未验证) 提交于 2019-12-03 02:49:01

问题:

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.

This question has two parts one theoretical and one practical:

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

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.. 

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.

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

https://127.0.0.5:8888/wsTest 

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.

     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);                 });             });         }  

if i change the line

var socket = new WebSocket("wss://127.0.0.5:8888/hello");  

to the http version i.e.

var socket = new WebSocket("ws://127.0.0.5:8080/hello");  

then all works again. The problem seems to be with the line

stompClient.connect({}, function(frame) { 

however according to this bug note (https://jira.spring.io/browse/SPR-11436) this should be the correct line

I have generated the ceritficate with the command:

keytool -genkey -alias tomcat -keyalg RSA  -keystore /home/tito/Projects/syncServer/Server/certificate/sync.keystore 

The server side:

@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);               }         };     } 

here is the web socket configuration portion

@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<MessageConverter> arg0) {          return true;     }  

additional messages seen on the firefox debug console

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 

here is full version of the html page

<!DOCTYPE html> <html> <head>     <title>Hello WebSocket</title>     <script src="/js/stomp.js"></script>     <script type="text/javascript">         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);         }     </script> </head> <body> <noscript><h2 style="color: #ff0000">Seems your browser doesn't support Javascript! Websocket relies on Javascript being enabled. Please enable     Javascript and reload this page!</h2></noscript> <div>     <div>         <button id="connect" onclick="connect();">Connect</button>         <button id="disconnect" disabled="disabled" onclick="disconnect();">Disconnect</button>     </div>     <div id="conversationDiv">         <label>What is your name?</label><input type="text" id="name" />         <button id="sendName" onclick="sendName();">Send</button>         <p id="response"></p>     </div> </div> </body> </html> 

the stomp script version used is "// Generated by CoffeeScript 1.6.3"

here is how the certificate was generated

$ 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 <tomcat>         (RETURN if same as keystore password):   

Addition: I have also noticed that web sockets are working if i call

https://127.0.0.5:8888/wsTest   

but not working if I call

https://localhost:8888/wsTest 

however i still have not found why is this happening. This behavior is the same with chrome and firefox.

回答1:

You definitely need an HTTPS connector for Websockets with SSL (I.e. your "wss://*" client). It's possible it isn't working because of the certificate problem. If I were you I'd double check the browser configuration for the certificate exceptions. Maybe regenerate the certificate and try again.



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