New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document use of TLS with RSocket #719
Comments
package com.foobar.rsocket.TcpSslUriHandler;
import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.rsocket.transport.ClientTransport;
import io.rsocket.transport.ServerTransport;
import io.rsocket.transport.netty.client.TcpClientTransport;
import io.rsocket.transport.netty.server.TcpServerTransport;
import io.rsocket.uri.UriHandler;
import reactor.netty.tcp.TcpClient;
import reactor.netty.tcp.TcpServer;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLDecoder;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.*;
/**
* A SSL implementation of {@link UriHandler} that creates {@link TcpClientTransport}s and {@link TcpServerTransport}s.
*
* @author linux_china
*/
public final class TcpSslUriHandler implements UriHandler {
private static final String SCHEME = "tcps";
private static final String DEFAULT_PASSWORD = "changeit";
public static List<String> fingerPrintsSha256 = new ArrayList<>();
public static String[] protocols = new String[]{"TLSv1.3", "TLSv.1.2"};
@Override
public Optional<ClientTransport> buildClient(URI uri) {
Objects.requireNonNull(uri, "uri must not be null");
if (!SCHEME.equals(uri.getScheme())) {
return Optional.empty();
}
try {
SslContext context = SslContextBuilder
.forClient()
.protocols(protocols)
.sslProvider(getSslProvider())
//.trustManager(new FingerPrintTrustManagerFactory(fingerPrintsSha256))
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
TcpClient tcpClient = TcpClient.create()
.host(uri.getHost())
.port(uri.getPort())
.secure(ssl -> ssl.sslContext(context));
return Optional.of(TcpClientTransport.create(tcpClient));
} catch (Exception e) {
return Optional.empty();
}
}
@Override
public Optional<ServerTransport> buildServer(URI uri) {
Objects.requireNonNull(uri, "uri must not be null");
if (!SCHEME.equals(uri.getScheme())) {
return Optional.empty();
}
try {
KeyStore store = KeyStore.getInstance("PKCS12");
Map<String, String> params = splitQuery(uri);
char[] password = params.getOrDefault("password", DEFAULT_PASSWORD).toCharArray();
String keyStore = params.getOrDefault("store", "/rsocket.p12");
store.load(this.getClass().getResourceAsStream(keyStore), password);
String alias = store.aliases().nextElement();
Certificate certificate = store.getCertificate(alias);
KeyStore.Entry entry = store.getEntry(alias, new KeyStore.PasswordProtection(password));
PrivateKey privateKey = ((KeyStore.PrivateKeyEntry) entry).getPrivateKey();
TcpServer tcpServer = TcpServer.create()
.host(uri.getHost())
.port(uri.getPort())
.secure(ssl -> ssl.sslContext(
SslContextBuilder.forServer(privateKey, (X509Certificate) certificate)
.protocols(protocols)
.sslProvider(getSslProvider())
));
return Optional.of(TcpServerTransport.create(tcpServer));
} catch (Exception e) {
return Optional.empty();
}
}
private SslProvider getSslProvider() {
if (OpenSsl.isAvailable()) {
return SslProvider.OPENSSL_REFCNT;
} else {
return SslProvider.JDK;
}
}
private Map<String, String> splitQuery(URI url) throws UnsupportedEncodingException {
Map<String, String> query_pairs = new LinkedHashMap<>();
String query = url.getQuery();
if (query != null && !query.isEmpty()) {
String[] pairs = query.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
}
}
return query_pairs;
}
}
|
Try sending the Client Cert as below for 2 way SSL; it works for me:
|
Hi @pckeyan In my case I’d rather have only server authentication. The point is in my sample the secure TLS channel seems to be correctly stablished, the client request reaches the acceptor but for some reason it ends up throwing that exception... |
@codependent working on the example for you |
@OlegDokuka Thank you!! |
@codependent I tried without client certs but at least it expects trustmanager to be configured or OS to present the default trustmanger. I am not sure how we set the DefaultSSLFactory settings to netty via RSocket. @OlegDokuka might have an answer. Below code works without client certs:
Server should not enable ClientAuth. |
I've updated the sample with @pckeyan's latest suggestion. The use of the trustmanager is equivalent to setting this on the client, but I think the tm is a better approach:
In any case, I keep getting the same errors :S |
Hi @OlegDokuka, could you have a look at this? |
For now please take a look at the Reactor Netty reference and #719 (comment) |
After upgrading to RC7 and replacing the deprecated classes the sample started working: Server:
Client:
|
@codependent Sending TrustManager earlier as well worked for me as stated above. Did you find the root cause of this issue or @OlegDokuka can you please update on the root cause for our knowledge? Just curious to learn. |
Sample project available on Github: https://github.com/codependent/rsocket-tls/
The full context of this problem can be found on StackOverflow.
The problem is that without TLS on the server/client, the communication works perfectly, but after securing them it fails.
Here's the full server and client code:
Server log:
Client log:
I've searched everywhere for a TLS RSocket example but found nothing. Also the docs don't show anything in this regard so I'm not sure whether I'm doing something wrong or there's an actual problem when using TLS.
The text was updated successfully, but these errors were encountered: