Merge branch 'jetty-12.1.x' into experiment/jetty-12.1.x/delayedDispatch

This commit is contained in:
gregw 2024-09-19 07:55:00 +10:00
commit cac0d62f51
27 changed files with 514 additions and 810 deletions

View File

@ -15,6 +15,9 @@ package org.eclipse.jetty.docs.programming;
import java.util.concurrent.Executors;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.transport.HttpClientTransportOverHTTP;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.VirtualThreadPool;
@ -26,9 +29,26 @@ public class ArchitectureDocs
{
// tag::queuedVirtual[]
QueuedThreadPool threadPool = new QueuedThreadPool();
// Simple, unlimited, virtual thread Executor.
threadPool.setVirtualThreadsExecutor(Executors.newVirtualThreadPerTaskExecutor());
// Configurable, bounded, virtual thread executor (preferred).
VirtualThreadPool virtualExecutor = new VirtualThreadPool();
virtualExecutor.setMaxThreads(128);
threadPool.setVirtualThreadsExecutor(virtualExecutor);
// For server-side usage.
Server server = new Server(threadPool);
// Simple client-side usage.
HttpClient client = new HttpClient();
client.setExecutor(threadPool);
// Client-side usage with explicit HttpClientTransport.
ClientConnector clientConnector = new ClientConnector();
clientConnector.setExecutor(threadPool);
HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
// end::queuedVirtual[]
}
@ -38,8 +58,21 @@ public class ArchitectureDocs
VirtualThreadPool threadPool = new VirtualThreadPool();
// Limit the max number of current virtual threads.
threadPool.setMaxThreads(200);
// Track, with details, virtual threads usage.
threadPool.setTracking(true);
threadPool.setDetailedDump(true);
// For server-side usage.
Server server = new Server(threadPool);
// Simple client-side usage.
HttpClient client = new HttpClient();
client.setExecutor(threadPool);
// Client-side usage with explicit HttpClientTransport.
ClientConnector clientConnector = new ClientConnector();
clientConnector.setExecutor(threadPool);
HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP(clientConnector));
// end::virtualVirtual[]
}
}

View File

@ -714,7 +714,6 @@ See also the xref:server/index.adoc#threadpool[section about configuring the thr
The `threadpool-all-virtual` module allows you to configure the server-wide thread pool, similarly to what you can do with the <<threadpool,`threadpool`>> Jetty module, so that all threads are virtual threads, introduced as an official feature since Java 21.
CAUTION: Only use this module if you are using Java 21 or later.
If you are using Java 19 or Java 20, use the <<threadpool-virtual-preview,`threadpool-virtual-preview`>> Jetty module instead.
The module properties to configure the thread pool are:
@ -724,17 +723,7 @@ include::{jetty-home}/modules/threadpool-all-virtual.mod[tags=documentation]
The property `jetty.threadpool.maxThreads` limits, using a `Semaphore`, the number of current virtual threads in use.
Limiting the number of current virtual threads helps to limit resource usage in applications, especially in case of load spikes.
When an unlimited number of virtual threads is allowed, the server might be brought down due to resource (typically memory) exhaustion.
[CAUTION]
====
Even when using virtual threads, Jetty uses non-blocking I/O, and dedicates a thread to each `java.nio.channels.Selector` to perform the `Selector.select()` operation.
Currently (up to Java 22), calling `Selector.select()` from a virtual thread pins the carrier thread.
When using the `threadpool-all-virtual` Jetty module, if you have `N` selectors, then `N` carrier threads will be pinned by the virtual threads calling `Selector.select()`, possibly making your system less efficient, and at worst locking up the entire system if there are no carrier threads available to run virtual threads.
====
Please refer to the xref:programming-guide:arch/threads.adoc#thread-pool-virtual-threads[virtual threads section] of the Jetty Threading Architecture for more information about virtual threads and their pitfalls.
[[threadpool-virtual]]
== Module `threadpool-virtual`

View File

@ -269,6 +269,35 @@ Defaulting the number of reserved threads to zero ensures that the <<execution-s
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/ArchitectureDocs.java[tags=virtualVirtual]
----
Despite the name, `VirtualThreadPool` does not pool virtual threads, but allows you to impose a limit on the maximum number of current virtual threads, in order to limit resource consumption.
Despite the name, `VirtualThreadPool` does not pool virtual threads, but allows you to impose a limit on the maximum number of current virtual threads, using a `Semaphore`.
Furthermore, you can configure it to track virtual threads so that a xref:troubleshooting/component-dump.adoc[Jetty component dump] will show all virtual threads, including those that are unmounted.
Limiting the number of current virtual threads helps to limit resource usage in applications, especially in case of load spikes.
When an unlimited number of virtual threads is allowed, the server might be brought down due to resource (typically memory) exhaustion.
Furthermore, you can configure it to track virtual threads so that a xref:troubleshooting/component-dump.adoc[Jetty component dump] will show all virtual threads currently in use, including those that are unmounted.
[[thread-pool-virtual-threads-pinning]]
==== Virtual Threads Pinning
Even when using virtual threads, Jetty uses non-blocking I/O, and dedicates a thread to each `java.nio.channels.Selector` to perform the `Selector.select()` operation.
Currently (up to Java 22), calling `Selector.select()` from a virtual thread *pins* the carrier thread.
If you configure a server-side `Connector`, or Jetty's `HttpClient` with `N` selectors, then `N` carrier threads will be pinned by the virtual threads calling `Selector.select()`.
If you have less than `N` CPU cores in your system, then by default all carriers will be pinned in the `Selector.select()` call, leaving no carrier to execute virtual threads, and therefore completely locking up your system, which will become completely unresponsive.
If you have more than `N` CPU cores in your system, then by default your system may be less efficient, since the carrier threads may be pinned in the `Selector.select()` call, and therefore not available to run virtual threads.
[WARNING]
====
The number of CPU cores of your system determines, by default, the number of carrier threads.
The number of carrier threads may be explicitly configured by setting the system property `-Djdk.virtualThreadScheduler.parallelism=N`, where `N` is your desired number of carrier threads.
Selector threads used by Jetty pin carrier threads.
Choose the number of selectors wisely when using virtual threads: the number of selectors must always be less than the number of carrier threads, to leave some of the carrier threads free to run virtual threads.
As an extreme example, if your system only has `1` CPU core, then `1` selector is enough to pin the only carrier thread, and your system will eventually lock up.
In this case, you must explicitly configure the number of carrier threads by setting the system property `-Djdk.virtualThreadScheduler.parallelism=2` (or to a larger value).
====

