0

I want to retrieve Common Name (CN) property from client certificate in SOAP communication. I'm using Spring WebServiceTemplate to create my webservice endpoint. I have already implemented WS mutual authentication following the example.

Is there any solution to obtain certificate details from client request by means of WebServiceTemplate or some other library?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459

2 Answers2

0

Fortunately, I have managed to figure it out! Spring WS provides very convenient way to retrieve the X509Certificate.

Normally, You have an endpoint like this:

@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;
    }
}

However, Spring allows to add additional parameters the method annotated as @PayloadRoot. It can be a MessageContext instance.

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

Then You will be able to obtain the wsse:Security header as follows:

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

Now get the right content of BinarySecurityToken tag:

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

At the end, you should recreate the X509Certificate by passing binarySecurityToken as its constructor parameter. Later You can extract CN by many different ways for example by means of LDAP utlis.

0

There is another way.

  1. Create AbstractSoapInterceptor with this body :
    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. Register it in configuration of endpoint :
    @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;
    }