如何在 WebServiceTemplate 中检索有关证书的信息?

How to retrieve information about certificate in WebServiceTemplate?

我想从 SOAP 通信中的客户端证书中检索 Common Name (CN) 属性。我正在使用 Spring WebServiceTemplate 创建我的网络服务端点。我已经在 example 之后实现了 WS 相互身份验证。

是否有任何解决方案可以通过 WebServiceTemplate 或其他库从客户端请求中获取证书详细信息

还好我想通了! Spring WS 提供了非常方便的方法来检索 X509Certificate。

通常,您有这样的端点:

@Endpoint
public class CountryEndpoint {
    private static final String NAMESPACE_URI = "http://spring.io/guides/gs-producing-web-service";

    ...

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
    @ResponsePayload
    public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
        //method body here
        return response;
    }
}

但是,Spring 允许添加额外的参数,注释为 @PayloadRoot 的方法。它可以是 MessageContext 实例。

public GetCountryResponse getCountry(@RequestPayload MessageContext context, @RequestPayload GetCountryRequest request)`

那么您将能够获得wsse:Securityheader如下:

WebServiceMessage webServiceMessageRequest = context.getRequest(); 
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) webServiceMessageRequest;
SOAPMessage doc = saajSoapMessage.getSaajMessage();
Element elem = WSSecurityUtil.getSecurityHeader(doc.getSOAPPart(), "");

现在获取 BinarySecurityToken 标签的正确内容:

String binarySecurityToken = elem.getElementsByTagName("BinarySecurityToken").item(0).getTextContent(); 

最后,您应该通过将 binarySecurityToken 作为其构造函数参数传递来重新创建 X509Certificate。稍后您可以通过许多不同的方式提取 CN,例如通过 LDAP utlis。

还有一个办法。

  1. 用这个主体创建 AbstractSoapInterceptor :
    private final static QName SECURITY_QNAME = new QName("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", "");
    private static CertificateFactory certFactory;
    public xxx() throws CertificateException {
        super(Phase.PRE_PROTOCOL);
        certFactory = CertificateFactory.getInstance("X.509");
    }
    @SneakyThrows
    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        SoapHeader header = (SoapHeader) message.getHeader(SECURITY_QNAME);
        Node binarySignatureTag = ((Element) header.getObject()).getFirstChild();
        BinarySecurity token = new X509Security((Element) binarySignatureTag, new BSPEnforcer());
        InputStream in = new ByteArrayInputStream(token.getToken());
        X509Certificate cert = (X509Certificate) certFactory.generateCertificate(in);
    }
  1. 在端点配置中注册它:
    @Bean
    public Endpoint endpoint() throws CertificateException {
        EndpointImpl endpoint = new EndpointImpl(springBus(), xxxPortType());
        endpoint.setServiceName(xxxService().getServiceName());
        endpoint.publish("/xxxx");
        endpoint.getInInterceptors().add(new xxx());
        return endpoint;
    }