Управление доступом на стороне сервера с использованием DN сертификата X509 клиента

Народы,

Я использую JAX-RS с Jersey 2.17 и Grizzly в качестве своего HTTP-сервера. У меня настроена и работает аутентификация клиента, однако я пытаюсь реализовать контроль доступа к DN сертификата X.509 клиента. Это даст мне возможности, эквивалентные тем, что у меня есть с настроенными Apache httpd и FakeBasicAuth.

Я попытался использовать ContainerRequestFilter, но, похоже, нашел способ получить ссылку на DN клиента, связанный с сеансом TLS. Может ли кто-нибудь показать мне способ получить доступ к сертификату с помощью ContainerRequestFilter или любого другого механизма для достижения той же конечной цели?

РЕДАКТИРОВАТЬ: я попробовал запрос "@javax.ws.rs.core.Context HttpServletRequest;" прошлой ночью перед публикацией, но контекст HttpServletRequest всегда был нулевым. Я использую GrizzlyHttpServerFactory следующим образом:

GrizzlyHttpServerFactory.createHttpServer(
                getServerURI(), getResourceConfig(), true,
                new SSLEngineConfigurator(sslContext.get())
                    .setNeedClientAuth(true).setClientMode(false))

Который, как полагают, не является контейнером сервлета и, следовательно, не поддерживает контекст HttpServletRequest. Я быстро посмотрел на GrizzlyWebContainerFactory, но инициализация совершенно другая, и я хотел бы избежать этой боли. Есть ли другой способ получить доступ к сертификату пользователя в «javax.ws.rs.container.ContainerRequestFilter»?

Благодарю вас!

Джон


person Hacksaw    schedule 18.03.2015    source источник
comment
См. Спецификацию сервлета. Сертификат клиента доступен через свойство запроса.   -  person user207421    schedule 18.03.2015


Ответы (2)


Из спецификации сервлета Java:

Если с запросом связан SSL-сертификат, он должен быть представлен контейнером сервлета программисту сервлета в виде массива объектов типа java.security.cert.X509Certificate и доступен через атрибут ServletRequest типа javax.servlet.request.X509Certificate.

Порядок этого массива определяется в порядке возрастания доверия. Первый сертификат в цепочке — это сертификат, установленный клиентом, следующий — тот, который используется для аутентификации первого, и так далее.

На практике это означает:

X509Certificate[] certs = (X509Certificate[])
    req.getAttribute("javax.servlet.request.X509Certificate")
if (certs != null && certs.length > 0) {
    X509Certificate cert = certs[0];  // the client certificate
    // further processing (extract and compare DN, etc)
}

Если у вас еще нет доступа к ServletRequest, вы можете использовать @Context, чтобы включить его в свой класс обслуживания:

@javax.ws.rs.core.Context
HttpServletRequest req;
person frasertweedale    schedule 18.03.2015
comment
Спасибо за ответ. Я пробовал это прошлой ночью перед публикацией, но контекст HttpServletRequest всегда был нулевым, но теперь, когда вы конкретно определили это как решение, я провел дополнительные раскопки. См. выше. - person Hacksaw; 18.03.2015

С помощью списка рассылки Джерси я смог найти ответ. Вот пример работающего RequestFilter:

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.ext.Provider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Provider
@PreMatching
public class SecurityFilter implements ContainerRequestFilter {
    private final Logger log = LoggerFactory.getLogger(getClass());

    @javax.inject.Inject
    private javax.inject.Provider<org.glassfish.grizzly.http.server.Request> request;

    @Override
    public void filter(ContainerRequestContext filterContext) {
        if (request != null) {
            log.debug("User principle: " + request.get().getUserPrincipal().getName());
        }
    }
}

Спасибо вам за помощь!

person Hacksaw    schedule 18.03.2015