Пользовательский клапан аутентификации SAML в Spring Boot Embedded Tomcat — не применять к конечным точкам привода

Старый общий метод Tomcat

У меня есть собственный клапан аутентификации SAML 2.0, который я использую в настоящее время на некоторых автономных веб-серверах Tomcat для реализации единого входа.

Чтобы реализовать это, мы добавляем клапан в context.xml сервера tomcat, например (некоторые значения используются вместо реальных значений):

<Context>
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

    <Valve className="example.CustomIdpValve"
        idp="default" issuerName="SAMLIssuer" 
        idpUrl="https://example.idp.com/sso/"
        certificatePath="${catalina.base}/conf/idp.cer"
    />
</Context>

Затем мы будем контролировать, какие конечные точки должны быть защищены на основе файла web.xml.

Новый метод Spring Boot Embedded Tomcat

Теперь мы используем этот клапан в автономных приложениях с пружинной загрузкой, работающих через встроенный tomcat с пружинной загрузкой. Мы добавляем один и тот же пользовательский клапан аутентификации в эти приложения через конфигурацию Java:

@Bean
public ConfigurableServletWebServerFactory embeddedServletContainerCustomizer() {
    final CustomIdpValve customIdpValve = new CustomIdpValve();
    final Valve singleSignOnValve = new SingleSignOn();

    final TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
    factory.addContextValves(customIdpValve);
    factory.addContextValves(singleSignOnValve);

    return factory;
}

Затем мы требуем, чтобы определенные роли были включены в UserPrincipal для доступа к приложению. Это снова настраивается с помощью конфигурации Java (роли извлекаются из application.properties):

@Component
public class WebAppInitializer implements ServletContextInitializer  {

    private final String[] roles;

    public WebAppInitializer(@Value("${tomcat.embedded.roles}") final String[] roles) {
        this.roles = roles;
    }

    public void onStartup(final ServletContext container) {
        final ServletRegistration.Dynamic servlet = (ServletRegistration.Dynamic) container.getServletRegistration("default");
        servlet.setServletSecurity(new ServletSecurityElement(new HttpConstraintElement(ServletSecurity.TransportGuarantee.NONE, roles)));
        servlet.setServletSecurity(new ServletSecurityElement(new HttpConstraintElement(ServletSecurity.TransportGuarantee.CONFIDENTIAL, roles)));
    }
}

Проблема

Это прекрасно работает — новые приложения весенней загрузки будут перенаправлять любой входящий запрос к IdP для аутентификации, который затем отправляет ответ SAML обратно на первоначально запрошенный URL-адрес, и страница загружается, как и ожидалось.

Проблема в том, что мы включили конечные точки привода Spring Boot, которым необходимо обойти эту аутентификацию. В частности, нам нужно, чтобы конечная точка проверки работоспособности /actuator/health была незащищенной, чтобы ее можно было использовать в качестве проверки готовности для kubernetes.

Я не могу определить способ применения этого ServletSecurity для каждого пути запроса, чтобы нам не требовалась аутентификация для любых запросов к пути /actuator/*.

Возможно ли что-то подобное?


person Andrew Mairose    schedule 31.07.2018    source источник


Ответы (1)


Нашел очень простое решение.

Если вы измените свойство management.server.port на порт, отличный от того, на котором работает ваш основной контекст приложения, spring boot автоматически создаст контекст дочернего приложения для конечных точек привода.

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

person Andrew Mairose    schedule 31.07.2018