fix: remove the reliance on allowed classes (#27368)
closes: #25038 Signed-off-by: Steve Hawkins <shawkins@redhat.com>
This commit is contained in:
parent
a4a6b4f015
commit
be3e2fabc4
20 changed files with 212 additions and 21 deletions
|
@ -102,7 +102,10 @@ import org.keycloak.representations.provider.ScriptProviderDescriptor;
|
|||
import org.keycloak.representations.provider.ScriptProviderMetadata;
|
||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||
import org.keycloak.services.ServicesLogger;
|
||||
import org.keycloak.services.resources.JsResource;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
import org.keycloak.services.resources.LoadBalancerResource;
|
||||
import org.keycloak.services.resources.admin.AdminRoot;
|
||||
import org.keycloak.theme.ClasspathThemeProviderFactory;
|
||||
import org.keycloak.theme.ClasspathThemeResourceProviderFactory;
|
||||
import org.keycloak.theme.FolderThemeProviderFactory;
|
||||
|
@ -640,6 +643,21 @@ class KeycloakProcessor {
|
|||
buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple(
|
||||
KeycloakApplication.class.getName())), false));
|
||||
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.ADMIN_API)) {
|
||||
buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple(
|
||||
AdminRoot.class.getName())), false));
|
||||
}
|
||||
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.JS_ADAPTER)) {
|
||||
buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple(
|
||||
JsResource.class.getName())), false));
|
||||
}
|
||||
|
||||
if (!Profile.isFeatureEnabled(Profile.Feature.MULTI_SITE)) {
|
||||
buildTimeConditionBuildItemBuildProducer.produce(new BuildTimeConditionBuildItem(index.getIndex().getClassByName(DotName.createSimple(
|
||||
LoadBalancerResource.class.getName())), false));
|
||||
}
|
||||
|
||||
KeycloakHandlerChainCustomizer chainCustomizer = new KeycloakHandlerChainCustomizer();
|
||||
|
||||
scanner.produce(new MethodScannerBuildItem(new MethodScanner() {
|
||||
|
|
|
@ -17,23 +17,20 @@
|
|||
|
||||
package org.keycloak.quarkus.runtime.integration.jaxrs;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import io.quarkus.runtime.ShutdownEvent;
|
||||
import io.quarkus.runtime.StartupEvent;
|
||||
import io.smallrye.common.annotation.Blocking;
|
||||
|
||||
import jakarta.enterprise.event.Observes;
|
||||
import jakarta.ws.rs.ApplicationPath;
|
||||
|
||||
import org.keycloak.config.HostnameOptions;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.platform.Platform;
|
||||
import org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory;
|
||||
import org.keycloak.quarkus.runtime.integration.QuarkusPlatform;
|
||||
import org.keycloak.quarkus.runtime.services.resources.DebugHostnameSettingsResource;
|
||||
import org.keycloak.services.resources.KeycloakApplication;
|
||||
|
||||
import io.quarkus.runtime.ShutdownEvent;
|
||||
import io.quarkus.runtime.StartupEvent;
|
||||
import io.smallrye.common.annotation.Blocking;
|
||||
import java.util.Set;
|
||||
|
||||
import jakarta.enterprise.event.Observes;
|
||||
import jakarta.ws.rs.ApplicationPath;
|
||||
|
||||
@ApplicationPath("/")
|
||||
@Blocking
|
||||
|
@ -69,13 +66,6 @@ public class QuarkusKeycloakApplication extends KeycloakApplication {
|
|||
|
||||
@Override
|
||||
public Set<Class<?>> getClasses() {
|
||||
Set<Class<?>> classes = new HashSet<>(super.getClasses());
|
||||
|
||||
classes.add(QuarkusObjectMapperResolver.class);
|
||||
classes.add(CloseSessionHandler.class);
|
||||
|
||||
classes.add(DebugHostnameSettingsResource.class);
|
||||
|
||||
return classes;
|
||||
return Set.of();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ import jakarta.ws.rs.core.Context;
|
|||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.MediaType;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.HashMap;
|
||||
|
@ -44,6 +46,7 @@ import java.util.LinkedHashMap;
|
|||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
@Provider
|
||||
@Path("/realms")
|
||||
@EndpointDisabled(name = "kc.hostname-debug", stringValue = "false", disableIfMissing = true)
|
||||
public class DebugHostnameSettingsResource {
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright 2024 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.it.jaxrs.filter;
|
||||
|
||||
import io.vertx.core.http.HttpServerRequest;
|
||||
import io.vertx.core.net.SocketAddress;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
||||
import jakarta.ws.rs.container.ContainerRequestFilter;
|
||||
import jakarta.ws.rs.container.PreMatching;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
@Provider
|
||||
@PreMatching
|
||||
public class TestFilter implements ContainerRequestFilter {
|
||||
|
||||
private static final Logger LOG = Logger.getLogger(TestFilter.class);
|
||||
|
||||
@Context
|
||||
UriInfo info;
|
||||
|
||||
@Context
|
||||
HttpServerRequest request;
|
||||
|
||||
@Context
|
||||
KeycloakSession session;
|
||||
|
||||
@Override
|
||||
public void filter(ContainerRequestContext requestContext) throws IOException {
|
||||
final String method = requestContext.getMethod();
|
||||
final String path = info.getPath();
|
||||
final SocketAddress address = request.remoteAddress();
|
||||
|
||||
KeycloakSession s = null;
|
||||
try {
|
||||
if (session != null) {
|
||||
session.getContext();
|
||||
}
|
||||
s = session;
|
||||
} catch (RuntimeException e) {
|
||||
// should say something like Normal scoped producer method may not return null: org.keycloak.quarkus.runtime.integration.cdi.KeycloakBeanProducer.getKeycloakSession()
|
||||
}
|
||||
|
||||
LOG.infof("Request %s %s has context request %s has keycloaksession %s", method, path, address != null, s != null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2024 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.it.jaxrs.filter;
|
||||
|
||||
import org.keycloak.it.TestProvider;
|
||||
|
||||
public class TestFilterTestProvider implements TestProvider {
|
||||
|
||||
@Override
|
||||
public Class<?>[] getClasses() {
|
||||
return new Class[] {TestFilter.class};
|
||||
}
|
||||
|
||||
}
|
50
quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/JaxRsDistTest.java
vendored
Normal file
50
quarkus/tests/integration/src/test/java/org/keycloak/it/cli/dist/JaxRsDistTest.java
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2024 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.it.cli.dist;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.keycloak.it.jaxrs.filter.TestFilterTestProvider;
|
||||
import org.keycloak.it.junit5.extension.CLIResult;
|
||||
import org.keycloak.it.junit5.extension.DistributionTest;
|
||||
import org.keycloak.it.junit5.extension.RawDistOnly;
|
||||
import org.keycloak.it.junit5.extension.TestProvider;
|
||||
import org.keycloak.it.utils.KeycloakDistribution;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static io.restassured.RestAssured.when;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@DistributionTest(keepAlive = true)
|
||||
@RawDistOnly(reason = "Containers are immutable")
|
||||
public class JaxRsDistTest {
|
||||
|
||||
@Test
|
||||
@TestProvider(TestFilterTestProvider.class)
|
||||
public void requestFilterTest(KeycloakDistribution dist) {
|
||||
CLIResult cliResult = dist.run("start-dev");
|
||||
|
||||
cliResult.assertStartedDevMode();
|
||||
|
||||
assertEquals(200, when().get("/").getStatusCode());
|
||||
|
||||
Awaitility.await().atMost(5, TimeUnit.SECONDS).untilAsserted(
|
||||
() -> cliResult.assertMessage("Request GET / has context request true has keycloaksession false"));
|
||||
}
|
||||
}
|
|
@ -45,5 +45,7 @@ public interface TestProvider {
|
|||
* name of the manifest resource that should be created in the provider JAR file.
|
||||
* @return
|
||||
*/
|
||||
Map<String, String> getManifestResources();
|
||||
default Map<String, String> getManifestResources() {
|
||||
return Map.of();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import jakarta.ws.rs.BadRequestException;
|
|||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.ExceptionMapper;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
|
@ -31,6 +33,7 @@ import org.keycloak.models.KeycloakSession;
|
|||
*
|
||||
* <code>org.jboss.resteasy.plugins.providers.jackson.UnrecognizedPropertyExceptionHandler</code>
|
||||
*/
|
||||
@Provider
|
||||
public class KcUnrecognizedPropertyExceptionHandler implements ExceptionMapper<UnrecognizedPropertyException> {
|
||||
|
||||
@Context
|
||||
|
|
|
@ -32,6 +32,8 @@ import jakarta.ws.rs.WebApplicationException;
|
|||
import jakarta.ws.rs.core.HttpHeaders;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.ExceptionMapper;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
|
@ -40,6 +42,7 @@ import java.util.Properties;
|
|||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Provider
|
||||
public class KeycloakErrorHandler implements ExceptionMapper<Throwable> {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(KeycloakErrorHandler.class);
|
||||
|
|
|
@ -20,16 +20,17 @@
|
|||
package org.keycloak.services.error;
|
||||
|
||||
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
|
||||
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
|
||||
import jakarta.ws.rs.BadRequestException;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.ExceptionMapper;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
||||
/**
|
||||
* Override explicitly added ExceptionMapper for handling {@link MismatchedInputException} in RestEasy Jackson
|
||||
*/
|
||||
@Provider
|
||||
public class KeycloakMismatchedInputExceptionHandler implements ExceptionMapper<MismatchedInputException> {
|
||||
|
||||
@Context
|
||||
|
|
|
@ -26,10 +26,12 @@ import jakarta.annotation.Priority;
|
|||
import jakarta.ws.rs.container.ContainerResponseContext;
|
||||
import jakarta.ws.rs.container.ContainerResponseFilter;
|
||||
import jakarta.ws.rs.container.PreMatching;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@Provider
|
||||
@PreMatching
|
||||
@Priority(10)
|
||||
public class KeycloakSecurityHeadersFilter implements ContainerResponseFilter {
|
||||
|
|
|
@ -33,6 +33,8 @@ import jakarta.ws.rs.QueryParam;
|
|||
import jakarta.ws.rs.core.CacheControl;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
|
@ -40,6 +42,7 @@ import java.io.InputStream;
|
|||
*
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@Provider
|
||||
@Path("/js")
|
||||
public class JsResource {
|
||||
|
||||
|
|
|
@ -71,6 +71,8 @@ import java.util.Set;
|
|||
/**
|
||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*
|
||||
* Note: the classes and singletons are not used by Quarkus - see the KeycloakProcessor to do exclusions
|
||||
*/
|
||||
public class KeycloakApplication extends Application {
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ import jakarta.ws.rs.Path;
|
|||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.health.LoadBalancerCheckProvider;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
|
@ -37,6 +39,7 @@ import java.util.Set;
|
|||
*
|
||||
* @author <a href="mailto:aschwart@redhat.com">Alexander Schwartz</a>
|
||||
*/
|
||||
@Provider
|
||||
@Path("/lb-check")
|
||||
@NonBlocking
|
||||
public class LoadBalancerResource {
|
||||
|
|
|
@ -53,6 +53,8 @@ import jakarta.ws.rs.core.Response;
|
|||
import jakarta.ws.rs.core.Response.ResponseBuilder;
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Comparator;
|
||||
|
||||
|
@ -60,6 +62,7 @@ import java.util.Comparator;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@Provider
|
||||
@Path("/realms")
|
||||
public class RealmsResource {
|
||||
protected static final Logger logger = Logger.getLogger(RealmsResource.class);
|
||||
|
|
|
@ -22,7 +22,9 @@ import org.keycloak.utils.MediaType;
|
|||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.Path;
|
||||
import jakarta.ws.rs.Produces;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
@Provider
|
||||
@Path("/robots.txt")
|
||||
public class RobotsResource {
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.keycloak.theme.Theme;
|
|||
|
||||
import jakarta.ws.rs.core.Context;
|
||||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
@ -56,6 +57,7 @@ import static java.util.stream.Collectors.toSet;
|
|||
*
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@Provider
|
||||
@Path("/resources")
|
||||
public class ThemeResource {
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ import jakarta.ws.rs.core.MultivaluedMap;
|
|||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.Response.ResponseBuilder;
|
||||
import jakarta.ws.rs.core.Response.Status;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.common.ClientConnection;
|
||||
import org.keycloak.common.Profile;
|
||||
|
@ -64,6 +66,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||
/**
|
||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||
*/
|
||||
@Provider
|
||||
@Path("/")
|
||||
public class WelcomeResource {
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ import jakarta.ws.rs.core.HttpHeaders;
|
|||
import jakarta.ws.rs.core.Response;
|
||||
import jakarta.ws.rs.core.UriBuilder;
|
||||
import jakarta.ws.rs.core.UriInfo;
|
||||
import jakarta.ws.rs.ext.Provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
@ -59,6 +61,7 @@ import java.util.Properties;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@Provider
|
||||
@Path("/admin")
|
||||
public class AdminRoot {
|
||||
protected static final Logger logger = Logger.getLogger(AdminRoot.class);
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.stream.Stream;
|
|||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
@Provider
|
||||
public class ObjectMapperResolver implements ContextResolver<ObjectMapper> {
|
||||
protected ObjectMapper mapper;
|
||||
|
||||
|
|
Loading…
Reference in a new issue