Tuesday, November 18, 2014

Netty (3.9.x) client-server connection with 2-way SSL authentication

Ok, so this is about how to (1) create a simple text based client-server protocol with Netty 3.9 that uses 2-way SSL authentication, i.e. an encrypted connection that also authenticates the client, and (2) how to generate the SSL certificates yourself. Code examples are in Scala.

Make sure you know how Netty works, how messages are sent and received, that is not covered here.

1) Client-server


Client

Code here.

A few notable things here:
  1. SslManager, we'll get back to that in a bit...
  2. Once the channel is connected (channelConnected()), we initiate the ssl handshake and listen to the result.
  3. In the ChannelFutureListener we wait for the success of the handshake. Note that communicating over this channel before won't work and will be insecure!!! 

Server

Code here.

Pretty similar to the client side:
  1. SslManager, just wait...
  2. In this example, we have a bunch of channels (ChannelGroup) that want to listen to the same stuff. Your scenario might be different.
  3. Once the channel is connected we do the same handshake thing on the server side.
  4. Only once the connection is secure (ChannelFutureListener) do we add the channel to the group.

SslManager

Code here, thanks to Veebs. This is used by both the client and the server.

2) Generate SSL certificates

What you need here is:
  1. One key store for the client with the client's private and public key
  2. One key store for the server with the server's private and public key
  3. One trust store for the client with the server's public key
  4. One trust store for the server with the client's public key
For this we can use the keytool program that comes with any JDK.

We generate a key store for the client with the following command, step 1):

keytool -genkey -alias fcr-freq-client -keysize 2048 -keyalg RSA -validity 3650 -keystore client.keystore -storetype JKS

Here you will be asked for a password to access the keystore. This is the password you have to give as argument to the ClientPipelineFactory.

Next we have to extract the client's public key from the keystore. This can be done with the following command (use the password defined above when prompted):

keytool -export -alias fcr-freq-client -keystore client.keystore -rfc -file public-client.cert

The public-client.cert file now contains the client's public key. Next, generate the server's truststore that will contain the client's public key:

keytool -import -alias fcr-freq-client -file public-client.cert -storetype JKS -keystore server.truststore

Here you'll have to give a password for the server truststore. Use a different one from the one you used for the client.

You should now have three files, client.keystore, server.truststore and public-client.cert. You can delete the last one as there is no more use for it.

Now do this again, but for the server, i.e. generate the server keystore (and use the server password), extract the server's public key (with the server password) and generate the client truststore (use the client password). With this, the client code only needs to know the client password and the server code only needs to know the server password.

Sources

Wednesday, September 4, 2013

Integrating Vaadin + Spring Security + Hibernate and doing it in Scala

Ok, so this is a little project/tutorial to integrate Vaadin to Spring Security, and code everything in Scala. The project also uses Hibernate to persist data into an H2 database. It's developed with Eclipse (+ Scala plugin) and Maven. Code can be found here.

This project implements a web application that allows a user to:
  • register to the site by providing his/her personal info
  • log-in to the site
  • log-out of the site
  • change his/her personal info
  • change his/her password
The application also shows internationalization (i18n). The main challenge in this type of integration is how to define authorization for different pages and how to handle situations where a page is accessed with insufficient credentials, i.e. how to forward the user to a login page or similar.

Other projects have integrated Vaadin to Spring Security, notably these:
  1. http://morevaadin.com/content/spring-security-integration/ 
  2. http://vaadin.xpoft.ru/ 
Both of these alternatives have shortcomings that have been worked around in this project + this one is written in Scala.

The problem

