Issue with Apache Camel https rest api with username and password - apache-camel

I have the following piece of code, I've built for connecting to a "https" REST end point using Apache Camel. The problem is that I get 401 error if this is run.
from("timer:learnTimer?period=100s")
.to("log:?level=INFO&showBody=true")
.setHeader("currentTime", simple(currentTime))
.setHeader(Exchange.CONTENT_TYPE,constant("application/json"))
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.setHeader(Exchange.HTTP_URI, simple("https://xxxxxx/api/siem/offenses?filter=status%20%3D%20%22OPEN%22%20and%20start_time%20%3E%201543647979000?&authMethod=Basic&authUsername=xxxxx&authPassword=xxxxx"))
.to("https://xxxxxxx/api/siem/offenses?filter=status%20%3D%20%22OPEN%22%20and%20start_time%20%3E%201543647979000?&authMethod=Basic&authUsername=xxxx&authPassword=xxxx").convertBodyTo(String.class)
.to("log:?level=INFO&showBody=true");
The error I am receiving is:
Stacktrace
org.apache.camel.http.common.HttpOperationFailedException: HTTP operation failed invoking https://xx.xx.xx.xx/api/siem/offenses?filter=status+%3D+%22OPEN%22+and+start_time+%3E+1543647979000%3F with statusCode: 401
at org.apache.camel.component.http.HttpProducer.populateHttpOperationFailedException(HttpProducer.java:243)
at org.apache.camel.component.http.HttpProducer.process(HttpProducer.java:165)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:148)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:197)
at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:79)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
15:16| WARN | CamelLogger.java 213 | Error processing exchange. Exchange[ID-zabbixproxy-node2-1544019394005-0-1]. Caused by: [org.apache.camel.http.common.HttpOperationFailedException - HTTP operation failed invoking https://xx.xx.xx.xx/api/siem/offenses?filter=status+%3D+%22OPEN%22+and+start_time+%3E+1543647979000%3F with statusCode: 401]
org.apache.camel.http.common.HttpOperationFailedException: HTTP operation failed invoking https://10.96.40.66/api/siem/offenses?filter=status+%3D+%22OPEN%22+and+start_time+%3E+1543647979000%3F with statusCode: 401
at org.apache.camel.component.http.HttpProducer.populateHttpOperationFailedException(HttpProducer.java:243)
at org.apache.camel.component.http.HttpProducer.process(HttpProducer.java:165)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:148)

Are you sure you should set these header before making an rest call?
un necessary request headers in IN Message may cause some issue.
Exchange exchange = ExchangeBuilder.anExchange(camelContext)
.withHeader("").withProperty("")
.withPattern(ExchangePattern...)
.withHeader(Exchange.HTTP_METHOD, HttpMethod.GET)
.build();
producer.send("the end point to rest",exchange);
// producer is ProducerTemaplte
In above code you can set The ExchangePattern and required Headers and property (if only needed).
Hope this helps.

Related

Apache Camel return producer errors

