Cannot register a filter to the CXF bundle in my bundle

903 Views Asked by At

I am having trouble using the Pax Web Whiteboard service to register a javax.servlet.Filter to a running JaxRS endpoint registered through CXF. I have tried a few different approaches, namely registering the Filter as a service, and using the org.ops4j.pax.web.service.WebContainer to register the filter directly.

For my test, i booted karaf, and installed pax-web, webconsole, cxf and the pax-web whiteboard service. I the registered a bundle with a blueprint:

<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:jaxrs="http://cxf.apache.org/blueprint/jaxrs"
     xmlns:cxf="http://cxf.apache.org/blueprint/core"
     xsi:schemaLocation="
     http://www.osgi.org/xmlns/blueprint/v1.0.0 http://www.osgi.org/xmlns/blueprint/v1.0.0/blueprint.xsd
     http://cxf.apache.org/blueprint/jaxrs http://cxf.apache.org/schemas/blueprint/jaxrs.xsd
     http://cxf.apache.org/blueprint/core http://cxf.apache.org/schemas/blueprint/core.xsd
                 ">

     <cxf:bus>
        <cxf:features>
            <cxf:logging/>
        </cxf:features>
    </cxf:bus>

     <jaxrs:server id="webfiltersample" address="/webfilter">
        <jaxrs:serviceBeans>
           <ref component-id="serviceBean" />
        </jaxrs:serviceBeans>
     </jaxrs:server>

     <service id="servletFilterService" interface="javax.servlet.Filter">
        <service-properties>
            <entry key="filter-name" value="BasicWebFilter"/>
            <entry key="urlPatterns" value="/*"/>
            <entry key="initParams" value=""/>
        </service-properties>
    <bean class="test.webfilter.BasicWebFilter"/>
</service>

    <bean id="serviceBean" class="test.webfilter.WebFilterSample" init-method="init" destroy-method="destroy">
    <property name="bundleContext" ref="blueprintBundleContext"/>
    </bean>
</blueprint>

However, this filter is never called. I have tried both using servlet names and urlpatterns, going so far as to attempt the urlpattern /* I then tried a slightly different approach, removing the service declaration from the blueprint, and adding the filter directly though the init method of the blueprint instead:

public void init(){
    logger.info("Starting Sample");
    filter = new WebFilter();
    ServiceReference<WebContainer> ref = bundleContext.getServiceReference(BasicWebFilter.class);
    WebContainer container = bundleContext.getService(ref);
    logger.info("Registering "+ filter + " with "+ container);
    container.registerFilter(filter, new String[]{"/cxf/*"}, new String[]{""}, null, null);
    bundleContext.ungetService(ref);
    }

The method is indeed called, as reflected by the log statements, but the filter is still not executed.

So am i completely wrong in how this works? My "Application" is really just an endpoint registered to the CXF servlet. This part is working, and i can call the REST services defined therein. But no matter what i do, the filter is not executing. I am working with a few libraries here that i don't really know that well (Servlets/Filters, Pax-Web and the Writeboard extender) do i have no idea why exactly this isn't working? My guess is that there are different httpcontexts for each bundle, and that i can't simply register a filter for another bundle (CXF) in my own test bundle.

If this is true, can someone tell me how to properly go about this problem? I could get the CXF bundles bundlecontext and register the filter to that, but that seems like a terrible horrible hack. If that is NOT the case, can someone tell me why this is not working?

2

There are 2 best solutions below

1
Achim Nierbeck On

You are right, every bundle should have it's own httpContext. With Pax-Web it's possible to have shared httpContextes. For this you need to enable it for the bundle initially registering the httpContext. Though in this case it's the cxf bundle that does take care of it. As the shared context is a pax-web only feature (till v6 where OSGi R6 is implemented), this won't be added to cxf as cxf tends to rely on the smallest possible solution, which is the HttpService.
Basically even though it's possible to share httpContextes with different bundles, it's not possible for you with this scenario.

0
Christian Schneider On

I propose to use JAAS instead of shiro as a way to login and store the authentication information. You can then use this in shiro as well as in other security implementations to do the authorization.

For CXF there is a JAASLoginFeature. It can receive basic auth as well as UserNameToken. See https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=42568988

This also has the advantage that it works the same way as the standard karaf authentication. So by default you can define users and groups in etc/users.properties but you can also for example attach karaf to ldap.

If you use blueprint then you can use blueprint-authz do role based authorization using annotations. See https://github.com/apache/aries/tree/trunk/blueprint/blueprint-authz and https://github.com/apache/aries/blob/trunk/blueprint/blueprint-itests/src/test/java/org/apache/aries/blueprint/itests/authz/testbundle/impl/SecuredServiceImpl.java