Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CXF Fault interceptor: log useful information

Tags:

cxf

soapfault

I would like to log some information in case of fault. In particular I'd like to log the ip address and port of the client contacting the server, the username if the security in active, and, if possible, also the incoming message.

I added an interceptor in the getOutFaultInterceptors chain of the endpoint, but in the handleMessage I don't know which properties I can use.

Some ideas?

Thank you

like image 681
Francesco Avatar asked Nov 28 '25 08:11

Francesco


2 Answers

In your endpoint xml definition, you could add the following to log incoming messages:

<bean id="logInInterceptor" 
    class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<jaxws:inInterceptors>
    <ref bean="logInInterceptor"/>
</jaxws:inInterceptors>

and then use the bus to limit how many characters you want logged:

<cxf:bus>
    <cxf:features>
        <cxf:logging limit="102400"/>
    </cxf:features>
<cxf:bus>

You haven't mentioned what your method of authentication is, so ff you are using an implementation of UsernameTokenValidator, you could log the incoming username there.

To log details like the client's ip address and port, extend LoggingInInterceptor, then use the following code in handleMessage():

handleMessage() {
    HttpServletRequest request =
            (HttpServletRequest)message.get(AbstractHTTPDestination.HTTP_REQUEST);
    if (null != request) {              
        String clientAddress = request.getRemoteAddr();
        int remotePort = request.getRemotePort();
        // log them
    }
}

Also have a look at this thread.

like image 158
Jeshurun Avatar answered Dec 02 '25 03:12

Jeshurun


I solved in this way

public FaultInterceptor() {
    super(Phase.MARSHAL);
}

public void handleMessage(SoapMessage message) throws Fault {
    Fault fault = (Fault) message.getContent(Exception.class);
    Message inMessage = message.getExchange().getInMessage();
    if (inMessage == null) return;

    String xmlMessage = null;
    InputStream is = inMessage.getContent(InputStream.class);
    String rawXml = null;
    if (is != null) {
        rawXml = is.toString();
    }

    String username = null;
    if (rawXml != null && rawXml.length() > 0) {
        try {
            XPath xpath = XPathFactory.newInstance().newXPath();
            XPathExpression xpathExpression;

            xpathExpression = xpath.compile("//*[local-name()=\'Envelope\']/*[local-name()=\'Header\']/*[local-name()=\'Security\']" +
                    "/*[local-name()=\'UsernameToken\']/*[local-name()=\'Username\']");

            InputSource source = new InputSource(new StringReader(rawXml));

            username = xpathExpression.evaluate(source);
        } catch (XPathExpressionException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        xmlMessage = XMLUtils.prittyPrinter(is.toString());
    }

    String clientAddress = "<unknown>";
    int clientPort = -1;
    HttpServletRequest request = (HttpServletRequest)inMessage.get(AbstractHTTPDestination.HTTP_REQUEST); 
    if (null != request) {               
        clientAddress = request.getRemoteAddr(); 
        clientPort = request.getRemotePort();
    }

    logger.warn("User: " + username + " [" + clientAddress + ":" + clientPort + "] caused fault: " + fault +
            "\nMessage received: \n" + xmlMessage);



}

I found the "inMessage" property and on it I found the original message (and I can retrieve the username) and the "request" from which I retrieved the host and port.

Thank you.

like image 40
Francesco Avatar answered Dec 02 '25 03:12

Francesco



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!