SSL with Grizzly and Jersey

11,808

Solution 1

IMO you can use different Factory method to initialize secured Grizzly HttpServer:

HttpServer secure = GrizzlyServerFactory.createHttpServer(BASE_URI_SECURED,
                        ContainerFactory.createContainer(HttpHandler.class, rc),
                        true,
                        new SSLEngineConfigurator(sslCon));

If you initialize the server like this, you don't need to stop and reconfigure it again.

Hope this will help.

Solution 2

Sorry to take so long to post this up here. Alexey's answer led me to the working solution, which is a lot like Wolfgang Fahl's code. Here's what I ended up with:

static HttpServer startSecureServer() throws IOException
{
    System.out.println("Starting server on port " + ConfigLoader.getHttpsServerPort());
    ResourceConfig rc = new PackagesResourceConfig("com.kinpoint.server.grizzlyresources");

    SSLContextConfigurator sslCon = new SSLContextConfigurator();

    sslCon.setKeyStoreFile(ConfigLoader.getKeystoreLocation()); // contains server keypair
    sslCon.setKeyStorePass(ConfigLoader.getKeystorePassword());

    HttpHandler hand = ContainerFactory.createContainer(HttpHandler.class, rc);

    HttpServer secure = GrizzlyServerFactory.createHttpServer(BASE_URI_SECURED, hand, true,
            new SSLEngineConfigurator(sslCon, false, false, false));

    return secure;
}

The second parameter in the SSLEngineConfigurator tells it not to use client mode. That was what was messing me up. Thanks for the help.

Solution 3

I have a nice and tested example using Grizzly 2.3.3 in: https://github.com/danielnuriyev/scriptedstuff/tree/master/src/com/scriptedstuff/server

Solution 4

The following code works with Grizzly 2.3.7 and I am using Jersey 1.18 - this includes code for SSL Client Authentication - if you don't have the keystores this feature will simply be ignored.

/**
 * create a Server based on an url and possibly a ResourceConfig
 * 
 * @param url
 * @param rc
 * @param secure
 *          - true if SSL should be used
 * @param contextPath 
 * @return
 * @throws Exception
 */
public HttpServer createHttpServer(String url, ResourceConfig rc,
        boolean secure, String contextPath) throws Exception {
    // HttpServer result = GrizzlyServerFactory.createHttpServer(url, rc);
    // http://grepcode.com/file/repo1.maven.org/maven2/com.sun.jersey/jersey-grizzly2/1.6/com/sun/jersey/api/container/grizzly2/GrizzlyServerFactory.java#GrizzlyServerFactory.createHttpServer%28java.net.URI%2Ccom.sun.jersey.api.container.grizzly2.ResourceConfig%29
    HttpServer result = new HttpServer();
    final NetworkListener listener = new NetworkListener("grizzly",
            settings.getHost(), settings.getPort());
    result.addListener(listener);
    // do we need SSL?
    if (secure) {
        listener.setSecure(secure);
        SSLEngineConfigurator sslEngineConfigurator = createSSLConfig(true);
        listener.setSSLEngineConfig(sslEngineConfigurator);
    }
    // Map the path to the processor.
    final ServerConfiguration config = result.getServerConfiguration();
    final HttpHandler handler = ContainerFactory.createContainer(
            HttpHandler.class, rc);
    config.addHttpHandler(handler, contextPath);
    return result;
}

  /**
 * create SSL Configuration
 * 
 * @param isServer
 *          true if this is for the server
 * @return
 * @throws Exception
 */
private SSLEngineConfigurator createSSLConfig(boolean isServer)
        throws Exception {
    final SSLContextConfigurator sslContextConfigurator = new SSLContextConfigurator();
    // override system properties
    final File cacerts = getStoreFile("server truststore",
            "truststore_server.jks");
    if (cacerts != null) {
        sslContextConfigurator.setTrustStoreFile(cacerts.getAbsolutePath());
        sslContextConfigurator.setTrustStorePass(TRUSTSTORE_PASSWORD);
    }

    // override system properties
    final File keystore = getStoreFile("server keystore", "keystore_server.jks");
    if (keystore != null) {
        sslContextConfigurator.setKeyStoreFile(keystore.getAbsolutePath());
        sslContextConfigurator.setKeyStorePass(TRUSTSTORE_PASSWORD);
    }

    //
    boolean clientMode = false;
    // force client Authentication ...
    boolean needClientAuth = settings.isNeedClientAuth();
    boolean wantClientAuth = settings.isWantClientAuth();
    SSLEngineConfigurator result = new SSLEngineConfigurator(
            sslContextConfigurator.createSSLContext(), clientMode, needClientAuth,
            wantClientAuth);
    return result;
}
Share:
11,808
user1389906
Author by

user1389906

Updated on July 18, 2022