As described in (1), Spring Security (SS) works by securing subcontexts (myhost.com/public vs. myhost.com/private) whereas Vaadin uses fragments for different views (myhost.com/#!public vs. myhost.com/#!private). Fragments are a client side part of the URI that is not sent to the server, so SS cannot distinguish between the last two URIs.

Normally SS handles authentication and authorization (a&a) with exception handlers in a filter chain, so if a user tries to access a page (s)he is not authenticated for, SS will throw an exception and an exception handler will forward the user to a login page. This is illustrated below:

-> user sends request
 -> servlet invoked
  -> exception filter entered
   => page generation (with a&a that throws exceptions)
  -> exception filter catches a&a exception and sets up a login page forward
 -> servlet returns a redirect message to the browser
-> user's browser goes to a login page (that has a different URI i.e. subcontext)

If we want to implement all views (like the login and registration views that don't require authentication) and other views (that do require authentication and authorization) with Vaadin, we cannot use spring security's exception handling mechanism because the exception handling happens after the Vaadin page generation and needs to forward to another subcontext. If you try to forward to another fragment, you'll get a redirect loop:


The other projects mentioned above work around this by setting up a login page that is not a Vaadin view: The login page is implemented with FreeMarker or some other technology where the page can have a distinct subcontext.

Implementation

To avoid using different subcontexts, the access management has to be done in the Vaadin Navigator during the view generation. Here's a high level description of how this is done:
  • When a user navigates to a view, that view is provided by the Spring application context
  • The view object is defined with special annotations describing the roles the user must have in order to access the view
  • If the user does not have the proper role, the access manager throws an exception that is caught in a custom implementation of the navigator, which will then provide a login view
  • When the user provides his/her credentials, SS stores these credentials for the duration of the session (to be read by the access manager)

Spring integration with application context generated views


The integration of Spring to Vaadin starts with an extention of VaadinServlet. This is implemented in net.sf.vaadinturvaa.spring.SpringVaadinServlet. This implementation is pretty much copied from project (2) and loads the Spring application context as well as sets up a UIProvider for the application with net.sf.vaadinturvaa.spring.SpringUIProvider.

The Vaadin views are implemented in the net.sf.vaadinturvaa.views package and are marked with the following annotations:

Authentication

When a user register on the site, (s)he creates an account with personal information and a password. The password is hashed and stored to the database. When the user logs in, the password entered on the login form is hashed and compared to the hash in the database. If they match, the user is authenticated and a token is stored in the SecurityContextHolder:
SecurityContextHolder.getContext().setAuthentication(auth)
The SecurityContextPersistenceFilter will take care of persisting this between user requests.

Custom Navigator and error handling

When a page is accessed in Vaadin, the UI component defined for the VaadinServlet in the web.xml is invoked. More specifically, the Navigator configured in the UI's init method is invoked to access the appropriate view. The view instances are managed by Spring and returned by a custom implementation of Navigator. SS's AccessDecisionManager is responsible for making sure that the user accessing the view has proper credentials and if not, will throw an appropriate exception.

These exceptions are handled in class net.sf.vaadinturvaa.core.NavigatorFactory. This class returns Navigator instances that have a net.sf.vaadinturvaa.core.NavigationErrorHandlingStrategy. This is defined as follows:
abstract class NavigationErrorHandlingStrategy {

  def apply(navigationState: String, navigateTo: String => Unit)

}
The apply method takes the name of a navigation state and a function that takes the navigation state as parameter. This mirrors the way in which the Navigator object is invoked when navigating from one view to the next. The default implementation of this class is:
class DefaultNavigationErrorHandlingStrategy(val authenticationFailureView: String,
                                             val accessDeniedUnauthenticatedView: String,
                                             val accessDeniedAuthenticatedView: String)
    extends NavigationErrorHandlingStrategy {

  override def apply(navigationView: String, navigateTo: String => Unit) {
    try {
      navigateTo(navigationView)
    }
    catch {
      case e: AuthenticationException  => navigateTo(authenticationFailureView)
      case e: AlreadyLoggedInException => navigateTo(accessDeniedAuthenticatedView)
      case e: AccessDeniedException =>
        if(AuthenticationHelper.areWeAuthenticated)
          navigateTo(accessDeniedAuthenticatedView)
        else navigateTo(accessDeniedUnauthenticatedView)
    }
  }
}
This handles three different errors: unauthenticated user, insufficient privileges and a special case in which the user tries to access the login page when already logged in.

The NavigationErrorHandlingStrategy is used by the ExceptionHandlingNavigator returned by the NavigatorFactory:
  private class ExceptionHandlingNavigator(ui: UI,
                                           container: SingleComponentContainer,
                                           errorHandling: NavigationErrorHandlingStrategy)
      extends Navigator(ui, container) {
    addProvider(viewProvider)

    override def navigateTo(navigationState: String) {
      errorHandling(navigationState, super.navigateTo(_))
    }
  }
The viewProvider is an instance of ViewProvider that gets the view instances from the Spring application context.

Internationalization

i18n is made of two parts: localized view labels and localized validation messages. View labels come from ViewMessages_xx.properties files and validation messages come from ValidationMessages_xx.properties files. View labels are made available to the application with a MessageSource and all view implementations get access to it by extending the net.sf.vaadinturvaa.views.MessageSourced trait. Validation messages are accessed directly by Vaadin's BeanValidator.

Running the app

To run the app you need to 
  • start the H2 database as a separate process (./h2.sh -tcpAllowOthers -tcpPort 8043) or start it along with the rest of the application (see root-context.xml). You also need to place the accounts.h2.db file in your home directory (or modify the jdbc.properties file accordingly).
  • build the app as a WAR file and start it in a Servlet engine or from the project directory with mvn jetty:run.
  • go to http://localhost:9090/#!register and register away.