2017-06-23 16 views
2

私はこのJetty組み込みサーバーを自分のlocalhost:8008に持っており、それにアクセスするlocalhost:4200に別のAngularアプリケーションを持っています。次のコードでCORSを使用して、CrossOriginFilterをこのsvrContextに追加することができました(これは私のwebservicesの場所です)。Jetty Embedded:CORS +基本認証(ConstraintSecurityHandler)を使用

しかし、私はにこの安全なブール値を設定した場合、私の角度アプリケーションは以下のようにメッセージを与える:プリフライトリクエストに

OPTIONS http://localhost:8008/server/admin/session 401 (Unauthorized) scheduleTask @ zone.js:2263 webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:410 onScheduleTask @ zone.js:300 webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.scheduleTask @ zone.js:404 webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleTask @ zone.js:235 webpackJsonp.../../../../zone.js/dist/zone.js.Zone.scheduleMacroTask @ zone.js:258 (anonymous) @ zone.js:2287 proto.(anonymous function) @ zone.js:1426 (anonymous) @ http.es5.js:1275 webpackJsonp.../../../../rxjs/Observable.js.Observable._trySubscribe @ Observable.js:57 webpackJsonp.../../../../rxjs/Observable.js.Observable.subscribe @ Observable.js:45 webpackJsonp.../../../../rxjs/operator/map.js.MapOperator.call @ map.js:54 webpackJsonp.../../../../rxjs/Observable.js.Observable.subscribe @ Observable.js:42 webpackJsonp.../../../../../src/app/login/login.component.ts.LoginComponent.loginAdmin @ login.component.ts:42 (anonymous) @ LoginComponent.html:3 handleEvent @ core.es5.js:12076 callWithDebugContext @ core.es5.js:13535 debugHandleEvent @ core.es5.js:13123 dispatchEvent @ core.es5.js:8688 (anonymous) @ core.es5.js:10850 schedulerFn @ core.es5.js:3647 webpackJsonp.../../../../rxjs/Subscriber.js.SafeSubscriber.__tryOrUnsub @ Subscriber.js:238 webpackJsonp.../../../../rxjs/Subscriber.js.SafeSubscriber.next @ Subscriber.js:185 webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber._next @ Subscriber.js:125 webpackJsonp.../../../../rxjs/Subscriber.js.Subscriber.next @ Subscriber.js:89 webpackJsonp.../../../../rxjs/Subject.js.Subject.next @ Subject.js:55 webpackJsonp.../../../core/@angular/core.es5.js.EventEmitter.emit @ core.es5.js:3621 webpackJsonp.../../../forms/@angular/forms.es5.js.FormGroupDirective.onSubmit @ forms.es5.js:4801 (anonymous) @ LoginComponent.html:3 handleEvent @ core.es5.js:12076 callWithDebugContext @ core.es5.js:13535 debugHandleEvent @ core.es5.js:13123 dispatchEvent @ core.es5.js:8688 (anonymous) @ core.es5.js:9299 (anonymous) @ platform-browser.es5.js:2668 webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:424 onInvokeTask @ core.es5.js:3924 webpackJsonp.../../../../zone.js/dist/zone.js.ZoneDelegate.invokeTask @ zone.js:423 webpackJsonp.../../../../zone.js/dist/zone.js.Zone.runTask @ zone.js:191 ZoneTask.invoke @ zone.js:486 login:1 XMLHttpRequest cannot load http://localhost:8008/server/admin/session. 

応答は、アクセス制御チェックに合格しない:いいえ 「Access-Control-Allow-Origin」ヘッダーは、要求された リソースに存在します。したがって、「http://localhost:4200」の原点は許可されません。 応答にはHTTPステータスコード401が付きました。

何が欠けていますか?私は別々に使用することができました - 同じ原点アプリケーションを持つSecurtiyHandlerと(基本認証をオフにして)クロスオリジン要求。

public class JettyLauncher { 

    private static Server server; 
    private static Boolean prod = true; 
    private static String protocol = "https"; 
    private static String host = "localhost"; 
    private static int port = 8080; 
    private static String staticContent = ""; 
    private static String services = ""; 
    private static Boolean secure = true; 
    public static Resystoken tokenClass; 
    private static String realm = ""; 
    private static Boolean logToFile = false; 
    public static String url; 
    public static String usuario; 
    public static String senha; 

    public static void main(String[] args) throws Exception { 
     launch(); 
    } 