Comments

  • user1389906
    user1389906 almost 2 years

    I'm trying to get grizzly to use SSL encryption and still work fine with Jersey. I've looked all over the Internet, and I find all kinds of different attempts at SSL with Grizzly and Jersey. Seems like there are different ways of doing it depending on which version you are using, and how you decided to implement it. I haven't been able to get any examples to work with my code yet.

    Here's how I start up my server:

    static HttpServer startSecureServer() throws IOException{
            ResourceConfig rc=new PackagesResourceConfig("server.grizzlyresources");
            SSLContextConfigurator sslCon=new SSLContextConfigurator();
    
            sslCon.setKeyStoreFile(ConfigLoader.getKeystoreLocation()); // contains server keypair
            sslCon.setKeyStorePass(ConfigLoader.getKeystorePassword());
    
            System.out.println("Starting server on port "+ConfigLoader.getHttpsServerPort());
            HttpServer secure=GrizzlyServerFactory.createHttpServer(BASE_URI_SECURED, rc);
            secure.stop();
    
            HashSet<NetworkListener> lists=new HashSet<NetworkListener>(secure.getListeners());
            for (NetworkListener listener : lists){
                listener.setSecure(true);
                SSLEngineConfigurator ssle=new SSLEngineConfigurator(sslCon);
                listener.setSSLEngineConfig(ssle);
                secure.addListener(listener);
                System.out.println(listener);
            }
    
            secure.start();
            return secure;
    }
    
    private static URI getBaseURISecured(){
        return UriBuilder.fromUri("https://0.0.0.0/").port(ConfigLoader.getHttpsServerPort()).build();
    }
    
    private static final URI BASE_URI_SECURED = getBaseURISecured();
    

    ConfigLoader loads in information from a config file. When I run this code, it starts up the server, it finds the resources in the server.grizzlyresources package, and it works great! Except for one thing. The server isn't secured. I can telnet into it and send an HTTP request in plain text for one of my resources, and it will return it. So the code works for starting up the server, but the whole SSL part of it is just being bypassed. Any ideas how to fix this or why it might be doing this?

    Here's the output to the console when I run it:

    Starting server on port 9999
    Jan 13, 2014 9:51:08 AM com.sun.jersey.api.core.PackagesResourceConfig init
    INFO: Scanning for root resource and provider classes in the packages:
      server.grizzlyresources
    Jan 13, 2014 9:51:08 AM com.sun.jersey.api.core.ScanningResourceConfig logClasses
    INFO: Root resource classes found:
      class server.grizzlyresources.SessionResource
      class server.grizzlyresources.LoginResource
    Jan 13, 2014 9:51:08 AM com.sun.jersey.api.core.ScanningResourceConfig init
    INFO: No provider classes found.
    Jan 13, 2014 9:51:08 AM com.sun.jersey.server.impl.application.WebApplicationImpl _initiate
    INFO: Initiating Jersey application, version 'Jersey: 1.12 02/15/2012 04:51 PM'
    Jan 13, 2014 9:51:09 AM org.glassfish.grizzly.http.server.NetworkListener start
    INFO: Started listener bound to [0.0.0.0:9999]
    Jan 13, 2014 9:51:09 AM org.glassfish.grizzly.http.server.HttpServer start
    INFO: [HttpServer] Started.
    Jan 13, 2014 9:51:09 AM org.glassfish.grizzly.http.server.NetworkListener stop
    INFO: Stopped listener bound to [0.0.0.0:9999]
    NetworkListener{name='grizzly', host='0.0.0.0', port=9999, secure=true}
    Jan 13, 2014 9:51:09 AM org.glassfish.grizzly.http.server.NetworkListener start
    INFO: Started listener bound to [0.0.0.0:9999]
    Jan 13, 2014 9:51:09 AM org.glassfish.grizzly.http.server.HttpServer start
    INFO: [HttpServer] Started.
    

    I'm using Grizzly 2.2.1, and Jersey 1.12.

    Thanks a bunch!

  • user1389906
    user1389906 over 10 years
    Thanks for the response! This doesn't work, but it got me on a search path that I hope will lead to the solution. The server now starts up secured, but it dies on handshake when I try using openssl s_client -connect localhost:9999 I'm thinking I might just need to migrate everything over to the newest version of Jersey, which is drastically different from Jersey 1.12, as I understand it. I'll post back if I figure it out.
  • alexey
    alexey over 10 years
    You can enable SSL debugging: "-Djavax.net.debug=all" and see why handshake fails
  • user1389906
    user1389906 over 10 years
    Thanks so much! The debugging info showed that it was trying to authenticate the client (which I didn't want it to do). Looking through grizzly documentation, I found that in constructing SSLEngineConfigurator, I can pass in booleans telling it not to authenticate the client. That did it!
  • Rolf
    Rolf over 8 years
    I think he referred to this: new SSLEngineConfigurator(sslContextConfigurator).setNeedClientA‌​uth(false)
  • Rolf
    Rolf over 8 years
    Don't forget to disable client mode, see this StackOverflow question: stackoverflow.com/questions/22724862/…
  • Amber
    Amber over 8 years
    This was very helpful. I noticed when I start my server with bogus credentials (keystore location/password) I don't get any exceptions, but the service is unavailable. Does your ConfigLoader do some validation, or have you found another way to catch errors?