diff --git a/README.md b/README.md
index 2d529b0275a..969435deb35 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ Documentation
Project documentation is available on the Jetty Eclipse website.
-- [http://www.eclipse.org/jetty/documentation](http://www.eclipse.org/jetty/documentation)
+- [https://www.eclipse.org/jetty/documentation](https://www.eclipse.org/jetty/documentation)
Building
========
@@ -45,4 +45,4 @@ It is possible to bypass tests by building with `mvn clean install -DskipTests`.
Professional Services
---------------------
-Expert advice and production support are available through [Webtide.com](http://webtide.com).
+Expert advice and production support are available through [Webtide.com](https://webtide.com).
diff --git a/VERSION.txt b/VERSION.txt
index b5c40ca2bc7..471fef74d52 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -460,6 +460,11 @@ jetty-9.4.15.v20190215 - 15 February 2019
+ 3350 Do not expect to be able to connect to https URLs with the HttpClient
created from a parameterless constructor
+jetty-9.3.28.v20191105 - 05 November 2019
+ + 3989 Inform custom ManagedSelector of dead selector via optional
+ onFailedSelect()
+ + 4217 SslConnection.DecryptedEnpoint.flush eternal busy loop
+
jetty-9.3.27.v20190418 - 18 April 2019
+ 3549 Directory Listing on Windows reveals Resource Base path
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
@@ -472,6 +477,9 @@ jetty-9.3.26.v20190403 - 03 April 2019
ForwardedRequestCustomizer
+ 3319 Allow reverse sort for directory listed files
+jetty-9.2.29.v20191105 - 05 November 2019
+ + 4217 SslConnection.DecryptedEnpoint.flush eternal busy loop
+
jetty-9.2.28.v20190418 - 18 April 2019
+ 3549 Directory Listing on Windows reveals Resource Base path
+ 3555 DefaultHandler Reveals Base Resource Path of each Context
diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml
index d4691812295..0d16ccb6974 100644
--- a/jetty-jaspi/pom.xml
+++ b/jetty-jaspi/pom.xml
@@ -23,6 +23,24 @@
org.eclipse.jetty.jaspi.*
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+
+ manifest
+
+
+
+ osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"
+ osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory
+
+
+
+
+
diff --git a/jetty-jaspi/src/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factory b/jetty-jaspi/src/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factory
new file mode 100644
index 00000000000..2e24fa8ca2a
--- /dev/null
+++ b/jetty-jaspi/src/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factory
@@ -0,0 +1 @@
+org.eclipse.jetty.security.jaspi.JaspiAuthenticatorFactory
\ No newline at end of file
diff --git a/jetty-openid/pom.xml b/jetty-openid/pom.xml
index 48dcc6adaf1..928a51b0ca8 100644
--- a/jetty-openid/pom.xml
+++ b/jetty-openid/pom.xml
@@ -24,6 +24,24 @@
org.eclipse.jetty.security.openid.*
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+
+ manifest
+
+
+
+ osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"
+ osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory
+
+
+
+
+
diff --git a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticatorFactory.java b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticatorFactory.java
index 86eea6cdbde..20af7a7ed0e 100644
--- a/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticatorFactory.java
+++ b/jetty-openid/src/main/java/org/eclipse/jetty/security/openid/OpenIdAuthenticatorFactory.java
@@ -21,13 +21,12 @@ package org.eclipse.jetty.security.openid;
import javax.servlet.ServletContext;
import org.eclipse.jetty.security.Authenticator;
-import org.eclipse.jetty.security.DefaultAuthenticatorFactory;
import org.eclipse.jetty.security.IdentityService;
import org.eclipse.jetty.security.LoginService;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.security.Constraint;
-public class OpenIdAuthenticatorFactory extends DefaultAuthenticatorFactory
+public class OpenIdAuthenticatorFactory implements Authenticator.Factory
{
@Override
public Authenticator getAuthenticator(Server server, ServletContext context, Authenticator.AuthConfiguration configuration, IdentityService identityService, LoginService loginService)
@@ -35,6 +34,6 @@ public class OpenIdAuthenticatorFactory extends DefaultAuthenticatorFactory
String auth = configuration.getAuthMethod();
if (Constraint.__OPENID_AUTH.equalsIgnoreCase(auth))
return new OpenIdAuthenticator();
- return super.getAuthenticator(server, context, configuration, identityService, loginService);
+ return null;
}
}
\ No newline at end of file
diff --git a/jetty-openid/src/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factory b/jetty-openid/src/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factory
new file mode 100644
index 00000000000..cc53212a57b
--- /dev/null
+++ b/jetty-openid/src/main/resources/META-INF/services/org.eclipse.jetty.security.Authenticator$Factory
@@ -0,0 +1 @@
+org.eclipse.jetty.security.openid.OpenIdAuthenticatorFactory
\ No newline at end of file
diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml
index 90569d68b0f..ed204799803 100644
--- a/jetty-security/pom.xml
+++ b/jetty-security/pom.xml
@@ -24,6 +24,23 @@
org.eclipse.jetty.security.*
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+
+ manifest
+
+
+
+ osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional
+
+
+
+
+
diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
index 62df3199fd7..d5b74b488f2 100644
--- a/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
+++ b/jetty-security/src/main/java/org/eclipse/jetty/security/SecurityHandler.java
@@ -20,10 +20,13 @@ package org.eclipse.jetty.security;
import java.io.IOException;
import java.security.Principal;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.ServiceLoader;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -38,6 +41,7 @@ import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.handler.HandlerWrapper;
+import org.eclipse.jetty.util.component.DumpableCollection;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -58,20 +62,31 @@ import org.eclipse.jetty.util.log.Logger;
public abstract class SecurityHandler extends HandlerWrapper implements Authenticator.AuthConfiguration
{
private static final Logger LOG = Log.getLogger(SecurityHandler.class);
+ private static final List __knownAuthenticatorFactories = new ArrayList<>();
private boolean _checkWelcomeFiles = false;
private Authenticator _authenticator;
- private Authenticator.Factory _authenticatorFactory = new DefaultAuthenticatorFactory();
+ private Authenticator.Factory _authenticatorFactory;
private String _realmName;
private String _authMethod;
- private final Map _initParameters = new HashMap();
+ private final Map _initParameters = new HashMap<>();
private LoginService _loginService;
private IdentityService _identityService;
private boolean _renewSession = true;
+ static
+ {
+ for (Authenticator.Factory factory : ServiceLoader.load(Authenticator.Factory.class))
+ {
+ __knownAuthenticatorFactories.add(factory);
+ }
+
+ __knownAuthenticatorFactories.add(new DefaultAuthenticatorFactory());
+ }
+
protected SecurityHandler()
{
- addBean(_authenticatorFactory);
+ addBean(new DumpableCollection("knownAuthenticatorFactories", __knownAuthenticatorFactories));
}
/**
@@ -163,6 +178,14 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
_authenticatorFactory = authenticatorFactory;
}
+ /**
+ * @return the list of discovered authenticatorFactories
+ */
+ public List getKnownAuthenticatorFactories()
+ {
+ return __knownAuthenticatorFactories;
+ }
+
/**
* @return the realmName
*/
@@ -241,12 +264,12 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
* @param key the init key
* @param value the init value
* @return previous value
- * @throws IllegalStateException if the SecurityHandler is running
+ * @throws IllegalStateException if the SecurityHandler is started
*/
public String setInitParameter(String key, String value)
{
- if (isRunning())
- throw new IllegalStateException("running");
+ if (isStarted())
+ throw new IllegalStateException("started");
return _initParameters.put(key, value);
}
@@ -336,9 +359,40 @@ public abstract class SecurityHandler extends HandlerWrapper implements Authenti
throw new IllegalStateException("LoginService has different IdentityService to " + this);
}
- Authenticator.Factory authenticatorFactory = getAuthenticatorFactory();
- if (_authenticator == null && authenticatorFactory != null && _identityService != null)
- setAuthenticator(authenticatorFactory.getAuthenticator(getServer(), ContextHandler.getCurrentContext(), this, _identityService, _loginService));
+ if (_authenticator == null && _identityService != null)
+ {
+ // If someone has set an authenticator factory only use that, otherwise try the list of discovered factories.
+ if (_authenticatorFactory != null)
+ {
+ Authenticator authenticator = _authenticatorFactory.getAuthenticator(getServer(), ContextHandler.getCurrentContext(),
+ this, _identityService, _loginService);
+
+ if (authenticator != null)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Created authenticator {} with {}", authenticator, _authenticatorFactory);
+
+ setAuthenticator(authenticator);
+ }
+ }
+ else
+ {
+ for (Authenticator.Factory factory : getKnownAuthenticatorFactories())
+ {
+ Authenticator authenticator = factory.getAuthenticator(getServer(), ContextHandler.getCurrentContext(),
+ this, _identityService, _loginService);
+
+ if (authenticator != null)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("Created authenticator {} with {}", authenticator, factory);
+
+ setAuthenticator(authenticator);
+ break;
+ }
+ }
+ }
+ }
if (_authenticator != null)
_authenticator.setConfiguration(this);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
index 541db3eb23b..88a23363b7d 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ErrorHandler.java
@@ -27,11 +27,9 @@ import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
@@ -106,15 +104,23 @@ public class ErrorHandler extends AbstractHandler
{
if (errorDispatcher != null)
{
- errorDispatcher.error(request, response);
- }
- else
- {
- String message = (String)request.getAttribute(Dispatcher.ERROR_MESSAGE);
- if (message == null)
- message = baseRequest.getResponse().getReason();
- generateAcceptableResponse(baseRequest, request, response, response.getStatus(), message);
+ try
+ {
+ errorDispatcher.error(request, response);
+ return;
+ }
+ catch (ServletException e)
+ {
+ LOG.debug(e);
+ if (response.isCommitted())
+ return;
+ }
}
+
+ String message = (String)request.getAttribute(Dispatcher.ERROR_MESSAGE);
+ if (message == null)
+ message = baseRequest.getResponse().getReason();
+ generateAcceptableResponse(baseRequest, request, response, response.getStatus(), message);
}
finally
{