如何从嵌入式码头以root身份在端口80上启动jetty?

时间:2016-02-08 14:00:32

标签: jetty embedded-jetty setuid

我正在尝试以root身份启动https端口443,然后使用嵌入式jetty降级到非root用户。我经历了 https://www.eclipse.org/jetty/documentation/current/setting-port80-access.html#configuring-jetty-setuid-feature 但是没有从java程序中获得任何解决方案。

这是嵌入式码头代码:

package com.jetty.startup;

import java.io.File;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.webapp.WebAppContext;

import org.eclipse.jetty.annotations.ServletContainerInitializersStarter;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.plus.annotation.ContainerInitializer;

import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;

import org.apache.log4j.Logger;

import org.eclipse.jetty.setuid.*;

/**
 * Handles Webapp server's serviice
 * 
 * 
 */
class MyServer {
   private static Logger logger = Logger.getLogger(MyServer.class);

   private static Server server;
   private String jettyHome;

   /**
    * Creates an instance of {@link MyServer}
    * 
    * @param jettyHome
    *            jetty home path
    */
    public MyServer(String jettyHome) {
       this.jettyHome = jettyHome;
    }

    /**
     * Initializes Webapp server:
     * 
     */
    public Server init() throws Exception {
      server = new Server();

      int httpsPort = 443;

      String keyStoreFile = "/home/jetty/webserver/etc/keystore";
      String keyStorePassword = "secret";
      String keyManagerPassword = "secret";
      String trustStorePassword = "secret";

     SslContextFactory sslContextFactory = new SslContextFactory();
     sslContextFactory.setKeyStorePath(keyStoreFile);
     sslContextFactory.setKeyStoreType("JKS");
     sslContextFactory.setKeyStorePassword(keyStorePassword);
     sslContextFactory.setKeyManagerPassword(keyManagerPassword);

     SetUIDListener set = new SetUIDListener();
     set.setStartServerAsPrivileged(true);
     set.setUsername("jetty");
     set.setGroupname("jetty");
     set.setUmask(002);

     server.addLifeCycleListener(set);

     HttpConfiguration httpConfiguration = new HttpConfiguration();
     httpConfiguration.setSecurePort(httpsPort);
     httpConfiguration.setSecureScheme("https");
     httpConfiguration.addCustomizer(new SecureRequestCustomizer());

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

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

     WebAppContext myContext = new WebAppContext();
     myContext.setContextPath("/myapp");
     myContext.setWar(jettyHome + "/webapps/myapp/");
     myContext.setDefaultsDescriptor(jettyHome + "/etc/webdefault.xml");
     File overrideFile = new File(jettyHome
            + "/webapps/myapp/WEB-INF/generated-web.xml");
     if (overrideFile.exists()) {
        myContext.setOverrideDescriptor(jettyHome
                + "/webapps/myapp/WEB-INF/generated-web.xml");
     }

     server.setHandler(myContext);

     JettyJasperInitializer sci = new JettyJasperInitializer();
     ServletContainerInitializersStarter sciStarter = 
        new ServletContainerInitializersStarter(myContext);
     ContainerInitializer initializer = new ContainerInitializer(sci, null);
     List<ContainerInitializer> initializers = new ArrayList<>();
     initializers.add(initializer);

     myContext.setAttribute("org.eclipse.jetty.containerInitializers", initializers);
     myContext.addBean(sciStarter, true);

     ContextHandlerCollection contexts = new ContextHandlerCollection();
     contexts.setHandlers(new Handler[] { myContext });

     server.setHandler(contexts);
     return server;
}

 public static void main(String args[]) {
        String jetty_home = "/home/jetty/webServer";
        MyServer myServer = new MyServer(jetty_home);
        try {
            server = myServer.init();
            server.start();
        } catch (Exception excp) {
        }
 }
}

至于lib​​setuid-linux.so我已经使用mvn clean install项目中的jetty-setuid创建了它的原生版本。

如果httpsPort = 2400那么这是日志文件的详细信息:

记录

2016-02-11 15:36:16.413:INFO::main: Logging initialized @2424ms  
2016-02-11 15:36:16.593:INFO:oejs.SetUIDListener:main: Setting umask=02
2016-02-11 15:36:16.603:INFO:oejs.SetUIDListener:main: Opened         ServerConnector@b96fde{SSL,[ssl, http/1.1]}{0.0.0.0:2400}  
2016-02-11 15:36:16.603:INFO:oejs.SetUIDListener:main: Setting GID=504  
2016-02-11 15:36:16.676:INFO:oejs.SetUIDListener:main: Setting UID=504  
2016-02-11 15:36:16.680:INFO:oejs.Server:main: jetty-9.3.7.v20160115 

而当httpsPort = 443这就是日志文件的外观:

记录

2016-02-11 15:37:35.049:INFO::main: Logging initialized @2199ms  
2016-02-11 15:37:35.228:INFO:oejs.SetUIDListener:main: Setting umask=02

在此日志之后没有任何事情发生,并且webapp也无法正常工作。

2 个答案:

答案 0 :(得分:1)

这最终是一个操作系统权限问题,您需要一种解决方法。

  

这意味着您提出的任何解决方案也将是特定于操作系统的

一个例子是使用jetty-setuid-java工件和适当的jetty-setuid-native库来完成此任务。

  

在开始这项工作之前,请确保您完全了解setuid在所需操作系统上的功能

至于启用jetty setuid特定部分,您可以使用XmlConfiguration将适当的生命周期监听器注入Server,或者您可以完全使用代码。

请向Jetty Distribution&#39; etc/jetty-setuid.xml寻求帮助。

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
           "http://www.eclipse.org/jetty/configure_9_3.dtd">

<!-- ================================================================ -->
<!-- Configure the Jetty SetUIDListener                                -->
<!-- ================================================================ -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">

  <Call name="addLifeCycleListener">
    <Arg>
      <New class="org.eclipse.jetty.setuid.SetUIDListener">
        <Set name="startServerAsPrivileged">false</Set>
        <Set name="umaskOctal">002</Set>
        <Set name="username">jetty</Set>
        <Set name="groupname">jetty</Set>
        <!-- uncomment to change the limits on number of open file descriptors for root -->
        <!--
        <Call name="setRLimitNoFiles">
          <Arg>
            <New class="org.eclipse.jetty.setuid.RLimit">
              <Set name="soft">20000</Set>
              <Set name="hard">40000</Set>
            </New>
          </Arg>
        </Call>
        -->
      </New>
    </Arg>
  </Call>
</Configure>

答案 1 :(得分:1)

最后,我能够通过为32位创建一个libsetuid-linux.so来实现我在上述问题中提出的要求,这是一个随jetty-9.3.7提供的那个用于64位。

我是如何创建32位libsetuid-linux.so的?

此链接有助于http://www.eclipse.org/jetty/documentation/current/setting-port80-access.html 第5点是准确的

但不幸的是,jetty-setuid项目的链接已不再适用。

此外,sudo必须使用sudo -E完成。