hudi
hudi

Reputation: 16525

How to add chain of certificate in spring ws client request

I have simply spring ws client which sending request to some url:

  @SuppressWarnings("unchecked")
  private JAXBElement<O> sendSyncSoapRequest(final JAXBElement<I> req, final String iszrUrl) {
    if (iszrUrl != null) {
      return (JAXBElement<O>) this.wsTemplate.marshalSendAndReceive(iszrUrl, req);
    } else {
      return (JAXBElement<O>) this.wsTemplate.marshalSendAndReceive(req);
    }
  }

Now I need attach chain of certificate to the soap request. How should I do this ? Please help

Upvotes: 0

Views: 3794

Answers (2)

hudi
hudi

Reputation: 16525

So I already solve this problem. I need to create WebServiceMessageSender with new httpClient which contains sslFactory with my certificates:

WebServiceMessageSender sender = new HttpComponentsMessageSender(HttpClients.custom()
            .addInterceptorFirst(new RemoveSoapHeadersInterceptor()).setSSLSocketFactory(factory));
wsTemplate.setMessageSender(sender);        


// copy & paste from HttpComponentsMessageSender:
/**
 * HttpClient {@link org.apache.http.HttpRequestInterceptor} implementation that removes {@code Content-Length} and
 * {@code Transfer-Encoding} headers from the request. Necessary, because SAAJ and other SOAP implementations set
 * these headers themselves, and HttpClient throws an exception if they have been set.
 */
public static class RemoveSoapHeadersInterceptor implements HttpRequestInterceptor {



    @Override
    public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
        if (request instanceof HttpEntityEnclosingRequest) {
            if (request.containsHeader(HTTP.TRANSFER_ENCODING)) {
                request.removeHeaders(HTTP.TRANSFER_ENCODING);
            }
            if (request.containsHeader(HTTP.CONTENT_LEN)) {
                request.removeHeaders(HTTP.CONTENT_LEN);
            }
        }
    }
}

Upvotes: 1

Steve
Steve

Reputation: 9480

I'm not aware of any syntactic sugar in Spring for using certificate authentication on the client. However there may now be something I have missed. In the absence of someone else pointing out that there's a simple annotation that you can apply to your web service template, here's my thinking.

This isn't a fully step-by-step answer, but it should get you part way there. By using a WebServiceMessageCallback, you can modify the headers in your SOAP message before the message is sent. The code below demonstrates doing that to add a username and password to the headers.

You should be able to use the same mechanism to add certificates to the security headers in a similar manner. Take a look at the following document, which explains SOAP certificate-based authentication and shows example security headers for this on page 9.

http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0.pdf

Object response = getWebServiceTemplate().marshalSendAndReceive(
    exposureRequests,
    new WebServiceMessageCallback() {
    /**
     * The doWithMessage callback enables us to modify the message after it has
     * been built using the nice Spring/JAXB marshalling, just before it gets
     * sent out.
     */
    @Override
    public void doWithMessage(WebServiceMessage message)
        throws IOException, TransformerException {
            applySecurityHeaders(message, SOAP_ACTION);
        }
    }
);


/**
 * Add security headers to the outgoing message, so that the client is 
 * authenticated against the web service.
 */
private void applySecurityHeaders(WebServiceMessage message, String soapAction) 
        throws IOException, TransformerException {
    Assert.isInstanceOf(SoapMessage.class, message);

    SoapMessage soapMessage = (SoapMessage) message;
    soapMessage.setSoapAction(soapAction);
    SoapHeader header = soapMessage.getSoapHeader();
    Transformer transformer = TransformerFactory.newInstance().newTransformer();
    transformer.transform(getSecurityHeaderSource(), header.getResult());
    soapMessage.writeTo(new LoggingOutputStream(log));
}

/**
 * Returns the content required for a basic SOAP security header.
 */
private StringSource getSecurityHeaderSource() {
    return new StringSource(
            "<Security xmlns=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">\n "
                    + "<UsernameToken>\n"
                    + "<Username><![CDATA[" + username + "]]></Username>\n "
                    + "<Password><![CDATA[" + password + "]]></Password>\n "
                    + "</UsernameToken>\n"
                    + "</Security>\n");
}

Upvotes: 1

Related Questions