2013-11-24 125 views
3

我正在使用嵌入式Jetty構建沙盒RESTful API。我的概念驗證設計:一個簡單的嵌入式碼頭服務器,它(1)接受SSL端口上的連接,(2)使用ContextHandlerCollection根據URI前綴調用適當的Handler。Embedded Jetty:在安全的https服務器中,ContextHandler重定向到http URI

我原來的測試,使用簡單的非SSL連接,似乎完美工作(注意,代碼爲導入和助手HelloHandler類在附錄中)。

public static void main(String[] args) throws Exception { 
    Server server = new Server(12000); 

    ContextHandler test1Context = new ContextHandler(); 
    test1Context.setContextPath("/test1"); 
    test1Context.setHandler(new HelloHandler("Hello1")); 

    ContextHandler test2Context = new ContextHandler(); 
    test2Context.setContextPath("/test2"); 
    test2Context.setHandler(new HelloHandler("Hello2")); 

    ContextHandlerCollection contextHandlers = new ContextHandlerCollection(); 
    contextHandlers.setHandlers(new Handler[] { test1Context, test2Context }); 

    server.setHandler(contextHandlers); 
    server.start(); 
    server.join(); 
} 

然而,在測試這一點,它逃過了我的注意,當我省略了結尾斜線,所以http://localhost:12000/test1是越來越重定向到http://localhost:12000/test1/瀏覽器重定向正在發生。 (FWIW,這個oversite會稍後轉化爲4個小時以上的故障排除)。

當我切換到HTTPS SSL連接時,一切都出錯了。下面的代碼:

public static void main(String[] args) throws Exception { 
    Server server = new Server(); 

    // Setups 
    SslContextFactory sslContextFactory = new SslContextFactory(); 
    sslContextFactory.setKeyStorePath("C:/keystore.jks"); 
    sslContextFactory.setKeyStorePassword("password"); 
    sslContextFactory.setKeyManagerPassword("password"); 

    ContextHandler test1Context = new ContextHandler(); 
    test1Context.setContextPath("/test1"); 
    test1Context.setHandler(new HelloHandler("Hello1")); 

    ContextHandler test2Context = new ContextHandler(); 
    test2Context.setContextPath("/test2"); 
    test2Context.setHandler(new HelloHandler("Hello2")); 

    ContextHandlerCollection contextHandlers = new ContextHandlerCollection(); 
    contextHandlers.setHandlers(new Handler[] { test1Context, test2Context }); 

    ServerConnector serverConnector = new ServerConnector(server, 
      new SslConnectionFactory(sslContextFactory, "http/1.1"), 
      new HttpConnectionFactory()); 

    serverConnector.setPort(12000); 
    server.setConnectors(new Connector[] { serverConnector }); 
    server.setHandler(contextHandlers); 

    server.start(); 
    server.join(); 
} 

症狀:

嘗試使用https://localhost:12000/test1(沒有尾隨斜線)會導致瀏覽器報告,服務器必須重置連接。另外,我最初做的不是,URI被重定向到http://localhost:12000/test1/(不是https!)。有趣的是(以某種虐待感的方式),在某些情況下,我會改變代碼中無關緊要的內容,然後不經意地用https://localhost:12000/test1/進行測試,它會起作用。對於這種誤報帶來的挫折,言語並不公平。

除了瀏覽器重定向和報告的連接復位錯誤,我會得到下面的異常在我的服務器日誌:

2013-11-23 13:57:48 DEBUG org.eclipse.jetty.server.HttpConnection:282 - 
org.eclipse.jetty.io.EofException 
    at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:653) 
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:240) 
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.run(AbstractConnection.java:358) 
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:601) 
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:532) 
    at java.lang.Thread.run(Thread.java:722) 
Caused by: javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection? 
    at sun.security.ssl.EngineInputRecord.bytesInCompletePacket(EngineInputRecord.java:171) 
    at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:845) 
    at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758) 
    at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624) 
    at org.eclipse.jetty.io.ssl.SslConnection$DecryptedEndPoint.fill(SslConnection.java:518) 
    ... 5 more 

不幸的是,我花了我所有的時間試圖此異常直接排除故障,當時關鍵線索在瀏覽器重定向的URL中。事實證明,ContextHandler代碼有一個默認行爲,當不存在結尾的正斜槓時,會導致它重定向到一個具有尾部斜槓的URI。不幸的是,這個重定向到一個HTTP URI--所以HTTPS方案被丟棄,導致服務器抱怨純文本。

解決方法:

一旦這種重定向行爲,我就明白了,一個快速谷歌搜索,實際的問題,導致我ContextHandler.setAllowNullPathInfo(true)方法 - 這將關閉此重定向行爲。無法識別的SSL - :

test1Context.setAllowNullPathInfo(true); 
test2Context.setAllowNullPathInfo(true); 

要點這個帖子:4小時試圖解決「javax.net.ssl.SSLException

