Search code examples
keycloakwildfly

Keycloak: Add custom extension io.undertow.servlet.ServletExtension


I wanted to add a custom servlet extension to Keycloak which would install a http handler that gets invoked on every request sent to Keycloak and sets up some logging MDC context that our custom SPI code can use for logging the incoming request traces correctly.

Following the docs here I created a custom extension class:

public class UndertowHandlerExtension implements ServletExtension {
    @Override
    public void handleDeployment(DeploymentInfo deploymentInfo, ServletContext servletContext) {
        deploymentInfo.addInnerHandlerChainWrapper(TraceIdCapturingHandler::new);
    }
}

And have defined my custom http handler TraceIdCapturingHandler in the same JAR file. I also added a file to META-INF/services/io.undertow.servlet.ServletExtension and set the fully qualified reference to the extension class. I also updated my deployments jboss-deployment-structure.xml and added the following 2 entries as dependencies:

      <module name="io.undertow.servlet" />
      <module name="javax.servlet.api" />

However, when my deployment is created the extension is not being invoked and my filter is not executing. Is there something I am missing in terms of how to configure Wildfly for Keycloak so that my extension and handler are installed and used correctly?

EDIT:

After doing a bit of digging I realized I was headed down the wrong path. Looked at this repository and I think I need a custom RealResourceProvider as shown here which in turn can install my filter by obtaining an instance of ResteasyProviderFactory and invoking getContainerRequestFilterRegistry().registerSingleton().

Will try this out and report back.


Solution

  • Please see the edit above for my question. I was able to implement a RealmResourceProviderFactory instance that initialized the filters I needed on startup in the init() method:

    
        @Override
        public void init(Config.Scope scope) {
            log.info("Initializing");
            initializeKeycloakFilters();
        }
    
        private void initializeKeycloakFilters() {
            ResteasyProviderFactory providerFactory = ResteasyProviderFactory.getInstance();
            TraceIdCapturingFilter filter = new TraceIdCapturingFilter();
            providerFactory.getContainerRequestFilterRegistry().registerSingleton(filter);
        }