2013-11-24 2 views
3

내장 된 Jetty를 사용하여 샌드 박스 RESTful API를 구축하고 있습니다. 내 증명 설계 : (1) SSL 포트에서 연결을 허용하고 (2) ContextHandlerCollection을 사용하여 URI 접두사를 기반으로 적절한 Handler를 호출하는 간단한 임베디드 부두 (Jetty) 서버.Embedded Jetty : 보안 HTTPS 서버에서 ContextHandler가 http URI로 리디렉션합니다.

간단한 SSL 연결을 사용하여 본인의 원래 테스트가 완벽하게 작동하는 것처럼 보였습니다 (부록의 import 및 helper 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/test1http://localhost:12000/test1/로 리디렉션하기되었으며, 슬래시 뒤에 생략 된 경우 브라우저 리디렉션이 발생하고 있음을 내 관심을 탈출했다. (FWIW, 나중에 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 (NO 후행 슬래시)를 사용하려고. 또한 내가 수행 한 작업은 이 아니며 초기에 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 스키마가 삭제되어 서버가 일반 텍스트에 대해 불평을하게됩니다.

해결 방법 :이 리디렉션 행동이 나에게 분명 해졌다되면 해당 실제 문제의 빠른 Google 검색이 ContextHandler.setAllowNullPathInfo (참) 메소드를 알려준

-이 리디렉션 동작을 해제합니다. 인식 할 수없는 SSL : - :이 게시물의

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

주요 포인트 :은 "(자), javax.net.ssl.SSLException 문제를 해결하려고 4시간 내가 3을 보냈다

위의 내 코드에서,이 2 명 선으로 ​​이루어진다 메시지, 일반 텍스트 연결? " 예외 및 웹 어디에도 위의 솔루션/해결 방법과 관련된 예외가 발견되었습니다. 내가 경험 한 좌절에서 다른 개발자 한 명이라도 저장하면 임무가 완수됩니다.

질문을 던지기위한 다른 이유 : 좋아요,이 코드는 작동하지만 고백해야합니다. 믿을 수 없을만큼 간단한 개념 증명 테스트가 내가 흔히 생각하는 것은 완전히 전례가없는 상황을 겪었습니다.그 말은, 나는 아마도 "모범 사례"의 영역을 넘어서 뭔가를하고있을 것이다. 또는, 더 나쁜 것은, 내가 이것을 어떻게 디자인하고 있는지 완전히 잘못되었습니다. 따라서 질문 :

1) 내가 잘못 했나요?

2) 후행 공백이없는 URI를 리디렉션하는 ContextHandler의 기본 동작은 왜입니까? 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

관련 문제