Getting to know Apache CXF Interceptors has been interesting. On one hand, the concept of chaining interceptors, each modifying the message in some manner until the final product has been finished, is relatively simple. As with most frameworks, the devil is in the details.
I am currently working on a project that requires the use of both transport-level (SSL) and message-level encryption for SOAP messages. When something goes wrong during the inbound message handling, I want to log the request away so it can be analyzed later and appropriate action taken, if required (like reprocessing the request). I couldn't find any easy way to handle this.
- the request comes in as an encrypted message, the results being a marshalled object. Do I really want to convert the marshalled object back into XML again? I can, but what if the object wasn't successfully marshalled because something went awry with the inbound message handling?
- turn logging on. Sure. CXF has a wonderfully easy way to turn logging on, but the message is still encrypted. I would need to remove the WS-Policy configuration from my service's WSDL and rebuild my client and service again in order to see the message in plain text.
I just wasn't happy with those approaches. What I really wanted was to use a custom CXF Interceptor to grab the decrypted SOAP message, which seems like the right approach. So I rolled up my sleeves and started plowing into CXF Interceptors.
Some of the basics I've picked up with CXF Interceptors include:
- each request has both inbound and outbound processing, each with it's own "chain" of interceptors to, respectively, create and process the request.
- each CXF Interceptor is associated with a particular CXF phase; one CXF Interceptor does not fit all phases. You specify the phase where you want to peek in at the message.
- you configure your custom CXF Interceptor to precede or follow an existing CXF Interceptor that is in the chain.
- the Message object can be taken off of the InputStream (or OutputStream for requests being created), but this means once it's taken off, it's no longer there. So if you want the next interceptor to pick up where its supposed to, you will need to push that content back on the stream.
- if you want something like a request session, use the Message object and a unique key; along with the message being processed, it will also be persisted throughout the chain.
So, back to my challenge with getting the decrypted payload, after playing around and exploring the many standard CXF Interceptors, I finally discovered org.apache.cxf.interceptor.DocLiteralInInterceptor was likely what I wanted. It was riddled with XML parsing references; it smelled like it was the right place.
For your pleasure, I am providing my Java code for the CXF Interceptor:
com.reliacode.DumpMessageInterceptor.java
And you will need something like this in your Spring configuration in order for the custom CXF Interceptor to be recognized:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:cxf="http://cxf.apache.org/core"
xmlns:sec="http://cxf.apache.org/configuration/security"
xmlns:http="http://cxf.apache.org/transports/http/configuration"
xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration"
xsi:schemaLocation="
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd
http://cxf.apache.org/configuration/security
http://cxf.apache.org/schemas/configuration/security.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration
http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/transports/http-jetty/configuration
http://cxf.apache.org/schemas/configuration/http-jetty.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="dumpMessageInterceptor" class="edu.ucmerced.ucpath.common.DumpMessageInterceptor"/>
...
<jaxws:endpoint ...>
...
<jaxws:inInterceptors>
<ref bean="dumpMessageInterceptor"/>
</jaxws:inInterceptors>
</jaxws:endpoint>
</beans>
I found a similar approach in https://stackoverflow.com/questions/40019208/how-to-enable-debug-logging-in-apache-cxf-before-encrypting
ReplyDelete