Gottox / socket.io-java-client

Socket.IO Client Implementation in Java
MIT License
950 stars 387 forks source link

https connect #14

Open ofdrykkja opened 12 years ago

ofdrykkja commented 12 years ago

i'm trying to use your client for connect to https server. i'm calling method setDefaultSSLSocketFactory(getFactory()), but nothing happens - no connect, no errors, no warnings. getFactory code:

public static SSLSocketFactory getFactory() throws Exception {
        KeyStore trusted = KeyStore.getInstance("BKS");
        InputStream in = context.getResources().openRawResource(R.raw.mystore);
        try {
            trusted.load(in, "pass".toCharArray());
        } catch (Exception e) {
            throw new AssertionError(e);
        } finally {
            in.close();
        }

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(trusted);

        SSLContext ssl_context = SSLContext.getInstance("TLS");
        ssl_context.init(null, tmf.getTrustManagers(), null);

        return ssl_context.getSocketFactory();
    }

connect to server code:

try {
            socket = new SocketIO(context.getString(R.string.baseurl));
        } catch (MalformedURLException e1) {
            online = false;
            //e1.printStackTrace();
        }
        try {
            socket.setDefaultSSLSocketFactory(getFactory());
        } catch (Exception e2) {
            // TODO Auto-generated catch block
            e2.printStackTrace();
        }
        socket.connect(new IOCallback() {
//...

tell me please what i'm doing wrong?

Gottox commented 12 years ago

Hi sweetrenard!

This could be a bug in this implementation. Unfortunally I'm currently involved in my house moving. I'll investigate in this issue at the end of next week.

ofdrykkja commented 12 years ago

Thank you for your attention!

rsla commented 12 years ago

Hello. after a little investigation, I have found reason of this inconvienience.

  1. Unfortunatly, WebSocketConnection uses different SSLSocketFactory than you have created via your new SSLContext.
  2. Therefore WebSocketConnection uses different (default) TrustManager during wss handshaking
  3. In next consequence yours host certificate is untrusted and exception is generated during create WSS socket.
  4. Unfortunatly, IOConnection.transportError does not log an error before reconect (infinity reconnect cycle)

How is workarround for my case (I think for you too):

  1. To pass ssl_context.getSocketFactory(); to WebSoccketConnection layer I've used HttpsURLConnection.setDefaultSSLSocketFactory(ssl_context.getSocketFactory()); (I think that your socket.setDefaultSSLSocketFactory(getFactory()); is enought)
  2. To use this factory I've modified WebSoccketConnection.createSocket() for WSS connection ;-): SocketFactory factory = HttpsURLConnection.getDefaultSSLSocketFactory(); // instead of SSLSocketFactory.getDefault();
  3. In addition I've set my own host verifier: HttpsURLConnection .setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String s, SSLSession sslsession) { Log.i(this.getClass().getName(), "Accepted host " + s
    • " during SSL Handshaking"); return true; } });

I couldn't find better way for now. It's working.

Gottox commented 12 years ago

Thanks :)

So it's a bug in Weberknecht which prevents to implement this properly. I suspect switching the Websocket library is the sanest solution to this issue. Java-Websocket seems nice, but I remembering having issues with this library. I'll try it today.

regards

Enno

tagrudev commented 12 years ago

any progress on this :?

Gottox commented 12 years ago

Yes, @TooTallNate s library does the job well and supports custom SSLFactorys. Unfortunally to make this work, there will be a small API-Change to socket.io-java-client. Expect an update today. :)

Gottox commented 12 years ago

Please recheck current master. Does it work as desired?

tagrudev commented 12 years ago

https://gist.github.com/3698101 I cant build it any ideas ?

mvecchio commented 12 years ago

Hi, try to change the following line in build.xml:

With the following

Gottox commented 12 years ago

Recheck master. :)

tagrudev commented 12 years ago

Can you give an example usage ? Here is a Gist on my onCreate() method ->

https://gist.github.com/3714074

It doesnt seem to get inside the connect method :|

tagrudev commented 12 years ago

any ideas ?>

Gottox commented 12 years ago

Hi!

See https://github.com/TooTallNate/Java-WebSocket/blob/master/example/SSLClientExample.java for using an SSLContext in your source. SSL with socket.io-java-client is currently untested, so expect and report bugs.

kind regards :)

Gottox commented 12 years ago

Hell is SSL with Java fucked up... -.-

tagrudev commented 12 years ago

what if I don't want to use a key? I have a trusted RapidSSL.

Gottox commented 12 years ago

So you need a DefaultHostnameVerifier? Like in this question? http://stackoverflow.com/questions/11307195/java-https-connection-and-security-popup

tagrudev commented 12 years ago

yeah I need a SocketIO implementation of Thrust All Certs, even with this it doesnt seem to get inside the connect method, it doesnt get any callback, can you give and example of thrust all certs ? I am still new to this certs things and It is been several days of pain in the a&&.

tagrudev commented 12 years ago

