【问题标题】:SSL with Grizzly and JerseySSL 与 Grizzly 和 Jersey
【发布时间】:2014-02-01 14:25:43
【问题描述】:

我正在努力让 grizzly 使用 SSL 加密并且仍然可以在 Jersey 上正常工作。我浏览了整个互联网,我发现在 SSL 方面的各种不同尝试与 Grizzly 和 Jersey。根据您使用的版本以及您决定如何实现它,似乎有不同的方法。我还没有找到任何示例来处理我的代码。

我是这样启动服务器的:

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 从配置文件中加载信息。当我运行这段代码时,它会启动服务器,它会在 server.grizzlyresources 包中找到资源,而且效果很好!除了一件事。服务器不安全。我可以远程登录它并以纯文本形式为我的一个资源发送 HTTP 请求,它会返回它。因此,该代码可用于启动服务器,但它的整个 SSL 部分只是被绕过了。任何想法如何解决此问题或为什么会这样做?

这是我运行控制台时的输出:

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.

我正在使用 Grizzly 2.2.1 和 Jersey 1.12。

非常感谢!

【问题讨论】:

    标签: java rest ssl jersey grizzly


    【解决方案1】:

    IMO 你可以使用不同的工厂方法来初始化安全的 Grizzly HttpServer:

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

    如果你像这样初始化服务器,你不需要停下来重新配置它。

    希望这会有所帮助。

    【讨论】:

    • 感谢您的回复!这不起作用,但它让我走上了一条我希望能找到解决方案的搜索路径。服务器现在已安全启动,但是当我尝试使用 openssl s_client -connect localhost:9999 时它在握手时死机 我想我可能只需要将所有内容迁移到 Jersey 的最新版本,据我了解,这与 Jersey 1.12 完全不同.如果我弄明白了,我会回帖。
    • 您可以启用 SSL 调试:“-Djavax.net.debug=all”并查看握手失败的原因
    • 非常感谢!调试信息表明它正在尝试对客户端进行身份验证(我不希望它这样做)。查看 grizzly 文档,我发现在构造 SSLEngineConfigurator 时,我可以传入布尔值,告诉它不要对客户端进行身份验证。做到了!
    • 我想他指的是这个:new SSLEngineConfigurator(sslContextConfigurator).setNeedClientAuth(false)
    • 不要忘记禁用客户端模式,请参阅 StackOverflow 问题:stackoverflow.com/questions/22724862/…
    【解决方案2】:

    我有一个使用 Grizzly 2.3.3 的很好且经过测试的示例: https://github.com/danielnuriyev/scriptedstuff/tree/master/src/com/scriptedstuff/server

    【讨论】:

      【解决方案3】:

      以下代码适用于 Grizzly 2.3.7,而我使用的是 Jersey 1.18 - 这包括用于 SSL 客户端身份验证的代码 - 如果您没有密钥库,则此功能将被忽略。

      /**
       * 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;
      }
      

      【讨论】:

        【解决方案4】:

        很抱歉花了这么长时间才在这里发布。 Alexey 的回答让我找到了可行的解决方案,这很像 Wolfgang Fahl 的代码。这是我最终得到的结果:

        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;
        }
        

        SSLEngineConfigurator 中的第二个参数告诉它不要使用客户端模式。这就是让我感到困惑的原因。感谢您的帮助。

        【讨论】:

        • 这很有帮助。我注意到当我使用伪造的凭据(密钥库位置/密码)启动服务器时,我没有收到任何异常,但服务不可用。您的 ConfigLoader 是否进行了一些验证,或者您是否找到了另一种捕获错误的方法?
        猜你喜欢
        • 2015-09-03
        • 2015-04-12
        • 1970-01-01
        • 1970-01-01
        • 2013-09-09
        • 2018-01-28
        • 1970-01-01
        • 2012-08-06
        • 2013-11-14
        相关资源
        最近更新 更多