1
votes

I am trying to start the https port 443 as root then downgrade to non-root user using embedded jetty. I gone through the https://www.eclipse.org/jetty/documentation/current/setting-port80-access.html#configuring-jetty-setuid-feature but didn't get any solution how to do it from java program.

This is the embedded jetty code :

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) {
        }
 }
}

As for the libsetuid-linux.so I've already created the native version of it using mvn clean install from the jetty-setuid project.

If httpsPort = 2400 then this is the log file details:

Log

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 

whereas when httpsPort = 443 this is how the log file looks:

Log

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

Nothing happens after this on the log and also the webapp isn't working.

2

2 Answers

1
votes

This is ultimately a OS permissions issue, and you'll need a way to work around that.

This means any solution you come up with will also be OS specific

One example is to use the jetty-setuid-java artifact, and appropriate jetty-setuid-native library to accomplish this.

Make sure you fully understand how setuid functions on your desired OS before starting this effort

As for enabling the jetty setuid specific pieces, you can either use the XmlConfiguration to inject the appropriate lifecycle listener into your Server, or you can do it entirely in code.

See the Jetty Distribution's etc/jetty-setuid.xml for help.

<?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
votes

Well finally I was able to achieve what I'd asked in the above question by creating a libsetuid-linux.so for 32-bit, the one that's supplied with jetty-9.3.7 is for 64-bit.

How I created the 32-bit libsetuid-linux.so?

This link helped http://www.eclipse.org/jetty/documentation/current/setting-port80-access.html Point number 5 to be precise

But unfortunately the link for jetty-setuid project isn't working anymore.

Also, the sudo had to be done with sudo -E.