there is a problem with the emit, with this implementation it doesnt send anything to the server

Gottox commented 12 years ago

Yea, have to look into it after the exam next week. :)

tagrudev commented 12 years ago

Cool will be looking forward to it

AlexNovar commented 12 years ago

I have the same behaviour for https (wss). It doesn't work for me.

tagrudev commented 12 years ago

any progress on this :?

Gottox commented 12 years ago

I'm currently building a test infrastructure with SSL. What happens if you wait longer than two minutes for a response? normally, it should timeout. (silly values, but that's what we get from the socket.io server :])

JiboStore commented 11 years ago

I used the latest master branch ( commit id: fc80d8e3c217fd93ec8ffea2bb5487dcb1d61f04 )

It doesn't work on Android, but on J2SE version, it works, I just need to initialize it this way:

        SocketIO.setDefaultSSLSocketFactory(SSLContext.getInstance("Default"));
        m_pSocket = new SocketIO( m_szUrl, this );

I've ran out of idea to make it works on Android, would you please give some clues? will greatly appreciate! Thanks!

JiboStore commented 11 years ago

I got it working, as note for the next person, the WebSocket.jar version's SSL is not working anymore. What I did:

  1. revert to commit id 91ccf13d6add3dd12a39cfe08dafefe1e0942b46 - Fixing crash when using xhr during disconnect
  2. just like @rsla mentioned above https://github.com/Gottox/socket.io-java-client/issues/14#issuecomment-8004585, change these lines in io.socket.IOConnection.java line 69:

    // private static SSLSocketFactory sslSocketFactory = (SSLSocketFactory) SSLSocketFactory
       .getDefault();
    
      private static SSLSocketFactory sslSocketFactory = (SSLSocketFactory) HttpsURLConnection.getDefaultSSLSocketFactory();

add in io.socket.IOConnection.java handshake() line 287:

    try {
        setState(STATE_HANDSHAKE);
        url = new URL(IOConnection.this.url.toString() + SOCKET_IO_1);

                    // begin add
        HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
            @Override
            public boolean verify(String s, SSLSession sslsession) {
                return true;
            }
        });

        connection = url.openConnection();

just before url.openConnection();

Hope this helps!

jingzhaoou commented 11 years ago

Hi, @JiboStore, you probably don't need to change the source code. According to this link, you just need to add the following to you application code:

static {
    // for localhost testing only
    javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(
    new javax.net.ssl.HostnameVerifier() {
        public boolean verify(String hostname,
                javax.net.ssl.SSLSession sslSession) {
            if (hostname.equals("localhost")) {
                return true;
            }
            return false;
        }
    });
} 

This is how I create SocketIO:

    SocketIO.setDefaultSSLSocketFactory(SSLContext.getInstance("Default"));
    SocketIO socket = new SocketIO("https://localhost:8080/");

I tried and it works perfectly for me.

tagrudev commented 11 years ago

hmm can you give an example on using it with Android ?

2fours commented 11 years ago

I'm trying to get ssl with socket.io working on android also. I have implemented all of the suggestions above and the initial handshake in IOConnection works correctly. The subsequent connect (to /socket.io/1/websocket/sessionId) does not seem to be recognized by the server ...there is no response, and no inclination that the server received the data. There are also no error messages.

Any ideas?

Edit: I just submitted a pull request to Java-Websocket that fixes the issue for me: https://github.com/TooTallNate/Java-WebSocket/pull/153

Edit: Fixes the issue on android devices that don't suffer from this bug: https://code.google.com/p/android/issues/detail?id=12955. It appears that the only way this library will work on those devices is to use an implementation based on SSLSocket, not SSLEngine.

Javi44 commented 11 years ago

I am stuck in the same point as @2fours before he edited his message.

@2fours, does your first edit mean that the solution is to use another library? not Gottox's one?

2fours commented 11 years ago

