【问题标题】:Spring Boot in Azure - Client Certificate in Request HeaderAzure 中的 Spring Boot - 请求标头中的客户端证书
【发布时间】:2017-08-02 09:01:07
【问题描述】:

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

微软文档展示了如何在 .NET 应用程序中处理这个问题:https://docs.microsoft.com/en-gb/azure/app-service-web/app-service-web-configure-tls-mutual-auth

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

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 过滤器链中稍后会失败,但有以下异常:

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());
}

【问题讨论】:

    标签: spring azure spring-boot spring-security mutual-authentication


    【解决方案1】:

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

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

    我必须像这样设置一个证书数组:

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

    【讨论】:

      猜你喜欢
      • 2017-01-21
      • 2012-06-28
      • 2021-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-15
      • 2018-11-01
      • 2013-11-20
      相关资源
      最近更新 更多