diff --git a/tests/jetty-test-common/pom.xml b/tests/jetty-test-common/pom.xml
deleted file mode 100644
index d820ada4c30..00000000000
--- a/tests/jetty-test-common/pom.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
- 4.0.0
-
- org.eclipse.jetty.tests
- tests
- 12.1.0-SNAPSHOT
-
- jetty-test-common
- jar
- Tests :: Test Utilities
-
-
- ${project.groupId}.testers
-
-
-
-
- org.eclipse.jetty
- jetty-server
-
-
- org.eclipse.jetty
- jetty-util
-
-
-
-
diff --git a/tests/jetty-test-common/src/main/java/org/eclipse/jetty/tests/JwtEncoder.java b/tests/jetty-test-common/src/main/java/org/eclipse/jetty/tests/JwtEncoder.java
deleted file mode 100644
index d4611f07a77..00000000000
--- a/tests/jetty-test-common/src/main/java/org/eclipse/jetty/tests/JwtEncoder.java
+++ /dev/null
@@ -1,53 +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.tests;
-
-import java.util.Base64;
-
-/**
- * A basic JWT encoder for testing purposes.
- */
-public class JwtEncoder
-{
- private static final Base64.Encoder ENCODER = Base64.getUrlEncoder();
- private static final String DEFAULT_HEADER = "{\"INFO\": \"this is not used or checked in our implementation\"}";
- private static final String DEFAULT_SIGNATURE = "we do not validate signature as we use the authorization code flow";
-
- public static String encode(String idToken)
- {
- return stripPadding(ENCODER.encodeToString(DEFAULT_HEADER.getBytes())) + "." +
- stripPadding(ENCODER.encodeToString(idToken.getBytes())) + "." +
- stripPadding(ENCODER.encodeToString(DEFAULT_SIGNATURE.getBytes()));
- }
-
- private static String stripPadding(String paddedBase64)
- {
- return paddedBase64.split("=")[0];
- }
-
- /**
- * Create a basic JWT for testing using argument supplied attributes.
- */
- public static String createIdToken(String provider, String clientId, String subject, String name, long expiry)
- {
- return "{" +
- "\"iss\": \"" + provider + "\"," +
- "\"sub\": \"" + subject + "\"," +
- "\"aud\": \"" + clientId + "\"," +
- "\"exp\": " + expiry + "," +
- "\"name\": \"" + name + "\"," +
- "\"email\": \"" + name + "@example.com" + "\"" +
- "}";
- }
-}
diff --git a/tests/jetty-test-common/src/main/java/org/eclipse/jetty/tests/OpenIdProvider.java b/tests/jetty-test-common/src/main/java/org/eclipse/jetty/tests/OpenIdProvider.java
deleted file mode 100644
index aba79c2a0c3..00000000000
--- a/tests/jetty-test-common/src/main/java/org/eclipse/jetty/tests/OpenIdProvider.java
+++ /dev/null
@@ -1,421 +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.tests;
-
-import java.io.IOException;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.UUID;
-
-import org.eclipse.jetty.http.BadMessageException;
-import org.eclipse.jetty.http.HttpHeader;
-import org.eclipse.jetty.http.HttpMethod;
-import org.eclipse.jetty.http.HttpStatus;
-import org.eclipse.jetty.server.Handler;
-import org.eclipse.jetty.server.Request;
-import org.eclipse.jetty.server.Response;
-import org.eclipse.jetty.server.Server;
-import org.eclipse.jetty.server.ServerConnector;
-import org.eclipse.jetty.util.BufferUtil;
-import org.eclipse.jetty.util.Callback;
-import org.eclipse.jetty.util.Fields;
-import org.eclipse.jetty.util.StringUtil;
-import org.eclipse.jetty.util.component.ContainerLifeCycle;
-import org.eclipse.jetty.util.statistic.CounterStatistic;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class OpenIdProvider extends ContainerLifeCycle
-{
- private static final Logger LOG = LoggerFactory.getLogger(OpenIdProvider.class);
-
- private static final String CONFIG_PATH = "/.well-known/openid-configuration";
- private static final String AUTH_PATH = "/auth";
- private static final String TOKEN_PATH = "/token";
- private static final String END_SESSION_PATH = "/end_session";
- private final Map issuedAuthCodes = new HashMap<>();
-
- protected final String clientId;
- protected final String clientSecret;
- protected final List redirectUris = new ArrayList<>();
- private final ServerConnector connector;
- private final Server server;
- private int port = 0;
- private String provider;
- private User preAuthedUser;
- private final CounterStatistic loggedInUsers = new CounterStatistic();
- private long _idTokenDuration = Duration.ofSeconds(10).toMillis();
-
- public static void main(String[] args) throws Exception
- {
- String clientId = "CLIENT_ID123";
- String clientSecret = "PASSWORD123";
- int port = 5771;
- String redirectUri = "http://localhost:8080/j_security_check";
-
- OpenIdProvider openIdProvider = new OpenIdProvider(clientId, clientSecret);
- openIdProvider.addRedirectUri(redirectUri);
- openIdProvider.setPort(port);
- openIdProvider.start();
- try
- {
- openIdProvider.join();
- }
- finally
- {
- openIdProvider.stop();
- }
- }
-
- public OpenIdProvider()
- {
- this("clientId" + StringUtil.randomAlphaNumeric(4), StringUtil.randomAlphaNumeric(10));
- }
-
- public OpenIdProvider(String clientId, String clientSecret)
- {
- this.clientId = clientId;
- this.clientSecret = clientSecret;
-
- server = new Server();
- connector = new ServerConnector(server);
- server.addConnector(connector);
-
- server.setHandler(new OpenIdProviderHandler());
- addBean(server);
- }
-
- public String getClientId()
- {
- return clientId;
- }
-
- public String getClientSecret()
- {
- return clientSecret;
- }
-
- public void setIdTokenDuration(long duration)
- {
- _idTokenDuration = duration;
- }
-
- public long getIdTokenDuration()
- {
- return _idTokenDuration;
- }
-
- public void join() throws InterruptedException
- {
- server.join();
- }
-
- public CounterStatistic getLoggedInUsers()
- {
- return loggedInUsers;
- }
-
- @Override
- protected void doStart() throws Exception
- {
- connector.setPort(port);
- super.doStart();
- provider = "http://localhost:" + connector.getLocalPort();
- }
-
- public void setPort(int port)
- {
- if (isStarted())
- throw new IllegalStateException();
- this.port = port;
- }
-
- public void setUser(User user)
- {
- this.preAuthedUser = user;
- }
-
- public String getProvider()
- {
- if (!isStarted() && port == 0)
- throw new IllegalStateException("Port of OpenIdProvider not configured");
- return provider;
- }
-
- public void addRedirectUri(String uri)
- {
- redirectUris.add(uri);
- }
-
- public class OpenIdProviderHandler extends Handler.Abstract
- {
- @Override
- public boolean handle(Request request, Response response, Callback callback) throws Exception
- {
- String pathInContext = Request.getPathInContext(request);
- switch (pathInContext)
- {
- case CONFIG_PATH -> doGetConfigServlet(request, response, callback);
- case AUTH_PATH -> doAuthEndpoint(request, response, callback);
- case TOKEN_PATH -> doTokenEndpoint(request, response, callback);
- case END_SESSION_PATH -> doEndSessionEndpoint(request, response, callback);
- default -> Response.writeError(request, response, callback, HttpStatus.NOT_FOUND_404);
- }
-
- return true;
- }
- }
-
- protected void doAuthEndpoint(Request request, Response response, Callback callback) throws Exception
- {
- String method = request.getMethod();
- switch (method)
- {
- case "GET" -> doGetAuthEndpoint(request, response, callback);
- case "POST" -> doPostAuthEndpoint(request, response, callback);
- default -> throw new BadMessageException("Unsupported HTTP method: " + method);
- }
- }
-
- protected void doGetAuthEndpoint(Request request, Response response, Callback callback) throws Exception
- {
- Fields parameters = Request.getParameters(request);
-
- if (!clientId.equals(parameters.getValue("client_id")))
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "invalid client_id");
- return;
- }
-
- String redirectUri = parameters.getValue("redirect_uri");
- if (!redirectUris.contains(redirectUri))
- {
- LOG.warn("invalid redirectUri {}", redirectUri);
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "invalid redirect_uri");
- return;
- }
-
- String scopeString = parameters.getValue("scope");
- List scopes = (scopeString == null) ? Collections.emptyList() : Arrays.asList(scopeString.split(" "));
- if (!scopes.contains("openid"))
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "no openid scope");
- return;
- }
-
- if (!"code".equals(parameters.getValue("response_type")))
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "response_type must be code");
- return;
- }
-
- String state = parameters.getValue("state");
- if (state == null)
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "no state param");
- return;
- }
-
- if (preAuthedUser == null)
- {
- String responseContent = String.format("""
- Login to OpenID Connect Provider
-
- """, AUTH_PATH, redirectUri, state);
- response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/html");
- response.write(true, BufferUtil.toBuffer(responseContent), callback);
- }
- else
- {
- redirectUser(request, response, callback, preAuthedUser, redirectUri, state);
- }
- }
-
- protected void doPostAuthEndpoint(Request request, Response response, Callback callback) throws Exception
- {
- Fields parameters = Request.getParameters(request);
- String redirectUri = parameters.getValue("redirectUri");
- if (!redirectUris.contains(redirectUri))
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "invalid redirect_uri");
- return;
- }
-
- String state = parameters.getValue("state");
- if (state == null)
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "no state param");
- return;
- }
-
- String username = parameters.getValue("username");
- if (username == null)
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "no username");
- return;
- }
-
- User user = new User(username);
- redirectUser(request, response, callback, user, redirectUri, state);
- }
-
- public void redirectUser(Request request, Response response, Callback callback, User user, String redirectUri, String state) throws IOException
- {
- String authCode = UUID.randomUUID().toString().replace("-", "");
- issuedAuthCodes.put(authCode, user);
-
- try
- {
- redirectUri += "?code=" + authCode + "&state=" + state;
- Response.sendRedirect(request, response, callback, redirectUri);
- }
- catch (Throwable t)
- {
- issuedAuthCodes.remove(authCode);
- throw t;
- }
- }
-
- protected void doTokenEndpoint(Request request, Response response, Callback callback) throws Exception
- {
- if (!HttpMethod.POST.is(request.getMethod()))
- throw new BadMessageException("Unsupported HTTP method for token Endpoint: " + request.getMethod());
-
- Fields parameters = Request.getParameters(request);
- String code = parameters.getValue("code");
-
- if (!clientId.equals(parameters.getValue("client_id")) ||
- !clientSecret.equals(parameters.getValue("client_secret")) ||
- !redirectUris.contains(parameters.getValue("redirect_uri")) ||
- !"authorization_code".equals(parameters.getValue("grant_type")) ||
- code == null)
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "bad auth request");
- return;
- }
-
- User user = issuedAuthCodes.remove(code);
- if (user == null)
- {
- Response.writeError(request, response, callback, HttpStatus.FORBIDDEN_403, "invalid auth code");
- return;
- }
-
- String accessToken = "ABCDEFG";
- long accessTokenDuration = Duration.ofMinutes(10).toSeconds();
- String responseContent = "{" +
- "\"access_token\": \"" + accessToken + "\"," +
- "\"id_token\": \"" + JwtEncoder.encode(user.getIdToken(provider, clientId, _idTokenDuration)) + "\"," +
- "\"expires_in\": " + accessTokenDuration + "," +
- "\"token_type\": \"Bearer\"" +
- "}";
-
- loggedInUsers.increment();
- response.getHeaders().put(HttpHeader.CONTENT_TYPE, "text/plain");
- response.write(true, BufferUtil.toBuffer(responseContent), callback);
- }
-
- protected void doEndSessionEndpoint(Request request, Response response, Callback callback) throws Exception
- {
- Fields parameters = Request.getParameters(request);
- String idToken = parameters.getValue("id_token_hint");
- if (idToken == null)
- {
- Response.writeError(request, response, callback, HttpStatus.BAD_REQUEST_400, "no id_token_hint");
- return;
- }
-
- String logoutRedirect = parameters.getValue("post_logout_redirect_uri");
- if (logoutRedirect == null)
- {
- response.setStatus(HttpStatus.OK_200);
- response.write(true, BufferUtil.toBuffer("logout success on end_session_endpoint"), callback);
- return;
- }
-
- loggedInUsers.decrement();
- Response.sendRedirect(request, response, callback, logoutRedirect);
- }
-
- protected void doGetConfigServlet(Request request, Response response, Callback callback) throws IOException
- {
- String discoveryDocument = "{" +
- "\"issuer\": \"" + provider + "\"," +
- "\"authorization_endpoint\": \"" + provider + AUTH_PATH + "\"," +
- "\"token_endpoint\": \"" + provider + TOKEN_PATH + "\"," +
- "\"end_session_endpoint\": \"" + provider + END_SESSION_PATH + "\"," +
- "}";
-
- response.write(true, BufferUtil.toBuffer(discoveryDocument), callback);
- }
-
- public static class User
- {
- private final String subject;
- private final String name;
-
- public User(String name)
- {
- this(UUID.nameUUIDFromBytes(name.getBytes()).toString(), name);
- }
-
- public User(String subject, String name)
- {
- this.subject = subject;
- this.name = name;
- }
-
- public String getName()
- {
- return name;
- }
-
- public String getSubject()
- {
- return subject;
- }
-
- public String getIdToken(String provider, String clientId, long duration)
- {
- long expiryTime = Instant.now().plusMillis(duration).getEpochSecond();
- return JwtEncoder.createIdToken(provider, clientId, subject, name, expiryTime);
- }
-
- @Override
- public boolean equals(Object obj)
- {
- if (!(obj instanceof User))
- return false;
- return Objects.equals(subject, ((User)obj).subject) && Objects.equals(name, ((User)obj).name);
- }
-
- @Override
- public int hashCode()
- {
- return Objects.hash(subject, name);
- }
- }
-}
diff --git a/tests/pom.xml b/tests/pom.xml
index 022baf529be..0ec5773e2db 100644
--- a/tests/pom.xml
+++ b/tests/pom.xml
@@ -15,7 +15,6 @@
jetty-jmh
jetty-test-multipart
jetty-test-session-common
- jetty-test-common
test-cross-context-dispatch
test-distribution
test-integration
diff --git a/tests/test-distribution/pom.xml b/tests/test-distribution/pom.xml
index 31613448a04..1ff1e82c161 100644
--- a/tests/test-distribution/pom.xml
+++ b/tests/test-distribution/pom.xml
@@ -13,9 +13,6 @@
test-distribution-common
- test-ee11-distribution
- test-ee10-distribution
- test-ee9-distribution
diff --git a/tests/test-distribution/test-distribution-common/pom.xml b/tests/test-distribution/test-distribution-common/pom.xml
index fef3a356f7a..535c035944f 100644
--- a/tests/test-distribution/test-distribution-common/pom.xml
+++ b/tests/test-distribution/test-distribution-common/pom.xml
@@ -15,9 +15,21 @@
${project.groupId}.tests.distribution.common
2
+ 3.4.0
+
+ com.github.dasniko
+ testcontainers-keycloak
+ ${testcontainers-keycloak.version}
+
+
+ io.quarkus
+ quarkus-junit4-mock
+
+
+
org.apache.maven
maven-artifact
@@ -138,6 +150,12 @@
org.eclipse.jetty
jetty-infinispan-common
test
+
+
+ io.smallrye
+ jandex
+
+
org.eclipse.jetty
@@ -155,6 +173,20 @@
jetty-util-ajax
test
+
+ org.eclipse.jetty.ee10
+ jetty-ee10-test-log4j2-webapp
+ ${project.version}
+ war
+ test
+
+
+ org.eclipse.jetty.ee9
+ jetty-ee9-test-openid-webapp
+ ${project.version}
+ war
+ test
+
org.eclipse.jetty.http2
jetty-http2-client
@@ -246,6 +278,7 @@
org.apache.maven.plugins
+<<<<<<< HEAD
maven-jar-plugin
@@ -257,6 +290,8 @@
org.apache.maven.plugins
+=======
+>>>>>>> jetty-12.0.x
maven-surefire-plugin
diff --git a/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/DisableUrlCacheTest.java b/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/DisableUrlCacheTest.java
similarity index 98%
rename from tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/DisableUrlCacheTest.java
rename to tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/DisableUrlCacheTest.java
index 81299ef8038..9b8a2919088 100644
--- a/tests/test-distribution/test-ee10-distribution/src/test/java/org/eclipse/jetty/ee10/tests/distribution/DisableUrlCacheTest.java
+++ b/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/DisableUrlCacheTest.java
@@ -11,7 +11,7 @@
// ========================================================================
//
-package org.eclipse.jetty.ee10.tests.distribution;
+package org.eclipse.jetty.tests.distribution;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@@ -23,7 +23,6 @@ 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;
diff --git a/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/OpenIdTests.java b/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/OpenIdTests.java
new file mode 100644
index 00000000000..c96fffe5cff
--- /dev/null
+++ b/tests/test-distribution/test-distribution-common/src/test/java/org/eclipse/jetty/tests/distribution/OpenIdTests.java
@@ -0,0 +1,203 @@
+//
+// ========================================================================
+// 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 tests()
+ {
+ return Stream.of(
+ Arguments.of("ee9", "ee9-openid"),
+ Arguments.of("ee10", "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