Merge branch 'jetty-9.4.x' into jetty-10.0.x

This commit is contained in:
olivier lamy 2018-09-11 14:21:49 +10:00
commit a8e9a8a78b
19 changed files with 541 additions and 478 deletions

View File

@ -70,6 +70,7 @@ public class AnnotationParser
{ {
private static final Logger LOG = Log.getLogger(AnnotationParser.class); private static final Logger LOG = Log.getLogger(AnnotationParser.class);
protected static int ASM_OPCODE_VERSION = Opcodes.ASM6; //compatibility of api protected static int ASM_OPCODE_VERSION = Opcodes.ASM6; //compatibility of api
protected static String ASM_OPCODE_VERSION_STR = "ASM6";
/** /**
* Map of classnames scanned and the first location from which scan occurred * Map of classnames scanned and the first location from which scan occurred
@ -87,12 +88,12 @@ public class AnnotationParser
int asmVersion = ASM_OPCODE_VERSION; int asmVersion = ASM_OPCODE_VERSION;
Package asm = Opcodes.class.getPackage(); Package asm = Opcodes.class.getPackage();
if (asm == null) if (asm == null)
LOG.warn("Unknown asm runtime version, assuming version {}", asmVersion); LOG.warn("Unknown asm runtime version, assuming version {}", ASM_OPCODE_VERSION_STR);
else else
{ {
String s = asm.getImplementationVersion(); String s = asm.getImplementationVersion();
if (s==null) if (s==null)
LOG.warn("Unknown asm implementation version, assuming version {}", asmVersion); LOG.info("Unknown asm implementation version, assuming version {}", ASM_OPCODE_VERSION_STR);
else else
{ {
int dot = s.indexOf('.'); int dot = s.indexOf('.');
@ -119,13 +120,13 @@ public class AnnotationParser
} }
default: default:
{ {
LOG.warn("Unrecognized runtime asm version, assuming {}", asmVersion); LOG.warn("Unrecognized runtime asm version, assuming {}", ASM_OPCODE_VERSION_STR);
} }
} }
} }
catch (NumberFormatException e) catch (NumberFormatException e)
{ {
LOG.warn("Unable to parse runtime asm version, assuming version {}", asmVersion); LOG.warn("Unable to parse runtime asm version, assuming version {}", ASM_OPCODE_VERSION_STR);
} }
} }
} }

View File

@ -22,7 +22,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@ -48,16 +47,17 @@ import org.eclipse.jetty.client.util.FutureResponseListener;
import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.JavaVersion;
import org.eclipse.jetty.util.ssl.SslContextFactory; import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledOnJre; import org.junit.jupiter.api.condition.EnabledOnJre;
import org.junit.jupiter.api.condition.JRE; import org.junit.jupiter.api.condition.JRE;
/* This whole test is very specific to how TLS < 1.3 works.
* Starting in Java 11, TLS/1.3 is now enabled by default.
*/
@EnabledOnJre({JRE.JAVA_8, JRE.JAVA_9, JRE.JAVA_10})
public class SslBytesClientTest extends SslBytesTest public class SslBytesClientTest extends SslBytesTest
{ {
private ExecutorService threadPool; private ExecutorService threadPool;
@ -66,8 +66,6 @@ public class SslBytesClientTest extends SslBytesTest
private SSLServerSocket acceptor; private SSLServerSocket acceptor;
private SimpleProxy proxy; private SimpleProxy proxy;
// This whole test is very specific to how TLS < 1.3 works.
@DisabledOnJre( JRE.JAVA_11 )
@BeforeEach @BeforeEach
public void init() throws Exception public void init() throws Exception
{ {

View File

@ -81,10 +81,10 @@ Make sure you have it installed.
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
.... ....
# apt-get install openjdk-7-jdk # apt-get install openjdk-8-jdk
.... ....
Or download Java 7 from: http://www.oracle.com/technetwork/java/javase/downloads/index.html Or download Java 8 from: http://www.oracle.com/technetwork/java/javase/downloads/index.html
[source, screen, subs="{sub-order}"] [source, screen, subs="{sub-order}"]
.... ....

View File

@ -17,17 +17,17 @@
// //
[[spnego-support]] [[spnego-support]]
=== Spnego Support === SPNEGO Support
Simple and Protected GSSAPI Negotiation Mechanism (Spnego) is a way for users to be seamlessly authenticated when running on a Windows or Active Directory based network. Simple and Protected GSSAPI Negotiation Mechanism (SPNEGO) is a way for users to be seamlessly authenticated when running on a Windows or Active Directory based network.
Jetty supports this type of authentication and authorization through the JDK (which has been enabled since the later versions of Java 6 and 7). Jetty supports this type of authentication and authorization through the JDK (which has been enabled since the later versions of Java 6 and 7).
Also important to note is that this is an _incredibly_ fragile setup where everything needs to be configured just right for things to work, otherwise it can fail in fun and exciting, not to mention obscure, ways. Also important to note is that this is an _incredibly_ fragile setup where everything needs to be configured just right for things to work, otherwise it can fail in fun and exciting, not to mention obscure, ways.
There is a substantial amount of configuration and testing required to enable this feature as well as knowledge and access to central systems on a Windows network such as the Active Domain Controller and the ability to create and maintain service users. There is a substantial amount of configuration and testing required to enable this feature as well as knowledge and access to central systems on a Windows network such as the Active Domain Controller and the ability to create and maintain service users.
==== Configuring Jetty and Spnego ==== Configuring Jetty and SPNEGO
To run with Spengo enabled the following command line options are required: To run with SPNEGO enabled the following command line options are required:
[source,screen, subs="{sub-order}"] [source,screen, subs="{sub-order}"]
---- ----
@ -36,7 +36,7 @@ To run with Spengo enabled the following command line options are required:
-Djavax.security.auth.useSubjectCredsOnly=false -Djavax.security.auth.useSubjectCredsOnly=false
---- ----
For debugging the Spengo authentication the following options are very helpful: For debugging the SPNEGO authentication the following options are very helpful:
[source,screen, subs="{sub-order}"] [source,screen, subs="{sub-order}"]
---- ----
@ -44,7 +44,7 @@ For debugging the Spengo authentication the following options are very helpful:
-Dsun.security.spnego.debug=all -Dsun.security.spnego.debug=all
---- ----
Spengo Authentication must be enabled in the webapp in the following way. SPNEGO Authentication must be enabled in the webapp in the following way.
The name of the role will be different for your network. The name of the role will be different for your network.
[source, xml, subs="{sub-order}"] [source, xml, subs="{sub-order}"]
@ -65,7 +65,7 @@ The name of the role will be different for your network.
<realm-name>Test Realm</realm-name> <realm-name>Test Realm</realm-name>
<!-- optionally to add custom error page --> <!-- optionally to add custom error page -->
<spnego-login-config> <spnego-login-config>
<spengo-error-page>/loginError.html?param=foo</spnego-error-page> <spnego-error-page>/loginError.html?param=foo</spnego-error-page>
</spnego-login-config> </spnego-login-config>
</login-config> </login-config>
@ -119,7 +119,7 @@ krb5.ini::
spnego.conf:: spnego.conf::
configures the glue between gssapi and kerberos configures the glue between gssapi and kerberos
It is important to note that the keytab file referenced in the `krb5.ini` and the `spengo.conf` files needs to contain the keytab for the `targetName` for the http server. It is important to note that the keytab file referenced in the `krb5.ini` and the `spnego.conf` files needs to contain the keytab for the `targetName` for the http server.
To do this use a process similar to this: To do this use a process similar to this:
On the Windows Active Domain Controller run: On the Windows Active Domain Controller run:
@ -159,12 +159,12 @@ The follows steps have been required to inform Internet Explorer that it should
5. Tools -> Options -> Advanced -> Security (in the checkbox list) 5. Tools -> Options -> Advanced -> Security (in the checkbox list)
6. Locate and select `Enable Integrated Windows Authentication` 6. Locate and select `Enable Integrated Windows Authentication`
7. Tools -> Options -> Advanced -> Security -> Ok 7. Tools -> Options -> Advanced -> Security -> Ok
8. Close IE then reopen and browse to your Spengo protected resource 8. Close IE then reopen and browse to your SPNEGO protected resource
You *must* use hostname and not the IP. You *must* use hostname and not the IP.
If you use the IP it will default to NTLM authentication. If you use the IP it will default to NTLM authentication.
The following conditions must be true for Spnego authentication to work: The following conditions must be true for SPNEGO authentication to work:
* You must be within the Intranet Zone of the network * You must be within the Intranet Zone of the network
* Access the server using a Hostname rather than IP * Access the server using a Hostname rather than IP

View File

@ -49,7 +49,7 @@ Files associated with the development of Jetty -- code styles, formatting, iplog
==== Build ==== Build
Jetty requires the use of Java 7 and the latest releases are always recommended to build. Jetty requires the use of Java 8 and the latest releases are always recommended to build.
Jetty uses http://maven.apache.org/[Apache Maven 3] for managing its build and primary project metadata. Jetty uses http://maven.apache.org/[Apache Maven 3] for managing its build and primary project metadata.

View File

@ -31,7 +31,6 @@ import org.eclipse.jetty.security.DefaultIdentityService;
import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.UserIdentity; import org.eclipse.jetty.server.UserIdentity;
import org.junit.Test; import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import javax.security.auth.login.AppConfigurationEntry; import javax.security.auth.login.AppConfigurationEntry;

View File

@ -54,7 +54,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -37,7 +37,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -66,7 +66,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -67,7 +67,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -73,7 +73,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -67,7 +67,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -67,7 +67,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -67,7 +67,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version> <version>3.8.0</version>
<configuration> <configuration>
<target>1.8</target> <target>1.8</target>
<source>1.8</source> <source>1.8</source>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>org.olamy</groupId> <groupId>org.olamy</groupId>
@ -44,7 +45,7 @@
<plugins> <plugins>
<plugin> <plugin>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version> <version>3.8.0</version>
<configuration> <configuration>
<source>1.8</source> <source>1.8</source>
<target>1.8</target> <target>1.8</target>

View File

@ -95,9 +95,8 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
/* ------------------------------------------------------------ */
@Override @Override
public Class<?> loadClass(String name) throws ClassNotFoundException protected Class<?> findClass(String name) throws ClassNotFoundException
{ {
try try
{ {
@ -107,7 +106,8 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
{ {
try try
{ {
return super.loadClass(name);
return super.findClass(name);
} }
catch (ClassNotFoundException cne2) catch (ClassNotFoundException cne2)
{ {
@ -147,6 +147,48 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
return url != null ? url : super.getResource(name); return url != null ? url : super.getResource(name);
} }
@Override
public URL findResource(String name)
{
URL url = _osgiBundleClassLoader.getResource(name);
return url != null ? url : super.findResource(name);
}
/**
* Try to load the class from the bundle classloader.
* We do NOT load it as a resource as the WebAppClassLoader does because the
* url that is returned is an osgi-special url that does not play
* properly with WebAppClassLoader's method of extracting the class
* from the resource. This implementation directly asks the osgi
* bundle classloader to load the given class name.
*
* @see org.eclipse.jetty.webapp.WebAppClassLoader#loadAsResource(java.lang.String, boolean)
*/
@Override
protected Class<?> loadAsResource(String name, boolean checkSystemResource) throws ClassNotFoundException
{
try
{
return _osgiBundleClassLoader.loadClass(name);
}
catch (ClassNotFoundException cne)
{
try
{
return super.loadAsResource(name, checkSystemResource);
}
catch (ClassNotFoundException cne2)
{
throw cne;
}
}
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2) private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
{ {

View File

@ -1,7 +1,7 @@
This setup will enable you to authenticate a user via spnego into your This setup will enable you to authenticate a user via SPNEGO into your
webapp. webapp.
To run with spengo enabled the following command line options are required: To run with SPNEGO enabled the following command line options are required:
-Djava.security.krb5.conf=/path/to/jetty/etc/krb5.ini -Djava.security.krb5.conf=/path/to/jetty/etc/krb5.ini
-Djava.security.auth.login.config=/path/to/jetty/etc/spnego.conf -Djava.security.auth.login.config=/path/to/jetty/etc/spnego.conf
@ -9,13 +9,13 @@ To run with spengo enabled the following command line options are required:
The easiest place to put these lines are in the start.ini file. The easiest place to put these lines are in the start.ini file.
For debugging the spengo authentication the following options are helpful: For debugging the SPNEGO authentication the following options are helpful:
-Dorg.eclipse.jetty.LEVEL=debug -Dorg.eclipse.jetty.LEVEL=debug
-Dsun.security.spnego.debug=true -Dsun.security.spnego.debug=true
Spengo Authentication is enabled in the webapp with the following setup. SPNEGO Authentication is enabled in the webapp with the following setup.
<security-constraint> <security-constraint>
<web-resource-collection> <web-resource-collection>
@ -32,7 +32,7 @@ Spengo Authentication is enabled in the webapp with the following setup.
<realm-name>Test Realm</realm-name> <realm-name>Test Realm</realm-name>
(optionally to add custom error page) (optionally to add custom error page)
<spnego-login-config> <spnego-login-config>
<spengo-error-page>/loginError.html?param=foo</spnego-error-page> <spnego-error-page>/loginError.html?param=foo</spnego-error-page>
</spnego-login-config> </spnego-login-config>
</login-config> </login-config>

View File

@ -45,7 +45,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
} }
/** /**
* Allow for a custom authMethod value to be set for instances where SPENGO may not be appropriate * Allow for a custom authMethod value to be set for instances where SPNEGO may not be appropriate
* @param authMethod the auth method * @param authMethod the auth method
*/ */
public SpnegoAuthenticator( String authMethod ) public SpnegoAuthenticator( String authMethod )
@ -96,7 +96,7 @@ public class SpnegoAuthenticator extends LoginAuthenticator
return Authentication.UNAUTHENTICATED; return Authentication.UNAUTHENTICATED;
} }
LOG.debug("SpengoAuthenticator: sending challenge"); LOG.debug("Sending challenge");
res.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), HttpHeader.NEGOTIATE.asString()); res.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), HttpHeader.NEGOTIATE.asString());
res.sendError(HttpServletResponse.SC_UNAUTHORIZED); res.sendError(HttpServletResponse.SC_UNAUTHORIZED);
return Authentication.SEND_CONTINUE; return Authentication.SEND_CONTINUE;

View File

@ -544,27 +544,17 @@ public class WebAppClassLoader extends URLClassLoader
else else
{ {
// Not parent loader priority, so... // Not parent loader priority, so...
webapp_class = loadAsResource(name, true);
// Try the webapp classloader first if (webapp_class != null)
// Look in the webapp classloader as a resource, to avoid
// loading a system class.
String path = name.replace('.', '/').concat(".class");
URL webapp_url = findResource(path);
if (webapp_url!=null && !_context.isSystemResource(name,webapp_url))
{ {
webapp_class = this.foundClass(name,webapp_url);
resolveClass(webapp_class);
if (LOG.isDebugEnabled())
LOG.debug("WAP webapp loaded {}",webapp_class);
return webapp_class; return webapp_class;
} }
// Try the parent loader // Try the parent loader
try try
{ {
parent_class = _parent.loadClass(name); parent_class = _parent.loadClass(name);
// If the webapp is allowed to see this class // If the webapp is allowed to see this class
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parent_class)) if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parent_class))
{ {
@ -580,12 +570,9 @@ public class WebAppClassLoader extends URLClassLoader
// We couldn't find a parent class, so OK to return a webapp one if it exists // We couldn't find a parent class, so OK to return a webapp one if it exists
// and we just couldn't see it before // and we just couldn't see it before
if (webapp_url!=null) webapp_class = loadAsResource(name, false);
if (webapp_class != null)
{ {
webapp_class = this.foundClass(name,webapp_url);
resolveClass(webapp_class);
if (LOG.isDebugEnabled())
LOG.debug("WAP !server webapp loaded {}",webapp_class);
return webapp_class; return webapp_class;
} }
@ -629,12 +616,47 @@ public class WebAppClassLoader extends URLClassLoader
return _transformers.remove(transformer); return _transformers.remove(transformer);
} }
/**
* Look for the classname as a resource to avoid loading a class that is
* potentially a system resource.
*
* @param name the name of the class to load
* @param checkSystemResource if true and the class isn't a system class we return it
* @return the loaded class
* @throws ClassNotFoundException
*/
protected Class<?> loadAsResource (final String name, boolean checkSystemResource) throws ClassNotFoundException
{
// Try the webapp classloader first
// Look in the webapp classloader as a resource, to avoid
// loading a system class.
Class<?> webapp_class = null;
String path = name.replace('.', '/').concat(".class");
URL webapp_url = findResource(path);
if (webapp_url!=null && (!checkSystemResource || !_context.isSystemResource(name,webapp_url)))
{
webapp_class = this.foundClass(name,webapp_url);
resolveClass(webapp_class);
if (LOG.isDebugEnabled())
LOG.debug("WAP webapp loaded {}",webapp_class);
}
return webapp_class;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@Override @Override
protected Class<?> findClass(final String name) throws ClassNotFoundException protected Class<?> findClass(final String name) throws ClassNotFoundException
{ {
if (_transformers.isEmpty()) if (_transformers.isEmpty())
{
return super.findClass(name); return super.findClass(name);
}
String path = name.replace('.', '/').concat(".class"); String path = name.replace('.', '/').concat(".class");
URL url = findResource(path); URL url = findResource(path);