I have a simple proxy configuration like the following:
from("netty-http://0.0.0.0:8080/xyz")
.toD("netty-http:" + "https://abc/xyu")
.process(this::processResponse);
But when abc service return 400 with readable errors, camel return own exception:
org.apache.camel.component.netty.http.NettyHttpOperationFailedException: Netty HTTP operation failed invoking
What can I do to simply return the error from producer service?
You can try setting the throwExceptionOnFailure option to false. Http components in camel have this enabled on default, probably so that failures can easily be caught and handled like any other exceptions in camel.
When its enabled you can get the Exception and details about the exception through Exchange properties which in this chase you can probably cast to NettyHttpOperationFailedException to get more information about it.
Exception cause = exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Exception.class);
I had a similar issue with jetty (Apache-Camel / Camel-Jetty / Don't return exception-stack-trace in case of 401 response)
In my case the options bridgeEndpoint=true and throwExceptionOnFailure=false solved the issue (except for http 401)
from("netty-http://0.0.0.0:8080/xyz")
.toD("netty-http:" + "https://abc/xyu?bridgeEndpoint=true&throwExceptionOnFailure=false")
.process(this::processResponse);

Camel REST DSL - Premature end of Content-Length delimited message body

I'm using Camel Rest DSL to build endpoints to use as proxies between different networks.
I have created 2 endpoints. Below the code:
First:
restConfiguration().host("localhost").component("undertow").bindingMode(RestBindingMode.off);
rest("/endpoint?{1param}&{2param}")
.get("/")
.route().routeId("Ednpoint1")
.autoStartup(true)
.setProperty("uri", simple("http4://0.0.0.0:8080/endpoint?1param=${header.1param}&2param=${header.2param}"))
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.removeHeaders("CamelHttp*")
.toD("${header.uri}").endRest().responseMessage().message("${body}");
Second:
restConfiguration().host("localhost").component("undertow").bindingMode(RestBindingMode.off);
rest("/endpoint?{param1}&{param2}")
.get("/")
.route().routeId("Endpoint2")
.autoStartup(true)
.setProperty("uri", simple("http4://endpoint-destionation/service?dhi=${header.param1}&dhf=${header.param2}"))
.setHeader(Exchange.HTTP_METHOD, constant("GET"))
.removeHeaders("*")
.toD("${header.uri}").endRest().responseMessage().message("${body}");
I'm currently getting the following error:
org.apache.http.ConnectionClosedException: Premature end of Content-Length delimited message body (expected: 146541; received: 54482
at org.apache.http.impl.io.ContentLengthInputStream.read(ContentLengthInputStream.java:180)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:137)
at org.apache.http.conn.EofSensorInputStream.read(EofSensorInputStream.java:150)
at org.apache.camel.util.IOHelper.copy(IOHelper.java:219)
at org.apache.camel.util.IOHelper.copy(IOHelper.java:174)
at org.apache.camel.util.IOHelper.copy(IOHelper.java:170)
at org.apache.camel.component.http4.HttpProducer.doExtractResponseBodyAsStream(HttpProducer.java:414)
at org.apache.camel.component.http4.HttpProducer.extractResponseBody(HttpProducer.java:397)
at org.apache.camel.component.http4.HttpProducer.populateResponse(HttpProducer.java:242)
at org.apache.camel.component.http4.HttpProducer.process(HttpProducer.java:203)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.SendDynamicProcessor$1.doInAsyncProducer(SendDynamicProcessor.java:178)
at org.apache.camel.impl.ProducerCache.doInAsyncProducer(ProducerCache.java:445)
at org.apache.camel.processor.SendDynamicProcessor.process(SendDynamicProcessor.java:160)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
at org.apache.camel.processor.DelegateAsyncProcessor.process(DelegateAsyncProcessor.java:97)
at org.apache.camel.component.undertow.UndertowConsumer.handleRequest(UndertowConsumer.java:126)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:360)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:830)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
at java.lang.Thread.run(Thread.java:748)
Is there a way to bypass this problem with camel? Thanks!
Found the issue.
In my case, I use Wildfly 13 to deploy my Camel Routes.
The problem is with the field Send Buffer inside HTTP Listener Undertow component.
Configuration⇒Subsystems⇒Web (Undertow)⇒Server ⇒default-server
Listener⇒HTTP Listener
I change to value to 10000000 (KBytes), and now is working fine.

java.io.IOException: Authorization loop detected on Conduit in Apache Camel

org.apache.cxf.interceptor.Fault: Could not send Message.
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:514)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:416)
at org.apache.camel.component.cxf.CxfProducer.process(CxfProducer.java:120)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:141)
at org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:77)
at org.apache.camel.processor.interceptor.TraceInterceptor.process(TraceInterceptor.java:163)
at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:460)
at org.apache.camel.spring.spi.TransactionErrorHandler.processByErrorHandler(TransactionErrorHandler.java:218)
at org.apache.camel.spring.spi.TransactionErrorHandler.process(TransactionErrorHandler.java:99)
Camel version - 2.16.1.
Caused by: java.io.IOException: Authorization loop detected on Conduit "webserviceURL here..."
trying to call a WS published, from "route id=1" which is available in "routeContext id=1", from "route id=2" which is defined in "routeContext id=2"..
WS - defined using CXF-endpoint..
Both the "routeContext" has "http:conduit" defined..
Tried removing one of it..Not successful..
The solution is,
you have to be more specific of the scope of http:conduit, can be acheived by providing the specific name to the configured conduit, eg: http:conduit name="abcd.http", will be available only to the 'abcd', here abcd~=Webservice

