Jetty

Questions answered

How to reconfigure JUL when running Jetty with jetty-maven-plugin?

The problem is that JUL is initialized from JRE logging.properties when Maven is started and is not re-initialized when Jetty is run as it is launched within same JVM.

Solutions:

  • Run Jetty in separate JVM (see jetty:run-forked)
  • Reinitialize JUL when Jetty is started. For this add to your pom.xml:

    pom.xml

    <build>
        <plugins>
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                ...
                <configuration>
                    <systemProperties>
                        <systemProperty>
                            <name>java.util.logging.config.file</name>
                            <value>jetty/logging.properties</value>
                        </systemProperty>
                    </systemProperties>
                </configuration>
            </plugin>
        </plugins>
    </build>

    and to your jetty.xml:

    jetty/jetty.xml

    <Configure id="Server" class="org.eclipse.jetty.server.Server">
        ...
        <Get class="java.util.logging.LogManager" name="logManager">
            <Call name="reset" />
            <Call name="readConfiguration" />
        </Get>
    </Configure>

    or you can even set system property directly in your jetty.xml:

    jetty/jetty.xml

    <Configure id="Server" class="org.eclipse.jetty.server.Server">
        ...
        <Call class="java.lang.System" name="setProperty">
            <Arg>java.util.logging.config.file</Arg>
            <Arg>jetty/logging.properties</Arg>
        </Call>
    </Configure>

How to configure Jetty to authenticate a user via SPNEGO/NEGOTIATE?

For Jetty build-in implementation follow Jetty Spnego Howto:
  • One needs to set following system properties either by passing them to JVM:
    -Djava.security.krb5.conf=/etc/krb5.conf -Djava.security.auth.login.config=/path/to/login.config -Djavax.security.auth.useSubjectCredsOnly=false
    or via maven:

    pom.xml

    <plugin>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>jetty-maven-plugin</artifactId>
        <configuration>
            <jettyConfig>/path/to/jetty.xml</jettyConfig>
            <systemProperties>
                <systemProperty>
                    <name>java.security.auth.login.config</name>
                    <value>/path/to/login.config</value>
                </systemProperty>
                <systemProperty>
                    <name>java.security.krb5.conf</name>
                    <value>/etc/krb5.conf</value>
                </systemProperty>
                <systemProperty>
                    <name>javax.security.auth.useSubjectCredsOnly</name>
                    <value>false</value>
                </systemProperty>
                <!-- systemProperty>
                    <name>sun.security.krb5.debug</name>
                    <value>true</value>
                </systemProperty>
                <systemProperty>
                    <name>org.eclipse.jetty.LEVEL</name>
                    <value>DEBUG</value>
                </systemProperty -->
            </systemProperties>
        </configuration>
    </plugin>
  • Add to jetty.xml:

    jetty.xml

    <Configure id="Server" class="org.eclipse.jetty.server.Server">
        <Call name="addBean">
            <Arg>
                <New class="org.eclipse.jetty.security.SpnegoLoginService">
                    <!-- Should match web.xml//login-config/realm-name -->
                    <Set name="name">MYAPP</Set>
                    <Set name="config">/path/to/spnego.properties</Set>
                </New>
            </Arg>
        </Call>
    </Configure>
  • spnego.properties should refer the principal in keytab file:

    spnego.properties

    targetName = HTTP/service-id.company.org
  • login.config file:

    login.config

    // Login entry for a Kerberos client (initiator of a secure Kerberos connection):
    com.sun.security.jgss.krb5.initiate {
        com.sun.security.auth.module.Krb5LoginModule required
        useTicketCache=true;
    };
     
    // Login entry for a secure server (acceptor of a Kerberos ticket):
    com.sun.security.jgss.krb5.accept {
        com.sun.security.auth.module.Krb5LoginModule required
        principal="HTTP/service-id.company.org@REALM.COMPANY.ORG"
        useKeyTab=true
        keyTab="/path/to/service.keytab"
        storeKey=true
        debug=true
        isInitiator=false;
    };
  • Finally in web.xml:

    web.xml

    <login-config>
        <auth-method>SPNEGO</auth-method>
        <realm-name>MYAPP</realm-name>
    </login-config>

Perhaps you will also have to increase the limit of header size, as NEGOTIATE token can be large (few KB):

jetty.xml

<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Call name="addConnector">
        <Arg>
            <New class="org.eclipse.jetty.server.nio.SelectChannelConnector">
                <!-- Set host and port the same way as default configuration does -->
                <Set name="host">
                    <SystemProperty name="jetty.host" />
                </Set>
                <Set name="port">
                    <SystemProperty name="jetty.port" default="8080" />
                </Set>
                <!-- Negotiate header can be large -->
                <Set name="requestHeaderSize">50000</Set>
            </New>
        </Arg>
    </Call>
