CXF OSGi bundle - зарегистрировать фильтр для CXFServlet?

У меня есть пакет CXF OSGi, развернутый в контейнере karaf с несколькими конечными точками, каждая в своем собственном пакете. Конечные точки представляют собой смесь вкусов JAX-RS и JAX-WS. Я хотел бы включить некоторую защиту на конечных точках с помощью JOSSO, и для этого нужно зарегистрировать фильтр сервлетов. Очевидно, что без web.xml для объявления фильтра мне нужно зарегистрировать их в реестре службы OSGi.

Я пытался использовать доску pax-web http для регистрации фильтра, но метод doFilter никогда не вызывался. Я заметил, что в реализации Distributed OSGI cxf есть условие для установки для свойства org.apache.cxf.httpservice.filter значения true в фильтре и указания фиктивной строки для servletNames, чтобы не перепутать интерактивную доску pax-web. Есть ли что-то похожее для стандартного CXF (нераспределенного) пакета OSGi, которое я могу сделать, чтобы зарегистрировать фильтр сервлета?

2 ответа

Решение

После многих копаний я смог установить фильтр для сервлета CXF с помощью Felix + PAX Web. Хитрость заключается в том, чтобы зарегистрировать фильтр в пакете CXF (для каждого пакета существует отдельный http-контекст).

В моем коде я извлек контекст пакета, называемый getBundles(), нашел пакет cxf и получил контекст пакета CXF. Затем я зарегистрировал фильтр в контексте пакета CXF. Сейчас я чувствую себя очень грязно, но это работает.

Напомню, что я видел рекомендацию о создании пакета fragement для конфигурации сервера Jetty PAX, это, вероятно, также будет работать для регистрации фильтра - однако я не хотел создавать еще один артефакт в нашем проекте в настоящее время.

Я оказался в ситуации, когда нужно было написать глобальный фильтр для Apache CXF, но не мог понять, как это сделать.

Некоторые исследования показали, что Apache CXF использует OSGi и напрямую регистрирует сервлет. Подробнее см. https://github.com/apache/cxf/blob/90df32db98d8fc76f091723561f42c6d16021db4/rt/transports/http/src/main/java/org/apache/cxf/transport/http/osgi/ServletExporter.java#L126 .

Вы можете видеть, что используется контекст http по умолчанию, который привязан к пакету. См. 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

Следовательно, вы не можете просто открыть фильтр и заставить его работать с сервлетом CXF.

Однако, как говорил froh42, можно получить пакет, экспортировав сервлет CXF, и использовать его контекст пакета для регистрации фильтра. Если вы сомневаетесь, какой пакет вам нужен, используйте следующую команду в оболочке Karaf: service:list javax.servlet.ServletContextи он покажет символическое имя пакета, раскрывающего контексты:

      [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)

Короче говоря, вот как вы могли бы написать такую ​​логику регистрации. Имейте в виду, что вам нужно использовать WebContainerот pax-web-apiмодуль, так как это позволяет зарегистрировать фильтр. HttpServiceне имеет такой возможности.

      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;
    }
}
Другие вопросы по тегам