camel with netty4-http - EncoderException

I'm using camel 2.14.0 with netty4-http
and I get the following exception.
the scenario is this:
I have a route that sends a request, waits for the response (inOut) and then sends another request.
the first request works, and then the second one fails.
also, if I do it quickly enough after the failure - the first request will also fail.
while debugging a bit (HttpObjectEncoder) - I saw that in the working flow the state of the request is: state = ST_INIT (0)
and in the request that failed it is: ST_CONTENT_NON_CHUNK (1)
which causes the illegal state when the type of message is HttpMessage
is this a bug or is there anything I can configure to fix it?
Caused by: io.netty.handler.codec.EncoderException: java.lang.IllegalStateException: unexpected message type: DefaultFullHttpRequest
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:107)
at io.netty.channel.CombinedChannelDuplexHandler.write(CombinedChannelDuplexHandler.java:192)
at io.netty.channel.AbstractChannelHandlerContext.invokeWrite(AbstractChannelHandlerContext.java:658)
at io.netty.channel.AbstractChannelHandlerContext.access$2000(AbstractChannelHandlerContext.java:32)
at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.write(AbstractChannelHandlerContext.java:939)
at io.netty.channel.AbstractChannelHandlerContext$WriteAndFlushTask.write(AbstractChannelHandlerContext.java:991)
at io.netty.channel.AbstractChannelHandlerContext$AbstractWriteTask.run(AbstractChannelHandlerContext.java:924)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalStateException: unexpected message type: DefaultFullHttpRequest
at io.netty.handler.codec.http.HttpObjectEncoder.encode(HttpObjectEncoder.java:63)
at io.netty.handler.codec.http.HttpClientCodec$Encoder.encode(HttpClientCodec.java:106)
at io.netty.handler.codec.MessageToMessageEncoder.write(MessageToMessageEncoder.java:89)
... 10 more
I managed to identify the problem:
the first request I sent was a GET request with null body.
in the class org.apache.camel.component.netty4.http.NettyHttpProducer -
the method getRequestBody(Exchange exchange) is creating the actual request object from the exchange.
in it - the method "toNettyRequest" in class org.apache.camel.component.netty4.http.DefaultNettyHttpBinding
checks if the body is null, and if so - it is creating a DefaultHttpRequest, and not DefaultHttpFullRequest
when the request reaches the encoder as a result of a writeAndFlush call - the encoder does not clean its state because of this part of the code:
if (msg instanceof LastHttpContent) {
state = ST_INIT;
}
the DefaultHttpRequest is not instanceof LastHttpContent, so the state remains ST_CONTENT_NON_CHUNK and the next request will get an IllegalStateException because the state is not ST_INIT
this bug did not exist in netty-http, it only happened when I moved to use netty4-http
the workaround is simple - use an empty String ("") as body

CXF - catching/handling HTTP exceptions

This is rather a basic cxf usage question. How/where can we catch the actual HTTP exception/error. I kind of followed the Interceptor/MessageObserver concept but could not capture the HTTP error using them.
I see this error in the log4j log file.
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response
'401: Unauthorized' when communicating with http://10.107.172.79/test/_vti_bin/lists.asmx
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1502)
at org.apache.cxf.transpot.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1448)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1356)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:614)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62)
... 9 more
Only javax.xml.ws.WebServiceException with "Could not send Message."
message is thrown while calling the service
try{
GetListCollectionResult result = port.getListCollection();
}catch (javax.xml.ws.WebServiceException excep){
}
This is how we call the service.
To provide NTLM credentials:
Authenticator.setDefault( extended class of Authenticator);
Create the service.
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(ListsSoap.class);
factory.setAddress(list_url);
ListsSoap port = (ListsSoap) factory.create();
Update the conduit.
..
Client client = ClientProxy.getClient(port);
HTTPConduit http = (HTTPConduit) client.getConduit();
HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
httpClientPolicy.setConnectionTimeout(36000);
httpClientPolicy.setAllowChunking(false);
http.setClient(httpClientPolicy);
Call service and get the result.
GetListCollectionResult result = port.getListCollection();
Nevermind, I found the answer in the CXF mailing list.
excep.getCause()
gives access to the underlying exception, in my case it is the HTTP Transport exception.

Resources