我花了3在上面我的代碼,這是與2號線實現消息,明文連接?「例外情況以及網絡上的任何地方,我都發現與上述解決方案/解決方法相關的異常。如果我從其中一位開發人員那裏獲得經驗的挫折,那麼任務就完成了。

揮之不去的問題(另一個原因張貼本): 好了,所以我得到這個代碼的工作,但不得不承認:我極其不安的事實,我非常簡單的證明了概念測試,做事情我認爲這是相當普遍的,遇到了這種似乎前所未有的局面。這告訴我,我可能做了超出「最佳實踐」領域的事情;或者更糟糕的是,我在設計這個方面做了一些完全錯誤的事情。所以,問題:

1)AM我做錯了嗎?

2)爲什麼ContextHandler的默認行爲會重定向缺少尾部空格的URI?通過使用setAllowNullPathInfo(true)來覆蓋該默認行爲會帶來什麼風險?

附錄(幫助類和進口代碼) 進口: import java.io.IOException;

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.eclipse.jetty.server.Connector; 
import org.eclipse.jetty.server.Handler; 
import org.eclipse.jetty.server.HttpConfiguration; 
import org.eclipse.jetty.server.HttpConnectionFactory; 
import org.eclipse.jetty.server.Request; 
import org.eclipse.jetty.server.Server; 
import org.eclipse.jetty.server.ServerConnector; 
import org.eclipse.jetty.server.SslConnectionFactory; 
import org.eclipse.jetty.server.handler.AbstractHandler; 
import org.eclipse.jetty.server.handler.ContextHandler; 
import org.eclipse.jetty.server.handler.ContextHandlerCollection; 
import org.eclipse.jetty.util.ssl.SslContextFactory; 

助手類:

static class HelloHandler extends AbstractHandler { 
    final String _greeting; 

    public HelloHandler(String greeting) { 
     _greeting = greeting; 
    } 

    public void handle(String target, Request baseRequest, 
      HttpServletRequest request, HttpServletResponse response) 
      throws IOException, ServletException { 
     response.setContentType("text/html;charset=utf-8"); 
     response.setStatus(HttpServletResponse.SC_OK); 
     baseRequest.setHandled(true); 
     response.getWriter().println("<h1>" + _greeting + "</h1>"); 
    } 
} 

回答

4

你缺少HttpConfiguration設置。

這裏......

package jetty.examples; 

import org.eclipse.jetty.server.Connector; 
import org.eclipse.jetty.server.Handler; 
import org.eclipse.jetty.server.HttpConfiguration; 
import org.eclipse.jetty.server.HttpConnectionFactory; 
import org.eclipse.jetty.server.SecureRequestCustomizer; 
import org.eclipse.jetty.server.Server; 
import org.eclipse.jetty.server.ServerConnector; 
import org.eclipse.jetty.server.SslConnectionFactory; 
import org.eclipse.jetty.server.handler.ContextHandler; 
import org.eclipse.jetty.server.handler.ContextHandlerCollection; 
import org.eclipse.jetty.util.ssl.SslContextFactory; 

public class SecureContexts 
{ 
    public static void main(String[] args) throws Exception 
    { 
     Server server = new Server(); 
     int port = 12000; 

     // Setup SSL 
     SslContextFactory sslContextFactory = new SslContextFactory(); 
     sslContextFactory.setKeyStorePath(System.getProperty("jetty.keystore.path","C:/keystore.jks")); 
     sslContextFactory.setKeyStorePassword(System.getProperty("jetty.keystore.password","password")); 
     sslContextFactory.setKeyManagerPassword(System.getProperty("jetty.keymanager.password","password")); 

     // Setup HTTP Configuration 
     HttpConfiguration httpConf = new HttpConfiguration(); 
     httpConf.setSecurePort(port); 
     httpConf.setSecureScheme("https"); 
     httpConf.addCustomizer(new SecureRequestCustomizer()); 

     ContextHandler test1Context = new ContextHandler(); 
     test1Context.setContextPath("/test1"); 
     test1Context.setHandler(new HelloHandler("Hello1")); 

     ContextHandler test2Context = new ContextHandler(); 
     test2Context.setContextPath("/test2"); 
     test2Context.setHandler(new HelloHandler("Hello2")); 

     ContextHandlerCollection contextHandlers = new ContextHandlerCollection(); 
     contextHandlers.setHandlers(new Handler[] 
     { test1Context, test2Context }); 

     ServerConnector serverConnector = new ServerConnector(server, 
      new SslConnectionFactory(sslContextFactory,"http/1.1"), 
      new HttpConnectionFactory(httpConf)); // <-- use it! 
     serverConnector.setPort(port); 

     server.setConnectors(new Connector[] 
     { serverConnector }); 
     server.setHandler(contextHandlers); 

     server.start(); 
     server.join(); 
    } 
} 
+0

釘它!補充它,我甚至嘗試過,但省略了httpConf.addCustomizer(新的SecureRequestCustomizer())步驟;所以添加沒有影響,看起來多餘。 – KevinKirkpatrick

相關問題