开发者

CXF OSGi bundle - register a filter against CXFServlet?

I've got the CXF OSGi bundle deployed on a karaf container with several endpoints ea开发者_高级运维ch in their own bundle. The endpoints are a mix of JAX-RS and JAX-WS flavors. I'd like to enable some security on the endpoints with JOSSO and need to register a servlet filter to do so. Obviously, with no web.xml to declare the filter, I need to register them in the OSGi service registry.

I've attempted to use the pax-web http whiteboard to register a filter but the doFilter method is never invoked. I noticed the Distributed OSGI cxf implementation has a provision for setting a org.apache.cxf.httpservice.filter property to true on the filter and specifying a dummy string for servletNames so as not to confuse pax-web whiteboard. Is there something similar for the standard CXF (non-distributed) OSGi bundle that I can do to register a servlet filter?


After lots of digging I was able to set a filter to the CXF Servlet with Felix + PAX Web. The trick is to register the filter from within the CXF bundle (there is a distinct http context for each bundle).

In my code I fetched the bundle context, called getBundles(), located the cxf bundle and obtained the bundle context of the CXF bundle. Then I registered the filter on the CXF bundle's context. I feel very dirty now, but it works.

I recall to have seen a recommendation to create a fragement bundle for configuration of PAX's Jetty server, this would probably also work for registering a filter - however I didn't want to create another artifact in our project at the current time.


I found myself in the situation to write a global filter for Apache CXF, but couldn't figure out how to do it.

Some investigations revealed, that Apache CXF is using the HttpService from OSGi and registers the servlet directly. See https://github.com/apache/cxf/blob/90df32db98d8fc76f091723561f42c6d16021db4/rt/transports/http/src/main/java/org/apache/cxf/transport/http/osgi/ServletExporter.java#L126 for more details.

You can see, that a default http context is used, which is bound to the bundle. See https://github.com/ops4j/org.ops4j.pax.web/blob/d2172a91ad2579714d40b509d6c420e5c28fa2d0/pax-web-runtime/src/main/java/org/ops4j/pax/web/service/internal/HttpServiceStarted.java#L337

Therefore you cannot simply expose a filter and have it work for the CXF Servlet.

However, as froh42 was saying, it is possible to fetch the bundle, exporting the CXF Servlet, and use its bundle context to register the filter. If you are in doubt, which bundle you want to look out for, use the following command in the Karaf shell: service:list javax.servlet.ServletContext and it will reveal the symbolic name of the bundle exposing the contexts:

[javax.servlet.ServletContext]
------------------------------
 osgi.web.contextname = default
 osgi.web.contextpath = /
 osgi.web.symbolicname = org.apache.cxf.cxf-rt-transports-http
 osgi.web.version = 3.5.0
 service.bundleid = 97
 service.id = 218
 service.scope = singleton
Provided by :
 Apache CXF Runtime HTTP Transport (97)
Used by:
 OPS4J Pax Web - Runtime (182)

Long story short, this is how you would write such registration logic. Be aware, that you need to use WebContainer from the pax-web-api module, as that allows you to register a filter. HttpService does not have that capability.

package org.example.cxf.filter;

import org.ops4j.pax.web.service.WebContainer;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.http.HttpContext;

import java.util.Collection;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Component
public class CxfFilterRegistrator {

    @Activate
    public void onActivate(BundleContext bundleContext) throws InvalidSyntaxException {
        final WebContainer cxfWebContainer = findCxfWebContainerOrFail(bundleContext);
        final HttpContext otherContext = cxfWebContainer.createDefaultHttpContext();
        final Dictionary<String, String> initProperties = new Hashtable<>();
        initProperties.put("key", "value");
        cxfWebContainer.registerFilter(MyFilter.class, new String[]{"/*"}, null, initProperties, otherContext);
    }

    @Deactivate
    public void onDeactivate(BundleContext bundleContext) throws InvalidSyntaxException {
        final WebContainer cxfWebContainer = findCxfWebContainerOrFail(bundleContext);
        cxfWebContainer.unregisterFilter(MyFilter.class);
    }

    private WebContainer findCxfWebContainerOrFail(final BundleContext bundleContext) throws InvalidSyntaxException {
        final List<Bundle> cxf = Stream.of(bundleContext.getBundles())
                .filter(bundle -> bundle.getSymbolicName().equals("org.apache.cxf.cxf-rt-transports-http"))
                .collect(Collectors.toList());
        if (cxf.isEmpty()) {
            throw new IllegalStateException("CXF not found, Bailing");
        }
        final BundleContext cxfBundleContext = cxf.get(0).getBundleContext();
        final Collection<ServiceReference<WebContainer>> serviceReferences = cxfBundleContext.getServiceReferences(WebContainer.class, null);
        final WebContainer otherWebContainer = cxfBundleContext.getService(serviceReferences.iterator().next());
        return otherWebContainer;
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