Azure中的Spring Boot-请求标头中的客户端证书 [英] Spring Boot in Azure - Client Certificate in Request Header

查看:139
本文介绍了Azure中的Spring Boot-请求标头中的客户端证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们当前在Spring Boot应用程序中实现了相互身份验证,需要将其部署在Azure中. Azure的负载平衡器在请求标头字段"X-ARR-ClientCert"中重定向客户端证书(Base64编码),而Spring无法在该位置找到它. =>身份验证失败

We currently implemented mutual authentication in our Spring Boot application and need to deploy it in Azure. Azure's loadbalancer redirects the client certificate (Base64 encoded) in the request header field "X-ARR-ClientCert" and Spring is not able to find it there. => Authentication fails

Microsoft文档显示了如何在.NET应用程序中处理此问题:

The microsoft documentation shows how to handle this in a .NET application: https://docs.microsoft.com/en-gb/azure/app-service-web/app-service-web-configure-tls-mutual-auth

我试图从OncePerRequestFilter的标头中提取证书,并将其设置为这样的请求:

I tried to extract the certificate from the header in an OncePerRequestFilter and set it to the request like this:

public class AzureCertificateFilter extends OncePerRequestFilter {
    private static final Logger LOG = LoggerFactory.getLogger(AzureCertifacteFilter.class);
    private static final String AZURE_CLIENT_CERTIFICATE_HEADER = "X-ARR-ClientCert";
    private static final String JAVAX_SERVLET_REQUEST_X509_CERTIFICATE = "javax.servlet.request.X509Certificate";
    private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----\n";
    private static final String END_CERT = "\n-----END CERTIFICATE-----";

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        X509Certificate x509Certificate = extractClientCertificate(httpServletRequest);

        // azure redirects the certificate in a header field
        if (x509Certificate == null && StringUtils.isNotBlank(httpServletRequest.getHeader(AZURE_CLIENT_CERTIFICATE_HEADER))) {
            String x509CertHeader = BEGIN_CERT + httpServletRequest.getHeader(AZURE_CLIENT_CERTIFICATE_HEADER) + END_CERT;

            try (ByteArrayInputStream certificateStream = new ByteArrayInputStream(x509CertHeader.getBytes())) {
                X509Certificate certificate = (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(certificateStream);
                httpServletRequest.setAttribute(JAVAX_SERVLET_REQUEST_X509_CERTIFICATE, certificate);
            } catch (CertificateException e) {
                LOG.error("X.509 certificate could not be created out of the header field {}. Exception: {}", AZURE_CLIENT_CERTIFICATE_HEADER, e.getMessage());
            }
        }

        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }

    private X509Certificate extractClientCertificate(HttpServletRequest request) {
        X509Certificate[] certs = (X509Certificate[]) request.getAttribute(JAVAX_SERVLET_REQUEST_X509_CERTIFICATE);

        if (certs != null && certs.length > 0) {
            LOG.debug("X.509 client authentication certificate:" + certs[0]);
            return certs[0];
        }

        LOG.debug("No client certificate found in request.");
        return null;
    }
}

但是这在Spring过滤器链中稍后会失败,但以下情况除外:

But this fails later in the Spring filter chain with the following exception:

sun.security.x509.X509CertImpl cannot be cast to [Ljava.security.cert.X509Certificate; /oaa/v1/spaces

配置如下:

@Override
public void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("**/docs/restapi/**").permitAll()
        .anyRequest().authenticated()
        .and()
        .httpBasic()
        .disable()
        .addFilterBefore(new AzureCertificateFilter(), X509AuthenticationFilter.class)
        .x509()
        .subjectPrincipalRegex("CN=(.*?)(?:,|$)")
        .userDetailsService(userDetailsService());
}

推荐答案

我应该更仔细地阅读该异常:

I should have read the exception more carefully:

sun.security.x509.X509CertImpl cannot be cast to [Ljava.security.cert.X509Certificate; /oaa/v1/spaces

我必须像这样设置一系列证书:

I had to set an array of certificates like this:

httpServletRequest.setAttribute(JAVAX_SERVLET_REQUEST_X509_CERTIFICATE, new X509Certificate[]{x509Certificate});

这篇关于Azure中的Spring Boot-请求标头中的客户端证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