Как защитить некоторые конечные точки с помощью mTL, а некоторые с помощью JWT?JAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Как защитить некоторые конечные точки с помощью mTL, а некоторые с помощью JWT?

Сообщение Anonymous »

У меня есть приложение Spring Boot (3.0.5) с тремя наборами API:
  • — вызывается клиентским приложением пользовательского интерфейса — использует аутентификацию на основе JWT.
  • Код: Выделить всё

    /integration/**
    — вызываются другим приложением — должны быть защищены аутентификацией клиента.
  • Остальное — общедоступно.
Я устанавливаю для server.ssl.client-auth значение, так как мне не нужно, чтобы все мои конечные точки следовали аутентификации X502.
Я сделал это после нескольких сообщений здесь с похожими вопросами и придумал систему безопасности. конфигурация, как показано ниже. Все работает так, как и ожидалось, но, как видите, мне придется выполнить множество дополнительных проверок. Есть ли лучший способ добиться этого?
Эта конфигурация устанавливает /api/** для использования проверки JWT, а остальная часть открыта для публичного доступа.

Код: Выделить всё

@Bean
public SecurityFilterChain configureSecurityFilters(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(a -> a
.requestMatchers(new AntPathRequestMatcher("/api/**")).authenticated()
.anyRequest().permitAll()
)
.csrf().disable()
.addFilterBefore(jwtValidationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
Это моя вторая конфигурация для пользовательской проверки вызовов API /integration/**.

Код: Выделить всё

@Bean
@Order(1)
public SecurityFilterChain x502Config(HttpSecurity http, HttpServletRequest request) throws Exception {

http
.securityMatcher("/integration/**")
.csrf().disable()
.addFilterBefore(customX509AuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
.authorizeHttpRequests()
.anyRequest().permitAll();
return http.build();
}
А это пользовательский фильтр, который проверяет, произошла ли проверка сертификата клиента и имеется ли в контексте действительный сертификат X509:

Код: Выделить всё

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.NegatedRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.Arrays;

@Component
public class CustomX509AuthenticationFilter extends OncePerRequestFilter {

@Value("${server.ssl.client-auth}")
private String mutualTLSConfig;

@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
X509Certificate[] clientCertificates = (X509Certificate[]) request.getAttribute(
"jakarta.servlet.request.X509Certificate");
if (isMutualTLSEnabled() && (clientCertificates == null
|| clientCertificates.length == 0)) {
response.sendError(HttpStatus.UNAUTHORIZED.value(), HttpStatus.UNAUTHORIZED.name());
return;
} else if (isMutualTLSEnabled()) {
X509Certificate clientCertificate = clientCertificates[0];
String username = extractUsernameFromCertificate(clientCertificate);
Authentication authentication = new UsernamePasswordAuthenticationToken(username, "",
Arrays.asList());
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}

private String extractUsernameFromCertificate(X509Certificate certificate) {
Principal principal = certificate.getSubjectDN();
String name = principal.getName();
int startIndex = name.indexOf("CN=") + 3;
int endIndex = name.indexOf(",", startIndex);
if (endIndex == -1) {
endIndex = name.length();
}
return name.substring(startIndex, endIndex);
}

// Ignore this validation if "none" is set (dev purposes)
// "need" will never be used in this application (because if used, client-auth will be applied to all requests)
private boolean isMutualTLSEnabled() {
return StringUtils.isNotEmpty(mutualTLSConfig) &&  mutualTLSConfig.equalsIgnoreCase("want");
}

// I had to add this, otherwise all requests goes through this - which means the "securityMatcher" configuration is not applied properly.

@Override protected boolean shouldNotFilter(HttpServletRequest request) {
RequestMatcher matcher = new NegatedRequestMatcher(new AntPathRequestMatcher("/integration/**"));
return matcher.matches(request);
}
}
У меня также есть второй фильтр для проверки JWT (

Код: Выделить всё

jwtValidationFilter
) для конечных точек /api/**.

Код: Выделить всё

@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res,
FilterChain chain) throws IOException, ServletException {

final String requstUri = req.getRequestURI();
final String jwtAuthToken = getCookieValue(req, AUTH_TOKEN_COOKIE_NAME);
// Validates the token and set the authentication in SecurityContextHolder
....
....
UsernamePasswordAuthenticationToken authentication = getAuthentication(jwtToken, res);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
Эта конфигурация работает должным образом, но у меня такое ощущение, что моя конфигурация безопасности не идеальна.
Использование JDK 17, Spring Boot 3.0.5 .

Подробнее здесь: https://stackoverflow.com/questions/761 ... e-with-jwt
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»