javaapache-camelhttpclientntlmntlmv2

Call NTLMv2 secured endpoint via Apache Camel


I am using Apache Camel 2.19 and I am able to use NTLMv1 when calling my endpoint using camel-http module that supports NTLMv1 out of the box:

from("activemq:{{queue.feedback}}")
    .to("http://localhost:8888/ntlm/secured?authMethodPriority=NTLM 
                 &authMethod=NTLM&authUsername=Zaphod
                 &authPassword=Beeblebrox&authDomain=Minor
                 &authHost=LightCity")

The problem is that I can't figure out how to make a request using NTLMv2. The official documentation states that:

Note: camel-http is based on HttpClient v3.x and as such has only limited support for what is known as NTLMv1, the early version of the NTLM protocol. It does not support NTLMv2 at all. camel-http4 has support for NTLMv2.

When I try to use camel-http4 it does just nothing:

from("activemq:{{queue.feedback}}")
    .to("http4://localhost:8888/ntlm/secured?authMethodPriority=NTLM 
                 &authMethod=NTLM&authUsername=Zaphod
                 &authPassword=Beeblebrox&authDomain=Minor
                 &authHost=LightCity")

It seems that camel-http4 is not aware of NTLM at all. I tried to investigate camel-http4 repo on GitHub and I couldn't find anything related to NTLM besides the documentation.

Any ideas of how can I use NTLMv2 in Camel 2.19 (other versions of Camel may be a good fit as well)?


Solution

  • The problem was in camel-http4 component. By default, it uses InputStreamEntity which is not a repeatable implementation of HttpEntity entity meaning that once you read a stream - it's closed and you can't read it again. This causes a failure in MainClientExec:

    if (execCount > 1 && !RequestEntityProxy.isRepeatable(request)) {
        throw new NonRepeatableRequestException("Cannot retry request with a non-repeatable request entity.");
    }
    

    This seems to be a bug, therefore the workaround is to convert InputStreamEntity to the ByteArrayEntity (which is repeatable) just before sending the request:

    @Component
    public class NtlmProcessor implements Processor {
    
        @Override
        public void process(Exchange exchange) throws Exception {
            HttpEntity httpEntity = exchange.getIn().getBody(HttpEntity.class);
    
            byte[] bytes = EntityUtils.toByteArray(httpEntity);
    
            ByteArrayEntity byteArrayEntity = new ByteArrayEntity(bytes, ContentType.get(httpEntity));
    
            exchange.getOut().setBody(byteArrayEntity);
        }
    }