View File

@ -24,7 +24,6 @@ import org.eclipse.jetty.client.Origin;
import org.eclipse.jetty.client.Request;
import org.eclipse.jetty.io.ClientConnector;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.ProcessorUtils;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.slf4j.Logger;
@ -42,7 +41,7 @@ public class HttpClientTransportOverHTTP extends AbstractConnectorHttpClientTran
public HttpClientTransportOverHTTP()
{
this(Math.max(1, ProcessorUtils.availableProcessors() / 2));
this(1);
}
public HttpClientTransportOverHTTP(int selectors)

View File

@ -422,6 +422,11 @@ public class HttpParser
return _state;
}
public boolean hasContent()
{
return _endOfContent != EndOfContent.NO_CONTENT;
}
public boolean inContentState()
{
return _state.ordinal() >= State.CONTENT.ordinal() && _state.ordinal() < State.END.ordinal();

View File

@ -385,6 +385,15 @@ public class HttpConnection extends AbstractMetaDataConnection implements Runnab
if (LOG.isDebugEnabled())
LOG.debug("HANDLE {} {}", request, this);
// If the buffer is empty and no body is expected, then release the buffer
if (isRequestBufferEmpty() && !_parser.hasContent())
{
// try parsing now to the end of the message
parseRequestBuffer();
if (_parser.isComplete())
releaseRequestBuffer();
}
// Handle the request by running the task.
_handling.set(true);
Runnable onRequest = _onRequest;
@ -411,7 +420,15 @@ public class HttpConnection extends AbstractMetaDataConnection implements Runnab
{
if (LOG.isDebugEnabled())
LOG.debug("upgraded {} -> {}", this, getEndPoint().getConnection());
releaseRequestBuffer();
if (_requestBuffer != null)
releaseRequestBuffer();
break;
}
// If we have already released the request buffer, then use fill interest before allocating another
if (_requestBuffer == null)
{
fillInterested();
break;
}
}

View File

@ -292,7 +292,7 @@ public abstract class IteratingCallback implements Callback
{
ExceptionUtil.callAndThen(cause, this::onAborted, this::onFailure);
}
private void doOnAbortedOnFailureOnCompleted(Throwable cause)
{
ExceptionUtil.callAndThen(cause, this::doOnAbortedOnFailure, _onCompleted);
@ -423,6 +423,7 @@ public abstract class IteratingCallback implements Callback
{
// we won the race against the callback, so the callback has to process and we can break processing
_state = State.PENDING;
_reprocess = false;
if (_aborted)
{
onAbortedOnFailureIfNotPendingDoCompleted = _failure;
@ -482,6 +483,7 @@ public abstract class IteratingCallback implements Callback
}
callOnSuccess = true;
_state = State.PROCESSING;
_reprocess = false;
break;
}
@ -818,6 +820,14 @@ public abstract class IteratingCallback implements Callback
return true;
}
boolean isPending()
{
try (AutoLock ignored = _lock.lock())
{
return _state == State.PENDING;
}
}
/**
* @return whether this callback is idle, and {@link #iterate()} needs to be called
*/

View File

