Skip to content

Commit

Permalink
Add SSL support (issue ReactiveX#106).
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomasz Bak committed Jun 19, 2014
1 parent 825850e commit f71f24e
Show file tree
Hide file tree
Showing 21 changed files with 1,125 additions and 20 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version=0.3.6
netty_version=4.0.14.Final
netty_version=4.0.20.Final
slf4j_version=1.7.6
rxjava_version=[0.17,)
2 changes: 2 additions & 0 deletions rx-netty-examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,14 @@ Examples Catalog
Protocol | Example / Test | Description
---------|---------|------------
HTTP | [Hello World](src/main/java/io/reactivex/netty/examples/http/helloworld/README.md) | Simple HTTP GET client/server implementation.
HTTP | [SSL Hello World](src/main/java/io/reactivex/netty/examples/ssl/README.md) | Hello World version with SSL connection.
HTTP | [Simple POST](src/main/java/io/reactivex/netty/examples/http/post/README.md) | Simple HTTP POST client/server implementation.
HTTP | [Chunked GET](src/main/java/io/reactivex/netty/examples/http/chunk/README.md) | An example of how to handle large, chunked reply that is not pre-aggregated by the default pipline configurator.
HTTP | [Server Side Events](src/main/java/io/reactivex/netty/examples/http/sse/README.md) | This examples demonstrates how to implement server side event stream, and how to handle it on the client side.
HTTP | [Log tail](src/main/java/io/reactivex/netty/examples/http/logtail/README.md) | A more sophisticated server side event example, with multiple event sources and an intermediary aggregating separate data streams.
HTTP | [Word Counter](src/main/java/io/reactivex/netty/examples/http/wordcounter/README.md) | More complex HTTP POST example demonstrating how to use ContentSource framework to upload a file onto the server.
TCP | [Echo Server](src/main/java/io/reactivex/netty/examples/tcp/echo/README.md) | A simple echo client.
TCP | [SSL Echo Server](src/main/java/io/reactivex/netty/examples/tcp/ssl/README.md) | A simple echo client with SSL connection.
TCP | [TCP Server Side Event Stream](src/main/java/io/reactivex/netty/examples/tcp/event/README.md) | TCP server side event stream example, with configurable client side processing delay.
TCP | [Interval](src/main/java/io/reactivex/netty/examples/tcp/interval/README.md) | A bit more sophisticated event stream example, with explicit subscribe/unsubscribe control mechanism.
UDP | [Hello World](src/main/java/io/reactivex/netty/examples/udp/README.md) | UDP version of a simple request - reply client/server implementation.
Expand Down
31 changes: 31 additions & 0 deletions rx-netty-examples/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ targetCompatibility = JavaVersion.VERSION_1_6

dependencies {
compile project(':rx-netty')
compile "org.slf4j:slf4j-log4j12:${slf4j_version}"
testCompile 'junit:junit:4.10'
}

Expand All @@ -41,6 +42,21 @@ task runHelloWorldServer (dependsOn: [classes], type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
}

task runSslHelloWorldClient (dependsOn: [classes], type: JavaExec) {
group = "Examples"
description = "Run SSL Hello World client"

main = "io.reactivex.netty.examples.http.ssl.SslHelloWorldClient"
classpath = sourceSets.main.runtimeClasspath
}
task runSslHelloWorldServer (dependsOn: [classes], type: JavaExec) {
group = "Examples"
description = "Run SSL Hello World server"

main = "io.reactivex.netty.examples.http.ssl.SslHelloWorldServer"
classpath = sourceSets.main.runtimeClasspath
}

task runSimplePostClient (dependsOn: [classes], type: JavaExec) {
group = "Examples"
description = "Run simple POST client"
Expand Down Expand Up @@ -158,6 +174,21 @@ task runTcpEchoServer (dependsOn: [classes], type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
}

task runSslTcpEchoClient (dependsOn: [classes], type: JavaExec) {
group = "Examples"
description = "Run SSL TCP echo client"

main = "io.reactivex.netty.examples.tcp.ssl.SslTcpEchoClient"
classpath = sourceSets.main.runtimeClasspath
}
task runSslTcpEchoServer (dependsOn: [classes], type: JavaExec) {
group = "Examples"
description = "Run SSL TCP echo server"

main = "io.reactivex.netty.examples.tcp.ssl.SslTcpEchoServer"
classpath = sourceSets.main.runtimeClasspath
}

task runTcpEventStreamClient (dependsOn: [classes], type: JavaExec) {
group = "Examples"
description = "Run TCP event stream client"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
Overview
========

RxNetty supports SSL protocol with server side certificate validation. Two modes are provided:
* insecure
* trusted server

Insecure mode trusts all X.509 certificates without any verification on client side, and on server side generates
self signed certificate per each RxServer instance created.

In trusted mode, the client can be configured with application or standard Java SDK trust store. On server side,
certificate chain file and private key (optionally protected with password) must be configured.

SSL support comes with a set of convenience factory methods in ```RxServer``` and a set of predefined pipeline configurators
in ```PipelineConfigurators``` class. For more complex configurations or non-typical use cases
```ClientSslPipelineConfiguratorBuilder``` and ```ServerSslPipelineConfiguratorBuilder``` builders can be used.
One example of that would be creating server side pipeline configurator for trusted server mode.

Running
=======

To run the example execute:

```
$ cd RxNetty/rx-netty-examples
$ ../gradlew runSslHelloWorldServer
```

and in another console:

```
$ cd RxNetty/rx-netty-examples
$ ../gradlew runSslHelloWorldClient
```

HTTP client
===========

Here is the snippet from [SslHelloWordClient](SslHelloWorldClient.java):

```java
public HttpResponseStatus sendHelloRequest() throws Exception {
HttpClient<ByteBuf, ByteBuf> rxClient = RxNetty.createSslInsecureHttpClient("localhost", port);

HttpResponseStatus statusCode = rxClient.submit(HttpClientRequest.createGet("/hello"))
...
}
}
```

The client code is identical to its non-encrypted counterpart ([HelloWorldClient](../helloworld/README.md)), except
the HTTPClient creation step. In this example, the predefined RxNetty.createSslInsecureHttpClient method is used
which configures SSH handler in the pipeline with trust-all trust store.

HTTP server
===========

Here is the snippet from [SslHelloWordClient](SslHelloWorldServer.java):

```java
public HttpServer<ByteBuf, ByteBuf> createServer() throws CertificateException, SSLException {
HttpServer<ByteBuf, ByteBuf> server = RxNetty.createSslInsecureHttpServer(port, new RequestHandler<ByteBuf, ByteBuf>() {
...
}
```

On the server side, a convenience factory method is again used to create HTTPServer with SSL handler.
In the insecure mode, a self signed certificate will be automatically generated and used for authentication.
It will be accepted on the client side, since in the insecure mode client trusts all certificates.
The insecure mode should NEVER be used in the production deployment. Its usage is limited to test code/examples.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.reactivex.netty.examples.http.ssl;

import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.reactivex.netty.RxNetty;
import io.reactivex.netty.protocol.http.client.HttpClient;
import io.reactivex.netty.protocol.http.client.HttpClientRequest;
import io.reactivex.netty.protocol.http.client.HttpClientResponse;
import rx.Observable;
import rx.functions.Action0;
import rx.functions.Func1;
import rx.functions.Func2;

import java.nio.charset.Charset;

import static io.reactivex.netty.examples.http.ssl.SslHelloWorldServer.DEFAULT_PORT;

/**
* @author Tomasz Bak
*/
public class SslHelloWorldClient {

private final int port;

public SslHelloWorldClient(int port) {
this.port = port;
}

public HttpResponseStatus sendHelloRequest() throws Exception {
HttpClient<ByteBuf, ByteBuf> rxClient = RxNetty.createSslInsecureHttpClient("localhost", port);

HttpResponseStatus statusCode = rxClient.submit(HttpClientRequest.createGet("/hello"))
.mergeMap(new Func1<HttpClientResponse<ByteBuf>, Observable<ByteBuf>>() {
@Override
public Observable<ByteBuf> call(HttpClientResponse<ByteBuf> response) {
return response.getContent();
}
}, new Func2<HttpClientResponse<ByteBuf>, ByteBuf, HttpResponseStatus>() {
@Override
public HttpResponseStatus call(HttpClientResponse<ByteBuf> response, ByteBuf content) {
System.out.println(content.toString(Charset.defaultCharset()));
return response.getStatus();
}
})
.doOnTerminate(new Action0() {
@Override
public void call() {
System.out.println("=======================");
}
}).toBlocking().last();

return statusCode;
}

public static void main(String[] args) {
try {
new SslHelloWorldClient(DEFAULT_PORT).sendHelloRequest();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2014 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.reactivex.netty.examples.http.ssl;

import io.netty.buffer.ByteBuf;
import io.reactivex.netty.RxNetty;
import io.reactivex.netty.protocol.http.server.HttpServer;
import io.reactivex.netty.protocol.http.server.HttpServerRequest;
import io.reactivex.netty.protocol.http.server.HttpServerResponse;
import io.reactivex.netty.protocol.http.server.RequestHandler;
import rx.Observable;

import javax.net.ssl.SSLException;
import java.security.cert.CertificateException;

/**
* @author Tomasz Bak
*/
public final class SslHelloWorldServer {

static final int DEFAULT_PORT = 8105;

private int port;

public SslHelloWorldServer(int port) throws CertificateException {
this.port = port;
}

public HttpServer<ByteBuf, ByteBuf> createServer() throws CertificateException, SSLException {
HttpServer<ByteBuf, ByteBuf> server = RxNetty.createSslInsecureHttpServer(port, new RequestHandler<ByteBuf, ByteBuf>() {
@Override
public Observable<Void> handle(HttpServerRequest<ByteBuf> request, final HttpServerResponse<ByteBuf> response) {
response.writeStringAndFlush("Welcome!!");
return response.close();
}
});

System.out.println("HTTP hello world server started...");
return server;
}

public static void main(final String[] args) {
try {
new SslHelloWorldServer(DEFAULT_PORT).createServer().startAndWait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
Overview
========

This example is a small modification of [TCP echo](../echo/README.md) example that demonstrates how to setup SSL connection.
More detailed explanation of SSL handling is provided with the [SSL HelloWorld](../../ssl/README.md) example.

Running
=======

To run the example execute:

```
$ cd RxNetty/rx-netty-examples
$ ../gradlew runSslTcpEchoServer
```

and in another console:

```
$ cd RxNetty/rx-netty-examples
$ ../gradlew runSslTcpEchoClient
```
Loading

0 comments on commit f71f24e

Please sign in to comment.