0

我想在 SOAP 通信中从客户端证书中检索公用名(CN) 属性。我正在使用 Spring WebServiceTemplate创建我的 web 服务端点。我已经按照示例实现了 WS 相互认证。

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

4

2 回答 2

0

幸运的是,我已经设法弄清楚了!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:Security标题,如下所示:

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。

于 2018-11-07T19:28:11.990 回答
0

还有另一种方法。

  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;
    }
于 2022-01-31T06:24:04.377 回答