@ -33,7 +33,9 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
@ -63,6 +65,45 @@ public class IteratingCallbackTest
scheduler.stop();
}
@ParameterizedTest
@ValueSource(booleans = {true, false})
public void testIterateWhileProcessingLoopCount(boolean succeededWinsRace)
{
var icb = new IteratingCallback()
{
int counter = 0;
@Override
protected Action process()
{
int counter = this.counter++;
if (counter == 0)
{
iterate();
if (succeededWinsRace)
{
succeeded();
}
else
{
new Thread(() ->
{
await().atMost(5, TimeUnit.SECONDS).until(this::isPending, is(true));
succeeded();
}).start();
}
return Action.SCHEDULED;
}
return Action.IDLE;
}
};
icb.iterate();
await().atMost(10, TimeUnit.SECONDS).until(icb::isIdle, is(true));
assertEquals(2, icb.counter);
}
@Test
public void testNonWaitingProcess() throws Exception
{

View File

@ -76,20 +76,20 @@ public class Response implements HttpServletResponse
* String used in the {@code Comment} attribute of {@link Cookie}
* to support the {@code HttpOnly} attribute.
**/
private static final String HTTP_ONLY_COMMENT = "__HTTP_ONLY__";
protected static final String HTTP_ONLY_COMMENT = "__HTTP_ONLY__";
/**
* String used in the {@code Comment} attribute of {@link Cookie}
* to support the {@code Partitioned} attribute.
**/
private static final String PARTITIONED_COMMENT = "__PARTITIONED__";
protected static final String PARTITIONED_COMMENT = "__PARTITIONED__";
/**
* The strings used in the {@code Comment} attribute of {@link Cookie}
* to support the {@code SameSite} attribute.
**/
private static final String SAME_SITE_COMMENT = "__SAME_SITE_";
private static final String SAME_SITE_NONE_COMMENT = SAME_SITE_COMMENT + "NONE__";
private static final String SAME_SITE_LAX_COMMENT = SAME_SITE_COMMENT + "LAX__";
private static final String SAME_SITE_STRICT_COMMENT = SAME_SITE_COMMENT + "STRICT__";
protected static final String SAME_SITE_COMMENT = "__SAME_SITE_";
protected static final String SAME_SITE_NONE_COMMENT = SAME_SITE_COMMENT + "NONE__";
protected static final String SAME_SITE_LAX_COMMENT = SAME_SITE_COMMENT + "LAX__";
protected static final String SAME_SITE_STRICT_COMMENT = SAME_SITE_COMMENT + "STRICT__";
public enum OutputType
{
@ -1465,7 +1465,7 @@ public class Response implements HttpServletResponse
return (HttpServletResponse)servletResponse;
}
private static class HttpFieldsSupplier implements Supplier<HttpFields>
protected static class HttpFieldsSupplier implements Supplier<HttpFields>
{
private final Supplier<Map<String, String>> _supplier;
@ -1494,7 +1494,7 @@ public class Response implements HttpServletResponse
}
}
private static class HttpCookieFacade implements HttpCookie
protected static class HttpCookieFacade implements HttpCookie
{
private final Cookie _cookie;
private final String _comment;
@ -1622,12 +1622,12 @@ public class Response implements HttpServletResponse
return comment != null && comment.contains(HTTP_ONLY_COMMENT);
}
private static boolean isPartitionedInComment(String comment)
protected static boolean isPartitionedInComment(String comment)
{
return comment != null && comment.contains(PARTITIONED_COMMENT);
}
private static SameSite getSameSiteFromComment(String comment)
protected static SameSite getSameSiteFromComment(String comment)
{
if (comment == null)
return null;
@ -1640,7 +1640,7 @@ public class Response implements HttpServletResponse
return null;
}
private static String getCommentWithoutAttributes(String comment)
protected static String getCommentWithoutAttributes(String comment)
{
if (comment == null)
return null;

View File

@ -53,6 +53,7 @@ import org.eclipse.jetty.session.SessionConfig;
import org.eclipse.jetty.session.SessionIdManager;
import org.eclipse.jetty.session.SessionManager;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -613,7 +614,8 @@ public class SessionHandler extends ScopedHandler implements SessionConfig.Mutab
* CookieConfig
*
* Implementation of the jakarta.servlet.SessionCookieConfig.
* SameSite configuration can be achieved by using setComment
* SameSite configuration can be achieved by using setComment.
* Partitioned configuration can be achieved by using setComment.
*
* @see HttpCookie
*/
@ -671,7 +673,19 @@ public class SessionHandler extends ScopedHandler implements SessionConfig.Mutab
public void setComment(String comment)
{
checkAvailable();
_sessionManager.setSessionComment(comment);
if (!StringUtil.isEmpty(comment))
{
HttpCookie.SameSite sameSite = Response.HttpCookieFacade.getSameSiteFromComment(comment);
if (sameSite != null)
_sessionManager.setSameSite(sameSite);
boolean partitioned = Response.HttpCookieFacade.isPartitionedInComment(comment);
if (partitioned)
_sessionManager.setPartitioned(partitioned);
_sessionManager.setSessionComment(Response.HttpCookieFacade.getCommentWithoutAttributes(comment));
}
}
@Override

View File

@ -168,7 +168,7 @@ public class SessionHandlerTest
}
@Test
public void testSessionCookie() throws Exception
public void testSessionCookieConfig() throws Exception
{
Server server = new Server();
MockSessionIdManager idMgr = new MockSessionIdManager(server);
@ -190,12 +190,51 @@ public class SessionHandlerTest
sessionCookieConfig.setSecure(false);
sessionCookieConfig.setPath("/foo");
sessionCookieConfig.setMaxAge(99);
//test setting SameSite and Partitioned the old way in the comment
sessionCookieConfig.setComment(Response.PARTITIONED_COMMENT + " " + Response.SAME_SITE_STRICT_COMMENT);
//for < ee10, SameSite cannot be set on the SessionCookieConfig, only on the SessionManager, or
//a default value on the context attribute org.eclipse.jetty.cookie.sameSiteDefault
HttpCookie cookie = mgr.getSessionManager().getSessionCookie(session, false);
assertEquals("SPECIAL", cookie.getName());
assertEquals("universe", cookie.getDomain());
assertEquals("/foo", cookie.getPath());
assertFalse(cookie.isHttpOnly());
assertFalse(cookie.isSecure());
assertTrue(cookie.isPartitioned());
assertEquals(99, cookie.getMaxAge());
assertEquals(HttpCookie.SameSite.STRICT, cookie.getSameSite());
String cookieStr = HttpCookieUtils.getRFC6265SetCookie(cookie);
assertThat(cookieStr, containsString("; Partitioned; SameSite=Strict"));
}
@Test
public void testSessionCookieViaSetters() throws Exception
{
Server server = new Server();
MockSessionIdManager idMgr = new MockSessionIdManager(server);
idMgr.setWorkerName("node1");
SessionHandler mgr = new SessionHandler();
MockSessionCache cache = new MockSessionCache(mgr.getSessionManager());
cache.setSessionDataStore(new NullSessionDataStore());
mgr.setSessionCache(cache);
mgr.setSessionIdManager(idMgr);
long now = System.currentTimeMillis();
ManagedSession session = new ManagedSession(mgr.getSessionManager(), new SessionData("123", "_foo", "0.0.0.0", now, now, now, 30));
session.setExtendedId("123.node1");
//test setting up session cookie via setters on SessionHandler
mgr.setSessionCookie("SPECIAL");
mgr.setSessionDomain("universe");
mgr.setHttpOnly(false);
mgr.setSecureCookies(false);
mgr.setSessionPath("/foo");
mgr.setMaxCookieAge(99);
mgr.setSameSite(HttpCookie.SameSite.STRICT);
mgr.setPartitioned(true);
HttpCookie cookie = mgr.getSessionManager().getSessionCookie(session, false);
assertEquals("SPECIAL", cookie.getName());
assertEquals("universe", cookie.getDomain());

View File

@ -13,9 +13,9 @@
<modules>
<module>jetty-testers</module>
<module>jetty-jmh</module>
<module>jetty-test-common</module>
<module>jetty-test-multipart</module>
<module>jetty-test-session-common</module>
<module>jetty-test-common</module>
<module>test-cross-context-dispatch</module>
<module>test-distribution</module>
<module>test-integration</module>

View File

@ -13,9 +13,6 @@
<modules>
<module>test-distribution-common</module>
<module>test-ee11-distribution</module>
<module>test-ee10-distribution</module>
<module>test-ee9-distribution</module>
</modules>
<properties>

View File

@ -15,9 +15,21 @@
<bundle-symbolic-name>${project.groupId}.tests.distribution.common</bundle-symbolic-name>
<!-- <junit.jupiter.execution.parallel.enabled>false</junit.jupiter.execution.parallel.enabled>-->
<junit.jupiter.execution.parallel.config.fixed.parallelism>2</junit.jupiter.execution.parallel.config.fixed.parallelism>
<testcontainers-keycloak.version>3.4.0</testcontainers-keycloak.version>
</properties>
<dependencies>
<dependency>
<groupId>com.github.dasniko</groupId>
<artifactId>testcontainers-keycloak</artifactId>
<version>${testcontainers-keycloak.version}</version>
<exclusions>
<exclusion>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit4-mock</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-artifact</artifactId>
@ -54,6 +66,10 @@
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-util</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-xml</artifactId>
@ -64,6 +80,10 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ethereum</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
@ -138,6 +158,12 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-infinispan-common</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>io.smallrye</groupId>
<artifactId>jandex</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
@ -155,6 +181,41 @@
<artifactId>jetty-util-ajax</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-test-log4j2-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-test-openid-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee11</groupId>
<artifactId>jetty-ee11-test-log4j2-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee11</groupId>
<artifactId>jetty-ee11-test-openid-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee9</groupId>
<artifactId>jetty-ee9-test-openid-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>jetty-http2-client</artifactId>
@ -244,17 +305,6 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>

View File

@ -11,7 +11,7 @@
// ========================================================================
//
package org.eclipse.jetty.ee11.tests.distribution;
package org.eclipse.jetty.tests.distribution;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@ -19,16 +19,21 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.toolchain.test.FS;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -43,8 +48,17 @@ public class DisableUrlCacheTest extends AbstractJettyHomeTest
{
private static final Logger LOG = LoggerFactory.getLogger(DisableUrlCacheTest.class);
@Test
public void testReloadWebAppWithLog4j2() throws Exception
public static Stream<Arguments> tests()
{
return Stream.of(
Arguments.of("ee10", "Started oeje10w.WebAppContext@"),
Arguments.of("ee11", "Started oeje11w.WebAppContext@")
);
}
@ParameterizedTest
@MethodSource("tests")
public void testReloadWebAppWithLog4j2(String env, String logToSearch) throws Exception
{
Path jettyBase = newTestJettyBaseDirectory();
String jettyVersion = System.getProperty("jettyVersion");
@ -55,7 +69,7 @@ public class DisableUrlCacheTest extends AbstractJettyHomeTest
.build();
String[] setupArgs = {
"--add-modules=http,ee11-webapp,ee11-deploy,disable-urlcache"
"--add-modules=http," + toEnvironment("webapp", env) + "," + toEnvironment("deploy", env) + ",disable-urlcache"
};
try (JettyHomeTester.Run setupRun = distribution.start(setupArgs))
@ -63,7 +77,7 @@ public class DisableUrlCacheTest extends AbstractJettyHomeTest
assertTrue(setupRun.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, setupRun.getExitValue());
Path webApp = distribution.resolveArtifact("org.eclipse.jetty.ee11:jetty-ee11-test-log4j2-webapp:war:" + jettyVersion);
Path webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-log4j2-webapp:war:" + jettyVersion);
Path testWebApp = distribution.getJettyBase().resolve("webapps/test.war");
Files.copy(webApp, testWebApp);
@ -75,16 +89,15 @@ public class DisableUrlCacheTest extends AbstractJettyHomeTest
FS.ensureEmpty(resourcesDir);
Path webappsDir = distribution.getJettyBase().resolve("webapps");
String warXml = """
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">
<Configure class="org.eclipse.jetty.ee11.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war"><Property name="jetty.webapps"/>/test.war</Set>
<Set name="tempDirectory"><Property name="jetty.base"/>/work/test</Set>
<Set name="tempDirectoryPersistent">false</Set>
</Configure>
""";
String warXml =
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>" +
"<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"https://jetty.org/configure_10_0.dtd\">" +
"<Configure class=\"org.eclipse.jetty." + env + ".webapp.WebAppContext\">" +
" <Set name=\"contextPath\">/test</Set>" +
" <Set name=\"war\"><Property name=\"jetty.webapps\"/>/test.war</Set>" +
" <Set name=\"tempDirectory\"><Property name=\"jetty.base\"/>/work/test</Set>" +
" <Set name=\"tempDirectoryPersistent\">false</Set>" +
"</Configure>";
Path warXmlPath = webappsDir.resolve("test.xml");
Files.writeString(warXmlPath, warXml, StandardCharsets.UTF_8);
@ -92,10 +105,11 @@ public class DisableUrlCacheTest extends AbstractJettyHomeTest
String loggingConfig = """
org.eclipse.jetty.LEVEL=INFO
org.eclipse.jetty.deploy.LEVEL=DEBUG
org.eclipse.jetty.ee11.webapp.LEVEL=DEBUG
org.eclipse.jetty.ee11.webapp.WebAppClassLoader.LEVEL=INFO
org.eclipse.jetty.ee11.servlet.LEVEL=DEBUG
org.eclipse.jetty.eexx.webapp.LEVEL=DEBUG
org.eclipse.jetty.eexx.webapp.WebAppClassLoader.LEVEL=INFO
org.eclipse.jetty.exx.servlet.LEVEL=DEBUG
""";
loggingConfig = loggingConfig.replace("eexx", env);
Files.writeString(loggingFile, loggingConfig, StandardCharsets.UTF_8);
@ -121,7 +135,7 @@ public class DisableUrlCacheTest extends AbstractJettyHomeTest
touch(warXmlPath);
// Wait for reload to start context
assertTrue(run2.awaitConsoleLogsFor("Started oeje11w.WebAppContext@", START_TIMEOUT, TimeUnit.SECONDS));
assertTrue(run2.awaitConsoleLogsFor(logToSearch, START_TIMEOUT, TimeUnit.SECONDS));
// wait for deployer node to complete so context is Started not Starting
assertTrue(run2.awaitConsoleLogsFor("Executing Node Node[started]", START_TIMEOUT, TimeUnit.SECONDS));

View File

@ -0,0 +1,204 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.tests.distribution;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;
import dasniko.testcontainers.keycloak.KeycloakContainer;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.util.Fields;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.keycloak.admin.client.CreatedResponseUtil;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class OpenIdTests extends AbstractJettyHomeTest
{
private static final Logger LOGGER = LoggerFactory.getLogger(OpenIdTests.class);
private static final KeycloakContainer KEYCLOAK_CONTAINER = new KeycloakContainer();
private static final String clientId = "jetty-api";
private static final String clientSecret = "JettyRocks!";
private static final String userName = "jetty";
private static final String password = "JettyRocks!Really";
private static final String firstName = "John";
private static final String lastName = "Doe";
private static final String email = "jetty@jetty.org";
private static String userId;
@BeforeAll
public static void startKeycloak()
{
KEYCLOAK_CONTAINER.start();
// init keycloak
try (Keycloak keycloak = KEYCLOAK_CONTAINER.getKeycloakAdminClient())
{
RealmRepresentation jettyRealm = new RealmRepresentation();
jettyRealm.setId("jetty");
jettyRealm.setRealm("jetty");
jettyRealm.setEnabled(true);
keycloak.realms().create(jettyRealm);
ClientRepresentation clientRepresentation = new ClientRepresentation();
clientRepresentation.setClientId(clientId);
clientRepresentation.setSecret(clientSecret);
clientRepresentation.setRedirectUris(List.of("http://localhost:*"));
clientRepresentation.setEnabled(true);
clientRepresentation.setPublicClient(Boolean.TRUE);
keycloak.realm("jetty").clients().create(clientRepresentation);
UserRepresentation user = new UserRepresentation();
user.setEnabled(true);
user.setFirstName(firstName);
user.setLastName(lastName);
user.setUsername(userName);
user.setEmail(email);
userId = CreatedResponseUtil.getCreatedId(keycloak.realm("jetty").users().create(user));
CredentialRepresentation passwordCred = new CredentialRepresentation();
passwordCred.setTemporary(false);
passwordCred.setType(CredentialRepresentation.PASSWORD);
passwordCred.setValue(password);
// Set password credential
keycloak.realm("jetty").users().get(userId).resetPassword(passwordCred);
}
}
@AfterAll
public static void stopKeycloak()
{
if (KEYCLOAK_CONTAINER.isRunning())
{
KEYCLOAK_CONTAINER.stop();
}
}
public static Stream<Arguments> tests()
{
return Stream.of(
Arguments.of("ee9", "ee9-openid"),
Arguments.of("ee10", "openid"),
Arguments.of("ee11", "openid")
);
}
@ParameterizedTest
@MethodSource("tests")
public void testOpenID(String env, String openIdModule) throws Exception
{
Path jettyBase = newTestJettyBaseDirectory();
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.jettyBase(jettyBase)
.build();
String[] args1 = {
"--create-startd",
"--approve-all-licenses",
"--add-to-start=http," + toEnvironment("webapp", env) + "," + toEnvironment("deploy", env) + "," + openIdModule
};
try (JettyHomeTester.Run run1 = distribution.start(args1))
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
Path webApp = distribution.resolveArtifact("org.eclipse.jetty." + env + ":jetty-" + env + "-test-openid-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
String openIdProvider = KEYCLOAK_CONTAINER.getAuthServerUrl() + "/realms/jetty";
LOGGER.info("openIdProvider: {}", openIdProvider);
int port = Tester.freePort();
String[] args2 = {
"jetty.http.port=" + port,
"jetty.ssl.port=" + port,
"jetty.openid.provider=" + openIdProvider,
"jetty.openid.clientId=" + clientId,
"jetty.openid.clientSecret=" + clientSecret,
//"jetty.server.dumpAfterStart=true",
};
try (JettyHomeTester.Run run2 = distribution.start(args2))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
String uri = "http://localhost:" + port + "/test";
// Initially not authenticated
startHttpClient();
ContentResponse contentResponse = client.GET(uri + "/");
assertThat(contentResponse.getStatus(), is(HttpStatus.OK_200));
assertThat(contentResponse.getContentAsString(), containsString("not authenticated"));
// Request to login is success
contentResponse = client.GET(uri + "/login");
assertThat(contentResponse.getStatus(), is(HttpStatus.OK_200));
// need to extract form
String html = contentResponse.getContentAsString();
// need this attribute <form ***** action="***"
String postUrl = html.substring(html.indexOf("action=\"")).substring(0, html.substring(html.indexOf("action=\"")).indexOf("\"", 9)).substring(8);
Fields fields = new Fields();
fields.put("username", userName);
fields.add("password", password);
contentResponse = client.FORM(postUrl, fields);
assertThat(contentResponse.getStatus(), is(HttpStatus.OK_200));
assertThat(contentResponse.getContentAsString(), containsString("success"));
// Now authenticated we can get info
String content = client.GET(uri + "/").getContentAsString();
assertThat(content, containsString("userId: " + userId));
assertThat(content, containsString("name: " + firstName + " " + lastName));
assertThat(content, containsString("email: " + email));
// Request to admin page gives 403 as we do not have admin role
contentResponse = client.GET(uri + "/admin");
assertThat(contentResponse.getStatus(), is(HttpStatus.FORBIDDEN_403));
// We are no longer authenticated after logging out
contentResponse = client.GET(uri + "/logout");
assertThat(contentResponse.getStatus(), is(HttpStatus.OK_200));
content = contentResponse.getContentAsString();
assertThat(content, containsString("not authenticated"));
}
}
}
}

View File

@ -6,3 +6,6 @@ org.testcontainers.LEVEL=INFO
#org.testcontainers.LEVEL=DEBUG
#org.eclipse.jetty.LEVEL=DEBUG
#org.eclipse.jetty.tests.distribution.LEVEL=DEBUG
# uncomment to get output of forked jetty process in the logs
#org.eclipse.jetty.tests.testers.ProcessWrapper.LEVEL=DEBUG
com.gargoylesoftware.htmlunit.LEVEL=ERROR

View File

@ -1,81 +0,0 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution</artifactId>
<version>12.1.0-SNAPSHOT</version>
</parent>
<artifactId>test-ee10-distribution</artifactId>
<packaging>jar</packaging>
<name>Tests :: Distribution :: EE10</name>
<properties>
<bundle-symbolic-name>${project.groupId}.ee10.distribution</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
<type>zip</type>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ethereum</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-openid</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-servlet</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-test-openid-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-test-common</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-testers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,143 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee10.tests.distribution;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.eclipse.jetty.toolchain.test.FS;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Isolated
public class DisableUrlCacheTest extends AbstractJettyHomeTest
{
private static final Logger LOG = LoggerFactory.getLogger(DisableUrlCacheTest.class);
@Test
public void testReloadWebAppWithLog4j2() throws Exception
{
Path jettyBase = newTestJettyBaseDirectory();
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.jettyBase(jettyBase)
.jvmArgs(List.of("-Dorg.eclipse.jetty.deploy.LEVEL=DEBUG"))
.build();
String[] setupArgs = {
"--add-modules=http,ee10-webapp,ee10-deploy,disable-urlcache"
};
try (JettyHomeTester.Run setupRun = distribution.start(setupArgs))
{
assertTrue(setupRun.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, setupRun.getExitValue());
Path webApp = distribution.resolveArtifact("org.eclipse.jetty.ee10:jetty-ee10-test-log4j2-webapp:war:" + jettyVersion);
Path testWebApp = distribution.getJettyBase().resolve("webapps/test.war");
Files.copy(webApp, testWebApp);
Path tempDir = distribution.getJettyBase().resolve("work");
FS.ensureEmpty(tempDir);
Path resourcesDir = distribution.getJettyBase().resolve("resources");
FS.ensureEmpty(resourcesDir);
Path webappsDir = distribution.getJettyBase().resolve("webapps");
String warXml = """
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">
<Configure class="org.eclipse.jetty.ee10.webapp.WebAppContext">
<Set name="contextPath">/test</Set>
<Set name="war"><Property name="jetty.webapps"/>/test.war</Set>
<Set name="tempDirectory"><Property name="jetty.base"/>/work/test</Set>
<Set name="tempDirectoryPersistent">false</Set>
</Configure>
""";
Path warXmlPath = webappsDir.resolve("test.xml");
Files.writeString(warXmlPath, warXml, StandardCharsets.UTF_8);
Path loggingFile = resourcesDir.resolve("jetty-logging.properties");
String loggingConfig = """
org.eclipse.jetty.LEVEL=INFO
org.eclipse.jetty.deploy.LEVEL=DEBUG
org.eclipse.jetty.ee10.webapp.LEVEL=DEBUG
org.eclipse.jetty.ee10.webapp.WebAppClassLoader.LEVEL=INFO
org.eclipse.jetty.ee10.servlet.LEVEL=DEBUG
""";
Files.writeString(loggingFile, loggingConfig, StandardCharsets.UTF_8);
int port = Tester.freePort();
String[] runArgs = {
"jetty.http.port=" + port,
"jetty.deploy.scanInterval=1"
//"jetty.server.dumpAfterStart=true",
};
try (JettyHomeTester.Run run2 = distribution.start(runArgs))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
startHttpClient(false);
// Test webapp is there
ContentResponse response = client.GET("http://localhost:" + port + "/test/log/");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
String content = response.getContentAsString();
assertThat(content, containsString("GET at LogServlet"));
// Trigger a hot-reload
run2.getLogs().clear();
touch(warXmlPath);
// Wait for reload to start context
assertTrue(run2.awaitConsoleLogsFor("Started oeje10w.WebAppContext@", START_TIMEOUT, TimeUnit.SECONDS));
// wait for deployer node to complete so context is Started not Starting
assertTrue(run2.awaitConsoleLogsFor("Executing Node Node[started]", START_TIMEOUT, TimeUnit.SECONDS));
// Is webapp still there?
response = client.GET("http://localhost:" + port + "/test/log/");
content = response.getContentAsString();
assertThat(content, response.getStatus(), is(HttpStatus.OK_200));
assertThat(content, containsString("GET at LogServlet"));
}
}
}
private void touch(Path path) throws IOException
{
LOG.info("Touch: {}", path);
FileTime now = FileTime.fromMillis(System.currentTimeMillis() + 2000);
Files.setLastModifiedTime(path, now);
}
}

View File

@ -1,119 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee10.tests.distribution;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.OpenIdProvider;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Isolated
public class OpenIdTests extends AbstractJettyHomeTest
{
@Test
public void testOpenID() throws Exception
{
Path jettyBase = newTestJettyBaseDirectory();
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.jettyBase(jettyBase)
.build();
String[] args1 = {
"--create-startd",
"--approve-all-licenses",
"--add-to-start=http,ee10-webapp,ee10-deploy,openid"
};
String clientId = "clientId123";
String clientSecret = "clientSecret456";
OpenIdProvider openIdProvider = new OpenIdProvider(clientId, clientSecret);
try (JettyHomeTester.Run run1 = distribution.start(args1))
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
Path webApp = distribution.resolveArtifact("org.eclipse.jetty.ee10:jetty-ee10-test-openid-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
int port = Tester.freePort();
openIdProvider.addRedirectUri("http://localhost:" + port + "/test/j_security_check");
openIdProvider.start();
String[] args2 = {
"jetty.http.port=" + port,
"jetty.ssl.port=" + port,
"jetty.openid.provider=" + openIdProvider.getProvider(),
"jetty.openid.clientId=" + clientId,
"jetty.openid.clientSecret=" + clientSecret,
//"jetty.server.dumpAfterStart=true",
};
try (JettyHomeTester.Run run2 = distribution.start(args2))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
startHttpClient(false);
String uri = "http://localhost:" + port + "/test";
openIdProvider.setUser(new OpenIdProvider.User("123456789", "Alice"));
// Initially not authenticated
ContentResponse response = client.GET(uri + "/");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
String content = response.getContentAsString();
assertThat(content, containsString("not authenticated"));
// Request to login is success
response = client.GET(uri + "/login");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("success"));
// Now authenticated we can get info
response = client.GET(uri + "/");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("userId: 123456789"));
assertThat(content, containsString("name: Alice"));
assertThat(content, containsString("email: Alice@example.com"));
// Request to admin page gives 403 as we do not have admin role
response = client.GET(uri + "/admin");
assertThat(response.getStatus(), is(HttpStatus.FORBIDDEN_403));
// We are no longer authenticated after logging out
response = client.GET(uri + "/logout");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("not authenticated"));
}
}
finally
{
openIdProvider.stop();
}
}
}