@Javi44 on android < 3.0 this library will not work. I was able to use autobahn (actually @palmerc fork with ssl support: https://github.com/palmerc/SecureWebSockets) with minor modification.

Javi44 commented 11 years ago

I am using android 4.0.3, so I guess there is no problem, but I am a bit lost. I had running my client (android) - server (node.js with socket.io) over normal http, but now I want to add security, so... to achieve this, am I suppose to download palmerc's fork and use it instead of Gottox's socket.io? Is that what you mean?

Btw, thank for your fast reply

palmerc commented 11 years ago

@Javi44 If you want to do WebSockets with SSL/TLS encryption I would recommend using my fork of the Autobahn client. I had to modify Autobahn's client because he used Java NIO which is broken on Android. https://github.com/palmerc/SecureWebSockets

2fours commented 11 years ago

If your app is never going to run on android < 3.0 you are fine with things as they are. If it is going to run on < 3.0 you will need to modify this library to use @palmerc fork instead of java-websocket.

Javi44 commented 11 years ago

Thanks @palmerc I think I will give a try to your solution.

@2fours, I was using android 4.0.3 since the begining and I still have the problem. I can see the handshake in the server, but the client doesn't reach the onConnect() method and I don't get any error... I cannot let the things as they are, can I?

2fours commented 11 years ago

Assuming you have implemented all of the SSL cert stuff correctly then I'm not sure what the problem is. I would get wireshark and your debugger out. Good luck.

palmerc commented 11 years ago

@2fours @Javi44 Can I recommend you just pull out an SSL Cert checker as your preliminary test? The SSL negotiation happens before the WebSocket so any off the shelf checker will make sure you have SSL working and that your certificate chain is valid. Traditionally I use the Thawte SSL Certificate Checker, but I'm sure there are others.

Javi44 commented 11 years ago

Thanks booth for the advises I think that my SSL certificate should be ok, since I have create my own certification authority, which I have installed in my android device and that I have used to create the server key and cert. Besides, I can access to the server using the web browser of the mobile phone and there are no annoying pop ups about certs.

palmerc commented 11 years ago

@Javi44 never underestimate the pickiness of the SSL implementations on Mobile devices. The reason for testing with an SSL Certificate Checker is because it is possibly much more thorough than your web browser. In my experience you might be forced to disable SSL checks on the phone with certain certificates. You can disable all certificate checks according to SSLCertificateSocketFactory by:

On development devices, "setprop socket.relaxsslcheck yes" bypasses all SSL certificate and hostname checks > for testing purposes. This setting requires root access.

Javi44 commented 11 years ago

Sorry for my late answer.

Finally I have the application running over ssl, @JiboStore's solution is what worked for me.

z4ce commented 11 years ago

I've been struggling with the "silent" failures with SSL on android as well. The handshake seems to work fine, but when the transport actually tries to connect it seems to blow up. I've tried disabling SSL checks and putting a host verifier that returns "true" in just for kicks, but I'm actually using a valid SSL certificate so I'm not sure what is going on.

If I use HTTP it works fine. HTTPS also works using Koush's android library. Any ideas?

Superlukec commented 10 years ago

I have android application, which needs to connect to Socket.IO server running on Node.js.

Well my problem is that I can connect to my local server (handshake authorized), but function onConnect is not triggered?

I am using self-signed SSL.

I have used android guidelines for self-signed certificates: http://developer.android.com/training/articles/security-ssl.html#SelfSigned

And also solution from @jingzhaoou ... static { ..... }

Thank you for your help.

Superlukec commented 10 years ago

I have found the solution. I have used the library https://github.com/koush/AndroidAsync. It works very well with self-signed certificate.

whuhenrylee commented 10 years ago

@Superlukec i have not found any SSL support of AndroidAsync.could you please show shom example?

Superlukec commented 10 years ago

Sorry about my late reply. Here is the quick snippet.


CertificateFactory cf = CertificateFactory.getInstance("X.509");

InputStream caInput = getResources().openRawResource(R.raw.mycert); Certificate ca;

ca = cf.generateCertificate(caInput); System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());

// Create a KeyStore containing our trusted CAs String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); keyStore.setCertificateEntry("ca", ca);

// Create a TrustManager that trusts the CAs in our KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); tmf.init(keyStore);

// Create an SSLContext that uses our TrustManager context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null);

AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setSSLContext(context); AsyncHttpClient.getDefaultInstance().getSSLSocketMiddleware().setTrustManagers(tmf.getTrustManagers());

SocketIORequest req = new SocketIORequest("https://myadress");

client = SocketIOClient.connect(AsyncHttpClient.getDefaultInstance(), req, new com.koushikdutta.async.http.socketio.ConnectCallback() { @Override public void onConnectCompleted(Exception e, SocketIOClient socketIOClient) {

}   

}).get();


You can find more on their documentation page.

Cheers, Luka

piovezan commented 10 years ago

@2fours Hi, by any chance do you have the code for your Gottox socket.io client modified to use the palmerc fork? Thanks.

arpitjoshi08 commented 7 years ago

getting issue with https. used SSL then socket not connecting i used this code ` setState(STATE_HANDSHAKE); url = new URL(IOConnection.this.url.toString() + SOCKET_IO_1); ((HttpsURLConnection) connection).setHostnameVerifier(hostnameVerifier);

        connection = url.openConnection();

        if (connection instanceof HttpsURLConnection) {
                ((HttpsURLConnection) connection)
                    .setSSLSocketFactory(sslContext.getSocketFactory());

        }
        connection.setConnectTimeout(connectTimeout);
        connection.setReadTimeout(connectTimeout);

`

and connection ` SSLContext context = SSLContext.getInstance("TLS"); context.init(null, trustAllCerts, null);

        SocketIO.setDefaultSSLSocketFactory(context);`

`

private final TrustManager[] trustAllCerts= new TrustManager[] { new X509TrustManager() {
    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
        return new java.security.cert.X509Certificate[] {};
    }

    public void checkClientTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }

    public void checkServerTrusted(X509Certificate[] chain,
                                   String authType) throws CertificateException {
    }
} };`

but getting error on handshake method