    public static void launch() throws IOException, Exception{ 

     String buildPath = new File("").getAbsolutePath(); 
     System.out.println("* Build path: " + buildPath); 

     prod = Boolean.valueOf(PropertySource.props.getProperty("resysclagem.launch.prod")); 
     String sufixoProd = ""; 

     if(prod){ 
      System.out.println("* Production mode ON (Prod mode)"); 
      sufixoProd = ".prod"; 
     } else { 
      System.out.println("* Not prod application (Dev mode)"); 
     } 

     services = PropertySource.props.getProperty("resysclagem.launch.services"); 
     staticContent = PropertySource.props.getProperty("resysclagem.webapps"); 
     secure = Boolean.valueOf(PropertySource.props.getProperty("resysclagem.launch.security.basicauth")); 
     realm = PropertySource.props.getProperty("resysclagem.realm.props"); 
     logToFile = Boolean.valueOf(PropertySource.props.getProperty("resysclagem.launch.logtofile")); 

     tokenClass = new Resystoken(
            PropertySource.props.getProperty("resysclagem.launch.token.key"), 
            Boolean.valueOf(PropertySource.props.getProperty("resysclagem.launch.security.requiretoken")) 
            ); 

     url = PropertySource.props.getProperty("resysclagem.bd"+ sufixoProd +".url"); 
     usuario = PropertySource.props.getProperty("resysclagem.bd"+ sufixoProd +".usuario"); 
     senha = PropertySource.props.getProperty("resysclagem.bd"+ sufixoProd +".senha"); // pensar em em maneira de encriptar 

     protocol = PropertySource.props.getProperty("resysclagem.launch"+ sufixoProd +".protocol"); 
     host = PropertySource.props.getProperty("resysclagem.launch"+ sufixoProd +".host"); 


     if(!host.equalsIgnoreCase("localhost")) { 
      host = Inet4Address.getLocalHost().getHostAddress(); 
     } 
     try { 
      port = Integer.valueOf(PropertySource.props.getProperty("resysclagem.launch"+ sufixoProd +".port")); 
     } catch(NumberFormatException nfe){ 
      String strPort = PropertySource.props.getProperty("resysclagem.launch"+ sufixoProd +".port"); 
      if(strPort.equalsIgnoreCase("heroku")){ 
       port = Integer.valueOf(System.getenv("PORT")); 
      } 
     } 


     server = new Server(port); 
     HandlerList a = new HandlerList(); 

     HttpConfiguration http_config = new HttpConfiguration(); 
     SslContextFactory sslContextFactory = new SslContextFactory(); 
     if(protocol.equalsIgnoreCase("https")){ 
      port = port + 1; 
      // https://github.com/eclipse/jetty.project/blob/jetty-9.3.x/examples/embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java 
      // HTTP Configuration 
      http_config.setSecureScheme("https"); 
      http_config.setSecurePort(port); // port 8443 
      http_config.setOutputBufferSize(32768); 
      http_config.setRequestHeaderSize(8192); 
      http_config.setResponseHeaderSize(8192); 
      http_config.setSendServerVersion(true); 
      http_config.setSendDateHeader(false); 

      // SSL Context Factory    
      String keystorePath = buildPath + File.separator + "resources" + File.separator + "reskey"; 
      File f = new File(keystorePath); 
      if(!f.exists()) { 
       throw new Exception("File doesn't exist at "+ keystorePath); 
      } 
      sslContextFactory.setKeyStorePath(keystorePath); 
      String obf = Password.obfuscate("resysadmin*$"); 
      sslContextFactory.setKeyStorePassword(obf); 
      sslContextFactory.setKeyManagerPassword(obf); 
      sslContextFactory.setTrustStorePath("resources" + File.separator + "/reskey"); 
      sslContextFactory.setTrustStorePassword("resysadmin*$"); 
      sslContextFactory.setExcludeCipherSuites("SSL_RSA_WITH_DES_CBC_SHA", 
        "SSL_DHE_RSA_WITH_DES_CBC_SHA", "SSL_DHE_DSS_WITH_DES_CBC_SHA", 
        "SSL_RSA_EXPORT_WITH_RC4_40_MD5", 
        "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", 
        "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", 
        "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); 

      // SSL HTTP Configuration 
      HttpConfiguration https_config = new HttpConfiguration(http_config); 
      https_config.addCustomizer(new SecureRequestCustomizer()); 

      // SSL Connector 
      ServerConnector sslConnector = new ServerConnector(server, 
       new SslConnectionFactory(sslContextFactory,HttpVersion.HTTP_1_1.asString()), 
       new HttpConnectionFactory(https_config)); 
      sslConnector.setPort(port);  // 8443 
      server.addConnector(sslConnector); 
     } 

     //static content 
     ResourceHandler resourceHandler= new ResourceHandler(); 
     resourceHandler.setResourceBase(staticContent);  // webapps 
     resourceHandler.setDirectoriesListed(true); 
     resourceHandler.setWelcomeFiles(new String[]{"index.html"}); 
     ContextHandler webContext = new ContextHandler("/"); /* the server uri path */ 
     webContext.setHandler(resourceHandler); 

     //webservices 
     ResourceConfig config = new ResourceConfig(); 
     config.register(MultiPartFeature.class); 
     config.packages("resysclagem.ws.services"); 
     config.register(JacksonFeature.class); 
     ServletHolder servlet = new ServletHolder(new ServletContainer(config)); 
     ServletContextHandler svrContext = new ServletContextHandler(server, services); //context path, services == /server 
     svrContext.addServlet(servlet, "/*"); //server/endpoints 
     svrContext.setInitParameter("jersey.config.server.provider.packages", "com.jersey.jaxb,com.fasterxml.jackson.jaxrs.json"); 
     svrContext.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", "true"); 
     /* 
     * TODO aqui: posteriormente, autorizar apenas o domínio do módulo WEB a fazer alterações aqui 
     */ 
     FilterHolder holder = new FilterHolder(new CrossOriginFilter()); 
     holder.setInitParameter("allowedMethods", "GET,POST,PUT,DELETE,HEAD,OPTIONS"); 
     //holder.setInitParameter("allowedOrigins", "http://localhost:4200"); 
     holder.setInitParameter("allowedHeaders", "Content-Type, Accept, X-Requested-With"); 
     svrContext.addFilter(holder, "/*", EnumSet.of(DispatcherType.REQUEST)); 

     a.addHandler(webContext); // index 
     a.addHandler(svrContext); 

     // basic authentication - ver resysclagem.realm.props 
     if (secure){ 

      HashLoginService loginService = new HashLoginService("ResysRealm", 
                     realm); 
      server.addBean(loginService); 

      ConstraintSecurityHandler security = new ConstraintSecurityHandler(); 


      // This constraint requires authentication and in addition that an 
      // authenticated user be a member of a given set of roles for 
      // authorization purposes. 
      Constraint constraint = new Constraint(); 
      constraint.setName("auth"); 
      constraint.setAuthenticate(true); 
      constraint.setRoles(new String[] { "user", "admin" }); 

      // Binds a url pattern with the previously created constraint. The roles 
      // for this constraing mapping are mined from the Constraint itself 
      // although methods exist to declare and bind roles separately as well. 
      ConstraintMapping mapping = new ConstraintMapping(); 
      mapping.setPathSpec("/*"); 
      mapping.setConstraint(constraint); 
      security.setConstraintMappings(Collections.singletonList(mapping)); 
      security.setAuthenticator(new BasicAuthenticator()); //base64 
      security.setLoginService(loginService); 
      /* 
      HashLoginService login = new HashLoginService(); 
      login.setName("Test Realm"); 
      login.setConfig("./resources/realm.properties"); 
      login.setHotReload(false); 
      server.addBean(login); 
      */ 

      security.setHandler(a); 
      server.setHandler(security);    

     } else { 
      System.out.println("* Warn: services and static content are not secured by authentication"); 
      server.setHandler(a); 
     } 

     try { 
      if(logToFile){   
       System.out.println("* From here, output will be printed on log file instead of console."); 
       PrintStream out = new PrintStream(new FileOutputStream("launchLog.txt")); 
       System.setOut(out); 
      } 
      server.start(); 
      System.out.println("* Up at "+ host +":"+ port); 
      server.join(); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
      throw e; 
     } 
    } 

    public static boolean isRunning() { 
     if (server == null){ 
      return false; 
     } 
     return server.isRunning(); 
    } 

} 

答えて

2

問題があることが吸う CORSプリフライトメッセージを含むセキュリティハンドラ・ブロックのすべての未認証の要求、:

は、ここに私のコードです。

要するに、Jettyはこの組み合わせ(HTTP Basic auth + CORS)をそのまま使用することはできません。そのためにカスタムコードを書く必要があります。

+0

(プリフライトメッセージに使用されるOPTIONSのような)一部のリクエストのみがSecurityHandlerをバイパスできるようにする方法はありますか?私はあなたの答えが受け入れられるほど明確になっていると思うので、カスタムコードを試してみます:) –

+1

@RodrigoNantes:OPTIONSリクエストのSecurityHandlerをバイパスする方法があると確信していますが、試してみる。 : - \私は掲示板に掲示し、回答があった場合はここに返信することをお勧めします。 ;)私はプログラム的に模倣しようとしたいくつかの高度なweb.xmlの例を見てきましたが、運はありません。 –

0

他の誰かがこのナンセンスに遭遇する場合。 jetty.xmlにHandlerを追加する必要があります。ハンドラの例を次に示します(https://github.com/datadidit/jaxrs-dynamic-security/blob/master/jetty-cors-handler/src/main/java/com/datadidit/cors/CORSHandler.java)。

+0

このハンドラは埋め込み桟橋に追加/設定しますか?私はこのアプローチを試してきましたが、ContainerResponseFilterを実装しているCORSFilterを試してみましたが、これまで成功していませんでした。 –

+0

このweb.xml(https://github.com/datadidit/jaxrs-dynamic-security /blob/master/jaxrs-basic-example/src/main/webapp/WEB-INF/web.xml)。埋め込み桟橋で同様のことができるはずです。 – mkwyche