View File

@ -1,81 +0,0 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution</artifactId>
<version>12.1.0-SNAPSHOT</version>
</parent>
<artifactId>test-ee11-distribution</artifactId>
<packaging>jar</packaging>
<name>Tests :: Distribution :: EE11</name>
<properties>
<bundle-symbolic-name>${project.groupId}.ee11.distribution</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
<type>zip</type>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-openid</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee11</groupId>
<artifactId>jetty-ee11-servlet</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee11</groupId>
<artifactId>jetty-ee11-test-openid-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-test-common</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-testers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,119 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee11.tests.distribution;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.OpenIdProvider;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Isolated
public class OpenIdTests extends AbstractJettyHomeTest
{
@Test
public void testOpenID() throws Exception
{
Path jettyBase = newTestJettyBaseDirectory();
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.jettyBase(jettyBase)
.build();
String[] args1 = {
"--create-startd",
"--approve-all-licenses",
"--add-to-start=http,ee11-webapp,ee11-deploy,openid"
};
String clientId = "clientId123";
String clientSecret = "clientSecret456";
OpenIdProvider openIdProvider = new OpenIdProvider(clientId, clientSecret);
try (JettyHomeTester.Run run1 = distribution.start(args1))
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
Path webApp = distribution.resolveArtifact("org.eclipse.jetty.ee11:jetty-ee11-test-openid-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
int port = Tester.freePort();
openIdProvider.addRedirectUri("http://localhost:" + port + "/test/j_security_check");
openIdProvider.start();
String[] args2 = {
"jetty.http.port=" + port,
"jetty.ssl.port=" + port,
"jetty.openid.provider=" + openIdProvider.getProvider(),
"jetty.openid.clientId=" + clientId,
"jetty.openid.clientSecret=" + clientSecret,
//"jetty.server.dumpAfterStart=true",
};
try (JettyHomeTester.Run run2 = distribution.start(args2))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
startHttpClient(false);
String uri = "http://localhost:" + port + "/test";
openIdProvider.setUser(new OpenIdProvider.User("123456789", "Alice"));
// Initially not authenticated
ContentResponse response = client.GET(uri + "/");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
String content = response.getContentAsString();
assertThat(content, containsString("not authenticated"));
// Request to login is success
response = client.GET(uri + "/login");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("success"));
// Now authenticated we can get info
response = client.GET(uri + "/");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("userId: 123456789"));
assertThat(content, containsString("name: Alice"));
assertThat(content, containsString("email: Alice@example.com"));
// Request to admin page gives 403 as we do not have admin role
response = client.GET(uri + "/admin");
assertThat(response.getStatus(), is(HttpStatus.FORBIDDEN_403));
// We are no longer authenticated after logging out
response = client.GET(uri + "/logout");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("not authenticated"));
}
}
finally
{
openIdProvider.stop();
}
}
}

