diff --git a/tests/base/src/test/java/org/keycloak/tests/error/EscapeErrorPageTest.java b/tests/base/src/test/java/org/keycloak/tests/error/EscapeErrorPageTest.java
new file mode 100644
index 000000000000..2971d5e41777
--- /dev/null
+++ b/tests/base/src/test/java/org/keycloak/tests/error/EscapeErrorPageTest.java
@@ -0,0 +1,76 @@
+package org.keycloak.tests.error;
+
+import java.net.URI;
+
+import org.keycloak.common.util.KeycloakUriBuilder;
+import org.keycloak.testframework.annotations.InjectKeycloakUrls;
+import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
+import org.keycloak.testframework.server.KeycloakUrls;
+import org.keycloak.testframework.ui.annotations.InjectPage;
+import org.keycloak.testframework.ui.annotations.InjectWebDriver;
+import org.keycloak.testframework.ui.page.ErrorPage;
+import org.keycloak.testframework.ui.webdriver.ManagedWebDriver;
+import org.keycloak.tests.common.CustomProvidersServerConfig;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+
+@KeycloakIntegrationTest(config = CustomProvidersServerConfig.class)
+class EscapeErrorPageTest {
+
+ @InjectPage
+ ErrorPage errorPage;
+
+ @InjectWebDriver
+ ManagedWebDriver driver;
+
+ @InjectKeycloakUrls
+ KeycloakUrls keycloakUrls;
+
+ @Test
+ void innerScript() {
+ checkMessage("\"
alert(1)/>\"", "\"alert(1)/>\"");
+ }
+
+ @Test
+ void innerURL() {
+ checkMessage("\"See https://www.keycloak.org/docs\"", "\"See https://www.keycloak.org/docs\"");
+ }
+
+ @Test
+ void url() {
+ checkMessage("See https://www.keycloak.org/docs", "See https://www.keycloak.org/docs");
+ }
+
+ @Test
+ void ampersandEscape() {
+ checkMessage("<img src="something">", "");
+ }
+
+ @Test
+ void hexEscape() {
+ checkMessage("<img src=something/>", "");
+ }
+
+ @Test
+ void plainText() {
+ checkMessage("It doesn't work", "It doesn't work");
+ }
+
+ @Test
+ void textWithPlus() {
+ checkMessage("Fact: 1+1=2", "Fact: 1+1=2");
+ }
+
+ private void checkMessage(String queryParam, String expected) {
+ URI uri = KeycloakUriBuilder.fromUri(keycloakUrls.getMasterRealm())
+ .path("error-testing/display-error-message")
+ .queryParam("message", queryParam)
+ .build();
+ driver.open(uri.toString());
+ errorPage.assertCurrent();
+ assertThat("Sanitized error message for input: " + queryParam, errorPage.getError(), is(expected));
+ }
+}
diff --git a/tests/base/src/test/java/org/keycloak/tests/error/UncaughtErrorPageTest.java b/tests/base/src/test/java/org/keycloak/tests/error/UncaughtErrorPageTest.java
new file mode 100644
index 000000000000..9ac5aec21816
--- /dev/null
+++ b/tests/base/src/test/java/org/keycloak/tests/error/UncaughtErrorPageTest.java
@@ -0,0 +1,255 @@
+package org.keycloak.tests.error;
+
+import java.io.IOException;
+import java.net.URI;
+
+import org.keycloak.OAuthErrorException;
+import org.keycloak.admin.client.Keycloak;
+import org.keycloak.common.util.KeycloakUriBuilder;
+import org.keycloak.models.BrowserSecurityHeaders;
+import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
+import org.keycloak.testframework.annotations.InjectAdminClient;
+import org.keycloak.testframework.annotations.InjectHttpClient;
+import org.keycloak.testframework.annotations.InjectKeycloakUrls;
+import org.keycloak.testframework.annotations.InjectRealm;
+import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
+import org.keycloak.testframework.injection.LifeCycle;
+import org.keycloak.testframework.oauth.OAuthClient;
+import org.keycloak.testframework.oauth.annotations.InjectOAuthClient;
+import org.keycloak.testframework.realm.ManagedRealm;
+import org.keycloak.testframework.server.KeycloakUrls;
+import org.keycloak.testframework.ui.annotations.InjectPage;
+import org.keycloak.testframework.ui.annotations.InjectWebDriver;
+import org.keycloak.testframework.ui.page.ErrorPage;
+import org.keycloak.testframework.ui.webdriver.ManagedWebDriver;
+import org.keycloak.tests.common.CustomProvidersServerConfig;
+import org.keycloak.util.JsonSerialization;
+import org.keycloak.utils.MediaType;
+
+import org.apache.http.Header;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.util.EntityUtils;
+import org.junit.jupiter.api.Test;
+import org.openqa.selenium.By;
+
+import static org.keycloak.utils.MediaType.APPLICATION_JSON;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+@KeycloakIntegrationTest(config = CustomProvidersServerConfig.class)
+class UncaughtErrorPageTest {
+
+ @InjectPage
+ ErrorPage errorPage;
+
+ @InjectWebDriver
+ ManagedWebDriver driver;
+
+ @InjectKeycloakUrls
+ KeycloakUrls keycloakUrls;
+
+ @InjectHttpClient
+ HttpClient httpClient;
+
+ @InjectAdminClient
+ Keycloak adminClient;
+
+ @InjectOAuthClient(lifecycle = LifeCycle.METHOD)
+ OAuthClient oauth;
+
+ @InjectRealm(attachTo = "master")
+ ManagedRealm masterRealm;
+
+ @Test
+ void invalidResource() {
+ checkPageNotFound("/nosuch");
+ }
+
+ @Test
+ void invalidRealm() {
+ checkPageNotFound("/realms/nosuch");
+ }
+
+ @Test
+ void invalidRealmResource() {
+ checkPageNotFound("/realms/master/nosuch");
+ }
+
+ @Test
+ void uncaughtErrorJson() throws IOException {
+ HttpResponse response = httpClient.execute(new HttpGet(errorTestingUri("uncaught-error")));
+
+ assertThat("status code", response.getStatusLine().getStatusCode(), is(500));
+
+ OAuth2ErrorRepresentation error = readError(response);
+ assertThat("error code", error.getError(), is("unknown_error"));
+ assertThat("error description", error.getErrorDescription(),
+ containsString("For more on this error consult the server log"));
+ }
+
+ @Test
+ void uncaughtErrorClientRegistration() throws IOException {
+ HttpPost post = new HttpPost(masterRealmUri("clients-registrations/openid-connect"));
+ post.setEntity(new StringEntity("{ invalid : invalid }"));
+ post.setHeader("Content-Type", APPLICATION_JSON);
+
+ HttpResponse response = httpClient.execute(post);
+ assertThat("status code", response.getStatusLine().getStatusCode(), is(400));
+
+ OAuth2ErrorRepresentation error = readError(response);
+ assertThat("error code", error.getError(), is(OAuthErrorException.INVALID_REQUEST));
+ assertThat("error description", error.getErrorDescription(), is(notNullValue()));
+ }
+
+ @Test
+ void uncaughtErrorAdmin() throws IOException {
+ HttpPost post = newAdminPost(adminUri("realms/master/components"));
+ post.setEntity(new StringEntity("{ invalid : invalid }"));
+
+ HttpResponse response = httpClient.execute(post);
+ assertThat("status code", response.getStatusLine().getStatusCode(), is(400));
+
+ OAuth2ErrorRepresentation error = readError(response);
+ assertThat("error code", error.getError(), is(OAuthErrorException.INVALID_REQUEST));
+ assertThat("error description", error.getErrorDescription(), is(notNullValue()));
+ }
+
+ @Test
+ void uncaughtErrorAdminPropertyError() throws IOException {
+ HttpPost post = newAdminPost(adminUri("realms/master/components"));
+ post.setEntity(new StringEntity("{\"
\":1}"));
+
+ HttpResponse response = httpClient.execute(post);
+ assertThat("status code", response.getStatusLine().getStatusCode(), is(400));
+
+ assertContentTypeJson(response);
+
+ String body = EntityUtils.toString(response.getEntity());
+ assertThat("XSS payload should be escaped in response", body,
+ containsString("Unrecognized field \\\"
\\\""));
+ }
+
+ @Test
+ void uncaughtError() {
+ driver.open(errorTestingUri("uncaught-error").toString());
+ errorPage.assertCurrent();
+ assertThat("error page message", errorPage.getError(), is("An internal server error has occurred"));
+ }
+
+ @Test
+ void uncaughtErrorHeaders() throws IOException {
+ HttpGet get = new HttpGet(errorTestingUri("uncaught-error"));
+ get.setHeader("Accept", MediaType.TEXT_HTML_UTF_8);
+
+ HttpResponse response = httpClient.execute(get);
+
+ for (BrowserSecurityHeaders header : BrowserSecurityHeaders.values()) {
+ String expectedValue = header.getDefaultValue();
+ if (expectedValue == null || expectedValue.isEmpty()) {
+ assertThat(header.getHeaderName() + " should be absent",
+ response.getFirstHeader(header.getHeaderName()), is(nullValue()));
+ } else {
+ Header actual = response.getFirstHeader(header.getHeaderName());
+ assertThat(header.getHeaderName() + " should be present", actual, is(notNullValue()));
+ assertThat(header.getHeaderName() + " value", actual.getValue(), is(expectedValue));
+ }
+ }
+ }
+
+ @Test
+ void errorPageException() {
+ oauth.realm("master");
+ oauth.client("nosuch");
+ oauth.openLoginForm();
+
+ errorPage.assertCurrent();
+ assertThat("error page message", errorPage.getError(), is("Client not found."));
+ }
+
+ @Test
+ void internationalisationEnabled() {
+ masterRealm.updateWithCleanup(r -> r
+ .internationalizationEnabled(true)
+ .defaultLocale("en")
+ .supportedLocales("en"));
+
+ checkPageNotFound("/realms/master/nosuch");
+ checkPageNotFound("/nosuch");
+ }
+
+ @Test
+ void switchLocale() {
+ masterRealm.updateWithCleanup(r -> r
+ .internationalizationEnabled(true)
+ .defaultLocale("en")
+ .supportedLocales("en", "de"));
+
+ checkPageNotFound("/realms/master/nosuch");
+ String localeUrl = driver.findElement(
+ By.xpath("//option[text()[contains(.,'Deutsch')]]")).getDomAttribute("value");
+ driver.open(localeUrl);
+ errorPage.assertCurrent();
+ }
+
+ @Test
+ void jsonProcessingException() throws IOException {
+ HttpPost post = newAdminPost(adminUri("realms/master/users"));
+ post.setEntity(new StringEntity("[]"));
+
+ HttpResponse response = httpClient.execute(post);
+ assertThat("status code", response.getStatusLine().getStatusCode(), is(400));
+
+ assertContentTypeJson(response);
+
+ OAuth2ErrorRepresentation error = readError(response);
+ assertThat("error code", error.getError(), is("unknown_error"));
+ }
+
+ private void checkPageNotFound(String path) {
+ URI uri = keycloakUrls.getBaseBuilder().path(path).build();
+ driver.open(uri.toString());
+ errorPage.assertCurrent();
+ assertThat("error message for path " + path, errorPage.getError(), is("Page not found"));
+ }
+
+ private HttpPost newAdminPost(URI uri) {
+ HttpPost post = new HttpPost(uri);
+ post.setHeader("Authorization", "Bearer " + adminClient.tokenManager().getAccessTokenString());
+ post.setHeader("Content-Type", APPLICATION_JSON);
+ return post;
+ }
+
+ private void assertContentTypeJson(HttpResponse response) {
+ Header contentType = response.getFirstHeader("Content-Type");
+ assertThat("Content-Type header", contentType, is(notNullValue()));
+ assertThat("Content-Type value", contentType.getValue(), is(MediaType.APPLICATION_JSON));
+ }
+
+ private OAuth2ErrorRepresentation readError(HttpResponse response) throws IOException {
+ return JsonSerialization.readValue(response.getEntity().getContent(), OAuth2ErrorRepresentation.class);
+ }
+
+ private URI errorTestingUri(String subPath) {
+ return KeycloakUriBuilder.fromUri(keycloakUrls.getMasterRealm())
+ .path("error-testing/" + subPath)
+ .build();
+ }
+
+ private URI masterRealmUri(String subPath) {
+ return KeycloakUriBuilder.fromUri(keycloakUrls.getMasterRealm())
+ .path(subPath)
+ .build();
+ }
+
+ private URI adminUri(String subPath) {
+ return keycloakUrls.getAdminBuilder().path(subPath).build();
+ }
+}
diff --git a/tests/base/src/test/java/org/keycloak/tests/suites/Base2TestSuite.java b/tests/base/src/test/java/org/keycloak/tests/suites/Base2TestSuite.java
index dc55f9058d78..a5c51bdb06c0 100644
--- a/tests/base/src/test/java/org/keycloak/tests/suites/Base2TestSuite.java
+++ b/tests/base/src/test/java/org/keycloak/tests/suites/Base2TestSuite.java
@@ -12,6 +12,7 @@
"org.keycloak.tests.common",
"org.keycloak.tests.cors",
"org.keycloak.tests.db",
+ "org.keycloak.tests.error",
"org.keycloak.tests.events",
"org.keycloak.tests.forms",
"org.keycloak.tests.i18n",
diff --git a/tests/custom-providers/src/main/java/org/keycloak/tests/providers/rest/ErrorTestingRealmResourceProvider.java b/tests/custom-providers/src/main/java/org/keycloak/tests/providers/rest/ErrorTestingRealmResourceProvider.java
new file mode 100644
index 000000000000..35d5757357da
--- /dev/null
+++ b/tests/custom-providers/src/main/java/org/keycloak/tests/providers/rest/ErrorTestingRealmResourceProvider.java
@@ -0,0 +1,41 @@
+package org.keycloak.tests.providers.rest;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.QueryParam;
+import jakarta.ws.rs.core.Response;
+
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.services.ErrorPage;
+import org.keycloak.services.resource.RealmResourceProvider;
+
+public class ErrorTestingRealmResourceProvider implements RealmResourceProvider {
+
+ private final KeycloakSession session;
+
+ ErrorTestingRealmResourceProvider(KeycloakSession session) {
+ this.session = session;
+ }
+
+ @Override
+ public Object getResource() {
+ return this;
+ }
+
+ @GET
+ @Path("display-error-message")
+ public Response displayErrorMessage(@QueryParam("message") String message) {
+ return ErrorPage.error(session, session.getContext().getAuthenticationSession(),
+ Response.Status.BAD_REQUEST, message == null ? "" : message);
+ }
+
+ @GET
+ @Path("uncaught-error")
+ public Response uncaughtError() {
+ throw new RuntimeException("Uncaught error");
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/tests/custom-providers/src/main/java/org/keycloak/tests/providers/rest/ErrorTestingRealmResourceProviderFactory.java b/tests/custom-providers/src/main/java/org/keycloak/tests/providers/rest/ErrorTestingRealmResourceProviderFactory.java
new file mode 100644
index 000000000000..543bf54d994a
--- /dev/null
+++ b/tests/custom-providers/src/main/java/org/keycloak/tests/providers/rest/ErrorTestingRealmResourceProviderFactory.java
@@ -0,0 +1,34 @@
+package org.keycloak.tests.providers.rest;
+
+import org.keycloak.Config;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.models.KeycloakSessionFactory;
+import org.keycloak.services.resource.RealmResourceProvider;
+import org.keycloak.services.resource.RealmResourceProviderFactory;
+
+public class ErrorTestingRealmResourceProviderFactory implements RealmResourceProviderFactory {
+
+ static final String ID = "error-testing";
+
+ @Override
+ public RealmResourceProvider create(KeycloakSession session) {
+ return new ErrorTestingRealmResourceProvider(session);
+ }
+
+ @Override
+ public String getId() {
+ return ID;
+ }
+
+ @Override
+ public void init(Config.Scope config) {
+ }
+
+ @Override
+ public void postInit(KeycloakSessionFactory factory) {
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/tests/custom-providers/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory b/tests/custom-providers/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
new file mode 100644
index 000000000000..3eb9ebc604c7
--- /dev/null
+++ b/tests/custom-providers/src/main/resources/META-INF/services/org.keycloak.services.resource.RealmResourceProviderFactory
@@ -0,0 +1 @@
+org.keycloak.tests.providers.rest.ErrorTestingRealmResourceProviderFactory
diff --git a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
index 6785ed882e48..d67d5d827c36 100644
--- a/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
+++ b/testsuite/integration-arquillian/servers/auth-server/services/testsuite-providers/src/main/java/org/keycloak/testsuite/rest/TestingResourceProvider.java
@@ -104,7 +104,6 @@
import org.keycloak.representations.idm.AuthenticationFlowRepresentation;
import org.keycloak.representations.idm.EventRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
-import org.keycloak.services.ErrorPage;
import org.keycloak.services.ErrorResponse;
import org.keycloak.services.managers.AuthenticationSessionManager;
import org.keycloak.services.resource.RealmResourceProvider;
@@ -740,12 +739,6 @@ public Response suspendPeriodicTasks() {
return Response.noContent().build();
}
- @GET
- @Path("/uncaught-error")
- public Response uncaughtError() {
- throw new RuntimeException("Uncaught error");
- }
-
private void suspendTask(String taskName) {
TimerProvider.TimerTaskContext taskContext = session.getProvider(TimerProvider.class).cancelTask(taskName);
@@ -1023,18 +1016,6 @@ public Response simulatePostRequest(@QueryParam("postRequestUrl") String postReq
}
- /**
- * Display message to Error Page - for testing purposes
- *
- * @param message message
- */
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/display-error-message")
- public Response displayErrorMessage(@QueryParam("message") String message) {
- return ErrorPage.error(session, session.getContext().getAuthenticationSession(), Response.Status.BAD_REQUEST, message == null ? "" : message);
- }
-
@GET
@Path("/get-provider-implementation-class")
@Produces(MediaType.APPLICATION_JSON)
diff --git a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
index 1839f2e30a28..9729178ebefc 100644
--- a/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
+++ b/testsuite/integration-arquillian/tests/base/src/main/java/org/keycloak/testsuite/client/resources/TestingResource.java
@@ -286,15 +286,6 @@ public UserRepresentation getUserByUsernameFromFedProviderFactory(@QueryParam("r
@Produces(MediaType.APPLICATION_JSON)
Response restorePeriodicTasks();
- @GET
- @Path("/uncaught-error")
- @Produces(MediaType.TEXT_HTML_UTF_8)
- Response uncaughtError();
-
- @GET
- @Path("/uncaught-error")
- Response uncaughtErrorJson();
-
@POST
@Path("/run-on-server")
@Consumes(MediaType.TEXT_PLAIN_UTF_8)
@@ -378,16 +369,6 @@ void reinitializeProviderFactoryWithSystemPropertiesScope(@QueryParam("provider-
Response simulatePostRequest(@QueryParam("postRequestUrl") String postRequestUrl,
@QueryParam("encodedFormParameters") String encodedFormParameters);
- /**
- * Display message to Error Page - for testing purposes
- *
- * @param message message
- */
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/display-error-message")
- Response displayErrorMessage(@QueryParam("message") String message);
-
/**
* @param providerClass Full name of class such as for example "org.keycloak.authentication.Authenticator"
* @param providerId providerId referenced in particular provider factory. Can be null (in this case we're returning default provider for particular providerClass)
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/EscapeErrorPageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/EscapeErrorPageTest.java
deleted file mode 100644
index cb31f7421124..000000000000
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/EscapeErrorPageTest.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2021 Red Hat, Inc. and/or its affiliates
- * and other contributors as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.keycloak.testsuite.error;
-
-import java.net.URI;
-import java.util.List;
-
-import org.keycloak.common.util.KeycloakUriBuilder;
-import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.testsuite.AbstractKeycloakTest;
-import org.keycloak.testsuite.pages.ErrorPage;
-
-import org.hamcrest.CoreMatchers;
-import org.jboss.arquillian.graphene.page.Page;
-import org.junit.Test;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-
-public class EscapeErrorPageTest extends AbstractKeycloakTest {
-
- @Page
- public ErrorPage errorPage;
-
- @Override
- public void addTestRealms(List testRealms) {
- }
-
- @Test
- public void innerScript() {
- checkMessage("\"
alert(1)/>\"", "\"alert(1)/>\"");
- }
-
- @Test
- public void innerURL() {
- checkMessage("\"See https://www.keycloak.org/docs\"", "\"See https://www.keycloak.org/docs\"");
- }
-
- @Test
- public void URL() {
- checkMessage("See https://www.keycloak.org/docs", "See https://www.keycloak.org/docs");
- }
-
- @Test
- public void ampersandEscape() {
- checkMessage("<img src="something">", "");
- }
-
- @Test
- public void hexEscape() {
- checkMessage("<img src=something/>", "");
- }
-
- @Test
- public void plainText() {
- checkMessage("It doesn't work", "It doesn't work");
- }
-
- @Test
- public void textWithPlus() {
- checkMessage("Fact: 1+1=2", "Fact: 1+1=2");
- }
-
- private void checkMessage(String queryParam, String expected) {
- try {
- final URI uri = KeycloakUriBuilder.fromUri(suiteContext.getAuthServerInfo().getContextRoot().toURI())
- .path("/auth/realms/master/testing/display-error-message")
- .queryParam("message", queryParam)
- .build();
-
- driver.navigate().to(uri.toURL());
- errorPage.assertCurrent();
- assertThat(errorPage.getError(), CoreMatchers.is(expected));
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java
deleted file mode 100644
index c03a54c3abd0..000000000000
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/error/UncaughtErrorPageTest.java
+++ /dev/null
@@ -1,270 +0,0 @@
-package org.keycloak.testsuite.error;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.net.URI;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-
-import jakarta.ws.rs.core.Response;
-
-import org.keycloak.OAuthErrorException;
-import org.keycloak.admin.client.resource.RealmResource;
-import org.keycloak.common.util.StreamUtil;
-import org.keycloak.http.simple.SimpleHttpResponse;
-import org.keycloak.models.BrowserSecurityHeaders;
-import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
-import org.keycloak.representations.idm.RealmRepresentation;
-import org.keycloak.testsuite.AbstractKeycloakTest;
-import org.keycloak.testsuite.arquillian.annotation.UncaughtServerErrorExpected;
-import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
-import org.keycloak.testsuite.pages.ErrorPage;
-import org.keycloak.util.JsonSerialization;
-import org.keycloak.utils.MediaType;
-
-import org.apache.http.Header;
-import org.apache.http.HeaderElement;
-import org.apache.http.client.methods.CloseableHttpResponse;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
-import org.apache.http.util.EntityUtils;
-import org.hamcrest.CoreMatchers;
-import org.jboss.arquillian.graphene.page.Page;
-import org.junit.Test;
-import org.junit.jupiter.api.Assertions;
-import org.openqa.selenium.By;
-
-import static org.keycloak.utils.MediaType.APPLICATION_JSON;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.core.Is.is;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-public class UncaughtErrorPageTest extends AbstractKeycloakTest {
-
- @Page
- private ErrorPage errorPage;
-
- @Override
- public void addTestRealms(List testRealms) {
- }
-
- @Test
- public void invalidResource() throws MalformedURLException {
- checkPageNotFound("/auth/nosuch");
- }
-
- @Test
- public void invalidRealm() throws MalformedURLException {
- checkPageNotFound("/auth/realms/nosuch");
- }
-
- @Test
- public void invalidRealmResource() throws MalformedURLException {
- checkPageNotFound("/auth/realms/master/nosuch");
- }
-
- @Test
- @UncaughtServerErrorExpected
- public void uncaughtErrorJson() throws IOException {
- Response response = testingClient.testing().uncaughtError();
- assertEquals(500, response.getStatus());
-
- InputStream is = (InputStream) response.getEntity();
- String responseString = StreamUtil.readString(is, StandardCharsets.UTF_8);
-
- Assertions.assertTrue(responseString.contains("An internal server error has occurred"));
- }
-
- @Test
- @UncaughtServerErrorExpected
- public void uncaughtErrorClientRegistration() throws IOException {
- try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
- HttpPost post = new HttpPost(suiteContext.getAuthServerInfo().getUriBuilder().path("/auth/realms/master/clients-registrations/openid-connect").build());
- post.setEntity(new StringEntity("{ invalid : invalid }"));
- post.setHeader("Content-Type", "application/json");
-
- try (CloseableHttpResponse response = client.execute(post)) {
- assertEquals(400, response.getStatusLine().getStatusCode());
-
- OAuth2ErrorRepresentation error = JsonSerialization.readValue(response.getEntity().getContent(), OAuth2ErrorRepresentation.class);
- assertEquals(OAuthErrorException.INVALID_REQUEST, error.getError());
- assertNotNull(error.getErrorDescription(), "found error with " + error.getError() + "/" + error.getErrorDescription());
- }
- }
- }
-
- @Test
- @UncaughtServerErrorExpected
- public void uncaughtErrorAdmin() throws IOException {
- try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
- String accessToken = adminClient.tokenManager().getAccessTokenString();
-
- HttpPost post = new HttpPost(suiteContext.getAuthServerInfo().getUriBuilder().path("/auth/admin/realms/master/components").build());
- post.setEntity(new StringEntity("{ invalid : invalid }"));
- post.setHeader("Authorization", "bearer " + accessToken);
- post.setHeader("Content-Type", "application/json");
-
- try (CloseableHttpResponse response = client.execute(post)) {
- assertEquals(400, response.getStatusLine().getStatusCode());
-
- OAuth2ErrorRepresentation error = JsonSerialization.readValue(response.getEntity().getContent(), OAuth2ErrorRepresentation.class);
- assertEquals(OAuthErrorException.INVALID_REQUEST, error.getError());
- assertNotNull(error.getErrorDescription(), "found error with " + error.getError() + "/" + error.getErrorDescription());
- }
- }
- }
-
- @Test
- @UncaughtServerErrorExpected
- public void uncaughtErrorAdminPropertyError() throws IOException {
- try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
- String accessToken = adminClient.tokenManager().getAccessTokenString();
-
- HttpPost post = new HttpPost(suiteContext.getAuthServerInfo().getUriBuilder().path("/auth/admin/realms/master/components").build());
- post.setEntity(new StringEntity("{\"
\":1}"));
- post.setHeader("Authorization", "bearer " + accessToken);
- post.setHeader("Content-Type", "application/json");
-
- try (CloseableHttpResponse response = client.execute(post)) {
- assertEquals(400, response.getStatusLine().getStatusCode());
-
- Header header = response.getFirstHeader("Content-Type");
- assertThat(header, notNullValue());
-
- // Verify the Content-Type is not text/html
- assertThat(Arrays.stream(header.getElements())
- .map(HeaderElement::getName)
- .filter(Objects::nonNull)
- .anyMatch(f -> f.equals(APPLICATION_JSON)), is(true));
-
- // The alert is not executed
- assertThat(EntityUtils.toString(response.getEntity()), CoreMatchers.containsString("Unrecognized field \\\"
\\\""));
- }
- }
- }
-
- @Test
- @UncaughtServerErrorExpected
- public void uncaughtError() throws MalformedURLException {
- URI uri = suiteContext.getAuthServerInfo().getUriBuilder().path("/auth/realms/master/testing/uncaught-error").build();
- driver.navigate().to(uri.toURL());
-
- assertTrue(errorPage.isCurrent());
- assertEquals("An internal server error has occurred", errorPage.getError());
- }
-
- @Test
- @UncaughtServerErrorExpected
- public void uncaughtErrorHeaders() throws IOException {
- URI uri = suiteContext.getAuthServerInfo().getUriBuilder().path("/auth/realms/master/testing/uncaught-error").build();
-
- try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
- SimpleHttpResponse response = SimpleHttpDefault.doGet(uri.toString(), client).header("Accept", MediaType.TEXT_HTML_UTF_8).asResponse();
-
- for (BrowserSecurityHeaders header : BrowserSecurityHeaders.values()) {
- String expectedValue = header.getDefaultValue();
-
- if (expectedValue == null || expectedValue.isEmpty()) {
- assertNull(response.getFirstHeader(header.getHeaderName()));
- } else {
- assertEquals(expectedValue, response.getFirstHeader(header.getHeaderName()));
- }
- }
- }
- }
-
- @Test
- public void errorPageException() {
- oauth.realm("master");
- oauth.client("nosuch");
- oauth.openLoginForm();
-
- assertTrue(errorPage.isCurrent());
- assertEquals("Client not found.", errorPage.getError());
- }
-
- @Test
- public void internationalisationEnabled() throws MalformedURLException {
- RealmResource testRealm = realmsResouce().realm("master");
- RealmRepresentation rep = testRealm.toRepresentation();
- rep.setInternationalizationEnabled(true);
- rep.setDefaultLocale("en");
- rep.setSupportedLocales(Collections.singleton("en"));
- testRealm.update(rep);
-
- try {
- checkPageNotFound("/auth/realms/master/nosuch");
- checkPageNotFound("/auth/nosuch");
- } finally {
- rep.setInternationalizationEnabled(false);
- testRealm.update(rep);
- }
- }
-
- @Test
- public void switchLocale() throws MalformedURLException {
- RealmResource testRealm = realmsResouce().realm("master");
- RealmRepresentation rep = testRealm.toRepresentation();
- rep.setInternationalizationEnabled(true);
- rep.setDefaultLocale("en");
- HashSet supported = new HashSet<>();
- supported.add("en");
- supported.add("de");
- rep.setSupportedLocales(supported);
- testRealm.update(rep);
-
- try {
- checkPageNotFound("/auth/realms/master/nosuch");
- String url = driver.findElement(By.xpath("//option[text()[contains(.,'Deutsch')]]")).getAttribute("value");
- driver.navigate().to(url);
- errorPage.assertCurrent();
- } finally {
- rep.setInternationalizationEnabled(false);
- testRealm.update(rep);
- }
- }
-
- private void checkPageNotFound(String path) throws MalformedURLException {
- URI uri = suiteContext.getAuthServerInfo().getUriBuilder().path(path).build();
- driver.navigate().to(uri.toURL());
-
- assertTrue(errorPage.isCurrent());
- assertEquals("Page not found", errorPage.getError());
- }
-
- @Test
- public void jsonProcessingException() throws IOException {
- try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
- String accessToken = adminClient.tokenManager().getAccessTokenString();
-
- // send an empty array to the user endpoint which expects a User json object
- HttpPost post = new HttpPost(suiteContext.getAuthServerInfo().getUriBuilder().path("/auth/admin/realms/master/users").build());
- post.setEntity(new StringEntity("[]"));
- post.setHeader("Authorization", "bearer " + accessToken);
- post.setHeader("Content-Type", "application/json");
-
- try (CloseableHttpResponse response = client.execute(post)) {
- assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), response.getStatusLine().getStatusCode());
-
- Header header = response.getFirstHeader("Content-Type");
- assertThat(header, notNullValue());
- assertEquals(MediaType.APPLICATION_JSON, header.getValue());
-
- OAuth2ErrorRepresentation error = JsonSerialization.readValue(response.getEntity().getContent(), OAuth2ErrorRepresentation.class);
- assertEquals("unknown_error", error.getError());
- }
- }
- }
-}
diff --git a/testsuite/integration-arquillian/tests/base/testsuites/base-suite b/testsuite/integration-arquillian/tests/base/testsuites/base-suite
index 62a43aacda97..6e3381e02a3d 100644
--- a/testsuite/integration-arquillian/tests/base/testsuites/base-suite
+++ b/testsuite/integration-arquillian/tests/base/testsuites/base-suite
@@ -10,7 +10,6 @@ composites,4
cookies,4
docker,4
domainextension,4
-error,4
exportimport,4
federation,5
forms,5