</Configure>

To allow the role “*” to match any role, not only those mentioned in the deployment descriptor?

See bug#377537:

jetty-context.xml

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
    <Call name="setSecurityHandler">
        <Arg>
            <New class="org.eclipse.jetty.security.ConstraintSecurityHandler">
                <Set name="Strict">false</Set>
            </New>
        </Arg>
    </Call>
</Configure>

Now this configuration in web.xml works as expected:

web.xml

<security-constraint>
    <web-resource-collection>
        <web-resource-name>all</web-resource-name>
        <url-pattern>/secure/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
</security-constraint>

Deploying the application that installs custom protocol handler

Web application provides custom protocol handler which needs to be listed in java.protocol.handler.pkgs system property (for example if it would be CLI application). Deploying such web application to the server is challenging.

Depending on whether application server overrides URLStreamHandlerFactory or not (and it can be set only once, see java.net.URL#setURLStreamHandlerFactory(URLStreamHandlerFactory) unless one uses a hacker's approach to access private variable like in Custom URL handlers in Tomcat web app) the solutions vary:
  • JBoss 7+ overrides URLStreamHandlerFactory. The custom factory should be then registered as service in standard way (META-INF/services/java.net.URLStreamHandlerFactory, see Protocol handlers and JBoss and URL Protocol Handler doesn't work) which is then imported by org.jboss.modules.ModularURLStreamHandlerFactory.
  • Tomcat 6+ overrides URLStreamHandlerFactory (see java.protocol.handler.pkgs does not work with Tomcat 7). The solution is to use static method DirContextURLStreamHandlerFactory.addUserFactory(URLStreamHandlerFactory) to register custom handler factories (see bug#26701). The handle factory should be injected as early as possible (see URL to load resources from the classpath in Java).
  • Jetty 8 does not override URLStreamHandlerFactory, so the standard mechanism can be used to register handler factory. However note that if URLStreamHandlerFactory implementation is added to plugin classpath, then it will be loaded by Maven class loader org.codehaus.plexus.classworlds.realm.ClassRealm (plugin>org.mortbay.jetty:jetty-maven-plugin:…) and thus will have no access to Web application resources. Complete solution is based on calling the above mentioned static method to register handler factory and using context classloader to access web application resources:
    • Create the following jetty-context.xml:

      jetty/jetty-context.xml

      <?xml version="1.0"?>
      <!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">
       
      <Configure class="org.eclipse.jetty.webapp.WebAppContext">
          <Set class="java.net.URL" name="URLStreamHandlerFactory">
              <New class="org.mycompany.myproject.MyHandlerFactory" />
          </Set>
      </Configure>

      and include it via plugin configuration:

      pom.xml

      <configuration>
          ...
          <contextXml>jetty/jetty-context.xml</contextXml>
      </configuration>
    • Load the necessary resource in MyHandlerFactory via Thread.currentThread().getContextClassLoader().getResourceAsStream(webAppResourceName) (that class loader should the instance of org.eclipse.jetty.webapp.WebAppClassLoader).

How to increase the limit of submitted form size?

Sometimes POST forms require a lot of data to be submitted as multipart/form-data. To increase the limit, set the following property:

jetty-context.xml

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
    <Set name="maxFormContentSize">1500000</Set>
</Configure>

How to configure JNDI datasource?

jetty.xml

<Configure id="Server" class="org.eclipse.jetty.server.Server">
    <Call name="addBean">
        <Arg>
            <New class="org.eclipse.jetty.plus.jndi.Resource">
                <Arg></Arg>
                <Arg>java:jdbc/myDS</Arg>
                <Arg>
                    <New class="com.mchange.v2.c3p0.ComboPooledDataSource">
                        <Set name="driverClass">net.sourceforge.jtds.jdbc.Driver</Set>
                        <Set name="jdbcUrl">jdbc:jtds:sqlserver://dbhost:1433/mydb</Set>
                        <Set name="user">myuser</Set>
                        <Set name="password">mypassword</Set>
                        <Set name="maxPoolSize">20</Set>
                        <Set name="maxStatements">50</Set>
                        <Set name="testConnectionOnCheckin">true</Set>
                        <Set name="idleConnectionTestPeriod">7200</Set>
                        <Set name="preferredTestQuery">select 1</Set>
                    </New>
                </Arg>
            </New>
        </Arg>
    </Call>
</Configure>

For other pool configurations check JDBC datasource Spring configuration examples.

software/jetty.txt · Last modified: 2013/01/14 15:52 by dmitry
 
 
Recent changes RSS feed Driven by DokuWiki