View File

@ -1,77 +0,0 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution</artifactId>
<version>12.1.0-SNAPSHOT</version>
</parent>
<artifactId>test-ee9-distribution</artifactId>
<packaging>jar</packaging>
<name>Tests :: Distribution :: EE9</name>
<properties>
<bundle-symbolic-name>${project.groupId}.ee9.distribution</bundle-symbolic-name>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-home</artifactId>
<type>zip</type>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee9</groupId>
<artifactId>jetty-ee9-openid</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee9</groupId>
<artifactId>jetty-ee9-servlet</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.ee9</groupId>
<artifactId>jetty-ee9-test-openid-webapp</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-test-common</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>jetty-testers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.tests</groupId>
<artifactId>test-distribution-common</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -1,120 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee9.tests.distribution;
import java.nio.file.Path;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.tests.OpenIdProvider;
import org.eclipse.jetty.tests.distribution.AbstractJettyHomeTest;
import org.eclipse.jetty.tests.testers.JettyHomeTester;
import org.eclipse.jetty.tests.testers.Tester;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
@Isolated
public class OpenIdTests extends AbstractJettyHomeTest
{
@Test
public void testOpenID() throws Exception
{
Path jettyBase = newTestJettyBaseDirectory();
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.jettyBase(jettyBase)
.build();
String[] args1 = {
"--create-startd",
"--approve-all-licenses",
"--add-to-start=http,ee9-webapp,ee9-deploy,ee9-openid"
};
String clientId = "clientId123";
String clientSecret = "clientSecret456";
OpenIdProvider openIdProvider = new OpenIdProvider(clientId, clientSecret);
try (JettyHomeTester.Run run1 = distribution.start(args1))
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());
Path webApp = distribution.resolveArtifact("org.eclipse.jetty.ee9:jetty-ee9-test-openid-webapp:war:" + jettyVersion);
distribution.installWar(webApp, "test");
int port = Tester.freePort();
openIdProvider.addRedirectUri("http://localhost:" + port + "/test/j_security_check");
openIdProvider.start();
String[] args2 = {
"jetty.http.port=" + port,
"jetty.ssl.port=" + port,
"jetty.openid.provider=" + openIdProvider.getProvider(),
"jetty.openid.clientId=" + clientId,
"jetty.openid.clientSecret=" + clientSecret,
//"jetty.server.dumpAfterStart=true",
};
try (JettyHomeTester.Run run2 = distribution.start(args2))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));
startHttpClient(false);
String uri = "http://localhost:" + port + "/test";
openIdProvider.setUser(new OpenIdProvider.User("123456789", "Alice"));
// Initially not authenticated
ContentResponse response = client.GET(uri + "/");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
String content = response.getContentAsString();
assertThat(content, containsString("not authenticated"));
// Request to login is success
response = client.GET(uri + "/login");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("success"));
// Now authenticated we can get info
response = client.GET(uri + "/");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("userId: 123456789"));
assertThat(content, containsString("name: Alice"));
assertThat(content, containsString("email: Alice@example.com"));
// Request to admin page gives 403 as we do not have admin role
response = client.GET(uri + "/admin");
assertThat(response.getStatus(), is(HttpStatus.FORBIDDEN_403));
// We are no longer authenticated after logging out
response = client.GET(uri + "/logout");
assertThat(response.getStatus(), is(HttpStatus.OK_200));
content = response.getContentAsString();
assertThat(content, containsString("not authenticated"));
}
}
finally
{
openIdProvider.stop();
}
}
}