Merge branch 'jetty-10.0.x' into jetty-11.0.x
This commit is contained in:
commit
36bef3ec6e
|
@ -138,5 +138,10 @@
|
|||
<artifactId>testcontainers</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.testcontainers</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -46,11 +46,13 @@ import org.slf4j.LoggerFactory;
|
|||
import org.testcontainers.containers.GenericContainer;
|
||||
import org.testcontainers.containers.output.Slf4jLogConsumer;
|
||||
import org.testcontainers.containers.wait.strategy.LogMessageWaitStrategy;
|
||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@Testcontainers(disabledWithoutDocker = true)
|
||||
public class RemoteQueryManagerTest
|
||||
{
|
||||
public static final String DEFAULT_CACHE_NAME = "remote-session-test";
|
||||
|
|
|
@ -76,6 +76,8 @@
|
|||
<Set name="requestCookieCompliance"><Call class="org.eclipse.jetty.http.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.requestCookieCompliance" default="RFC6265"/></Arg></Call></Set>
|
||||
<Set name="responseCookieCompliance"><Call class="org.eclipse.jetty.http.CookieCompliance" name="valueOf"><Arg><Property name="jetty.httpConfig.responseCookieCompliance" default="RFC6265"/></Arg></Call></Set>
|
||||
<Set name="relativeRedirectAllowed"><Property name="jetty.httpConfig.relativeRedirectAllowed" default="false"/></Set>
|
||||
<Set name="useInputDirectByteBuffers" property="jetty.httpConfig.useInputDirectByteBuffers"></Set>
|
||||
<Set name="useOutputDirectByteBuffers" property="jetty.httpConfig.useOutputDirectByteBuffers"></Set>
|
||||
</New>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
# DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
|
||||
|
||||
[description]
|
||||
Enables logback request log.
|
||||
|
||||
[tags]
|
||||
requestlog
|
||||
logging
|
||||
logback
|
||||
|
||||
[depend]
|
||||
server
|
||||
logback-impl
|
||||
resources
|
||||
|
||||
[provide]
|
||||
requestlog-impl
|
||||
|
||||
[xml]
|
||||
etc/jetty-logback-access.xml
|
||||
|
||||
[files]
|
||||
logs/
|
||||
basehome:modules/logback-access/jetty-logback-access.xml|etc/jetty-logback-access.xml
|
||||
basehome:modules/logback-access/logback-access.xml|resources/logback-access.xml
|
||||
maven://ch.qos.logback/logback-access/${logback.version}|lib/logback/logback-access-${logback.version}.jar
|
||||
|
||||
[lib]
|
||||
lib/logback/logback-access-${logback.version}.jar
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||
|
||||
<!-- =============================================================== -->
|
||||
<!-- Configure the Logback Request Log -->
|
||||
<!-- =============================================================== -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
<Set name="RequestLog">
|
||||
<New id="RequestLog" class="ch.qos.logback.access.jetty.RequestLogImpl">
|
||||
<Set name="name">logback-access</Set>
|
||||
<Set name="resource">/logback-access.xml</Set>
|
||||
<Call name="start"/>
|
||||
</New>
|
||||
</Set>
|
||||
</Configure>
|
|
@ -1,17 +0,0 @@
|
|||
<configuration>
|
||||
<!-- always a good activate OnConsoleStatusListener -->
|
||||
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
|
||||
|
||||
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>logs/access.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>logs/access.%d{yyyy-MM-dd}.log.zip</fileNamePattern>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>combined</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender-ref ref="FILE" />
|
||||
</configuration>
|
||||
|
|
@ -74,6 +74,10 @@ etc/jetty.xml
|
|||
## Relative Redirect Locations allowed
|
||||
# jetty.httpConfig.relativeRedirectAllowed=false
|
||||
|
||||
## Whether to use direct ByteBuffers for reading or writing
|
||||
# jetty.httpConfig.useInputDirectByteBuffers=true
|
||||
# jetty.httpConfig.useOutputDirectByteBuffers=true
|
||||
|
||||
### Server configuration
|
||||
## Whether ctrl+c on the console gracefully stops the Jetty server
|
||||
# jetty.server.stopAtShutdown=true
|
||||
|
@ -91,3 +95,4 @@ etc/jetty.xml
|
|||
# jetty.scheduler.name=
|
||||
# jetty.scheduler.deamon=false
|
||||
# jetty.scheduler.threads=-1
|
||||
|
||||
|
|
|
@ -1692,7 +1692,8 @@ public class Request implements HttpServletRequest
|
|||
_httpFields = request.getFields();
|
||||
final HttpURI uri = request.getURI();
|
||||
|
||||
if (uri.isAmbiguous())
|
||||
boolean ambiguous = uri.isAmbiguous();
|
||||
if (ambiguous)
|
||||
{
|
||||
UriCompliance compliance = _channel == null || _channel.getHttpConfiguration() == null ? null : _channel.getHttpConfiguration().getUriCompliance();
|
||||
if (uri.hasAmbiguousSegment() && (compliance == null || !compliance.allows(UriCompliance.Violation.AMBIGUOUS_PATH_SEGMENT)))
|
||||
|
@ -1741,7 +1742,15 @@ public class Request implements HttpServletRequest
|
|||
// TODO this is not really right for CONNECT
|
||||
path = _uri.isAbsolute() ? "/" : null;
|
||||
else if (encoded.startsWith("/"))
|
||||
{
|
||||
path = (encoded.length() == 1) ? "/" : _uri.getDecodedPath();
|
||||
// Strictly speaking if a URI is legal and encodes ambiguous segments, then they should be
|
||||
// reflected in the decoded string version. However, it can be ambiguous to provide a decoded path as
|
||||
// a string, so we normalize again. If an application wishes to see ambiguous URIs, then they can look
|
||||
// at the encoded form of the URI
|
||||
if (ambiguous)
|
||||
path = URIUtil.canonicalPath(path);
|
||||
}
|
||||
else if ("*".equals(encoded) || HttpMethod.CONNECT.is(getMethod()))
|
||||
path = encoded;
|
||||
else
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
@ -48,10 +49,12 @@ import org.slf4j.LoggerFactory;
|
|||
public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SecureRequestCustomizer.class);
|
||||
|
||||
public static final String JAKARTA_SERVLET_REQUEST_X_509_CERTIFICATE = "jakarta.servlet.request.X509Certificate";
|
||||
public static final String JAKARTA_SERVLET_REQUEST_CIPHER_SUITE = "jakarta.servlet.request.cipher_suite";
|
||||
public static final String JAKARTA_SERVLET_REQUEST_KEY_SIZE = "jakarta.servlet.request.key_size";
|
||||
public static final String JAKARTA_SERVLET_REQUEST_SSL_SESSION_ID = "jakarta.servlet.request.ssl_session_id";
|
||||
public static final String X509_CERT = "org.eclipse.jetty.server.x509_cert";
|
||||
|
||||
private String sslSessionAttribute = "org.eclipse.jetty.servlet.request.ssl_session";
|
||||
|
||||
|
@ -244,25 +247,25 @@ public class SecureRequestCustomizer implements HttpConfiguration.Customizer
|
|||
if (isSniRequired() || isSniHostCheck())
|
||||
{
|
||||
String sniHost = (String)sslSession.getValue(SslContextFactory.Server.SNI_HOST);
|
||||
X509 cert = new X509(null, (X509Certificate)sslSession.getLocalCertificates()[0]);
|
||||
X509 x509 = (X509)sslSession.getValue(X509_CERT);
|
||||
if (x509 == null)
|
||||
{
|
||||
Certificate[] certificates = sslSession.getLocalCertificates();
|
||||
if (certificates == null || certificates.length == 0 || !(certificates[0] instanceof X509Certificate))
|
||||
throw new BadMessageException(400, "Invalid SNI");
|
||||
x509 = new X509(null, (X509Certificate)certificates[0]);
|
||||
sslSession.putValue(X509_CERT, x509);
|
||||
}
|
||||
String serverName = request.getServerName();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Host={}, SNI={}, SNI Certificate={}", serverName, sniHost, cert);
|
||||
LOG.debug("Host={}, SNI={}, SNI Certificate={}", serverName, sniHost, x509);
|
||||
|
||||
if (isSniRequired())
|
||||
{
|
||||
if (sniHost == null)
|
||||
if (isSniRequired() && (sniHost == null || !x509.matches(sniHost)))
|
||||
throw new BadMessageException(400, "Invalid SNI");
|
||||
if (!cert.matches(sniHost))
|
||||
throw new BadMessageException(400, "Invalid SNI");
|
||||
}
|
||||
|
||||
if (isSniHostCheck())
|
||||
{
|
||||
if (!cert.matches(serverName))
|
||||
if (isSniHostCheck() && !x509.matches(serverName))
|
||||
throw new BadMessageException(400, "Invalid SNI");
|
||||
}
|
||||
}
|
||||
|
||||
request.setAttributes(new SslAttributes(request, sslSession));
|
||||
}
|
||||
|
|
|
@ -28,8 +28,11 @@ import jakarta.servlet.GenericServlet;
|
|||
import jakarta.servlet.ServletContext;
|
||||
import jakarta.servlet.ServletRequest;
|
||||
import jakarta.servlet.ServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpTester;
|
||||
import org.eclipse.jetty.http.UriCompliance;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
|
@ -284,6 +287,43 @@ public class WebAppContextTest
|
|||
assertFalse(context.isProtectedTarget("/something-else/web-inf"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProtectedTarget() throws Exception
|
||||
{
|
||||
Server server = newServer();
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
WebAppContext context = new WebAppContext();
|
||||
Path testWebapp = MavenTestingUtils.getProjectDirPath("src/test/webapp");
|
||||
context.setBaseResource(new PathResource(testWebapp));
|
||||
context.setContextPath("/");
|
||||
server.setHandler(handlers);
|
||||
handlers.addHandler(contexts);
|
||||
contexts.addHandler(context);
|
||||
|
||||
LocalConnector connector = new LocalConnector(server);
|
||||
server.addConnector(connector);
|
||||
connector.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().setUriCompliance(UriCompliance.RFC3986);
|
||||
|
||||
server.start();
|
||||
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.OK_200));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /%2e/%2e/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.OK_200));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /foo/%2e%2e/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.OK_200));
|
||||
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /WEB-INF HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /WEB-INF/ HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /WEB-INF/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /web-inf/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /%2e/WEB-INF/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /%2e/%2e/WEB-INF/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /foo/%2e%2e/WEB-INF/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /%2E/WEB-INF/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET //WEB-INF/test.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
assertThat(HttpTester.parseResponse(connector.getResponse("GET /WEB-INF%2ftest.xml HTTP/1.1\r\nHost: localhost:8080\r\nConnection: close\r\n\r\n")).getStatus(), is(HttpStatus.NOT_FOUND_404));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullPath() throws Exception
|
||||
{
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
test
|
|
@ -0,0 +1 @@
|
|||
test
|
Loading…
Reference in New Issue