dev@grizzly.java.net

Re: Grizzly 2.0: SSL support

From: Oleksiy Stashok <Oleksiy.Stashok_at_Sun.COM>
Date: Tue, 18 Nov 2008 19:02:13 +0100

Hi,

>>
>> Hi,
>> I would like to ask for the community feedback on current SSL
>> implementation in Grizzly 2.0
>> Unlike Grizzly 1.x, Grizzly 2.0 doesn't have special SSL transport,
>> but uses SSL Encoder and Decoder Transformers.
>> Transformer API is topic for separate email and blog ;).
>
> Blog? Long time I saw one from you (:-) :-) :-))

:)) You will.

> Just in several
>> words - Transformer knows how to transform data from one
>> representation to another.
>
> Needs to improve the JavaDocs :-) I think it is time to publish the
> API online :-) :-)
>
>
>> In our case:
>> SSLEncoderTransformer encodes plaintext input Buffer into TLS/SSL
>> encoded output Buffer.
>> SSLDecoderTransformer decodes TLS/SSL encoded Buffer into plaintext
>> data Buffer.
>> SSLCodec - incapsulates encoder and decoder transformers and SSL
>> configuration objects.
>> It's possible to work with SSL in both standalone and Filter modes.
>> 1) Standalone mode.
>> In standalone mode developer should implicitly initialize SSL
>> connection with SSL handshake. And then use Connection I/O methods
>> (read/write) to send and receive data.
>> Example:
>> Connection connection = null;
>> // Initiate the SSLCodec
>> SSLCodec sslCodec = new SSLCodec(createSSLContext());
>
> Can you describe what you need to create inside the
> createSSLContext()?
Currently, for unit test, it looks like that:

     private SSLContext createSSLContext() {
         SSLContextConfigurator sslContextConfigurator =
                 new SSLContextConfigurator();
         ClassLoader cl = getClass().getClassLoader();
         // override system properties
         URL cacertsUrl = cl.getResource("ssltest-cacerts.jks");
         if (cacertsUrl != null) {
              
sslContextConfigurator.setTrustStoreFile(cacertsUrl.getFile());
         }

         // override system properties
         URL keystoreUrl = cl.getResource("ssltest-keystore.jks");
         if (keystoreUrl != null) {
              
sslContextConfigurator.setKeyStoreFile(keystoreUrl.getFile());
         }

         return sslContextConfigurator.createSSLContext();
     }

There could be different ways to create SSLContext... Grizzly 2.0 just
has a helper class SSLContextConfigurator, which makes SSLContext
initialization easier.


>> TCPNIOTransport transport =
>> TransportManager.instance().createTCPTransport();
>
> I think we have discused that part already :-), but should we rename
> TransportManager to TransportManagerFactory, and replace instance()
> with getInstance()?
TransportManagerFactory sounds like factory for TransportManagers...
It could be TransportFactory.getInstance().create(...) ?


>> try {
>> transport.bind(PORT);
>> transport.start();
>> // Connect client
>> ConnectFuture future = transport.connect("localhost",
>> PORT);
>> connection = (TCPNIOConnection) future.get(10,
>> TimeUnit.SECONDS);
>
> This is not related to SSL only, but since we are on the topic, I
> think we need to have a a way to execute asynchronous connect. Right
> now the connect operation is blocking (10 seconds). I would like to
> be able to pass some CallbackHandler (or CompletionHandler like NIO.
> 2) so asynchronous operations without blocking.
Agree. CompletionHandler could be useful.


>> // Run handshake
>> Future handshakeFuture = sslCodec.handshake(connection);
>> // Wait until handshake will be completed
>> handshakeFuture.get(10, TimeUnit.SECONDS);
>
> Same here. We need a CompletionHandler.
Ok, agree.


>> MemoryManager memoryManager =
>> transport.getMemoryManager();
>> Buffer message = MemoryUtils.wrap(memoryManager, "Hello
>> world!");
>
> What MemoryUtil.wrap does exactly?
It wraps the String to a Grizzly Buffer. It's possible to set charset
encoding additionally.


>> // Write the message with SSLCodec.getEncoder() parameter.
>> Future writeFuture = connection.write(null, message, null,
>> sslCodec.getEncoder(), 10, TimeUnit.SECONDS);
>> writeFuture.get();
>
> To make the review easier, do you think you can reference the method
> description/javadoc from here? So people don't have to checkout the
> code to understand the sample :-). Here, writeFuture.get() doesn't
> block, right?
Actually it blocks and waits the result. But the actual operation
(write) is executed async.


>> // Obtain the Buffer, which corresponds to the SSLEngine
>> requirements.
>> Buffer receiverBuffer =
>> SSLResourcesAccessor.getInstance().
>> obtainAppBuffer(connection);
>
> Hum...do we really need another "Factory" to get the receiverBuffer?
> Should this be retrieved from the Transport instance instead. I'm -1
> on having a specialized object (at least with this current API).
> Should we have a concept of Context/Session?
We have Connection, which actually represents session.
SSLResourcesAccessor just helps us to retrieve SSL related artifacts
from a connection. It's possible to get the same info using:
attribute.get(connection). For example to get SSLEngine, we can use:

Attribute<SSLEngine> sslEngineAttribute =
attributeBuilder.createAttribute("sslEngine");
SSLEngine sslEngine = sslEngineAttribute.get(connection);

But in that case we always have to care about Attribute, it's name
etc. With accessor it's just becoming easier.

Also in Grizzly 2.0 Transport is not aware of SSL. These 2 are
independent things.


>> // Read the message with SSLCodec.getDecoder() parameter
>> Future readFuture =
>> connection.read(receiverBuffer, null,
>> sslCodec.getDecoder(), null, 10,
>> TimeUnit.SECONDS);
>> .....................................................
>> 2) Filter mode.
>> In Filter mode developer should just add SSLFilter to the transport
>> filter chain. The SSLFilter itself has a SSLCodec, which in its
>> turn has SSL encode/decode transformers and SSL configuration.
>> Example (SSL Echo server)
>> Connection connection = null;
>> SSLCodec sslCodec = new SSLCodec(createSSLContext());
>> TCPNIOTransport transport =
>> TransportManager.instance().createTCPTransport();
>> transport.getFilterChain().add(new TransportFilter());
>> // Add SSLFilter
>> transport.getFilterChain().add(new SSLFilter(sslCodec));
>> transport.getFilterChain().add(new EchoFilter());
>
> Inside the EchoFilter, calling connection.write() will make sure the
> output is encrypted if SSL is used, and clean if not, right? That's
> something we don't support in 1.x and that would be nice if Filter
> can be written without knowing which transport is used.
Not exactly. connection.write(), if used without Transformers, will
write plain data. Though if you'll use filterChain.write(....), it
will pass throw all the filter chain's filter codecs (SSL, Transport,
etc) and will be written encrypted.


>> try {
>> transport.bind(PORT);
>> transport.start();
>> ...................
>> Will appreciate the feedback.
>
> I think we need to update the main page (grizzly.dev.java.net) with
> the following information:
>
> + Javadocs
> + XREF Code
> + Samples (like the on above).
Agree :))

Thanks.

WBR,
Alexey.

>
>
> Great work!
>
> -- Jeanfrancois
>
>
>
>
>> Thanks.
>> WBR,
>> Alexey.
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
>> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe_at_grizzly.dev.java.net
> For additional commands, e-mail: dev-help_at_grizzly.dev.java.net
>